mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-02 21:13:44 +00:00
Compare commits
78 Commits
on-waves/0
...
on-waves/0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ce50ba2f7 | ||
|
|
3f9b6a6539 | ||
|
|
b5bb75fbfd | ||
|
|
af5b88fb07 | ||
|
|
0366e67f78 | ||
|
|
c3f0aeee30 | ||
|
|
2413efa47b | ||
|
|
e6fd64d000 | ||
|
|
00d34cd8c6 | ||
|
|
58c5e587a5 | ||
|
|
13b24827d7 | ||
|
|
ba482438a0 | ||
|
|
4cc21eaa42 | ||
|
|
e9f8a258a8 | ||
|
|
5797ca85c1 | ||
|
|
2537b2f836 | ||
|
|
1168d13e0c | ||
|
|
588c423f12 | ||
|
|
088601004c | ||
|
|
55982ca9a7 | ||
|
|
91a035d2fb | ||
|
|
5ed2e3004b | ||
|
|
00460d3bc5 | ||
|
|
dcb7ad3f2c | ||
|
|
74e7cc4c4a | ||
|
|
667cba9d28 | ||
|
|
6f926f0197 | ||
|
|
c98d67d592 | ||
|
|
43dbcfe2cf | ||
|
|
98d949b02f | ||
|
|
4f5421a482 | ||
|
|
c8fdf0c4b6 | ||
|
|
45473477f6 | ||
|
|
cd7bed5327 | ||
|
|
83594c1f2c | ||
|
|
7e1524644b | ||
|
|
3ec13ed3a8 | ||
|
|
11557ecd8c | ||
|
|
c737fbd4af | ||
|
|
24963554a8 | ||
|
|
c7bd29e6d7 | ||
|
|
137523ef7c | ||
|
|
0457b4b6da | ||
|
|
c372b1eb75 | ||
|
|
55228e31be | ||
|
|
db544db73a | ||
|
|
f49d616427 | ||
|
|
1eecb1689b | ||
|
|
f55fc02e87 | ||
|
|
6bb3065e6d | ||
|
|
3c30a4bb1f | ||
|
|
636c1cadd8 | ||
|
|
20f3d21665 | ||
|
|
889fd79511 | ||
|
|
7e25253b71 | ||
|
|
f90c8c9d75 | ||
|
|
08a366f11f | ||
|
|
c12bfa45a5 | ||
|
|
e320fc115a | ||
|
|
5bf8f95701 | ||
|
|
6989b57350 | ||
|
|
edd980619c | ||
|
|
2c362abfb4 | ||
|
|
f8e0838f7a | ||
|
|
ec2886d1bd | ||
|
|
865ba8b572 | ||
|
|
9be1b5495f | ||
|
|
7cf7d27d10 | ||
|
|
9002169dcd | ||
|
|
43242f8947 | ||
|
|
83961de565 | ||
|
|
19776f70a2 | ||
|
|
6233ab9859 | ||
|
|
0037badb02 | ||
|
|
054efe1ef2 | ||
|
|
68fc12d89b | ||
|
|
7eccf5b0a5 | ||
|
|
6d346d8931 |
@@ -4,7 +4,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
||||
SUBDIRS = include src tests
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = openbsc.pc libsccp.pc
|
||||
pkgconfig_DATA = openbsc.pc
|
||||
|
||||
BUILT_SOURCES = $(top_srcdir)/.version
|
||||
$(top_srcdir)/.version:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
dnl Process this file with autoconf to produce a configure script
|
||||
AC_INIT(openbsc, 0.3.99.19onwaves)
|
||||
AC_INIT(openbsc, 0.3.99.20onwaves)
|
||||
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
|
||||
|
||||
dnl kernel style compile messages
|
||||
@@ -15,7 +15,8 @@ dnl checks for libraries
|
||||
AC_SEARCH_LIBS(crypt, crypt,
|
||||
[LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.15)
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.23)
|
||||
PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.3)
|
||||
|
||||
dnl checks for header files
|
||||
AC_HEADER_STDC
|
||||
@@ -39,10 +40,8 @@ AM_CONFIG_HEADER(bscconfig.h)
|
||||
|
||||
AC_OUTPUT(
|
||||
openbsc.pc
|
||||
libsccp.pc
|
||||
include/openbsc/Makefile
|
||||
include/vty/Makefile
|
||||
include/sccp/Makefile
|
||||
include/Makefile
|
||||
src/Makefile
|
||||
tests/Makefile
|
||||
@@ -50,5 +49,4 @@ AC_OUTPUT(
|
||||
tests/gsm0408/Makefile
|
||||
tests/db/Makefile
|
||||
tests/channel/Makefile
|
||||
tests/sccp/Makefile
|
||||
Makefile)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SUBDIRS = openbsc vty sccp
|
||||
SUBDIRS = openbsc vty
|
||||
|
||||
noinst_HEADERS = mISDNif.h compat_af_isdn.h
|
||||
|
||||
@@ -6,8 +6,8 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
|
||||
bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \
|
||||
silent_call.h mgcp.h meas_rep.h rest_octets.h \
|
||||
system_information.h handover.h mgcp_internal.h \
|
||||
vty.h bssap.h bsc_msc.h bsc_nat.h bsc_msc_rf.h \
|
||||
bsc_msc_grace.h
|
||||
vty.h bssap.h bsc_msc.h bsc_nat.h osmo_bsc_rf.h \
|
||||
osmo_bsc_grace.h
|
||||
|
||||
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
|
||||
openbscdir = $(includedir)/openbsc
|
||||
|
||||
@@ -55,6 +55,8 @@ struct ipac_bcch_info {
|
||||
u_int8_t ca_list_si1[16];
|
||||
};
|
||||
|
||||
extern const struct value_string abis_nm_adm_state_names[];
|
||||
extern const struct value_string abis_nm_obj_class_names[];
|
||||
extern const struct tlv_definition nm_att_tlvdef;
|
||||
|
||||
/* PUBLIC */
|
||||
@@ -172,4 +174,7 @@ const char *nm_avail_name(u_int8_t avail);
|
||||
int nm_is_running(struct gsm_nm_state *s);
|
||||
void abis_nm_clear_queue(struct gsm_bts *bts);
|
||||
|
||||
|
||||
int abis_nm_vty_init(void);
|
||||
|
||||
#endif /* _NM_H */
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef BSC_MSC_RF
|
||||
#define BSC_MSC_RF
|
||||
|
||||
#include <osmocore/write_queue.h>
|
||||
|
||||
struct gsm_network;
|
||||
|
||||
struct bsc_msc_rf {
|
||||
/* the value of signal.h */
|
||||
int policy;
|
||||
struct bsc_fd listen;
|
||||
struct gsm_network *gsm_network;
|
||||
};
|
||||
|
||||
struct bsc_msc_rf_conn {
|
||||
struct write_queue queue;
|
||||
struct bsc_msc_rf *rf;
|
||||
};
|
||||
|
||||
struct bsc_msc_rf *bsc_msc_rf_create(const char *path, struct gsm_network *net);
|
||||
|
||||
#endif
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "mgcp.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sccp/sccp_types.h>
|
||||
#include <osmocom/sccp/sccp_types.h>
|
||||
|
||||
#include <osmocore/select.h>
|
||||
#include <osmocore/msgb.h>
|
||||
@@ -322,7 +322,7 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg);
|
||||
|
||||
void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc);
|
||||
int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]);
|
||||
int bsc_mgcp_extract_ci(const char *resp);
|
||||
uint32_t bsc_mgcp_extract_ci(const char *resp);
|
||||
|
||||
|
||||
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
|
||||
|
||||
@@ -6,302 +6,9 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <osmocore/msgb.h>
|
||||
#include <osmocore/protocol/gsm_08_08.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_N_REJECT = 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_T2 = 18,
|
||||
GSM0808_IE_CLASSMARK_INFORMATION_T3 = 19,
|
||||
GSM0808_IE_INTERFERENCE_BAND_TO_USE = 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_CONFIG_EVO_INDI = 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_CTRL_SUPPR = 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,
|
||||
};
|
||||
|
||||
/* GSM 08.08 3.2.2.11 Channel Type */
|
||||
enum gsm0808_chan_indicator {
|
||||
GSM0808_CHAN_SPEECH = 1,
|
||||
GSM0808_CHAN_DATA = 2,
|
||||
GSM0808_CHAN_SIGN = 3,
|
||||
};
|
||||
|
||||
enum gsm0808_chan_rate_type_data {
|
||||
GSM0808_DATA_FULL_BM = 0x8,
|
||||
GSM0808_DATA_HALF_LM = 0x9,
|
||||
GSM0808_DATA_FULL_RPREF = 0xa,
|
||||
GSM0808_DATA_HALF_PREF = 0xb,
|
||||
GSM0808_DATA_FULL_PREF_NO_CHANGE = 0x1a,
|
||||
GSM0808_DATA_HALF_PREF_NO_CHANGE = 0x1b,
|
||||
GSM0808_DATA_MULTI_MASK = 0x20,
|
||||
GSM0808_DATA_MULTI_MASK_NO_CHANGE = 0x30,
|
||||
};
|
||||
|
||||
enum gsm0808_chan_rate_type_speech {
|
||||
GSM0808_SPEECH_FULL_BM = 0x8,
|
||||
GSM0808_SPEECH_HALF_LM = 0x9,
|
||||
GSM0808_SPEECH_FULL_PREF= 0xa,
|
||||
GSM0808_SPEECH_HALF_PREF= 0xb,
|
||||
GSM0808_SPEECH_FULL_PREF_NO_CHANGE = 0x1a,
|
||||
GSM0808_SPEECH_HALF_PREF_NO_CHANGE = 0x1b,
|
||||
GSM0808_SPEECH_PERM = 0xf,
|
||||
GSM0808_SPEECH_PERM_NO_CHANGE = 0x1f,
|
||||
};
|
||||
|
||||
enum gsm0808_permitted_speech {
|
||||
GSM0808_PERM_FR1 = 0x01,
|
||||
GSM0808_PERM_FR2 = 0x11,
|
||||
GSM0808_PERM_FR3 = 0x21,
|
||||
GSM0808_PERM_HR1 = GSM0808_PERM_FR1 | 0x4,
|
||||
GSM0808_PERM_HR2 = GSM0808_PERM_FR2 | 0x4,
|
||||
GSM0808_PERM_HR3 = GSM0808_PERM_FR3 | 0x4,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
@@ -3,28 +3,13 @@
|
||||
|
||||
#include <osmocore/msgb.h>
|
||||
#include <osmocore/protocol/gsm_04_80.h>
|
||||
#include <osmocore/gsm0480.h>
|
||||
|
||||
#define MAX_LEN_USSD_STRING 31
|
||||
|
||||
struct ussd_request {
|
||||
char text[MAX_LEN_USSD_STRING + 1];
|
||||
u_int8_t transaction_id;
|
||||
u_int8_t invoke_id;
|
||||
};
|
||||
|
||||
int gsm0480_decode_ussd_request(const struct msgb *msg,
|
||||
struct ussd_request *request);
|
||||
int gsm0480_send_ussd_response(const struct msgb *in_msg, const char* response_text,
|
||||
const struct ussd_request *req);
|
||||
int gsm0480_send_ussd_reject(const struct msgb *msg,
|
||||
const struct ussd_request *request);
|
||||
|
||||
struct msgb *gsm0480_create_notifySS(const char *text);
|
||||
struct msgb *gsm0480_create_unstructuredSS_Notify(int alertLevel, const char *text);
|
||||
|
||||
int gsm0480_wrap_invoke(struct msgb *msg, int op, int link_id);
|
||||
int gsm0480_wrap_facility(struct msgb *msg);
|
||||
|
||||
int gsm0480_send_ussdNotify(struct gsm_lchan *lchan, int level, const char *text);
|
||||
int gsm0480_send_releaseComplete(struct gsm_lchan *lchan);
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ typedef int gsm_cbfn(unsigned int hooknum,
|
||||
struct msgb *msg,
|
||||
void *data, void *param);
|
||||
|
||||
struct bsc_msc_rf;
|
||||
struct osmo_bsc_rf;
|
||||
struct sccp_connection;
|
||||
|
||||
/* Real authentication information containing Ki */
|
||||
@@ -125,6 +125,8 @@ struct bss_sccp_connection_data {
|
||||
struct sccp_connection *sccp;
|
||||
int ciphering_handled : 1;
|
||||
|
||||
int new_subscriber;
|
||||
|
||||
/* Timers... */
|
||||
|
||||
/* for assginment command */
|
||||
@@ -145,6 +147,9 @@ struct bss_sccp_connection_data {
|
||||
struct llist_head sccp_queue;
|
||||
unsigned int sccp_queue_size;
|
||||
|
||||
/* which msc connection to use? */
|
||||
struct bsc_msc_connection *msc_con;
|
||||
|
||||
/* Active connections */
|
||||
struct llist_head active_connections;
|
||||
};
|
||||
@@ -697,8 +702,10 @@ struct gsm_network {
|
||||
struct bsc_msc_connection *msc_con;
|
||||
int ping_timeout;
|
||||
int pong_timeout;
|
||||
struct bsc_msc_rf *rf;
|
||||
char *ussd_grace_txt;
|
||||
struct osmo_bsc_rf *rf;
|
||||
char *mid_call_txt;
|
||||
int mid_call_timeout;
|
||||
char *ussd_welcome_txt;
|
||||
};
|
||||
|
||||
#define SMS_HDR_SIZE 128
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define RTP_PORT_DEFAULT 4000
|
||||
#define RTP_PORT_NET_DEFAULT 16000
|
||||
/**
|
||||
* Calculate the RTP audio port for the given multiplex
|
||||
* and the direction. This allows a semi static endpoint
|
||||
@@ -74,10 +75,29 @@ struct mgcp_config;
|
||||
#define MGCP_POLICY_REJECT 5
|
||||
#define MGCP_POLICY_DEFER 6
|
||||
|
||||
typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state, int local_rtp);
|
||||
typedef int (*mgcp_realloc)(struct mgcp_config *cfg, int endpoint);
|
||||
typedef int (*mgcp_change)(struct mgcp_config *cfg, int endpoint, int state);
|
||||
typedef int (*mgcp_policy)(struct mgcp_config *cfg, int endpoint, int state, const char *transactio_id);
|
||||
typedef int (*mgcp_reset)(struct mgcp_config *cfg);
|
||||
|
||||
#define PORT_ALLOC_STATIC 0
|
||||
#define PORT_ALLOC_DYNAMIC 1
|
||||
|
||||
/**
|
||||
* This holds information on how to allocate ports
|
||||
*/
|
||||
struct mgcp_port_range {
|
||||
int mode;
|
||||
|
||||
/* pre-allocated from a base? */
|
||||
int base_port;
|
||||
|
||||
/* dynamically allocated */
|
||||
int range_start;
|
||||
int range_end;
|
||||
int last_port;
|
||||
};
|
||||
|
||||
struct mgcp_config {
|
||||
/* common configuration */
|
||||
int source_port;
|
||||
@@ -91,16 +111,11 @@ struct mgcp_config {
|
||||
char *audio_name;
|
||||
int audio_payload;
|
||||
int audio_loop;
|
||||
int early_bind;
|
||||
int rtp_base_port;
|
||||
|
||||
struct mgcp_port_range bts_ports;
|
||||
struct mgcp_port_range net_ports;
|
||||
int endp_dscp;
|
||||
|
||||
/* only used in forward mode */
|
||||
char *forward_ip;
|
||||
int forward_port;
|
||||
|
||||
unsigned int last_call_id;
|
||||
|
||||
/* endpoint configuration */
|
||||
unsigned int number_endpoints;
|
||||
struct mgcp_endpoint *endpoints;
|
||||
@@ -112,7 +127,10 @@ struct mgcp_config {
|
||||
mgcp_change change_cb;
|
||||
mgcp_policy policy_cb;
|
||||
mgcp_reset reset_cb;
|
||||
mgcp_realloc realloc_cb;
|
||||
void *data;
|
||||
|
||||
uint32_t last_call_id;
|
||||
};
|
||||
|
||||
/* config management */
|
||||
@@ -120,7 +138,6 @@ struct mgcp_config *mgcp_config_alloc(void);
|
||||
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg);
|
||||
int mgcp_vty_init(void);
|
||||
int mgcp_endpoints_allocate(struct mgcp_config *cfg);
|
||||
int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
|
||||
void mgcp_free_endp(struct mgcp_endpoint *endp);
|
||||
|
||||
/*
|
||||
@@ -134,7 +151,7 @@ static inline int mgcp_timeslot_to_endpoint(int multiplex, int timeslot)
|
||||
{
|
||||
if (timeslot == 0)
|
||||
timeslot = 1;
|
||||
return timeslot + (31 * multiplex);
|
||||
return timeslot + (32 * multiplex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -49,44 +49,65 @@ struct mgcp_rtp_state {
|
||||
int32_t timestamp_offset;
|
||||
};
|
||||
|
||||
struct mgcp_rtp_end {
|
||||
/* statistics */
|
||||
unsigned int packets;
|
||||
struct in_addr addr;
|
||||
|
||||
/* in network byte order */
|
||||
int rtp_port, rtcp_port;
|
||||
|
||||
int payload_type;
|
||||
|
||||
/*
|
||||
* Each end has a socket...
|
||||
*/
|
||||
struct bsc_fd rtp;
|
||||
struct bsc_fd rtcp;
|
||||
|
||||
int local_port;
|
||||
int local_alloc;
|
||||
};
|
||||
|
||||
enum {
|
||||
MGCP_TAP_BTS_IN,
|
||||
MGCP_TAP_BTS_OUT,
|
||||
MGCP_TAP_NET_IN,
|
||||
MGCP_TAP_NET_OUT,
|
||||
|
||||
/* last element */
|
||||
MGCP_TAP_COUNT
|
||||
};
|
||||
|
||||
struct mgcp_rtp_tap {
|
||||
int enabled;
|
||||
struct sockaddr_in forward;
|
||||
};
|
||||
|
||||
struct mgcp_endpoint {
|
||||
int ci;
|
||||
int allocated;
|
||||
uint32_t ci;
|
||||
char *callid;
|
||||
char *local_options;
|
||||
int conn_mode;
|
||||
int orig_mode;
|
||||
|
||||
int bts_payload_type;
|
||||
int net_payload_type;
|
||||
|
||||
/* the local rtp port we are binding to */
|
||||
int rtp_port;
|
||||
|
||||
/*
|
||||
* RTP mangling:
|
||||
* - we get RTP and RTCP to us and need to forward to the BTS
|
||||
* - we get RTP and RTCP from the BTS and forward to the network
|
||||
*/
|
||||
struct bsc_fd local_rtp;
|
||||
struct bsc_fd local_rtcp;
|
||||
|
||||
struct in_addr remote;
|
||||
struct in_addr bts;
|
||||
|
||||
/* in network byte order */
|
||||
int net_rtp, net_rtcp;
|
||||
int bts_rtp, bts_rtcp;
|
||||
|
||||
/* backpointer */
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
/* statistics */
|
||||
unsigned int in_bts;
|
||||
unsigned int in_remote;
|
||||
/* port status for bts/net */
|
||||
struct mgcp_rtp_end bts_end;
|
||||
struct mgcp_rtp_end net_end;
|
||||
|
||||
/* sequence bits */
|
||||
struct mgcp_rtp_state net_state;
|
||||
struct mgcp_rtp_state bts_state;
|
||||
|
||||
/* SSRC/seq/ts patching for loop */
|
||||
int allow_patch;
|
||||
|
||||
/* tap for the endpoint */
|
||||
struct mgcp_rtp_tap taps[MGCP_TAP_COUNT];
|
||||
};
|
||||
|
||||
#define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints)
|
||||
@@ -100,5 +121,8 @@ int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
|
||||
struct mgcp_msg_ptr *ptr, int size,
|
||||
const char **transaction_id, struct mgcp_endpoint **endp);
|
||||
int mgcp_send_dummy(struct mgcp_endpoint *endp);
|
||||
int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
|
||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
|
||||
int mgcp_free_rtp_port(struct mgcp_rtp_end *end);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BSC_MSC_GRACE_H
|
||||
#define BSC_MSC_GRACE_H
|
||||
#ifndef OSMO_BSC_GRACE_H
|
||||
#define OSMO_BSC_GRACE_H
|
||||
|
||||
#include "gsm_data.h"
|
||||
|
||||
35
openbsc/include/openbsc/osmo_bsc_rf.h
Normal file
35
openbsc/include/openbsc/osmo_bsc_rf.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef BSC_MSC_RF
|
||||
#define BSC_MSC_RF
|
||||
|
||||
#include <osmocore/write_queue.h>
|
||||
#include <osmocore/timer.h>
|
||||
|
||||
struct gsm_network;
|
||||
|
||||
struct osmo_bsc_rf {
|
||||
/* the value of signal.h */
|
||||
int policy;
|
||||
struct bsc_fd listen;
|
||||
struct gsm_network *gsm_network;
|
||||
|
||||
const char *last_state_command;
|
||||
|
||||
/* delay the command */
|
||||
char last_request;
|
||||
struct timer_list delay_cmd;
|
||||
|
||||
/* verify that RF is up as it should be */
|
||||
struct timer_list rf_check;
|
||||
|
||||
/* some handling for the automatic grace switch */
|
||||
struct timer_list grace_timeout;
|
||||
};
|
||||
|
||||
struct osmo_bsc_rf_conn {
|
||||
struct write_queue queue;
|
||||
struct osmo_bsc_rf *rf;
|
||||
};
|
||||
|
||||
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net);
|
||||
|
||||
#endif
|
||||
@@ -1,2 +0,0 @@
|
||||
sccp_HEADERS = sccp_types.h sccp.h
|
||||
sccpdir = $(includedir)/sccp
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* SCCP management code
|
||||
*
|
||||
* (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (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 SCCP_H
|
||||
#define SCCP_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sccp_types.h"
|
||||
|
||||
struct msgb;
|
||||
struct sccp_system;
|
||||
|
||||
enum {
|
||||
SCCP_CONNECTION_STATE_NONE,
|
||||
SCCP_CONNECTION_STATE_REQUEST,
|
||||
SCCP_CONNECTION_STATE_CONFIRM,
|
||||
SCCP_CONNECTION_STATE_ESTABLISHED,
|
||||
SCCP_CONNECTION_STATE_RELEASE,
|
||||
SCCP_CONNECTION_STATE_RELEASE_COMPLETE,
|
||||
SCCP_CONNECTION_STATE_REFUSED,
|
||||
SCCP_CONNECTION_STATE_SETUP_ERROR,
|
||||
};
|
||||
|
||||
struct sockaddr_sccp {
|
||||
sa_family_t sccp_family; /* AF_SCCP in the future??? */
|
||||
u_int8_t sccp_ssn; /* subssystem number for routing */
|
||||
|
||||
/* TODO fill in address indicator... if that is ever needed */
|
||||
|
||||
/* not sure about these */
|
||||
/* u_int8_t sccp_class; */
|
||||
};
|
||||
|
||||
/*
|
||||
* parsed structure of an address
|
||||
*/
|
||||
struct sccp_address {
|
||||
struct sccp_called_party_address address;
|
||||
u_int8_t ssn;
|
||||
u_int8_t poi[2];
|
||||
};
|
||||
|
||||
struct sccp_optional_data {
|
||||
u_int8_t data_len;
|
||||
u_int8_t data_start;
|
||||
};
|
||||
|
||||
struct sccp_connection {
|
||||
/* public */
|
||||
void *data_ctx;
|
||||
void (*data_cb)(struct sccp_connection *conn, struct msgb *msg, unsigned int len);
|
||||
|
||||
void *state_ctx;
|
||||
void (*state_cb)(struct sccp_connection *, int old_state);
|
||||
|
||||
struct sccp_source_reference source_local_reference;
|
||||
struct sccp_source_reference destination_local_reference;
|
||||
|
||||
int connection_state;
|
||||
|
||||
/* private */
|
||||
/* list of active connections */
|
||||
struct llist_head list;
|
||||
struct sccp_system *system;
|
||||
int incoming;
|
||||
};
|
||||
|
||||
/**
|
||||
* system functionality to implement on top of any other transport layer:
|
||||
* call sccp_system_incoming for incoming data (from the network)
|
||||
* sccp will call outgoing whenever outgoing data exists
|
||||
*/
|
||||
int sccp_system_init(void (*outgoing)(struct msgb *data, void *ctx), void *context);
|
||||
int sccp_system_incoming(struct msgb *data);
|
||||
|
||||
/**
|
||||
* Send data on an existing connection
|
||||
*/
|
||||
int sccp_connection_write(struct sccp_connection *connection, struct msgb *data);
|
||||
int sccp_connection_send_it(struct sccp_connection *connection);
|
||||
int sccp_connection_close(struct sccp_connection *connection, int cause);
|
||||
int sccp_connection_free(struct sccp_connection *connection);
|
||||
|
||||
/**
|
||||
* internal..
|
||||
*/
|
||||
int sccp_connection_force_free(struct sccp_connection *conn);
|
||||
|
||||
/**
|
||||
* Create a new socket. Set your callbacks and then call bind to open
|
||||
* the connection.
|
||||
*/
|
||||
struct sccp_connection *sccp_connection_socket(void);
|
||||
|
||||
/**
|
||||
* Open the connection and send additional data
|
||||
*/
|
||||
int sccp_connection_connect(struct sccp_connection *conn,
|
||||
const struct sockaddr_sccp *sccp_called,
|
||||
struct msgb *data);
|
||||
|
||||
/**
|
||||
* mostly for testing purposes only. Set the accept callback.
|
||||
* TODO: add true routing information... in analogy to socket, bind, accept
|
||||
*/
|
||||
int sccp_connection_set_incoming(const struct sockaddr_sccp *sock,
|
||||
int (*accept_cb)(struct sccp_connection *connection, void *data),
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* Send data in terms of unit data. A fixed address indicator will be used.
|
||||
*/
|
||||
int sccp_write(struct msgb *data,
|
||||
const struct sockaddr_sccp *sock_sender,
|
||||
const struct sockaddr_sccp *sock_target, int class);
|
||||
int sccp_set_read(const struct sockaddr_sccp *sock,
|
||||
int (*read_cb)(struct msgb *msgb, unsigned int, void *user_data),
|
||||
void *user_data);
|
||||
|
||||
/* generic sock addresses */
|
||||
extern const struct sockaddr_sccp sccp_ssn_bssap;
|
||||
|
||||
/* helpers */
|
||||
u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
|
||||
struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
|
||||
|
||||
struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *data, int length);
|
||||
struct msgb *sccp_create_cc(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref);
|
||||
struct msgb *sccp_create_rlsd(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref, int cause);
|
||||
struct msgb *sccp_create_dt1(struct sccp_source_reference *dst_ref, uint8_t *data, uint8_t len);
|
||||
|
||||
/**
|
||||
* Below this are helper functions and structs for parsing SCCP messages
|
||||
*/
|
||||
struct sccp_parse_result {
|
||||
struct sccp_address called;
|
||||
struct sccp_address calling;
|
||||
|
||||
/* point to the msg packet */
|
||||
struct sccp_source_reference *source_local_reference;
|
||||
struct sccp_source_reference *destination_local_reference;
|
||||
|
||||
/* data pointer */
|
||||
int data_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* helper functions for the nat code
|
||||
*/
|
||||
int sccp_determine_msg_type(struct msgb *msg);
|
||||
int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result);
|
||||
|
||||
#endif
|
||||
@@ -1,420 +0,0 @@
|
||||
/*
|
||||
* ITU Q.713 defined types for SCCP
|
||||
*
|
||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (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 SCCP_TYPES_H
|
||||
#define SCCP_TYPES_H
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
/* Table 1/Q.713 - SCCP message types */
|
||||
enum sccp_message_types {
|
||||
SCCP_MSG_TYPE_CR = 1,
|
||||
SCCP_MSG_TYPE_CC = 2,
|
||||
SCCP_MSG_TYPE_CREF = 3,
|
||||
SCCP_MSG_TYPE_RLSD = 4,
|
||||
SCCP_MSG_TYPE_RLC = 5,
|
||||
SCCP_MSG_TYPE_DT1 = 6,
|
||||
SCCP_MSG_TYPE_DT2 = 7,
|
||||
SCCP_MSG_TYPE_AK = 8,
|
||||
SCCP_MSG_TYPE_UDT = 9,
|
||||
SCCP_MSG_TYPE_UDTS = 10,
|
||||
SCCP_MSG_TYPE_ED = 11,
|
||||
SCCP_MSG_TYPE_EA = 12,
|
||||
SCCP_MSG_TYPE_RSR = 13,
|
||||
SCCP_MSG_TYPE_RSC = 14,
|
||||
SCCP_MSG_TYPE_ERR = 15,
|
||||
SCCP_MSG_TYPE_IT = 16,
|
||||
SCCP_MSG_TYPE_XUDT = 17,
|
||||
SCCP_MSG_TYPE_XUDTS = 18,
|
||||
SCCP_MSG_TYPE_LUDT = 19,
|
||||
SCCP_MSG_TYPE_LUDTS = 20
|
||||
};
|
||||
|
||||
/* Table 2/Q.713 - SCCP parameter name codes */
|
||||
enum sccp_parameter_name_codes {
|
||||
SCCP_PNC_END_OF_OPTIONAL = 0,
|
||||
SCCP_PNC_DESTINATION_LOCAL_REFERENCE = 1,
|
||||
SCCP_PNC_SOURCE_LOCAL_REFERENCE = 2,
|
||||
SCCP_PNC_CALLED_PARTY_ADDRESS = 3,
|
||||
SCCP_PNC_CALLING_PARTY_ADDRESS = 4,
|
||||
SCCP_PNC_PROTOCOL_CLASS = 5,
|
||||
SCCP_PNC_SEGMENTING = 6,
|
||||
SCCP_PNC_RECEIVE_SEQ_NUMBER = 7,
|
||||
SCCP_PNC_SEQUENCING = 8,
|
||||
SCCP_PNC_CREDIT = 9,
|
||||
SCCP_PNC_RELEASE_CAUSE = 10,
|
||||
SCCP_PNC_RETURN_CAUSE = 11,
|
||||
SCCP_PNC_RESET_CAUSE = 12,
|
||||
SCCP_PNC_ERROR_CAUSE = 13,
|
||||
SCCP_PNC_REFUSAL_CAUSE = 14,
|
||||
SCCP_PNC_DATA = 15,
|
||||
SCCP_PNC_SEGMENTATION = 16,
|
||||
SCCP_PNC_HOP_COUNTER = 17,
|
||||
SCCP_PNC_IMPORTANCE = 18,
|
||||
SCCP_PNC_LONG_DATA = 19,
|
||||
};
|
||||
|
||||
/* Figure 3/Q.713 Called/calling party address */
|
||||
enum {
|
||||
SCCP_TITLE_IND_NONE = 0,
|
||||
SCCP_TITLE_IND_NATURE_ONLY = 1,
|
||||
SCCP_TITLE_IND_TRANSLATION_ONLY = 2,
|
||||
SCCP_TITLE_IND_TRANS_NUM_ENC = 3,
|
||||
SCCP_TITLE_IND_TRANS_NUM_ENC_NATURE = 4,
|
||||
};
|
||||
|
||||
enum {
|
||||
SCCP_CALL_ROUTE_ON_SSN = 1,
|
||||
SCCP_CALL_ROUTE_ON_GT = 0,
|
||||
};
|
||||
|
||||
struct sccp_called_party_address {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
u_int8_t point_code_indicator : 1,
|
||||
ssn_indicator : 1,
|
||||
global_title_indicator : 4,
|
||||
routing_indicator : 1,
|
||||
reserved : 1;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
u_int8_t reserved : 1,
|
||||
routing_indicator : 1,
|
||||
global_title_indicator : 4,
|
||||
ssn_indicator : 1,
|
||||
point_code_indicator : 1;
|
||||
#endif
|
||||
u_int8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* indicator indicates presence in the above order */
|
||||
|
||||
/* Figure 6/Q.713 */
|
||||
struct sccp_signalling_point_code {
|
||||
u_int8_t lsb;
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
u_int8_t msb : 6,
|
||||
reserved : 2;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
u_int8_t reserved : 2,
|
||||
msb : 6;
|
||||
#endif
|
||||
} __attribute__((packed));
|
||||
|
||||
/* SSN == subsystem number */
|
||||
enum sccp_subsystem_number {
|
||||
SCCP_SSN_NOT_KNOWN_OR_USED = 0,
|
||||
SCCP_SSN_MANAGEMENT = 1,
|
||||
SCCP_SSN_RESERVED_ITU = 2,
|
||||
SCCP_SSN_ISDN_USER_PART = 3,
|
||||
SCCP_SSN_OMAP = 4, /* operation, maint and administration part */
|
||||
SCCP_SSN_MAP = 5, /* mobile application part */
|
||||
SCCP_SSN_HLR = 6,
|
||||
SCCP_SSN_VLR = 7,
|
||||
SCCP_SSN_MSC = 8,
|
||||
SCCP_SSN_EIC = 9, /* equipent identifier centre */
|
||||
SCCP_SSN_AUC = 10, /* authentication centre */
|
||||
SCCP_SSN_ISDN_SUPPL_SERVICES = 11,
|
||||
SCCP_SSN_RESERVED_INTL = 12,
|
||||
SCCP_SSN_ISDN_EDGE_TO_EDGE = 13,
|
||||
SCCP_SSN_TC_TEST_RESPONDER = 14,
|
||||
|
||||
/* From GSM 03.03 8.2 */
|
||||
SCCP_SSN_BSSAP = 254,
|
||||
SCCP_SSN_BSSOM = 253,
|
||||
};
|
||||
|
||||
/* Q.713, 3.4.2.3 */
|
||||
enum {
|
||||
SCCP_NAI_UNKNOWN = 0,
|
||||
SCCP_NAI_SUBSCRIBER_NUMBER = 1,
|
||||
SCCP_NAI_RESERVED_NATIONAL = 2,
|
||||
SCCP_NAI_NATIONAL_SIGNIFICANT = 3,
|
||||
SCCP_NAI_INTERNATIONAL = 4,
|
||||
};
|
||||
|
||||
struct sccp_global_title {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
u_int8_t nature_of_addr_ind : 7,
|
||||
odd_even : 1;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
u_int8_t odd_even : 1,
|
||||
nature_of_addr_ind : 7;
|
||||
#endif
|
||||
u_int8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Q.713, 3.3 */
|
||||
struct sccp_source_reference {
|
||||
u_int8_t octet1;
|
||||
u_int8_t octet2;
|
||||
u_int8_t octet3;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Q.714, 3.6 */
|
||||
enum sccp_protocol_class {
|
||||
SCCP_PROTOCOL_CLASS_0 = 0,
|
||||
SCCP_PROTOCOL_CLASS_1 = 1,
|
||||
SCCP_PROTOCOL_CLASS_2 = 2,
|
||||
SCCP_PROTOCOL_CLASS_3 = 3,
|
||||
};
|
||||
|
||||
/* bits 5-8 when class0, class1 is used */
|
||||
enum sccp_protocol_options {
|
||||
SCCP_PROTOCOL_NO_SPECIAL = 0,
|
||||
SCCP_PROTOCOL_RETURN_MESSAGE = 8,
|
||||
};
|
||||
|
||||
enum sccp_release_cause {
|
||||
SCCP_RELEASE_CAUSE_END_USER_ORIGINATED = 0,
|
||||
SCCP_RELEASE_CAUSE_END_USER_CONGESTION = 1,
|
||||
SCCP_RELEASE_CAUSE_END_USER_FAILURE = 2,
|
||||
SCCP_RELEASE_CAUSE_SCCP_USER_ORIGINATED = 3,
|
||||
SCCP_RELEASE_CAUSE_REMOTE_PROCEDURE_ERROR = 4,
|
||||
SCCP_RELEASE_CAUSE_INCONSISTENT_CONN_DATA = 5,
|
||||
SCCP_RELEASE_CAUSE_ACCESS_FAILURE = 6,
|
||||
SCCP_RELEASE_CAUSE_ACCESS_CONGESTION = 7,
|
||||
SCCP_RELEASE_CAUSE_SUBSYSTEM_FAILURE = 8,
|
||||
SCCP_RELEASE_CAUSE_SUBSYSTEM_CONGESTION = 9,
|
||||
SCCP_RELEASE_CAUSE_MTP_FAILURE = 10,
|
||||
SCCP_RELEASE_CAUSE_NETWORK_CONGESTION = 11,
|
||||
SCCP_RELEASE_CAUSE_EXPIRATION_RESET = 12,
|
||||
SCCP_RELEASE_CAUSE_EXPIRATION_INACTIVE = 13,
|
||||
SCCP_RELEASE_CAUSE_RESERVED = 14,
|
||||
SCCP_RELEASE_CAUSE_UNQUALIFIED = 15,
|
||||
SCCP_RELEASE_CAUSE_SCCP_FAILURE = 16,
|
||||
};
|
||||
|
||||
enum sccp_return_cause {
|
||||
SCCP_RETURN_CAUSE_NO_TRANSLATION_NATURE = 0,
|
||||
SCCP_RETURN_CAUSE_NO_TRANSLATION = 1,
|
||||
SCCP_RETURN_CAUSE_SUBSYSTEM_CONGESTION = 2,
|
||||
SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE = 3,
|
||||
SCCP_RETURN_CAUSE_UNEQUIPPED_USER = 4,
|
||||
SCCP_RETURN_CAUSE_MTP_FAILURE = 5,
|
||||
SCCP_RETURN_CAUSE_NETWORK_CONGESTION = 6,
|
||||
SCCP_RETURN_CAUSE_UNQUALIFIED = 7,
|
||||
SCCP_RETURN_CAUSE_ERROR_IN_MSG_TRANSPORT = 8,
|
||||
SCCP_RETURN_CAUSE_ERROR_IN_LOCAL_PROCESSING = 9,
|
||||
SCCP_RETURN_CAUSE_DEST_CANNOT_PERFORM_REASSEMBLY = 10,
|
||||
SCCP_RETURN_CAUSE_SCCP_FAILURE = 11,
|
||||
SCCP_RETURN_CAUSE_HOP_COUNTER_VIOLATION = 12,
|
||||
SCCP_RETURN_CAUSE_SEGMENTATION_NOT_SUPPORTED= 13,
|
||||
SCCP_RETURN_CAUSE_SEGMENTATION_FAOLURE = 14
|
||||
};
|
||||
|
||||
enum sccp_reset_cause {
|
||||
SCCP_RESET_CAUSE_END_USER_ORIGINATED = 0,
|
||||
SCCP_RESET_CAUSE_SCCP_USER_ORIGINATED = 1,
|
||||
SCCP_RESET_CAUSE_MSG_OUT_OF_ORDER_PS = 2,
|
||||
SCCP_RESET_CAUSE_MSG_OUT_OF_ORDER_PR = 3,
|
||||
SCCP_RESET_CAUSE_RPC_OUT_OF_WINDOW = 4,
|
||||
SCCP_RESET_CAUSE_RPC_INCORRECT_PS = 5,
|
||||
SCCP_RESET_CAUSE_RPC_GENERAL = 6,
|
||||
SCCP_RESET_CAUSE_REMOTE_END_USER_OPERATIONAL= 7,
|
||||
SCCP_RESET_CAUSE_NETWORK_OPERATIONAL = 8,
|
||||
SCCP_RESET_CAUSE_ACCESS_OPERATIONAL = 9,
|
||||
SCCP_RESET_CAUSE_NETWORK_CONGESTION = 10,
|
||||
SCCP_RESET_CAUSE_RESERVED = 11,
|
||||
};
|
||||
|
||||
enum sccp_error_cause {
|
||||
SCCP_ERROR_LRN_MISMATCH_UNASSIGNED = 0, /* local reference number */
|
||||
SCCP_ERROR_LRN_MISMATCH_INCONSISTENT = 1,
|
||||
SCCP_ERROR_POINT_CODE_MISMATCH = 2,
|
||||
SCCP_ERROR_SERVICE_CLASS_MISMATCH = 3,
|
||||
SCCP_ERROR_UNQUALIFIED = 4,
|
||||
};
|
||||
|
||||
enum sccp_refusal_cause {
|
||||
SCCP_REFUSAL_END_USER_ORIGINATED = 0,
|
||||
SCCP_REFUSAL_END_USER_CONGESTION = 1,
|
||||
SCCP_REFUSAL_END_USER_FAILURE = 2,
|
||||
SCCP_REFUSAL_SCCP_USER_ORIGINATED = 3,
|
||||
SCCP_REFUSAL_DESTINATION_ADDRESS_UKNOWN = 4,
|
||||
SCCP_REFUSAL_DESTINATION_INACCESSIBLE = 5,
|
||||
SCCP_REFUSAL_NET_QOS_NON_TRANSIENT = 6,
|
||||
SCCP_REFUSAL_NET_QOS_TRANSIENT = 7,
|
||||
SCCP_REFUSAL_ACCESS_FAILURE = 8,
|
||||
SCCP_REFUSAL_ACCESS_CONGESTION = 9,
|
||||
SCCP_REFUSAL_SUBSYSTEM_FAILURE = 10,
|
||||
SCCP_REFUSAL_SUBSYTEM_CONGESTION = 11,
|
||||
SCCP_REFUSAL_EXPIRATION = 12,
|
||||
SCCP_REFUSAL_INCOMPATIBLE_USER_DATA = 13,
|
||||
SCCP_REFUSAL_RESERVED = 14,
|
||||
SCCP_REFUSAL_UNQUALIFIED = 15,
|
||||
SCCP_REFUSAL_HOP_COUNTER_VIOLATION = 16,
|
||||
SCCP_REFUSAL_SCCP_FAILURE = 17,
|
||||
SCCP_REFUSAL_UNEQUIPPED_USER = 18,
|
||||
};
|
||||
|
||||
/*
|
||||
* messages... as of Q.713 Chapter 4
|
||||
*/
|
||||
struct sccp_connection_request {
|
||||
/* mandantory */
|
||||
u_int8_t type;
|
||||
struct sccp_source_reference source_local_reference;
|
||||
u_int8_t proto_class;
|
||||
|
||||
|
||||
/* variable */
|
||||
u_int8_t variable_called;
|
||||
#if VARIABLE
|
||||
called_party_address
|
||||
#endif
|
||||
|
||||
/* optional */
|
||||
u_int8_t optional_start;
|
||||
|
||||
#if OPTIONAL
|
||||
credit 3
|
||||
callingparty var 4-n
|
||||
data 3-130
|
||||
hop_counter 3
|
||||
importance 3
|
||||
end_of_optional 1
|
||||
#endif
|
||||
|
||||
u_int8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sccp_connection_confirm {
|
||||
/* mandantory */
|
||||
u_int8_t type;
|
||||
struct sccp_source_reference destination_local_reference;
|
||||
struct sccp_source_reference source_local_reference;
|
||||
u_int8_t proto_class;
|
||||
|
||||
/* optional */
|
||||
u_int8_t optional_start;
|
||||
|
||||
/* optional */
|
||||
#if OPTIONAL
|
||||
credit 3
|
||||
called party 4
|
||||
data 3-130
|
||||
importance 3
|
||||
end_of_optional 1
|
||||
#endif
|
||||
|
||||
u_int8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sccp_connection_refused {
|
||||
/* mandantory */
|
||||
u_int8_t type;
|
||||
struct sccp_source_reference destination_local_reference;
|
||||
u_int8_t cause;
|
||||
|
||||
/* optional */
|
||||
u_int8_t optional_start;
|
||||
|
||||
/* optional */
|
||||
#if OPTIONAL
|
||||
called party 4
|
||||
data 3-130
|
||||
importance 3
|
||||
end_of_optional 1
|
||||
#endif
|
||||
|
||||
u_int8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sccp_connection_released {
|
||||
/* mandantory */
|
||||
u_int8_t type;
|
||||
struct sccp_source_reference destination_local_reference;
|
||||
struct sccp_source_reference source_local_reference;
|
||||
u_int8_t release_cause;
|
||||
|
||||
|
||||
/* optional */
|
||||
u_int8_t optional_start;
|
||||
|
||||
#if OPTIONAL
|
||||
data 3-130
|
||||
importance 3
|
||||
end_of_optional 1
|
||||
#endif
|
||||
u_int8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sccp_connection_release_complete {
|
||||
u_int8_t type;
|
||||
struct sccp_source_reference destination_local_reference;
|
||||
struct sccp_source_reference source_local_reference;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sccp_data_form1 {
|
||||
/* mandantory */
|
||||
u_int8_t type;
|
||||
struct sccp_source_reference destination_local_reference;
|
||||
u_int8_t segmenting;
|
||||
|
||||
/* variable */
|
||||
u_int8_t variable_start;
|
||||
|
||||
#if VARIABLE
|
||||
data 2-256;
|
||||
#endif
|
||||
|
||||
u_int8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
struct sccp_data_unitdata {
|
||||
/* mandantory */
|
||||
u_int8_t type;
|
||||
u_int8_t proto_class;
|
||||
|
||||
|
||||
/* variable */
|
||||
u_int8_t variable_called;
|
||||
u_int8_t variable_calling;
|
||||
u_int8_t variable_data;
|
||||
|
||||
#if VARIABLE
|
||||
called party address
|
||||
calling party address
|
||||
#endif
|
||||
|
||||
u_int8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sccp_data_it {
|
||||
/* mandantory */
|
||||
u_int8_t type;
|
||||
struct sccp_source_reference destination_local_reference;
|
||||
struct sccp_source_reference source_local_reference;
|
||||
u_int8_t proto_class;
|
||||
|
||||
u_int8_t sequencing[2];
|
||||
u_int8_t credit;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sccp_proto_err {
|
||||
u_int8_t type;
|
||||
struct sccp_source_reference destination_local_reference;
|
||||
u_int8_t error_cause;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -65,6 +65,7 @@ enum node_type {
|
||||
VIEW_NODE, /* View node. Default mode of vty interface. */
|
||||
AUTH_ENABLE_NODE, /* Authentication mode for change enable. */
|
||||
ENABLE_NODE, /* Enable node. */
|
||||
OML_NODE,
|
||||
CONFIG_NODE, /* Config node. Default mode of config file. */
|
||||
SERVICE_NODE, /* Service node. */
|
||||
DEBUG_NODE, /* Debug node. */
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: OpenBSC SCCP Lib
|
||||
Description: OpenBSC SCCP Lib
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lsccp
|
||||
Cflags: -I${includedir}/
|
||||
@@ -1,6 +1,6 @@
|
||||
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
|
||||
AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS)
|
||||
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOSCCP_LIBS)
|
||||
|
||||
sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
|
||||
isdnsync bsc_mgcp ipaccess-proxy \
|
||||
@@ -8,11 +8,8 @@ sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
|
||||
noinst_LIBRARIES = libbsc.a libmsc.a libvty.a
|
||||
noinst_HEADERS = vty/cardshell.h
|
||||
|
||||
bscdir = $(libdir)
|
||||
bsc_LIBRARIES = libsccp.a
|
||||
|
||||
libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
|
||||
chan_alloc.c debug.c \
|
||||
chan_alloc.c debug.c abis_nm_vty.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 \
|
||||
input/misdn.c input/ipaccess.c \
|
||||
@@ -27,16 +24,14 @@ libmsc_a_SOURCES = gsm_subscriber.c db.c \
|
||||
|
||||
libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
|
||||
|
||||
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)
|
||||
|
||||
bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \
|
||||
rs232.c bts_siemens_bs11.c
|
||||
bsc_msc_ip_SOURCES = bssap.c bsc_msc_ip.c bsc_init.c vty_interface.c vty_interface_bsc.c \
|
||||
bsc_msc.c bsc_msc_rf.c bsc_msc_grace.c gsm_04_80.c
|
||||
bsc_msc_ip_LDADD = libbsc.a libvty.a libsccp.a
|
||||
bsc_msc.c osmo_bsc_rf.c osmo_bsc_grace.c gsm_04_80.c
|
||||
bsc_msc_ip_LDADD = libbsc.a libvty.a $(LIBOSMOSCCP_LIBS)
|
||||
|
||||
|
||||
ipaccess_find_SOURCES = ipaccess/ipaccess-find.c
|
||||
|
||||
@@ -439,30 +439,30 @@ static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
|
||||
|
||||
static int abis_nm_rcvmsg_sw(struct msgb *mb);
|
||||
|
||||
static struct value_string obj_class_names[] = {
|
||||
{ NM_OC_SITE_MANAGER, "SITE MANAGER" },
|
||||
const struct value_string abis_nm_obj_class_names[] = {
|
||||
{ NM_OC_SITE_MANAGER, "SITE-MANAGER" },
|
||||
{ NM_OC_BTS, "BTS" },
|
||||
{ NM_OC_RADIO_CARRIER, "RADIO CARRIER" },
|
||||
{ NM_OC_BASEB_TRANSC, "BASEBAND TRANSCEIVER" },
|
||||
{ NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
|
||||
{ NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
|
||||
{ NM_OC_CHANNEL, "CHANNEL" },
|
||||
{ NM_OC_BS11_ADJC, "ADJC" },
|
||||
{ NM_OC_BS11_HANDOVER, "HANDOVER" },
|
||||
{ NM_OC_BS11_PWR_CTRL, "POWER CONTROL" },
|
||||
{ NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
|
||||
{ NM_OC_BS11_BTSE, "BTSE" },
|
||||
{ NM_OC_BS11_RACK, "RACK" },
|
||||
{ NM_OC_BS11_TEST, "TEST" },
|
||||
{ NM_OC_BS11_ENVABTSE, "ENVABTSE" },
|
||||
{ NM_OC_BS11_BPORT, "BPORT" },
|
||||
{ NM_OC_GPRS_NSE, "GPRS NSE" },
|
||||
{ NM_OC_GPRS_CELL, "GPRS CELL" },
|
||||
{ NM_OC_GPRS_NSVC, "GPRS NSVC" },
|
||||
{ NM_OC_GPRS_NSE, "GPRS-NSE" },
|
||||
{ NM_OC_GPRS_CELL, "GPRS-CELL" },
|
||||
{ NM_OC_GPRS_NSVC, "GPRS-NSVC" },
|
||||
{ NM_OC_BS11, "SIEMENSHW" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const char *obj_class_name(u_int8_t oc)
|
||||
{
|
||||
return get_value_string(obj_class_names, oc);
|
||||
return get_value_string(abis_nm_obj_class_names, oc);
|
||||
}
|
||||
|
||||
const char *nm_opstate_name(u_int8_t os)
|
||||
@@ -510,18 +510,17 @@ static struct value_string test_names[] = {
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string abis_nm_adm_state_names[] = {
|
||||
{ NM_STATE_LOCKED, "Locked" },
|
||||
{ NM_STATE_UNLOCKED, "Unlocked" },
|
||||
{ NM_STATE_SHUTDOWN, "Shutdown" },
|
||||
{ NM_STATE_NULL, "NULL" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const char *nm_adm_name(u_int8_t adm)
|
||||
{
|
||||
switch (adm) {
|
||||
case 1:
|
||||
return "Locked";
|
||||
case 2:
|
||||
return "Unlocked";
|
||||
case 3:
|
||||
return "Shutdown";
|
||||
default:
|
||||
return "<not used>";
|
||||
}
|
||||
return get_value_string(abis_nm_adm_state_names, adm);
|
||||
}
|
||||
|
||||
int nm_is_running(struct gsm_nm_state *s) {
|
||||
|
||||
194
openbsc/src/abis_nm_vty.c
Normal file
194
openbsc/src/abis_nm_vty.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/* VTY interface for A-bis OML (Netowrk Management) */
|
||||
|
||||
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <osmocore/msgb.h>
|
||||
#include <osmocore/tlv.h>
|
||||
#include <osmocore/talloc.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/abis_nm.h>
|
||||
#include <openbsc/vty.h>
|
||||
|
||||
#include <vty/command.h>
|
||||
|
||||
extern struct gsm_network *bsc_gsmnet;
|
||||
|
||||
static struct cmd_node oml_node = {
|
||||
OML_NODE,
|
||||
"%s(oml)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
struct oml_node_state {
|
||||
struct gsm_bts *bts;
|
||||
uint8_t obj_class;
|
||||
uint8_t obj_inst[3];
|
||||
};
|
||||
|
||||
static int dummy_config_write(struct vty *v)
|
||||
{
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* FIXME: auto-generate those strings from the value_string lists */
|
||||
#define NM_OBJCLASS_VTY "(site-manager|bts|radio-carrier|baseband-transceiver|channel|adjc|handover|power-contorl|btse|rack|test|envabtse|bport|gprs-nse|gprs-cell|gprs-nsvc|siemenshw)"
|
||||
#define NM_OBJCLASS_VTY_HELP "FIXME"
|
||||
|
||||
DEFUN(oml_class_inst, oml_class_inst_cmd,
|
||||
"bts <0-255> oml class " NM_OBJCLASS_VTY
|
||||
" instance <0-255> <0-255> <0-255>",
|
||||
"BTS related commands\n" "BTS Number\n"
|
||||
"Manipulate the OML managed objects\n"
|
||||
"Object Class\n" NM_OBJCLASS_VTY_HELP
|
||||
"Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n")
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
struct oml_node_state *oms;
|
||||
int bts_nr = atoi(argv[0]);
|
||||
|
||||
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
|
||||
if (!oms)
|
||||
return CMD_WARNING;
|
||||
|
||||
oms->bts = bts;
|
||||
oms->obj_class = get_string_value(abis_nm_obj_class_names, argv[1]);
|
||||
oms->obj_inst[0] = atoi(argv[2]);
|
||||
oms->obj_inst[1] = atoi(argv[3]);
|
||||
oms->obj_inst[2] = atoi(argv[4]);
|
||||
|
||||
vty->index = oms;
|
||||
vty->node = OML_NODE;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
DEFUN(oml_classnum_inst, oml_classnum_inst_cmd,
|
||||
"bts <0-255> oml class <0-255> instance <0-255> <0-255> <0-255>",
|
||||
"BTS related commands\n" "BTS Number\n"
|
||||
"Manipulate the OML managed objects\n"
|
||||
"Object Class\n" "Object Class\n"
|
||||
"Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n")
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
struct oml_node_state *oms;
|
||||
int bts_nr = atoi(argv[0]);
|
||||
|
||||
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
|
||||
if (!oms)
|
||||
return CMD_WARNING;
|
||||
|
||||
oms->bts = bts;
|
||||
oms->obj_class = atoi(argv[1]);
|
||||
oms->obj_inst[0] = atoi(argv[2]);
|
||||
oms->obj_inst[1] = atoi(argv[3]);
|
||||
oms->obj_inst[2] = atoi(argv[4]);
|
||||
|
||||
vty->index = oms;
|
||||
vty->node = OML_NODE;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(oml_attrib_get, oml_attrib_get_cmd,
|
||||
"attribute get <0-255>",
|
||||
"OML Attribute Actions\n" "Get a single OML Attribute\n"
|
||||
"OML Attribute Number\n")
|
||||
{
|
||||
struct oml_node_state *oms = vty->index;
|
||||
|
||||
/* FIXME */
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(oml_attrib_set, oml_attrib_set_cmd,
|
||||
"attribute set <0-255> .HEX",
|
||||
"OML Attribute Actions\n" "Set a single OML Attribute\n"
|
||||
"OML Attribute Number\n")
|
||||
{
|
||||
struct oml_node_state *oms = vty->index;
|
||||
|
||||
/* FIXME */
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(oml_chg_adm_state, oml_chg_adm_state_cmd,
|
||||
"change-adm-state (locked|unlocked|shutdown|null)",
|
||||
"Change the Administrative State\n"
|
||||
"Locked\n" "Unlocked\n" "Shutdown\n" "NULL\n")
|
||||
{
|
||||
struct oml_node_state *oms = vty->index;
|
||||
enum abis_nm_adm_state state;
|
||||
|
||||
state = get_string_value(abis_nm_adm_state_names, argv[0]);
|
||||
|
||||
abis_nm_chg_adm_state(oms->bts, oms->obj_class, oms->obj_inst[0],
|
||||
oms->obj_inst[1], oms->obj_inst[2], state);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(oml_opstart, oml_opstart_cmd,
|
||||
"opstart", "Send an OPSTART message to the object")
|
||||
{
|
||||
struct oml_node_state *oms = vty->index;
|
||||
|
||||
abis_nm_opstart(oms->bts, oms->obj_class, oms->obj_inst[0],
|
||||
oms->obj_inst[1], oms->obj_inst[2]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int abis_nm_vty_init(void)
|
||||
{
|
||||
install_element(ENABLE_NODE, &oml_class_inst_cmd);
|
||||
install_element(ENABLE_NODE, &oml_classnum_inst_cmd);
|
||||
install_node(&oml_node, dummy_config_write);
|
||||
|
||||
install_default(OML_NODE);
|
||||
install_element(OML_NODE, &oml_attrib_get_cmd);
|
||||
install_element(OML_NODE, &oml_attrib_set_cmd);
|
||||
install_element(OML_NODE, &oml_chg_adm_state_cmd);
|
||||
install_element(OML_NODE, &oml_opstart_cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <osmocore/talloc.h>
|
||||
#include <openbsc/ipaccess.h>
|
||||
|
||||
/* global pointer to the gsm network data structure */
|
||||
extern struct gsm_network *bsc_gsmnet;
|
||||
@@ -469,8 +470,6 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
|
||||
sizeof(nanobts_attr_nse));
|
||||
abis_nm_opstart(bts, obj_class, bts->bts_nr,
|
||||
0xff, 0xff);
|
||||
abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
|
||||
0xff, 0xff, NM_STATE_UNLOCKED);
|
||||
}
|
||||
break;
|
||||
case NM_OC_GPRS_CELL:
|
||||
@@ -485,6 +484,8 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
|
||||
0, 0xff);
|
||||
abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
|
||||
0, 0xff, NM_STATE_UNLOCKED);
|
||||
abis_nm_chg_adm_state(bts, NM_OC_GPRS_NSE, bts->bts_nr,
|
||||
0xff, 0xff, NM_STATE_UNLOCKED);
|
||||
}
|
||||
break;
|
||||
case NM_OC_GPRS_NSVC:
|
||||
@@ -563,10 +564,19 @@ static int sw_activ_rep(struct msgb *mb)
|
||||
/* Callback function for NACK on the OML NM */
|
||||
static int oml_msg_nack(u_int8_t mt)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (mt == NM_MT_SET_BTS_ATTR_NACK) {
|
||||
LOGP(DNM, LOGL_FATAL, "Failed to set BTS attributes. That is fatal. "
|
||||
"Was the bts type and frequency properly specified?\n");
|
||||
exit(-1);
|
||||
} else {
|
||||
LOGP(DNM, LOGL_ERROR, "Got a NACK going to drop the OML links.\n");
|
||||
for (i = 0; i < bsc_gsmnet->num_bts; ++i) {
|
||||
struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, i);
|
||||
if (is_ipaccess_bts(bts))
|
||||
ipaccess_drop_oml(bts);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -58,20 +58,6 @@ static void msc_con_timeout(void *_con)
|
||||
bsc_msc_lost(con);
|
||||
}
|
||||
|
||||
static int bsc_msc_except(struct bsc_fd *bfd)
|
||||
{
|
||||
struct write_queue *wrt;
|
||||
struct bsc_msc_connection *con;
|
||||
|
||||
LOGP(DMSC, LOGL_ERROR, "Exception on the BFD. Closing down.\n");
|
||||
|
||||
wrt = container_of(bfd, struct write_queue, bfd);
|
||||
con = container_of(wrt, struct bsc_msc_connection, write_queue);
|
||||
|
||||
connection_loss(con);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called in the case of a non blocking connect */
|
||||
static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
|
||||
{
|
||||
@@ -83,13 +69,16 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
|
||||
socklen_t len = sizeof(val);
|
||||
|
||||
if ((what & BSC_FD_WRITE) == 0) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Callback but not readable.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Callback but not writable.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
queue = container_of(fd, struct write_queue, bfd);
|
||||
con = container_of(queue, struct bsc_msc_connection, write_queue);
|
||||
|
||||
/* From here on we will either be connected or reconnect */
|
||||
bsc_del_timer(&con->timeout_timer);
|
||||
|
||||
/* check the socket state */
|
||||
rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
|
||||
if (rc != 0) {
|
||||
@@ -107,7 +96,6 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
|
||||
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
|
||||
|
||||
con->is_connected = 1;
|
||||
bsc_del_timer(&con->timeout_timer);
|
||||
LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
|
||||
if (con->connected)
|
||||
con->connected(con);
|
||||
@@ -222,14 +210,16 @@ struct bsc_msc_connection *bsc_msc_create(const char *ip, int port, int prio)
|
||||
con->port = port;
|
||||
con->prio = prio;
|
||||
write_queue_init(&con->write_queue, 100);
|
||||
con->write_queue.except_cb = bsc_msc_except;
|
||||
return con;
|
||||
}
|
||||
|
||||
void bsc_msc_lost(struct bsc_msc_connection *con)
|
||||
{
|
||||
write_queue_clear(&con->write_queue);
|
||||
bsc_unregister_fd(&con->write_queue.bfd);
|
||||
bsc_del_timer(&con->timeout_timer);
|
||||
|
||||
if (con->write_queue.bfd.fd >= 0)
|
||||
bsc_unregister_fd(&con->write_queue.bfd);
|
||||
connection_loss(con);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,15 +45,15 @@
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <openbsc/bsc_msc.h>
|
||||
#include <openbsc/bsc_nat.h>
|
||||
#include <openbsc/bsc_msc_rf.h>
|
||||
#include <openbsc/bsc_msc_grace.h>
|
||||
#include <openbsc/osmo_bsc_rf.h>
|
||||
#include <openbsc/osmo_bsc_grace.h>
|
||||
|
||||
#include <osmocore/select.h>
|
||||
#include <osmocore/talloc.h>
|
||||
#include <osmocore/write_queue.h>
|
||||
#include <osmocore/gsm0808.h>
|
||||
|
||||
#include <sccp/sccp.h>
|
||||
#include <osmocom/sccp/sccp.h>
|
||||
|
||||
/* SCCP helper */
|
||||
#define SCCP_IT_TIMER 60
|
||||
@@ -326,6 +326,9 @@ static int open_sccp_connection(struct msgb *layer3)
|
||||
con_data->lchan = layer3->lchan;
|
||||
con_data->sccp = sccp_connection;
|
||||
|
||||
/* assign the outgoing msc connection */
|
||||
con_data->msc_con = bsc_gsmnet->msc_con;
|
||||
|
||||
sccp_connection->state_cb = msc_outgoing_sccp_state;
|
||||
sccp_connection->data_cb = msc_outgoing_sccp_data;
|
||||
sccp_connection->data_ctx = con_data;
|
||||
@@ -541,6 +544,38 @@ static int handle_modify_ack(struct msgb *msg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the subscriber is coming from our LAC
|
||||
*/
|
||||
static void handle_lu(struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh;
|
||||
struct gsm48_loc_upd_req *lu;
|
||||
struct gsm48_loc_area_id lai;
|
||||
struct gsm_network *net;
|
||||
|
||||
if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) {
|
||||
LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!msg->lchan->msc_data)
|
||||
return;
|
||||
|
||||
net = msg->trx->bts->network;
|
||||
|
||||
gh = msgb_l3(msg);
|
||||
lu = (struct gsm48_loc_upd_req *) gh->data;
|
||||
|
||||
gsm48_generate_lai(&lai, net->country_code, net->network_code,
|
||||
msg->trx->bts->location_area_code);
|
||||
|
||||
if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) {
|
||||
LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n");
|
||||
msg->lchan->msc_data->new_subscriber = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive a GSM 04.08 Radio Resource (RR) message */
|
||||
static int gsm0408_rcv_rr(struct msgb *msg)
|
||||
{
|
||||
@@ -586,6 +621,8 @@ static int gsm0408_rcv_mm(struct msgb *msg)
|
||||
case GSM48_MT_MM_CM_SERV_REQ:
|
||||
case GSM48_MT_MM_IMSI_DETACH_IND:
|
||||
rc = send_dtap_or_open_connection(msg);
|
||||
if ((gh->msg_type & 0xbf) == GSM48_MT_MM_LOC_UPD_REQUEST)
|
||||
handle_lu(msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -709,7 +746,7 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void msc_sccp_write_ipa(struct msgb *msg, void *data)
|
||||
static void msc_sccp_write_ipa(struct sccp_connection *conn, struct msgb *msg, void *data)
|
||||
{
|
||||
msc_queue_write(msg, IPAC_PROTO_SCCP);
|
||||
}
|
||||
@@ -1141,7 +1178,7 @@ static void signal_handler(int signal)
|
||||
talloc_report_full(tall_bsc_ctx, stderr);
|
||||
break;
|
||||
case SIGUSR2:
|
||||
if (!bsc_gsmnet->msc_con || !bsc_gsmnet->msc_con->is_connected)
|
||||
if (!bsc_gsmnet->msc_con)
|
||||
return;
|
||||
bsc_msc_lost(bsc_gsmnet->msc_con);
|
||||
break;
|
||||
@@ -1230,6 +1267,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* initialize sccp */
|
||||
sccp_set_log_area(DSCCP);
|
||||
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);
|
||||
@@ -1245,7 +1283,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (rf_ctl) {
|
||||
bsc_gsmnet->rf = bsc_msc_rf_create(rf_ctl, bsc_gsmnet);
|
||||
bsc_gsmnet->rf = osmo_bsc_rf_create(rf_ctl, bsc_gsmnet);
|
||||
if (!bsc_gsmnet->rf) {
|
||||
fprintf(stderr, "Failed to create the RF service.\n");
|
||||
exit(1);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* GSM 08.08 BSSMAP handling */
|
||||
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009 by On-Waves
|
||||
/* (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
|
||||
@@ -28,10 +28,11 @@
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/paging.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <openbsc/gsm_04_80.h>
|
||||
|
||||
#include <osmocore/gsm0808.h>
|
||||
|
||||
#include <sccp/sccp.h>
|
||||
#include <osmocom/sccp/sccp.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
@@ -45,9 +46,9 @@
|
||||
static void bts_queue_send(struct msgb *msg, int link_id);
|
||||
static void bssmap_free_secondary(struct bss_sccp_connection_data *data);
|
||||
|
||||
static uint32_t read_data32(const uint8_t *data)
|
||||
static uint16_t read_data16(const uint8_t *data)
|
||||
{
|
||||
uint32_t res;
|
||||
uint16_t res;
|
||||
|
||||
memcpy(&res, data, sizeof(res));
|
||||
return res;
|
||||
@@ -73,6 +74,19 @@ static int bssmap_paging_cb(unsigned int hooknum, unsigned int event, struct msg
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send a USSD message */
|
||||
static void send_welcome_ussd(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct gsm_network *network;
|
||||
|
||||
network = lchan->ts->trx->bts->network;
|
||||
if (!network->ussd_welcome_txt)
|
||||
return;
|
||||
|
||||
gsm0480_send_ussdNotify(lchan, 1, network->ussd_welcome_txt);
|
||||
gsm0480_send_releaseComplete(lchan);
|
||||
}
|
||||
|
||||
static int bssmap_handle_reset_ack(struct gsm_network *net, struct msgb *msg, unsigned int length)
|
||||
{
|
||||
LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC\n");
|
||||
@@ -131,7 +145,7 @@ static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsig
|
||||
* Support paging to all network or one BTS at one LAC
|
||||
*/
|
||||
if (data_length == 3 && data[0] == CELL_IDENT_LAC) {
|
||||
lac = ntohs(read_data32(&data[1]));
|
||||
lac = ntohs(read_data16(&data[1]));
|
||||
} else if (data_length > 1 || (data[0] & 0x0f) != CELL_IDENT_BSS) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Unsupported Cell Identifier List: %s\n", hexdump(data, data_length));
|
||||
return -1;
|
||||
@@ -513,7 +527,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
||||
goto reject;
|
||||
}
|
||||
|
||||
cic = ntohs(*(u_int16_t *)TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
|
||||
cic = ntohs(read_data16(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)));
|
||||
timeslot = cic & 0x1f;
|
||||
multiplex = (cic & ~0x1f) >> 5;
|
||||
|
||||
@@ -663,6 +677,7 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
|
||||
struct msgb *gsm48;
|
||||
u_int8_t *data;
|
||||
u_int8_t link_id;
|
||||
int is_lu = 0;
|
||||
|
||||
if (!lchan) {
|
||||
LOGP(DMSC, LOGL_ERROR, "No lchan available\n");
|
||||
@@ -712,6 +727,7 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
|
||||
gsm48_generate_lai(lai, net->country_code,
|
||||
net->network_code,
|
||||
gsm48->trx->bts->location_area_code);
|
||||
is_lu = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -724,6 +740,11 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
|
||||
link_id |= 0x40;
|
||||
|
||||
bts_queue_send(gsm48, link_id);
|
||||
|
||||
/* Feature to send a welcome USSD for a new subscriber */
|
||||
if (is_lu && lchan->msc_data->new_subscriber)
|
||||
send_welcome_ussd(lchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include <openbsc/transaction.h>
|
||||
#include <openbsc/ussd.h>
|
||||
#include <openbsc/silent_call.h>
|
||||
#include <osmocore/gsm0480.h>
|
||||
|
||||
void *tall_locop_ctx;
|
||||
|
||||
|
||||
@@ -36,17 +36,7 @@
|
||||
#include <osmocore/gsm_utils.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/gsm_04_80.h>
|
||||
|
||||
/* Forward declarations */
|
||||
static int parse_ussd(u_int8_t *ussd, struct ussd_request *req);
|
||||
static int parse_ussd_info_elements(u_int8_t *ussd_ie,
|
||||
struct ussd_request *req);
|
||||
static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length,
|
||||
struct ussd_request *req);
|
||||
static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length,
|
||||
struct ussd_request *req);
|
||||
static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length,
|
||||
struct ussd_request *req);
|
||||
#include <osmocore/gsm0480.h>
|
||||
|
||||
static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, u_int8_t tag)
|
||||
{
|
||||
@@ -69,291 +59,6 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, u_int8_t tag,
|
||||
}
|
||||
|
||||
|
||||
/* Decode a mobile-originated USSD-request message */
|
||||
int gsm0480_decode_ussd_request(const struct msgb *msg, struct ussd_request *req)
|
||||
{
|
||||
int rc = 0;
|
||||
u_int8_t *parse_ptr = msgb_l3(msg);
|
||||
|
||||
if ((*parse_ptr & 0x0F) == GSM48_PDISC_NC_SS) {
|
||||
req->transaction_id = *parse_ptr & 0x70;
|
||||
rc = parse_ussd(parse_ptr+1, req);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
DEBUGP(DMM, "Error occurred while parsing received USSD!\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int parse_ussd(u_int8_t *ussd, struct ussd_request *req)
|
||||
{
|
||||
int rc = 1;
|
||||
u_int8_t msg_type = ussd[0] & 0xBF; /* message-type - section 3.4 */
|
||||
|
||||
switch (msg_type) {
|
||||
case GSM0480_MTYPE_RELEASE_COMPLETE:
|
||||
DEBUGP(DMM, "USS Release Complete\n");
|
||||
/* could also parse out the optional Cause/Facility data */
|
||||
req->text[0] = 0xFF;
|
||||
break;
|
||||
case GSM0480_MTYPE_REGISTER:
|
||||
case GSM0480_MTYPE_FACILITY:
|
||||
rc &= parse_ussd_info_elements(ussd+1, req);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown GSM 04.80 message-type field 0x%02x\n",
|
||||
ussd[0]);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int parse_ussd_info_elements(u_int8_t *ussd_ie, struct ussd_request *req)
|
||||
{
|
||||
int rc;
|
||||
/* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */
|
||||
u_int8_t iei = ussd_ie[0];
|
||||
u_int8_t iei_length = ussd_ie[1];
|
||||
|
||||
switch (iei) {
|
||||
case GSM48_IE_CAUSE:
|
||||
break;
|
||||
case GSM0480_IE_FACILITY:
|
||||
rc = parse_facility_ie(ussd_ie+2, iei_length, req);
|
||||
break;
|
||||
case GSM0480_IE_SS_VERSION:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unhandled GSM 04.08 or 04.80 IEI 0x%02x\n",
|
||||
iei);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length,
|
||||
struct ussd_request *req)
|
||||
{
|
||||
int rc = 1;
|
||||
u_int8_t offset = 0;
|
||||
|
||||
do {
|
||||
/* Component Type tag - table 3.7 */
|
||||
u_int8_t component_type = facility_ie[offset];
|
||||
u_int8_t component_length = facility_ie[offset+1];
|
||||
|
||||
switch (component_type) {
|
||||
case GSM0480_CTYPE_INVOKE:
|
||||
rc &= parse_ss_invoke(facility_ie+2,
|
||||
component_length,
|
||||
req);
|
||||
break;
|
||||
case GSM0480_CTYPE_RETURN_RESULT:
|
||||
break;
|
||||
case GSM0480_CTYPE_RETURN_ERROR:
|
||||
break;
|
||||
case GSM0480_CTYPE_REJECT:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown GSM 04.80 Facility "
|
||||
"Component Type 0x%02x\n", component_type);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
offset += (component_length+2);
|
||||
} while (offset < length);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Parse an Invoke component - see table 3.3 */
|
||||
static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length,
|
||||
struct ussd_request *req)
|
||||
{
|
||||
int rc = 1;
|
||||
u_int8_t offset;
|
||||
|
||||
/* mandatory part */
|
||||
if (invoke_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) {
|
||||
fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag "
|
||||
"0x%02x (expecting Invoke ID tag)\n", invoke_data[0]);
|
||||
}
|
||||
|
||||
offset = invoke_data[1] + 2;
|
||||
req->invoke_id = invoke_data[2];
|
||||
|
||||
/* optional part */
|
||||
if (invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID)
|
||||
offset += invoke_data[offset+1] + 2; /* skip over it */
|
||||
|
||||
/* mandatory part */
|
||||
if (invoke_data[offset] == GSM0480_OPERATION_CODE) {
|
||||
u_int8_t operation_code = invoke_data[offset+2];
|
||||
switch (operation_code) {
|
||||
case GSM0480_OP_CODE_PROCESS_USS_REQ:
|
||||
rc = parse_process_uss_req(invoke_data + offset + 3,
|
||||
length - offset - 3,
|
||||
req);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "GSM 04.80 operation code 0x%02x "
|
||||
"is not yet handled\n", operation_code);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x "
|
||||
"(expecting Operation Code tag)\n",
|
||||
invoke_data[0]);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Parse the parameters of a Process UnstructuredSS Request */
|
||||
static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length,
|
||||
struct ussd_request *req)
|
||||
{
|
||||
int rc = 0;
|
||||
int num_chars;
|
||||
u_int8_t dcs;
|
||||
|
||||
if (uss_req_data[0] == GSM_0480_SEQUENCE_TAG) {
|
||||
if (uss_req_data[2] == ASN1_OCTET_STRING_TAG) {
|
||||
dcs = uss_req_data[4];
|
||||
if ((dcs == 0x0F) &&
|
||||
(uss_req_data[5] == ASN1_OCTET_STRING_TAG)) {
|
||||
num_chars = (uss_req_data[6] * 8) / 7;
|
||||
/* Prevent a mobile-originated buffer-overrun! */
|
||||
if (num_chars > MAX_LEN_USSD_STRING)
|
||||
num_chars = MAX_LEN_USSD_STRING;
|
||||
gsm_7bit_decode(req->text,
|
||||
&(uss_req_data[7]), num_chars);
|
||||
/* append null-terminator */
|
||||
req->text[num_chars+1] = 0;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct msgb *gsm0480_create_notifySS(const char *text)
|
||||
{
|
||||
struct msgb *msg;
|
||||
uint8_t *data, *tmp_len;
|
||||
uint8_t *seq_len_ptr, *cal_len_ptr, *opt_len_ptr, *nam_len_ptr;
|
||||
int len;
|
||||
|
||||
len = strlen(text);
|
||||
if (len < 1 || len > 160)
|
||||
return NULL;
|
||||
|
||||
msg = gsm48_msgb_alloc();
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msgb_put_u8(msg, GSM_0480_SEQUENCE_TAG);
|
||||
seq_len_ptr = msgb_put(msg, 1);
|
||||
|
||||
/* ss_code for CNAP { */
|
||||
msgb_put_u8(msg, 0x81);
|
||||
msgb_put_u8(msg, 1);
|
||||
msgb_put_u8(msg, 0x19);
|
||||
/* } ss_code */
|
||||
|
||||
|
||||
/* nameIndicator { */
|
||||
msgb_put_u8(msg, 0xB4);
|
||||
nam_len_ptr = msgb_put(msg, 1);
|
||||
|
||||
/* callingName { */
|
||||
msgb_put_u8(msg, 0xA0);
|
||||
opt_len_ptr = msgb_put(msg, 1);
|
||||
msgb_put_u8(msg, 0xA0);
|
||||
cal_len_ptr = msgb_put(msg, 1);
|
||||
|
||||
/* namePresentationAllowed { */
|
||||
/* add the DCS value */
|
||||
msgb_put_u8(msg, 0x80);
|
||||
msgb_put_u8(msg, 1);
|
||||
msgb_put_u8(msg, 0x0F);
|
||||
|
||||
/* add the lengthInCharacters */
|
||||
msgb_put_u8(msg, 0x81);
|
||||
msgb_put_u8(msg, 1);
|
||||
msgb_put_u8(msg, strlen(text));
|
||||
|
||||
/* add the actual string */
|
||||
msgb_put_u8(msg, 0x82);
|
||||
tmp_len = msgb_put(msg, 1);
|
||||
data = msgb_put(msg, 0);
|
||||
len = gsm_7bit_encode(data, text);
|
||||
tmp_len[0] = len;
|
||||
msgb_put(msg, len);
|
||||
|
||||
/* }; namePresentationAllowed */
|
||||
|
||||
cal_len_ptr[0] = 3 + 3 + 2 + len;
|
||||
opt_len_ptr[0] = cal_len_ptr[0] + 2;
|
||||
/* }; callingName */
|
||||
|
||||
nam_len_ptr[0] = opt_len_ptr[0] + 2;
|
||||
/* ); nameIndicator */
|
||||
|
||||
/* write the lengths... */
|
||||
seq_len_ptr[0] = 3 + nam_len_ptr[0] + 2;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char *text)
|
||||
{
|
||||
struct msgb *msg;
|
||||
uint8_t *seq_len_ptr, *ussd_len_ptr, *data;
|
||||
int len;
|
||||
|
||||
msg = gsm48_msgb_alloc();
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
/* SEQUENCE { */
|
||||
msgb_put_u8(msg, GSM_0480_SEQUENCE_TAG);
|
||||
seq_len_ptr = msgb_put(msg, 1);
|
||||
|
||||
/* DCS { */
|
||||
msgb_put_u8(msg, ASN1_OCTET_STRING_TAG);
|
||||
msgb_put_u8(msg, 1);
|
||||
msgb_put_u8(msg, 0x0F);
|
||||
/* } DCS */
|
||||
|
||||
/* USSD-String { */
|
||||
msgb_put_u8(msg, ASN1_OCTET_STRING_TAG);
|
||||
ussd_len_ptr = msgb_put(msg, 1);
|
||||
data = msgb_put(msg, 0);
|
||||
len = gsm_7bit_encode(data, text);
|
||||
msgb_put(msg, len);
|
||||
ussd_len_ptr[0] = len;
|
||||
/* USSD-String } */
|
||||
|
||||
/* alertingPattern { */
|
||||
msgb_put_u8(msg, ASN1_OCTET_STRING_TAG);
|
||||
msgb_put_u8(msg, 1);
|
||||
msgb_put_u8(msg, alertPattern);
|
||||
/* } alertingPattern */
|
||||
|
||||
seq_len_ptr[0] = 3 + 2 + ussd_len_ptr[0] + 3;
|
||||
/* } SEQUENCE */
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* Send response to a mobile-originated ProcessUnstructuredSS-Request */
|
||||
int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_text,
|
||||
const struct ussd_request *req)
|
||||
@@ -407,35 +112,6 @@ int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_t
|
||||
return gsm48_sendmsg(msg, NULL);
|
||||
}
|
||||
|
||||
/* wrap an invoke around it... the other way around
|
||||
*
|
||||
* 1.) Invoke Component tag
|
||||
* 2.) Invoke ID Tag
|
||||
* 3.) Operation
|
||||
* 4.) Data
|
||||
*/
|
||||
int gsm0480_wrap_invoke(struct msgb *msg, int op, int link_id)
|
||||
{
|
||||
/* 3. operation */
|
||||
msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, op);
|
||||
|
||||
/* 2. invoke id tag */
|
||||
msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, link_id);
|
||||
|
||||
/* 1. component tag */
|
||||
msgb_wrap_with_TL(msg, GSM0480_CTYPE_INVOKE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wrap the GSM 04.08 Facility IE around it */
|
||||
int gsm0480_wrap_facility(struct msgb *msg)
|
||||
{
|
||||
msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gsm0480_send_ussd_reject(const struct msgb *in_msg,
|
||||
const struct ussd_request *req)
|
||||
{
|
||||
|
||||
@@ -573,7 +573,7 @@ static int handle_ts1_write(struct bsc_fd *bfd)
|
||||
e1i_ts->sign.tx_timer.data = e1i_ts;
|
||||
|
||||
/* Reducing this might break the nanoBTS 900 init. */
|
||||
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 0);
|
||||
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -607,7 +607,7 @@ static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
|
||||
struct e1inp_driver ipaccess_driver = {
|
||||
.name = "ip.access",
|
||||
.want_write = ts_want_write,
|
||||
.default_delay = 100000,
|
||||
.default_delay = 0,
|
||||
};
|
||||
|
||||
/* callback of the OML listening filedescriptor */
|
||||
|
||||
@@ -128,7 +128,7 @@ static int mgcp_rsip_cb(struct mgcp_config *cfg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mgcp_change_cb(struct mgcp_config *cfg, int endpoint, int state, int local_rtp)
|
||||
static int mgcp_change_cb(struct mgcp_config *cfg, int endpoint, int state)
|
||||
{
|
||||
if (state != MGCP_ENDP_MDCX)
|
||||
return 0;
|
||||
|
||||
@@ -90,11 +90,12 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp)
|
||||
{
|
||||
static char buf[] = { DUMMY_LOAD };
|
||||
|
||||
return udp_send(endp->local_rtp.fd, &endp->remote,
|
||||
endp->net_rtp, buf, 1);
|
||||
return udp_send(endp->net_end.rtp.fd, &endp->net_end.addr,
|
||||
endp->net_end.rtp_port, buf, 1);
|
||||
}
|
||||
|
||||
static void patch_and_count(struct mgcp_rtp_state *state, int payload, char *data, int len)
|
||||
static void patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
|
||||
int payload, struct sockaddr_in *addr, char *data, int len)
|
||||
{
|
||||
uint16_t seq;
|
||||
uint32_t timestamp;
|
||||
@@ -116,9 +117,11 @@ static void patch_and_count(struct mgcp_rtp_state *state, int payload, char *dat
|
||||
state->ssrc = rtp_hdr->ssrc;
|
||||
state->seq_offset = (state->seq_no + 1) - seq;
|
||||
state->timestamp_offset = state->last_timestamp - timestamp;
|
||||
state->patch = 1;
|
||||
LOGP(DMGCP, LOGL_NOTICE, "The SSRC changed... SSRC: %u offset: %d\n",
|
||||
state->ssrc, state->seq_offset);
|
||||
state->patch = endp->allow_patch;
|
||||
LOGP(DMGCP, LOGL_NOTICE,
|
||||
"The SSRC changed on 0x%x SSRC: %u offset: %d from %s:%d in %d\n",
|
||||
ENDPOINT_NUMBER(endp), state->ssrc, state->seq_offset,
|
||||
inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode);
|
||||
}
|
||||
|
||||
/* apply the offset and store it back to the packet */
|
||||
@@ -145,87 +148,21 @@ static void patch_and_count(struct mgcp_rtp_state *state, int payload, char *dat
|
||||
}
|
||||
|
||||
/*
|
||||
* There is data coming. We will have to figure out if it
|
||||
* came from the BTS or the MediaGateway of the MSC. On top
|
||||
* of that we need to figure out if it was RTP or RTCP.
|
||||
*
|
||||
* Currently we do not communicate with the BSC so we have
|
||||
* no idea where the BTS is listening for RTP and need to
|
||||
* do the classic routing trick. Wait for the first packet
|
||||
* from the BTS and then go ahead.
|
||||
* The below code is for dispatching. We have a dedicated port for
|
||||
* the data coming from the net and one to discover the BTS.
|
||||
*/
|
||||
static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
||||
static int forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf, int len)
|
||||
{
|
||||
char buf[4096];
|
||||
struct sockaddr_in addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
struct mgcp_endpoint *endp;
|
||||
struct mgcp_config *cfg;
|
||||
int rc, dest, proto;
|
||||
|
||||
endp = (struct mgcp_endpoint *) fd->data;
|
||||
cfg = endp->cfg;
|
||||
|
||||
rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
|
||||
(struct sockaddr *) &addr, &slen);
|
||||
if (rc < 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
|
||||
ENDPOINT_NUMBER(endp), errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* do not forward aynthing... maybe there is a packet from the bts */
|
||||
if (endp->ci == CI_UNUSED) {
|
||||
LOGP(DMGCP, LOGL_DEBUG, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out where to forward it to. This code assumes that we
|
||||
* have received the Connection Modify and know who is a legitimate
|
||||
* partner. According to the spec we could attempt to forward even
|
||||
* after the Create Connection but we will not as we are not really
|
||||
* able to tell if this is legitimate.
|
||||
*/
|
||||
#warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
|
||||
dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
|
||||
(endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
|
||||
? DEST_BTS : DEST_NETWORK;
|
||||
proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
|
||||
|
||||
/* We have no idea who called us, maybe it is the BTS. */
|
||||
if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
|
||||
/* it was the BTS... */
|
||||
if (!cfg->bts_ip
|
||||
|| memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0
|
||||
|| memcmp(&addr.sin_addr, &endp->bts, sizeof(endp->bts)) == 0) {
|
||||
if (fd == &endp->local_rtp) {
|
||||
endp->bts_rtp = addr.sin_port;
|
||||
} else {
|
||||
endp->bts_rtcp = addr.sin_port;
|
||||
}
|
||||
|
||||
endp->bts = addr.sin_addr;
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d of %s\n",
|
||||
ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
|
||||
inet_ntoa(addr.sin_addr));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* throw away the dummy message */
|
||||
if (rc == 1 && buf[0] == DUMMY_LOAD) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy on 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
if (!tap->enabled)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do this before the loop handling */
|
||||
if (dest == DEST_NETWORK)
|
||||
++endp->in_bts;
|
||||
else
|
||||
++endp->in_remote;
|
||||
|
||||
return sendto(fd, buf, len, 0,
|
||||
(struct sockaddr *)&tap->forward, sizeof(tap->forward));
|
||||
}
|
||||
static int send_to(struct mgcp_endpoint *endp, int dest, int is_rtp,
|
||||
struct sockaddr_in *addr, char *buf, int rc)
|
||||
{
|
||||
struct mgcp_config *cfg = endp->cfg;
|
||||
/* For loop toggle the destination and then dispatch. */
|
||||
if (cfg->audio_loop)
|
||||
dest = !dest;
|
||||
@@ -235,22 +172,176 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
||||
dest = !dest;
|
||||
|
||||
if (dest == DEST_NETWORK) {
|
||||
if (proto == PROTO_RTP)
|
||||
patch_and_count(&endp->bts_state,
|
||||
endp->net_payload_type, buf, rc);
|
||||
return udp_send(fd->fd, &endp->remote,
|
||||
proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
|
||||
buf, rc);
|
||||
if (is_rtp) {
|
||||
patch_and_count(endp, &endp->bts_state,
|
||||
endp->net_end.payload_type,
|
||||
addr, buf, rc);
|
||||
forward_data(endp->net_end.rtp.fd,
|
||||
&endp->taps[MGCP_TAP_NET_OUT], buf, rc);
|
||||
return udp_send(endp->net_end.rtp.fd, &endp->net_end.addr,
|
||||
endp->net_end.rtp_port, buf, rc);
|
||||
} else {
|
||||
return udp_send(endp->net_end.rtcp.fd, &endp->net_end.addr,
|
||||
endp->net_end.rtcp_port, buf, rc);
|
||||
}
|
||||
} else {
|
||||
if (proto == PROTO_RTP)
|
||||
patch_and_count(&endp->net_state,
|
||||
endp->bts_payload_type, buf, rc);
|
||||
return udp_send(fd->fd, &endp->bts,
|
||||
proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
|
||||
buf, rc);
|
||||
if (is_rtp) {
|
||||
patch_and_count(endp, &endp->net_state,
|
||||
endp->bts_end.payload_type,
|
||||
addr, buf, rc);
|
||||
forward_data(endp->bts_end.rtp.fd,
|
||||
&endp->taps[MGCP_TAP_BTS_OUT], buf, rc);
|
||||
return udp_send(endp->bts_end.rtp.fd, &endp->bts_end.addr,
|
||||
endp->bts_end.rtp_port, buf, rc);
|
||||
} else {
|
||||
return udp_send(endp->bts_end.rtcp.fd, &endp->bts_end.addr,
|
||||
endp->bts_end.rtcp_port, buf, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int recevice_from(struct mgcp_endpoint *endp, int fd, struct sockaddr_in *addr,
|
||||
char *buf, int bufsize)
|
||||
{
|
||||
int rc;
|
||||
socklen_t slen = sizeof(*addr);
|
||||
|
||||
rc = recvfrom(fd, buf, bufsize, 0,
|
||||
(struct sockaddr *) addr, &slen);
|
||||
if (rc < 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
|
||||
ENDPOINT_NUMBER(endp), errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* do not forward aynthing... maybe there is a packet from the bts */
|
||||
if (!endp->allocated)
|
||||
return -1;
|
||||
|
||||
#warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rtp_data_net(struct bsc_fd *fd, unsigned int what)
|
||||
{
|
||||
char buf[4096];
|
||||
struct sockaddr_in addr;
|
||||
struct mgcp_endpoint *endp;
|
||||
int rc, proto;
|
||||
|
||||
endp = (struct mgcp_endpoint *) fd->data;
|
||||
|
||||
rc = recevice_from(endp, fd->fd, &addr, buf, sizeof(buf));
|
||||
if (rc <= 0)
|
||||
return -1;
|
||||
|
||||
if (memcmp(&addr.sin_addr, &endp->net_end.addr, sizeof(addr.sin_addr)) != 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR,
|
||||
"Data from wrong address %s on 0x%x\n",
|
||||
inet_ntoa(addr.sin_addr), ENDPOINT_NUMBER(endp));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (endp->net_end.rtp_port != addr.sin_port &&
|
||||
endp->net_end.rtcp_port != addr.sin_port) {
|
||||
LOGP(DMGCP, LOGL_ERROR,
|
||||
"Data from wrong source port %d on 0x%x\n",
|
||||
ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* throw away the dummy message */
|
||||
if (rc == 1 && buf[0] == DUMMY_LOAD) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from network on 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
proto = fd == &endp->net_end.rtp ? PROTO_RTP : PROTO_RTCP;
|
||||
endp->net_end.packets += 1;
|
||||
|
||||
forward_data(fd->fd, &endp->taps[MGCP_TAP_NET_IN], buf, rc);
|
||||
return send_to(endp, DEST_BTS, proto == PROTO_RTP, &addr, &buf[0], rc);
|
||||
}
|
||||
|
||||
static void discover_bts(struct mgcp_endpoint *endp, int proto, struct sockaddr_in *addr)
|
||||
{
|
||||
struct mgcp_config *cfg = endp->cfg;
|
||||
|
||||
if (proto == PROTO_RTP && endp->bts_end.rtp_port == 0) {
|
||||
if (!cfg->bts_ip ||
|
||||
memcmp(&addr->sin_addr,
|
||||
&cfg->bts_in, sizeof(cfg->bts_in)) == 0 ||
|
||||
memcmp(&addr->sin_addr,
|
||||
&endp->bts_end.addr, sizeof(endp->bts_end.addr)) == 0) {
|
||||
|
||||
endp->bts_end.rtp_port = addr->sin_port;
|
||||
endp->bts_end.addr = addr->sin_addr;
|
||||
|
||||
LOGP(DMGCP, LOGL_NOTICE,
|
||||
"Found BTS for endpoint: 0x%x on port: %d/%d of %s\n",
|
||||
ENDPOINT_NUMBER(endp), ntohs(endp->bts_end.rtp_port),
|
||||
ntohs(endp->bts_end.rtcp_port), inet_ntoa(addr->sin_addr));
|
||||
}
|
||||
} else if (proto == PROTO_RTCP && endp->bts_end.rtcp_port == 0) {
|
||||
if (memcmp(&endp->bts_end.addr, &addr->sin_addr,
|
||||
sizeof(endp->bts_end.addr)) == 0) {
|
||||
endp->bts_end.rtcp_port = addr->sin_port;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int rtp_data_bts(struct bsc_fd *fd, unsigned int what)
|
||||
{
|
||||
char buf[4096];
|
||||
struct sockaddr_in addr;
|
||||
struct mgcp_endpoint *endp;
|
||||
struct mgcp_config *cfg;
|
||||
int rc, proto;
|
||||
|
||||
endp = (struct mgcp_endpoint *) fd->data;
|
||||
cfg = endp->cfg;
|
||||
|
||||
rc = recevice_from(endp, fd->fd, &addr, buf, sizeof(buf));
|
||||
if (rc <= 0)
|
||||
return -1;
|
||||
|
||||
proto = fd == &endp->bts_end.rtp ? PROTO_RTP : PROTO_RTCP;
|
||||
|
||||
/* We have no idea who called us, maybe it is the BTS. */
|
||||
/* it was the BTS... */
|
||||
discover_bts(endp, proto, &addr);
|
||||
|
||||
if (memcmp(&endp->bts_end.addr, &addr.sin_addr, sizeof(addr.sin_addr)) != 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR,
|
||||
"Data from wrong bts %s on 0x%x\n",
|
||||
inet_ntoa(addr.sin_addr), ENDPOINT_NUMBER(endp));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (endp->bts_end.rtp_port != addr.sin_port &&
|
||||
endp->bts_end.rtcp_port != addr.sin_port) {
|
||||
LOGP(DMGCP, LOGL_ERROR,
|
||||
"Data from wrong bts source port %d on 0x%x\n",
|
||||
ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* throw away the dummy message */
|
||||
if (rc == 1 && buf[0] == DUMMY_LOAD) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from bts on 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do this before the loop handling */
|
||||
endp->bts_end.packets += 1;
|
||||
|
||||
forward_data(fd->fd, &endp->taps[MGCP_TAP_BTS_IN], buf, rc);
|
||||
return send_to(endp, DEST_NETWORK, proto == PROTO_RTP, &addr, &buf[0], rc);
|
||||
}
|
||||
|
||||
static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
@@ -269,6 +360,8 @@ static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
|
||||
inet_aton(source_addr, &addr.sin_addr);
|
||||
|
||||
if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
close(fd->fd);
|
||||
fd->fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -283,59 +376,96 @@ static int set_ip_tos(int fd, int tos)
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
static int bind_rtp(struct mgcp_endpoint *endp)
|
||||
static int bind_rtp(struct mgcp_config *cfg, struct mgcp_rtp_end *rtp_end, int endpno)
|
||||
{
|
||||
struct mgcp_config *cfg = endp->cfg;
|
||||
|
||||
if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) {
|
||||
if (create_bind(cfg->source_addr, &rtp_end->rtp, rtp_end->local_port) != 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n",
|
||||
cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp));
|
||||
cfg->source_addr, rtp_end->local_port, endpno);
|
||||
goto cleanup0;
|
||||
}
|
||||
|
||||
if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) {
|
||||
if (create_bind(cfg->source_addr, &rtp_end->rtcp, rtp_end->local_port + 1) != 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n",
|
||||
cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
|
||||
cfg->source_addr, rtp_end->local_port + 1, endpno);
|
||||
goto cleanup1;
|
||||
}
|
||||
|
||||
set_ip_tos(endp->local_rtp.fd, cfg->endp_dscp);
|
||||
set_ip_tos(endp->local_rtcp.fd, cfg->endp_dscp);
|
||||
set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
|
||||
set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
|
||||
|
||||
endp->local_rtp.cb = rtp_data_cb;
|
||||
endp->local_rtp.data = endp;
|
||||
endp->local_rtp.when = BSC_FD_READ;
|
||||
if (bsc_register_fd(&endp->local_rtp) != 0) {
|
||||
rtp_end->rtp.when = BSC_FD_READ;
|
||||
if (bsc_register_fd(&rtp_end->rtp) != 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n",
|
||||
endp->rtp_port, ENDPOINT_NUMBER(endp));
|
||||
rtp_end->local_port, endpno);
|
||||
goto cleanup2;
|
||||
}
|
||||
|
||||
endp->local_rtcp.cb = rtp_data_cb;
|
||||
endp->local_rtcp.data = endp;
|
||||
endp->local_rtcp.when = BSC_FD_READ;
|
||||
if (bsc_register_fd(&endp->local_rtcp) != 0) {
|
||||
rtp_end->rtcp.when = BSC_FD_READ;
|
||||
if (bsc_register_fd(&rtp_end->rtcp) != 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n",
|
||||
endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
|
||||
rtp_end->local_port + 1, endpno);
|
||||
goto cleanup3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup3:
|
||||
bsc_unregister_fd(&endp->local_rtp);
|
||||
bsc_unregister_fd(&rtp_end->rtp);
|
||||
cleanup2:
|
||||
close(endp->local_rtcp.fd);
|
||||
endp->local_rtcp.fd = -1;
|
||||
close(rtp_end->rtcp.fd);
|
||||
rtp_end->rtcp.fd = -1;
|
||||
cleanup1:
|
||||
close(endp->local_rtp.fd);
|
||||
endp->local_rtp.fd = -1;
|
||||
close(rtp_end->rtp.fd);
|
||||
rtp_end->rtp.fd = -1;
|
||||
cleanup0:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
|
||||
int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
|
||||
{
|
||||
endp->rtp_port = rtp_port;
|
||||
return bind_rtp(endp);
|
||||
if (endp->bts_end.rtp.fd != -1 || endp->bts_end.rtcp.fd != -1) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Previous bts-port was still bound on %d\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
mgcp_free_rtp_port(&endp->bts_end);
|
||||
}
|
||||
|
||||
endp->bts_end.local_port = rtp_port;
|
||||
endp->bts_end.rtp.cb = rtp_data_bts;
|
||||
endp->bts_end.rtp.data = endp;
|
||||
endp->bts_end.rtcp.data = endp;
|
||||
endp->bts_end.rtcp.cb = rtp_data_bts;
|
||||
return bind_rtp(endp->cfg, &endp->bts_end, ENDPOINT_NUMBER(endp));
|
||||
}
|
||||
|
||||
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
|
||||
{
|
||||
if (endp->net_end.rtp.fd != -1 || endp->net_end.rtcp.fd != -1) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Previous net-port was still bound on %d\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
mgcp_free_rtp_port(&endp->net_end);
|
||||
}
|
||||
|
||||
endp->net_end.local_port = rtp_port;
|
||||
endp->net_end.rtp.cb = rtp_data_net;
|
||||
endp->net_end.rtp.data = endp;
|
||||
endp->net_end.rtcp.data = endp;
|
||||
endp->net_end.rtcp.cb = rtp_data_net;
|
||||
return bind_rtp(endp->cfg, &endp->net_end, ENDPOINT_NUMBER(endp));
|
||||
}
|
||||
|
||||
int mgcp_free_rtp_port(struct mgcp_rtp_end *end)
|
||||
{
|
||||
if (end->rtp.fd != -1) {
|
||||
close(end->rtp.fd);
|
||||
end->rtp.fd = -1;
|
||||
bsc_unregister_fd(&end->rtp);
|
||||
}
|
||||
|
||||
if (end->rtcp.fd != -1) {
|
||||
close(end->rtcp.fd);
|
||||
end->rtcp.fd = -1;
|
||||
bsc_unregister_fd(&end->rtcp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
} \
|
||||
}
|
||||
|
||||
static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
|
||||
|
||||
struct mgcp_request {
|
||||
char *name;
|
||||
@@ -88,7 +89,7 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
|
||||
static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
|
||||
|
||||
static int generate_call_id(struct mgcp_config *cfg)
|
||||
static uint32_t generate_call_id(struct mgcp_config *cfg)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -169,13 +170,13 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
|
||||
addr = endp->cfg->source_addr;
|
||||
|
||||
snprintf(sdp_record, sizeof(sdp_record) - 1,
|
||||
"I: %d\n\n"
|
||||
"I: %u\n\n"
|
||||
"v=0\r\n"
|
||||
"c=IN IP4 %s\r\n"
|
||||
"m=audio %d RTP/AVP %d\r\n"
|
||||
"a=rtpmap:%d %s\r\n",
|
||||
endp->ci, addr, endp->rtp_port,
|
||||
endp->bts_payload_type, endp->bts_payload_type,
|
||||
endp->ci, addr, endp->net_end.local_port,
|
||||
endp->bts_end.payload_type, endp->bts_end.payload_type,
|
||||
endp->cfg->audio_name);
|
||||
return mgcp_create_response_with_data(200, msg, trans_id, sdp_record);
|
||||
}
|
||||
@@ -323,11 +324,13 @@ static int verify_call_id(const struct mgcp_endpoint *endp,
|
||||
}
|
||||
|
||||
static int verify_ci(const struct mgcp_endpoint *endp,
|
||||
const char *ci)
|
||||
const char *_ci)
|
||||
{
|
||||
if (atoi(ci) != endp->ci) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n",
|
||||
ENDPOINT_NUMBER(endp), endp->ci, ci);
|
||||
uint32_t ci = strtoul(_ci, NULL, 10);
|
||||
|
||||
if (ci != endp->ci) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "ConnectionIdentifiers do not match on 0x%x. %u != %s\n",
|
||||
ENDPOINT_NUMBER(endp), endp->ci, _ci);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -367,6 +370,54 @@ static int parse_conn_mode(const char* msg, int *conn_mode)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
|
||||
struct mgcp_port_range *range, int for_net)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (range->mode == PORT_ALLOC_STATIC) {
|
||||
end->local_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), range->base_port);
|
||||
end->local_alloc = PORT_ALLOC_STATIC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* attempt to find a port */
|
||||
for (i = 0; i < 200; ++i) {
|
||||
int rc;
|
||||
|
||||
if (range->last_port >= range->range_end)
|
||||
range->last_port = range->range_start;
|
||||
|
||||
rc = for_net ?
|
||||
mgcp_bind_net_rtp_port(endp, range->last_port) :
|
||||
mgcp_bind_bts_rtp_port(endp, range->last_port);
|
||||
|
||||
range->last_port += 2;
|
||||
if (rc == 0) {
|
||||
end->local_alloc = PORT_ALLOC_DYNAMIC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x net: %d\n",
|
||||
ENDPOINT_NUMBER(endp), for_net);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int allocate_ports(struct mgcp_endpoint *endp)
|
||||
{
|
||||
if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports, 1) != 0)
|
||||
return -1;
|
||||
|
||||
if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports, 0) != 0) {
|
||||
mgcp_rtp_end_reset(&endp->net_end);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
{
|
||||
struct mgcp_msg_ptr data_ptrs[6];
|
||||
@@ -374,17 +425,18 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
const char *trans_id;
|
||||
struct mgcp_endpoint *endp;
|
||||
int error_code = 500;
|
||||
int port;
|
||||
|
||||
found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
|
||||
if (found != 0)
|
||||
return create_response(500, "CRCX", trans_id);
|
||||
|
||||
if (endp->ci != CI_UNUSED) {
|
||||
if (endp->allocated) {
|
||||
if (cfg->force_realloc) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
mgcp_free_endp(endp);
|
||||
if (cfg->realloc_cb)
|
||||
cfg->realloc_cb(cfg, ENDPOINT_NUMBER(endp));
|
||||
} else {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
@@ -421,16 +473,13 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
MSG_TOKENIZE_END
|
||||
|
||||
/* initialize */
|
||||
endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
|
||||
endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;
|
||||
|
||||
/* set to zero until we get the info */
|
||||
memset(&endp->remote, 0, sizeof(endp->remote));
|
||||
memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr));
|
||||
|
||||
/* bind to the port now */
|
||||
port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port);
|
||||
if (cfg->early_bind)
|
||||
endp->rtp_port = port;
|
||||
else if (mgcp_bind_rtp_port(endp, port) != 0)
|
||||
if (allocate_ports(endp) != 0)
|
||||
goto error2;
|
||||
|
||||
/* assign a local call identifier or fail */
|
||||
@@ -438,7 +487,8 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
if (endp->ci == CI_UNUSED)
|
||||
goto error2;
|
||||
|
||||
endp->bts_payload_type = cfg->audio_payload;
|
||||
endp->allocated = 1;
|
||||
endp->bts_end.payload_type = cfg->audio_payload;
|
||||
|
||||
/* policy CB */
|
||||
if (cfg->policy_cb) {
|
||||
@@ -459,10 +509,11 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
}
|
||||
}
|
||||
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Creating endpoint on: 0x%x CI: %u port: %u\n",
|
||||
ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port);
|
||||
LOGP(DMGCP, LOGL_DEBUG, "Creating endpoint on: 0x%x CI: %u port: %u/%u\n",
|
||||
ENDPOINT_NUMBER(endp), endp->ci,
|
||||
endp->net_end.local_port, endp->bts_end.local_port);
|
||||
if (cfg->change_cb)
|
||||
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX, endp->rtp_port);
|
||||
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
|
||||
|
||||
return create_response_with_sdp(endp, "CRCX", trans_id);
|
||||
error:
|
||||
@@ -472,6 +523,7 @@ error:
|
||||
return create_response(error_code, "CRCX", trans_id);
|
||||
|
||||
error2:
|
||||
mgcp_free_endp(endp);
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
|
||||
return create_response(error_code, "CRCX", trans_id);
|
||||
}
|
||||
@@ -536,9 +588,9 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
const char *param = (const char *)&msg->l3h[line_start];
|
||||
|
||||
if (sscanf(param, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
|
||||
endp->net_rtp = htons(port);
|
||||
endp->net_rtcp = htons(port + 1);
|
||||
endp->net_payload_type = payload;
|
||||
endp->net_end.rtp_port = htons(port);
|
||||
endp->net_end.rtcp_port = htons(port + 1);
|
||||
endp->net_end.payload_type = payload;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -547,7 +599,7 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
const char *param = (const char *)&msg->l3h[line_start];
|
||||
|
||||
if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
|
||||
inet_aton(ipv4, &endp->remote);
|
||||
inet_aton(ipv4, &endp->net_end.addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -580,10 +632,10 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
}
|
||||
|
||||
/* modify */
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Modified endpoint on: 0x%x Server: %s:%u\n",
|
||||
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
|
||||
LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n",
|
||||
ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
|
||||
if (cfg->change_cb)
|
||||
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port);
|
||||
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
|
||||
if (silent)
|
||||
goto out_silent;
|
||||
|
||||
@@ -616,7 +668,7 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
if (found != 0)
|
||||
return create_response(error_code, "DLCX", trans_id);
|
||||
|
||||
if (endp->ci == CI_UNUSED) {
|
||||
if (!endp->allocated) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
|
||||
return create_response(error_code, "DLCX", trans_id);
|
||||
}
|
||||
@@ -665,11 +717,11 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
}
|
||||
|
||||
/* free the connection */
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Deleted endpoint on: 0x%x Server: %s:%u\n",
|
||||
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
|
||||
LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
|
||||
ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
|
||||
mgcp_free_endp(endp);
|
||||
if (cfg->change_cb)
|
||||
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port);
|
||||
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
|
||||
|
||||
if (silent)
|
||||
goto out_silent;
|
||||
@@ -709,11 +761,32 @@ struct mgcp_config *mgcp_config_alloc(void)
|
||||
cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
|
||||
cfg->audio_name = talloc_strdup(cfg, "GSM-EFR/8000");
|
||||
cfg->audio_payload = 97;
|
||||
cfg->rtp_base_port = RTP_PORT_DEFAULT;
|
||||
|
||||
cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
|
||||
cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end)
|
||||
{
|
||||
if (end->local_alloc == PORT_ALLOC_DYNAMIC)
|
||||
mgcp_free_rtp_port(end);
|
||||
|
||||
end->packets = 0;
|
||||
memset(&end->addr, 0, sizeof(end->addr));
|
||||
end->rtp_port = end->rtcp_port = end->local_port = 0;
|
||||
end->payload_type = -1;
|
||||
end->local_alloc = -1;
|
||||
}
|
||||
|
||||
static void mgcp_rtp_end_init(struct mgcp_rtp_end *end)
|
||||
{
|
||||
mgcp_rtp_end_reset(end);
|
||||
end->rtp.fd = -1;
|
||||
end->rtcp.fd = -1;
|
||||
}
|
||||
|
||||
int mgcp_endpoints_allocate(struct mgcp_config *cfg)
|
||||
{
|
||||
int i;
|
||||
@@ -726,12 +799,10 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < cfg->number_endpoints; ++i) {
|
||||
cfg->endpoints[i].local_rtp.fd = -1;
|
||||
cfg->endpoints[i].local_rtcp.fd = -1;
|
||||
cfg->endpoints[i].ci = CI_UNUSED;
|
||||
cfg->endpoints[i].cfg = cfg;
|
||||
cfg->endpoints[i].net_payload_type = -1;
|
||||
cfg->endpoints[i].bts_payload_type = -1;
|
||||
mgcp_rtp_end_init(&cfg->endpoints[i].net_end);
|
||||
mgcp_rtp_end_init(&cfg->endpoints[i].bts_end);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -741,6 +812,7 @@ void mgcp_free_endp(struct mgcp_endpoint *endp)
|
||||
{
|
||||
LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
|
||||
endp->ci = CI_UNUSED;
|
||||
endp->allocated = 0;
|
||||
|
||||
if (endp->callid) {
|
||||
talloc_free(endp->callid);
|
||||
@@ -752,19 +824,14 @@ void mgcp_free_endp(struct mgcp_endpoint *endp)
|
||||
endp->local_options = NULL;
|
||||
}
|
||||
|
||||
if (!endp->cfg->early_bind) {
|
||||
bsc_unregister_fd(&endp->local_rtp);
|
||||
bsc_unregister_fd(&endp->local_rtcp);
|
||||
}
|
||||
|
||||
endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
|
||||
endp->net_payload_type = endp->bts_payload_type = -1;
|
||||
endp->in_bts = endp->in_remote = 0;
|
||||
memset(&endp->remote, 0, sizeof(endp->remote));
|
||||
memset(&endp->bts, 0, sizeof(endp->bts));
|
||||
mgcp_rtp_end_reset(&endp->bts_end);
|
||||
mgcp_rtp_end_reset(&endp->net_end);
|
||||
|
||||
memset(&endp->net_state, 0, sizeof(endp->net_state));
|
||||
memset(&endp->bts_state, 0, sizeof(endp->bts_state));
|
||||
|
||||
endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE;
|
||||
endp->allow_patch = 0;
|
||||
|
||||
memset(&endp->taps, 0, sizeof(endp->taps));
|
||||
}
|
||||
|
||||
@@ -55,8 +55,19 @@ static int config_write_mgcp(struct vty *vty)
|
||||
vty_out(vty, " bts ip %s%s", g_cfg->bts_ip, VTY_NEWLINE);
|
||||
vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
|
||||
vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
|
||||
vty_out(vty, " bind early %u%s", !!g_cfg->early_bind, VTY_NEWLINE);
|
||||
vty_out(vty, " rtp base %u%s", g_cfg->rtp_base_port, VTY_NEWLINE);
|
||||
|
||||
if (g_cfg->bts_ports.mode == PORT_ALLOC_STATIC)
|
||||
vty_out(vty, " rtp bts-base %u%s", g_cfg->bts_ports.base_port, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " rtp bts-range %u %u%s",
|
||||
g_cfg->bts_ports.range_start, g_cfg->bts_ports.range_end, VTY_NEWLINE);
|
||||
|
||||
if (g_cfg->net_ports.mode == PORT_ALLOC_STATIC)
|
||||
vty_out(vty, " rtp net-base %u%s", g_cfg->net_ports.base_port, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " rtp net-range %u %u%s",
|
||||
g_cfg->net_ports.range_start, g_cfg->net_ports.range_end, VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE);
|
||||
if (g_cfg->audio_payload != -1)
|
||||
vty_out(vty, " sdp audio payload number %d%s", g_cfg->audio_payload, VTY_NEWLINE);
|
||||
@@ -64,10 +75,6 @@ static int config_write_mgcp(struct vty *vty)
|
||||
vty_out(vty, " sdp audio payload name %s%s", g_cfg->audio_name, VTY_NEWLINE);
|
||||
vty_out(vty, " loop %u%s", !!g_cfg->audio_loop, VTY_NEWLINE);
|
||||
vty_out(vty, " number endpoints %u%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
|
||||
if (g_cfg->forward_ip)
|
||||
vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
|
||||
if (g_cfg->forward_port != 0)
|
||||
vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
|
||||
if (g_cfg->call_agent_addr)
|
||||
vty_out(vty, " call agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
|
||||
|
||||
@@ -84,10 +91,11 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
|
||||
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
|
||||
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic received bts: %u/%u remote: %u/%u%s",
|
||||
i, endp->ci,
|
||||
ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
|
||||
ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
|
||||
inet_ntoa(endp->bts), endp->in_bts, endp->bts_state.lost_no,
|
||||
endp->in_remote, endp->net_state.lost_no,
|
||||
ntohs(endp->net_end.rtp_port), ntohs(endp->net_end.rtcp_port),
|
||||
ntohs(endp->bts_end.rtp_port), ntohs(endp->bts_end.rtcp_port),
|
||||
inet_ntoa(endp->bts_end.addr),
|
||||
endp->bts_end.packets, endp->bts_state.lost_no,
|
||||
endp->net_end.packets, endp->net_state.lost_no,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
@@ -152,21 +160,61 @@ DEFUN(cfg_mgcp_bind_early,
|
||||
"bind early (0|1)",
|
||||
"Bind all RTP ports early")
|
||||
{
|
||||
unsigned int bind = atoi(argv[0]);
|
||||
g_cfg->early_bind = bind == 1;
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "bind early is deprecated, remove it from the config.\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_rtp_base_port,
|
||||
cfg_mgcp_rtp_base_port_cmd,
|
||||
"rtp base <0-65534>",
|
||||
DEFUN(cfg_mgcp_rtp_bts_base_port,
|
||||
cfg_mgcp_rtp_bts_base_port_cmd,
|
||||
"rtp bts-base <0-65534>",
|
||||
"Base port to use")
|
||||
{
|
||||
unsigned int port = atoi(argv[0]);
|
||||
g_cfg->rtp_base_port = port;
|
||||
g_cfg->bts_ports.mode = PORT_ALLOC_STATIC;
|
||||
g_cfg->bts_ports.base_port = port;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_rtp_bts_range,
|
||||
cfg_mgcp_rtp_bts_range_cmd,
|
||||
"rtp bts-range <0-65534> <0-65534>",
|
||||
"Range of ports to allocate for endpoints\n"
|
||||
"Start of the range of ports\n" "End of the range of ports\n")
|
||||
{
|
||||
g_cfg->bts_ports.mode = PORT_ALLOC_DYNAMIC;
|
||||
g_cfg->bts_ports.range_start = atoi(argv[0]);
|
||||
g_cfg->bts_ports.range_end = atoi(argv[1]);
|
||||
g_cfg->bts_ports.last_port = g_cfg->bts_ports.range_start;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_rtp_net_range,
|
||||
cfg_mgcp_rtp_net_range_cmd,
|
||||
"rtp net-range <0-65534> <0-65534>",
|
||||
"Range of ports to allocate for endpoints\n"
|
||||
"Start of the range of ports\n" "End of the range of ports\n")
|
||||
{
|
||||
g_cfg->net_ports.mode = PORT_ALLOC_DYNAMIC;
|
||||
g_cfg->net_ports.range_start = atoi(argv[0]);
|
||||
g_cfg->net_ports.range_end = atoi(argv[1]);
|
||||
g_cfg->net_ports.last_port = g_cfg->net_ports.range_start;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_rtp_net_base_port,
|
||||
cfg_mgcp_rtp_net_base_port_cmd,
|
||||
"rtp net-base <0-65534>",
|
||||
"Base port to use for network port\n" "Port\n")
|
||||
{
|
||||
unsigned int port = atoi(argv[0]);
|
||||
g_cfg->net_ports.mode = PORT_ALLOC_STATIC;
|
||||
g_cfg->net_ports.base_port = port;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
ALIAS_DEPRECATED(cfg_mgcp_rtp_bts_base_port, cfg_mgcp_rtp_base_port_cmd,
|
||||
"rtp base <0-65534>", "Base port to use")
|
||||
|
||||
DEFUN(cfg_mgcp_rtp_ip_dscp,
|
||||
cfg_mgcp_rtp_ip_dscp_cmd,
|
||||
"rtp ip-dscp <0-255>",
|
||||
@@ -222,26 +270,6 @@ DEFUN(cfg_mgcp_number_endp,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_forward_ip,
|
||||
cfg_mgcp_forward_ip_cmd,
|
||||
"forward audio ip A.B.C.D",
|
||||
"Forward packets from and to the IP. This disables most of the MGCP feature.")
|
||||
{
|
||||
if (g_cfg->forward_ip)
|
||||
talloc_free(g_cfg->forward_ip);
|
||||
g_cfg->forward_ip = talloc_strdup(g_cfg, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_forward_port,
|
||||
cfg_mgcp_forward_port_cmd,
|
||||
"forward audio port <1-15000>",
|
||||
"Forward packets from and to the port. This disables most of the MGCP feature.")
|
||||
{
|
||||
g_cfg->forward_port = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mgcp_agent_addr,
|
||||
cfg_mgcp_agent_addr_cmd,
|
||||
"call agent ip IP",
|
||||
@@ -276,14 +304,61 @@ DEFUN(loop_endp,
|
||||
endp->conn_mode = MGCP_CONN_LOOPBACK;
|
||||
else
|
||||
endp->conn_mode = endp->orig_mode;
|
||||
endp->allow_patch = 1;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(tap_call,
|
||||
tap_call_cmd,
|
||||
"tap-call ENDPOINT (bts-in|bts-out|net-in|net-out) A.B.C.D <0-65534>",
|
||||
"Forward data on endpoint to a different system\n"
|
||||
"The endpoint in hex\n"
|
||||
"Forward the data coming from the bts\n"
|
||||
"Forward the data coming from the bts leaving to the network\n"
|
||||
"Forward the data coming from the net\n"
|
||||
"Forward the data coming from the net leaving to the bts\n"
|
||||
"destination IP of the data\n" "destination port\n")
|
||||
{
|
||||
struct mgcp_rtp_tap *tap;
|
||||
struct mgcp_endpoint *endp;
|
||||
int port = 0;
|
||||
|
||||
int endp_no = strtoul(argv[0], NULL, 16);
|
||||
if (endp_no < 1 || endp_no >= g_cfg->number_endpoints) {
|
||||
vty_out(vty, "Endpoint number %s/%d is invalid.%s",
|
||||
argv[0], endp_no, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
endp = &g_cfg->endpoints[endp_no];
|
||||
|
||||
if (strcmp(argv[1], "bts-in") == 0) {
|
||||
port = MGCP_TAP_BTS_IN;
|
||||
} else if (strcmp(argv[1], "bts-out") == 0) {
|
||||
port = MGCP_TAP_BTS_OUT;
|
||||
} else if (strcmp(argv[1], "net-in") == 0) {
|
||||
port = MGCP_TAP_NET_IN;
|
||||
} else if (strcmp(argv[1], "net-out") == 0) {
|
||||
port = MGCP_TAP_NET_OUT;
|
||||
} else {
|
||||
vty_out(vty, "Unknown mode... tricked vty?%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
tap = &endp->taps[port];
|
||||
memset(&tap->forward, 0, sizeof(tap->forward));
|
||||
inet_aton(argv[2], &tap->forward.sin_addr);
|
||||
tap->forward.sin_port = htons(atoi(argv[3]));
|
||||
tap->enabled = 1;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int mgcp_vty_init(void)
|
||||
{
|
||||
install_element(VIEW_NODE, &show_mgcp_cmd);
|
||||
install_element(ENABLE_NODE, &loop_endp_cmd);
|
||||
install_element(ENABLE_NODE, &tap_call_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_mgcp_cmd);
|
||||
install_node(&mgcp_node, config_write_mgcp);
|
||||
@@ -295,14 +370,16 @@ int mgcp_vty_init(void)
|
||||
install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_base_port_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_base_port_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_range_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_range_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
|
||||
install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
|
||||
return 0;
|
||||
}
|
||||
@@ -332,51 +409,32 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This application supports two modes.
|
||||
* 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
|
||||
* 2.) plain forwarding of RTP packets on the endpoints.
|
||||
* both modes are mutual exclusive
|
||||
*/
|
||||
if (g_cfg->forward_ip) {
|
||||
int port = g_cfg->rtp_base_port;
|
||||
if (g_cfg->forward_port != 0)
|
||||
port = g_cfg->forward_port;
|
||||
|
||||
if (!g_cfg->early_bind) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Forwarding requires early bind.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the forward IP and assign a ci. For early bind
|
||||
* the sockets will be created after this.
|
||||
*/
|
||||
for (i = 1; i < g_cfg->number_endpoints; ++i) {
|
||||
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
|
||||
inet_aton(g_cfg->forward_ip, &endp->remote);
|
||||
endp->ci = CI_UNUSED + 23;
|
||||
endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port));
|
||||
endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1);
|
||||
}
|
||||
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Configured for Audio Forwarding.\n");
|
||||
}
|
||||
|
||||
/* early bind */
|
||||
if (g_cfg->early_bind) {
|
||||
for (i = 1; i < g_cfg->number_endpoints; ++i) {
|
||||
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
|
||||
int rtp_port;
|
||||
for (i = 1; i < g_cfg->number_endpoints; ++i) {
|
||||
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
|
||||
int rtp_port;
|
||||
|
||||
rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), g_cfg->rtp_base_port);
|
||||
if (mgcp_bind_rtp_port(endp, rtp_port) != 0) {
|
||||
if (g_cfg->bts_ports.mode == PORT_ALLOC_STATIC) {
|
||||
rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
|
||||
g_cfg->bts_ports.base_port);
|
||||
if (mgcp_bind_bts_rtp_port(endp, rtp_port) != 0) {
|
||||
LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
|
||||
return -1;
|
||||
}
|
||||
endp->bts_end.local_alloc = PORT_ALLOC_STATIC;
|
||||
}
|
||||
|
||||
if (g_cfg->net_ports.mode == PORT_ALLOC_STATIC) {
|
||||
rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
|
||||
g_cfg->net_ports.base_port);
|
||||
if (mgcp_bind_net_rtp_port(endp, rtp_port) != 0) {
|
||||
LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
|
||||
return -1;
|
||||
}
|
||||
endp->net_end.local_alloc = PORT_ALLOC_STATIC;
|
||||
}
|
||||
}
|
||||
|
||||
return !!g_cfg->forward_ip;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/bsc_msc_grace.h>
|
||||
#include <openbsc/bsc_msc_rf.h>
|
||||
#include <openbsc/osmo_bsc_grace.h>
|
||||
#include <openbsc/osmo_bsc_rf.h>
|
||||
#include <openbsc/gsm_04_80.h>
|
||||
#include <openbsc/signal.h>
|
||||
|
||||
@@ -58,7 +58,7 @@ static int handle_grace(struct gsm_network *network)
|
||||
struct gsm_bts *bts;
|
||||
struct gsm_bts_trx *trx;
|
||||
|
||||
if (!network->ussd_grace_txt)
|
||||
if (!network->mid_call_txt)
|
||||
return 0;
|
||||
|
||||
llist_for_each_entry(bts, &network->bts_list, list) {
|
||||
@@ -67,7 +67,7 @@ static int handle_grace(struct gsm_network *network)
|
||||
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
|
||||
for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; ++lchan_nr) {
|
||||
handle_sub(&ts->lchan[lchan_nr],
|
||||
network->ussd_grace_txt);
|
||||
network->mid_call_txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/bsc_msc_rf.h>
|
||||
#include <openbsc/osmo_bsc_rf.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/ipaccess.h>
|
||||
|
||||
#include <osmocore/talloc.h>
|
||||
#include <osmocore/protocol/gsm_12_21.h>
|
||||
@@ -38,7 +39,8 @@
|
||||
#define RF_CMD_QUERY '?'
|
||||
#define RF_CMD_OFF '0'
|
||||
#define RF_CMD_ON '1'
|
||||
#define RF_CMD_GRACE 'g'
|
||||
#define RF_CMD_D_OFF 'd'
|
||||
#define RF_CMD_ON_G 'g'
|
||||
|
||||
static int lock_each_trx(struct gsm_network *net, int lock)
|
||||
{
|
||||
@@ -54,25 +56,9 @@ static int lock_each_trx(struct gsm_network *net, int lock)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a '1' when one TRX is online, otherwise send 0
|
||||
*/
|
||||
static void handle_query(struct bsc_msc_rf_conn *conn)
|
||||
static void send_resp(struct osmo_bsc_rf_conn *conn, char send)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct gsm_bts *bts;
|
||||
char send = RF_CMD_OFF;
|
||||
|
||||
llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) {
|
||||
struct gsm_bts_trx *trx;
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
if (trx->nm_state.availability == NM_AVSTATE_OK &&
|
||||
trx->nm_state.operational != NM_STATE_LOCKED) {
|
||||
send = RF_CMD_ON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg = msgb_alloc(10, "RF Query");
|
||||
if (!msg) {
|
||||
@@ -92,18 +78,125 @@ static void handle_query(struct bsc_msc_rf_conn *conn)
|
||||
return;
|
||||
}
|
||||
|
||||
static void send_signal(struct bsc_msc_rf_conn *conn, int val)
|
||||
|
||||
/*
|
||||
* Send a
|
||||
* 'g' when we are in grace mode
|
||||
* '1' when one TRX is online,
|
||||
* '0' otherwise
|
||||
*/
|
||||
static void handle_query(struct osmo_bsc_rf_conn *conn)
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
char send = RF_CMD_OFF;
|
||||
|
||||
if (conn->rf->policy == S_RF_GRACE)
|
||||
return send_resp(conn, RF_CMD_ON_G);
|
||||
|
||||
llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) {
|
||||
struct gsm_bts_trx *trx;
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
if (trx->nm_state.availability == NM_AVSTATE_OK &&
|
||||
trx->nm_state.operational != NM_STATE_LOCKED) {
|
||||
send = RF_CMD_ON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_resp(conn, send);
|
||||
}
|
||||
|
||||
static void rf_check_cb(void *_data)
|
||||
{
|
||||
struct gsm_bts *bts;
|
||||
struct osmo_bsc_rf *rf = _data;
|
||||
|
||||
llist_for_each_entry(bts, &rf->gsm_network->bts_list, list) {
|
||||
struct gsm_bts_trx *trx;
|
||||
|
||||
/* don't bother to check a booting or missing BTS */
|
||||
if (!bts->oml_link || !is_ipaccess_bts(bts))
|
||||
continue;
|
||||
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
if (trx->nm_state.availability != NM_AVSTATE_OK ||
|
||||
trx->nm_state.operational != NM_OPSTATE_ENABLED ||
|
||||
trx->nm_state.administrative != NM_STATE_UNLOCKED) {
|
||||
LOGP(DNM, LOGL_ERROR, "RF activation failed. Starting again.\n");
|
||||
ipaccess_drop_oml(bts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void send_signal(struct osmo_bsc_rf *rf, int val)
|
||||
{
|
||||
struct rf_signal_data sig;
|
||||
sig.net = conn->rf->gsm_network;
|
||||
sig.net = rf->gsm_network;
|
||||
|
||||
conn->rf->policy = val;
|
||||
rf->policy = val;
|
||||
dispatch_signal(SS_RF, val, &sig);
|
||||
}
|
||||
|
||||
static int switch_rf_off(struct osmo_bsc_rf *rf)
|
||||
{
|
||||
lock_each_trx(rf->gsm_network, 1);
|
||||
send_signal(rf, S_RF_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void grace_timeout(void *_data)
|
||||
{
|
||||
struct osmo_bsc_rf *rf = (struct osmo_bsc_rf *) _data;
|
||||
|
||||
LOGP(DINP, LOGL_NOTICE, "Grace timeout. Disabling the TRX.\n");
|
||||
switch_rf_off(rf);
|
||||
}
|
||||
|
||||
static int enter_grace(struct osmo_bsc_rf *rf)
|
||||
{
|
||||
rf->grace_timeout.cb = grace_timeout;
|
||||
rf->grace_timeout.data = rf;
|
||||
bsc_schedule_timer(&rf->grace_timeout, rf->gsm_network->mid_call_timeout, 0);
|
||||
LOGP(DINP, LOGL_NOTICE, "Going to switch RF off in %d seconds.\n",
|
||||
rf->gsm_network->mid_call_timeout);
|
||||
|
||||
send_signal(rf, S_RF_GRACE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rf_delay_cmd_cb(void *data)
|
||||
{
|
||||
struct osmo_bsc_rf *rf = data;
|
||||
|
||||
switch (rf->last_request) {
|
||||
case RF_CMD_D_OFF:
|
||||
rf->last_state_command = "RF Direct Off";
|
||||
bsc_del_timer(&rf->rf_check);
|
||||
bsc_del_timer(&rf->grace_timeout);
|
||||
switch_rf_off(rf);
|
||||
break;
|
||||
case RF_CMD_ON:
|
||||
rf->last_state_command = "RF Direct On";
|
||||
bsc_del_timer(&rf->grace_timeout);
|
||||
lock_each_trx(rf->gsm_network, 0);
|
||||
send_signal(rf, S_RF_ON);
|
||||
bsc_schedule_timer(&rf->rf_check, 3, 0);
|
||||
break;
|
||||
case RF_CMD_OFF:
|
||||
rf->last_state_command = "RF Scheduled Off";
|
||||
bsc_del_timer(&rf->rf_check);
|
||||
enter_grace(rf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int rf_read_cmd(struct bsc_fd *fd)
|
||||
{
|
||||
struct bsc_msc_rf_conn *conn = fd->data;
|
||||
struct osmo_bsc_rf_conn *conn = fd->data;
|
||||
char buf[1];
|
||||
int rc;
|
||||
|
||||
@@ -121,18 +214,15 @@ static int rf_read_cmd(struct bsc_fd *fd)
|
||||
case RF_CMD_QUERY:
|
||||
handle_query(conn);
|
||||
break;
|
||||
case RF_CMD_OFF:
|
||||
lock_each_trx(conn->rf->gsm_network, 1);
|
||||
send_signal(conn, S_RF_OFF);
|
||||
break;
|
||||
case RF_CMD_D_OFF:
|
||||
case RF_CMD_ON:
|
||||
lock_each_trx(conn->rf->gsm_network, 0);
|
||||
send_signal(conn, S_RF_ON);
|
||||
break;
|
||||
case RF_CMD_GRACE:
|
||||
send_signal(conn, S_RF_GRACE);
|
||||
case RF_CMD_OFF:
|
||||
conn->rf->last_request = buf[0];
|
||||
if (!bsc_timer_pending(&conn->rf->delay_cmd))
|
||||
bsc_schedule_timer(&conn->rf->delay_cmd, 1, 0);
|
||||
break;
|
||||
default:
|
||||
conn->rf->last_state_command = "Unknown command";
|
||||
LOGP(DINP, LOGL_ERROR, "Unknown command %d\n", buf[0]);
|
||||
break;
|
||||
}
|
||||
@@ -155,8 +245,8 @@ static int rf_write_cmd(struct bsc_fd *fd, struct msgb *msg)
|
||||
|
||||
static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
|
||||
{
|
||||
struct bsc_msc_rf_conn *conn;
|
||||
struct bsc_msc_rf *rf = bfd->data;
|
||||
struct osmo_bsc_rf_conn *conn;
|
||||
struct osmo_bsc_rf *rf = bfd->data;
|
||||
struct sockaddr_un addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
int fd;
|
||||
@@ -168,7 +258,7 @@ static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
|
||||
return -1;
|
||||
}
|
||||
|
||||
conn = talloc_zero(rf, struct bsc_msc_rf_conn);
|
||||
conn = talloc_zero(rf, struct osmo_bsc_rf_conn);
|
||||
if (!conn) {
|
||||
LOGP(DINP, LOGL_ERROR, "Failed to allocate mem.\n");
|
||||
close(fd);
|
||||
@@ -192,17 +282,17 @@ static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bsc_msc_rf *bsc_msc_rf_create(const char *path, struct gsm_network *net)
|
||||
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net)
|
||||
{
|
||||
unsigned int namelen;
|
||||
struct sockaddr_un local;
|
||||
struct bsc_fd *bfd;
|
||||
struct bsc_msc_rf *rf;
|
||||
struct osmo_bsc_rf *rf;
|
||||
int rc;
|
||||
|
||||
rf = talloc_zero(NULL, struct bsc_msc_rf);
|
||||
rf = talloc_zero(NULL, struct osmo_bsc_rf);
|
||||
if (!rf) {
|
||||
LOGP(DINP, LOGL_ERROR, "Failed to create bsc_msc_rf.\n");
|
||||
LOGP(DINP, LOGL_ERROR, "Failed to create osmo_bsc_rf.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -260,6 +350,15 @@ struct bsc_msc_rf *bsc_msc_rf_create(const char *path, struct gsm_network *net)
|
||||
|
||||
rf->gsm_network = net;
|
||||
rf->policy = S_RF_ON;
|
||||
rf->last_state_command = "";
|
||||
|
||||
/* check the rf state */
|
||||
rf->rf_check.data = rf;
|
||||
rf->rf_check.cb = rf_check_cb;
|
||||
|
||||
/* delay cmd handling */
|
||||
rf->delay_cmd.data = rf;
|
||||
rf->delay_cmd.cb = rf_delay_cmd_cb;
|
||||
|
||||
return rf;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,8 +45,11 @@ static int send_own_number(const struct msgb *msg, const struct ussd_request *re
|
||||
int handle_rcv_ussd(struct msgb *msg)
|
||||
{
|
||||
struct ussd_request req;
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
gsm0480_decode_ussd_request(msg, &req);
|
||||
memset(&req, 0, sizeof(req));
|
||||
gh = msgb_l3(msg);
|
||||
gsm0480_decode_ussd_request(gh, msgb_l3len(msg), &req);
|
||||
if (req.text[0] == 0xFF) /* Release-Complete */
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -1949,6 +1949,11 @@ enum node_type vty_go_parent(struct vty *vty)
|
||||
subscr_put(vty->index);
|
||||
vty->index = NULL;
|
||||
break;
|
||||
case OML_NODE:
|
||||
vty->node = ENABLE_NODE;
|
||||
talloc_free(vty->index);
|
||||
vty->index = NULL;
|
||||
break;
|
||||
default:
|
||||
vty->node = CONFIG_NODE;
|
||||
}
|
||||
@@ -2365,7 +2370,12 @@ DEFUN(config_exit,
|
||||
case MGCP_NODE:
|
||||
vty->node = CONFIG_NODE;
|
||||
vty->index = NULL;
|
||||
|
||||
break;
|
||||
case OML_NODE:
|
||||
vty->node = ENABLE_NODE;
|
||||
talloc_free(vty->index);
|
||||
vty->index = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <openbsc/vty.h>
|
||||
#include <openbsc/ipaccess.h>
|
||||
#include <openbsc/paging.h>
|
||||
#include <openbsc/osmo_bsc_rf.h>
|
||||
|
||||
static struct gsm_network *gsmnet;
|
||||
|
||||
@@ -164,6 +165,10 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net)
|
||||
vty_out(vty, "hr: %d ver: %d, ",
|
||||
net->audio_support[i]->hr, net->audio_support[i]->ver);
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
|
||||
/* show rf */
|
||||
vty_out(vty, " Last RF Command: %s%s",
|
||||
net->rf->last_state_command, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_net, show_net_cmd, "show network",
|
||||
@@ -227,11 +232,15 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
|
||||
vty_out(vty, " Paging: %u pending requests, %u free slots%s",
|
||||
paging_pending_requests_nr(bts),
|
||||
bts->paging.available_slots, VTY_NEWLINE);
|
||||
if (!is_ipaccess_bts(bts)) {
|
||||
if (is_ipaccess_bts(bts)) {
|
||||
vty_out(vty, " OML Link state: %s.%s",
|
||||
bts->oml_link ? "connected" : "disconnected", VTY_NEWLINE);
|
||||
} else {
|
||||
vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE);
|
||||
e1isl_dump_vty(vty, bts->oml_link);
|
||||
}
|
||||
/* FIXME: oml_link, chan_desc */
|
||||
|
||||
/* FIXME: chan_desc */
|
||||
memset(&pl, 0, sizeof(pl));
|
||||
bts_chan_load(&pl, bts);
|
||||
vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
|
||||
@@ -528,8 +537,11 @@ static int config_write_net(struct vty *vty)
|
||||
vty_out(vty, " msc ip-dscp %d%s", gsmnet->msc_ip_dscp, VTY_NEWLINE);
|
||||
vty_out(vty, " timeout ping %d%s", gsmnet->ping_timeout, VTY_NEWLINE);
|
||||
vty_out(vty, " timeout pong %d%s", gsmnet->pong_timeout, VTY_NEWLINE);
|
||||
if (gsmnet->ussd_grace_txt)
|
||||
vty_out(vty, " bsc-grace-text %s%s", gsmnet->ussd_grace_txt, VTY_NEWLINE);
|
||||
if (gsmnet->mid_call_txt)
|
||||
vty_out(vty, " mid-call-text %s%s", gsmnet->mid_call_txt, VTY_NEWLINE);
|
||||
vty_out(vty, " mid-call-timeout %d%s", gsmnet->mid_call_timeout, VTY_NEWLINE);
|
||||
if (gsmnet->ussd_welcome_txt)
|
||||
vty_out(vty, " bsc-welcome-text %s%s", gsmnet->ussd_welcome_txt, VTY_NEWLINE);
|
||||
|
||||
|
||||
return CMD_SUCCESS;
|
||||
@@ -1446,18 +1458,43 @@ DEFUN(cfg_net_pong_time,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_grace_ussd,
|
||||
cfg_net_grace_ussd_cmd,
|
||||
"bsc-grace-text .TEXT",
|
||||
DEFUN(cfg_net_mid_call_text,
|
||||
cfg_net_mid_call_text_cmd,
|
||||
"mid-call-text .TEXT",
|
||||
"Set the USSD notifcation to be send.\n" "Text to be sent\n")
|
||||
{
|
||||
char *data = argv_concat(argv, argc, 1);
|
||||
char *data = argv_concat(argv, argc, 0);
|
||||
if (!data)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (gsmnet->ussd_grace_txt)
|
||||
talloc_free(gsmnet->ussd_grace_txt);
|
||||
gsmnet->ussd_grace_txt = talloc_strdup(gsmnet, data);
|
||||
if (gsmnet->mid_call_txt)
|
||||
talloc_free(gsmnet->mid_call_txt);
|
||||
gsmnet->mid_call_txt = talloc_strdup(gsmnet, data);
|
||||
talloc_free(data);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_mid_call_timeout,
|
||||
cfg_net_mid_call_timeout_cmd,
|
||||
"mid-call-timeout NR",
|
||||
"Switch from Grace to Off in NR seconds.\n" "Timeout in seconds\n")
|
||||
{
|
||||
gsmnet->mid_call_timeout = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_welcome_ussd,
|
||||
cfg_net_welcome_ussd_cmd,
|
||||
"bsc-welcome-text .TEXT",
|
||||
"Set the USSD notification to be sent.\n" "Text to be sent\n")
|
||||
{
|
||||
char *data = argv_concat(argv, argc, 0);
|
||||
if (!data)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (gsmnet->ussd_welcome_txt)
|
||||
talloc_free(gsmnet->ussd_welcome_txt);
|
||||
gsmnet->ussd_welcome_txt = talloc_strdup(gsmnet, data);
|
||||
talloc_free(data);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -2284,7 +2321,9 @@ int bsc_vty_init(struct gsm_network *net)
|
||||
install_element(GSMNET_NODE, &cfg_net_msc_prio_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_ping_time_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_pong_time_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_grace_ussd_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_mid_call_text_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_mid_call_timeout_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_welcome_ussd_cmd);
|
||||
|
||||
install_element(GSMNET_NODE, &cfg_bts_cmd);
|
||||
install_node(&bts_node, config_write_bts);
|
||||
@@ -2338,6 +2377,8 @@ int bsc_vty_init(struct gsm_network *net)
|
||||
install_element(TS_NODE, &cfg_ts_pchan_cmd);
|
||||
install_element(TS_NODE, &cfg_ts_e1_subslot_cmd);
|
||||
|
||||
abis_nm_vty_init();
|
||||
|
||||
bsc_vty_init_extra(net);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <openbsc/bsc_msc.h>
|
||||
#include <openbsc/vty.h>
|
||||
|
||||
#include <sccp/sccp.h>
|
||||
#include <osmocom/sccp/sccp.h>
|
||||
|
||||
static struct gsm_network *gsmnet = NULL;
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
SUBDIRS = debug gsm0408 db channel sccp
|
||||
SUBDIRS = debug gsm0408 db channel
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
||||
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS)
|
||||
|
||||
noinst_PROGRAMS = sccp_test
|
||||
|
||||
sccp_test_SOURCES = sccp_test.c
|
||||
sccp_test_LDADD = $(top_builddir)/src/libsccp.a $(top_builddir)/src/libbsc.a $(LIBOSMOCORE_LIBS)
|
||||
|
||||
@@ -1,851 +0,0 @@
|
||||
/*
|
||||
* SCCP testing code
|
||||
*
|
||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009 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 <stdio.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <osmocore/msgb.h>
|
||||
|
||||
#include <sccp/sccp.h>
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
/* BSC -> MSC */
|
||||
static const u_int8_t bssmap_reset[] = {
|
||||
0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
|
||||
0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04,
|
||||
0x01, 0x20,
|
||||
};
|
||||
|
||||
/* MSC -> BSC reset ack */
|
||||
static const u_int8_t bssmap_reset_ack[] = {
|
||||
0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
|
||||
0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
|
||||
0x00, 0x01, 0x31,
|
||||
};
|
||||
|
||||
/* MSC -> BSC paging, connection less */
|
||||
static const u_int8_t bssmap_paging[] = {
|
||||
0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
|
||||
0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10,
|
||||
0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10,
|
||||
0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06,
|
||||
};
|
||||
|
||||
/* MSC -> BSC paging, UDT without PC */
|
||||
static const u_int8_t bssmap_udt[] = {
|
||||
0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
|
||||
0x02, 0x42, 0xfe, 0x10, 0x00, 0x0e, 0x52, 0x08,
|
||||
0x08, 0x29, 0x47, 0x10, 0x02, 0x01, 0x31, 0x97,
|
||||
0x61, 0x1a, 0x01, 0x06,
|
||||
};
|
||||
|
||||
/* BSC -> MSC connection open */
|
||||
static const u_int8_t bssmap_cr[] = {
|
||||
0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02,
|
||||
0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05,
|
||||
0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3,
|
||||
0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33,
|
||||
0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01,
|
||||
0x31, 0x97, 0x61, 0x00
|
||||
};
|
||||
|
||||
/* MSC -> BSC connection confirm */
|
||||
static const u_int8_t bssmap_cc[] = {
|
||||
0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00,
|
||||
};
|
||||
|
||||
/* MSC -> BSC DTAP
|
||||
*
|
||||
* we fake a bit and make it BSC -> MSC... so the
|
||||
* payload does not make any sense..
|
||||
*/
|
||||
static const u_int8_t bssmap_dtap[] = {
|
||||
0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x0c,
|
||||
0x03, 0x05, 0x5c, 0x08, 0x11, 0x81, 0x33, 0x66, 0x02, 0x13,
|
||||
0x45, 0xf4,
|
||||
};
|
||||
|
||||
/* MSC -> BSC clear command */
|
||||
static const u_int8_t bssmap_clear[] = {
|
||||
0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x06, 0x00, 0x04, 0x20,
|
||||
0x04, 0x01, 0x09,
|
||||
};
|
||||
|
||||
/* MSC -> BSC released */
|
||||
static const u_int8_t bssmap_released[] = {
|
||||
0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f,
|
||||
0x02, 0x23, 0x42, 0x00,
|
||||
};
|
||||
|
||||
/* BSC -> MSC released */
|
||||
static const u_int8_t bssmap_release_complete[] = {
|
||||
0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03
|
||||
};
|
||||
|
||||
struct test_data {
|
||||
int length;
|
||||
const u_int8_t *data;
|
||||
int payload_start;
|
||||
int payload_length;
|
||||
u_int8_t first_byte;
|
||||
|
||||
/* in case it should trigger a sccp response */
|
||||
int write;
|
||||
const u_int8_t *response;
|
||||
int response_length;
|
||||
};
|
||||
|
||||
static const struct test_data test_data[] = {
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_reset),
|
||||
.data = &bssmap_reset[0],
|
||||
.payload_start = 12,
|
||||
.payload_length = ARRAY_SIZE(bssmap_reset) - 12,
|
||||
.first_byte = 0x0,
|
||||
},
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_reset_ack),
|
||||
.data = &bssmap_reset_ack[0],
|
||||
.payload_start = 16,
|
||||
.payload_length = ARRAY_SIZE(bssmap_reset_ack) - 16,
|
||||
.first_byte = 0x0,
|
||||
},
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_paging),
|
||||
.data = &bssmap_paging[0],
|
||||
.payload_start = 16,
|
||||
.payload_length = ARRAY_SIZE(bssmap_paging) - 16,
|
||||
.first_byte = 0x0,
|
||||
},
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_cr),
|
||||
.data = &bssmap_cr[0],
|
||||
.payload_start = 12,
|
||||
/* 0x00 is end of optional data, subtract this byte */
|
||||
.payload_length = 31,
|
||||
.first_byte = 0x0,
|
||||
|
||||
/* the connection request should trigger a connection confirm */
|
||||
.write = 1,
|
||||
.response = &bssmap_cc[0],
|
||||
.response_length= ARRAY_SIZE(bssmap_cc),
|
||||
},
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_dtap),
|
||||
.data = &bssmap_dtap[0],
|
||||
.payload_start = 7,
|
||||
.payload_length = 15,
|
||||
.first_byte = 0x01,
|
||||
},
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_clear),
|
||||
.data = &bssmap_clear[0],
|
||||
.payload_start = 7,
|
||||
.payload_length = 6,
|
||||
.first_byte = 0x00,
|
||||
},
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_released),
|
||||
.data = &bssmap_released[0],
|
||||
.payload_length = 2,
|
||||
.payload_start = 11,
|
||||
.first_byte = 0x23,
|
||||
|
||||
.write = 1,
|
||||
.response = &bssmap_release_complete[0],
|
||||
.response_length= ARRAY_SIZE(bssmap_release_complete),
|
||||
},
|
||||
};
|
||||
|
||||
/* we will send UDTs and verify they look like this */
|
||||
static const struct test_data send_data[] = {
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_udt),
|
||||
.data = &bssmap_udt[0],
|
||||
.payload_start = 12,
|
||||
.payload_length = ARRAY_SIZE(bssmap_udt) - 12,
|
||||
.first_byte = 0x0,
|
||||
},
|
||||
{
|
||||
.length = ARRAY_SIZE(bssmap_reset),
|
||||
.data = &bssmap_reset[0],
|
||||
.payload_start = 12,
|
||||
.payload_length = ARRAY_SIZE(bssmap_reset) - 12,
|
||||
.first_byte = 0x0,
|
||||
},
|
||||
};
|
||||
|
||||
struct connection_test {
|
||||
/* should the connection be refused? */
|
||||
int refuse;
|
||||
|
||||
int with_data;
|
||||
|
||||
/* on which side to close the connection? */
|
||||
int close_side;
|
||||
int close_cause;
|
||||
};
|
||||
|
||||
/* sccp connection handling we want to test */
|
||||
static const struct connection_test connection_tests[] = {
|
||||
{
|
||||
.refuse = 1,
|
||||
},
|
||||
{
|
||||
.refuse = 1,
|
||||
.with_data = 1,
|
||||
},
|
||||
{
|
||||
.refuse = 0,
|
||||
.close_side = 0,
|
||||
.close_cause = 5,
|
||||
},
|
||||
{
|
||||
.refuse = 0,
|
||||
.close_side = 0,
|
||||
.close_cause = 5,
|
||||
.with_data = 1,
|
||||
},
|
||||
{
|
||||
.refuse = 0,
|
||||
.close_side = 1,
|
||||
.close_cause = 5,
|
||||
},
|
||||
{
|
||||
.refuse = 0,
|
||||
.close_side = 1,
|
||||
.close_cause = 5,
|
||||
.with_data = 1,
|
||||
},
|
||||
};
|
||||
|
||||
struct sccp_parse_header_result {
|
||||
/* results */
|
||||
int msg_type;
|
||||
int wanted_len;
|
||||
int src_ssn;
|
||||
int dst_ssn;
|
||||
|
||||
int has_src_ref, has_dst_ref;
|
||||
struct sccp_source_reference src_ref;
|
||||
struct sccp_source_reference dst_ref;
|
||||
|
||||
/* the input */
|
||||
const u_int8_t *input;
|
||||
int input_len;
|
||||
};
|
||||
|
||||
static const u_int8_t it_test[] = {
|
||||
0x10, 0x01, 0x07,
|
||||
0x94, 0x01, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00 };
|
||||
|
||||
static const u_int8_t proto_err[] = {
|
||||
0x0f, 0x0c, 0x04, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static const struct sccp_parse_header_result parse_result[] = {
|
||||
{
|
||||
.msg_type = SCCP_MSG_TYPE_IT,
|
||||
.wanted_len = 0,
|
||||
.src_ssn = -1,
|
||||
.dst_ssn = -1,
|
||||
.has_src_ref = 1,
|
||||
.has_dst_ref = 1,
|
||||
|
||||
.src_ref = {
|
||||
.octet1 = 0x01,
|
||||
.octet2 = 0x04,
|
||||
.octet3 = 0x00
|
||||
},
|
||||
.dst_ref = {
|
||||
.octet1 = 0x01,
|
||||
.octet2 = 0x07,
|
||||
.octet3 = 0x94,
|
||||
},
|
||||
|
||||
.input = it_test,
|
||||
.input_len = sizeof(it_test),
|
||||
},
|
||||
{
|
||||
.msg_type = SCCP_MSG_TYPE_ERR,
|
||||
.wanted_len = 0,
|
||||
.src_ssn = -1,
|
||||
.dst_ssn = -1,
|
||||
.has_src_ref = 0,
|
||||
.has_dst_ref = 1,
|
||||
.dst_ref = {
|
||||
.octet1 = 0x0c,
|
||||
.octet2 = 0x04,
|
||||
.octet3 = 0x00,
|
||||
},
|
||||
.input = proto_err,
|
||||
.input_len = sizeof(proto_err),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* testing procedure:
|
||||
* - we will use sccp_write and see what will be set in the
|
||||
* outgoing callback
|
||||
* - we will call sccp_system_incoming and see which calls
|
||||
* are made. And then compare it to the ones we expect. We
|
||||
* want the payload to arrive, or callbacks to be called.
|
||||
* - we will use sccp_connection_socket and sccp_connection_write
|
||||
* and verify state handling of connections
|
||||
*/
|
||||
|
||||
static int current_test;
|
||||
|
||||
/*
|
||||
* test state...
|
||||
*/
|
||||
static int called = 0;
|
||||
static int matched = 0;
|
||||
static int write_called = 0;
|
||||
|
||||
#define FAIL(x, args...) printf("FAILURE in %s:%d: " x, __FILE__, __LINE__, ## args)
|
||||
|
||||
/*
|
||||
* writing these packets and expecting a result
|
||||
*/
|
||||
int sccp_read_cb(struct msgb *data, unsigned len, void *context)
|
||||
{
|
||||
u_int16_t payload_length = test_data[current_test].payload_length;
|
||||
const u_int8_t *got, *wanted;
|
||||
int i;
|
||||
|
||||
called = 1;
|
||||
|
||||
if (msgb_l3len(data) < len) {
|
||||
/* this should never be reached */
|
||||
FAIL("Something horrible happened.. invalid packet..\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (len == 0 || len != payload_length) {
|
||||
FAIL("length mismatch: got: %d wanted: %d\n", msgb_l3len(data), payload_length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data->l3h[0] != test_data[current_test].first_byte) {
|
||||
FAIL("The first bytes of l3 do not match: 0x%x 0x%x\n",
|
||||
data->l3h[0], test_data[current_test].first_byte);
|
||||
return -1;
|
||||
}
|
||||
|
||||
got = &data->l3h[0];
|
||||
wanted = test_data[current_test].data + test_data[current_test].payload_start;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (got[i] != wanted[i]) {
|
||||
FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
|
||||
got[i], wanted[i], i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
matched = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sccp_write_cb(struct msgb *data, void *ctx)
|
||||
{
|
||||
int i = 0;
|
||||
const u_int8_t *got, *wanted;
|
||||
|
||||
if (test_data[current_test].response == NULL) {
|
||||
FAIL("Didn't expect write callback\n");
|
||||
goto exit;
|
||||
} else if (test_data[current_test].response_length != msgb_l2len(data)) {
|
||||
FAIL("Size does not match. Got: %d Wanted: %d\n",
|
||||
msgb_l2len(data), test_data[current_test].response_length);
|
||||
}
|
||||
|
||||
got = &data->l2h[0];
|
||||
wanted = test_data[current_test].response;
|
||||
|
||||
for (i = 0; i < msgb_l2len(data); ++i) {
|
||||
if (got[i] != wanted[i]) {
|
||||
FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
|
||||
got[i], wanted[i], i);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
write_called = 1;
|
||||
|
||||
exit:
|
||||
msgb_free(data);
|
||||
}
|
||||
|
||||
void sccp_c_read(struct sccp_connection *connection, struct msgb *msgb, unsigned int len)
|
||||
{
|
||||
sccp_read_cb(msgb, len, connection->data_ctx);
|
||||
}
|
||||
|
||||
void sccp_c_state(struct sccp_connection *connection, int old_state)
|
||||
{
|
||||
if (connection->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE)
|
||||
sccp_connection_free(connection);
|
||||
}
|
||||
|
||||
int sccp_accept_cb(struct sccp_connection *connection, void *user_data)
|
||||
{
|
||||
called = 1;
|
||||
unsigned int ref = 0;
|
||||
ref |= connection->destination_local_reference.octet1 << 24;
|
||||
ref |= connection->destination_local_reference.octet2 << 16;
|
||||
ref |= connection->destination_local_reference.octet3 << 8;
|
||||
ref = ntohl(ref);
|
||||
|
||||
connection->data_cb = sccp_c_read;
|
||||
connection->state_cb = sccp_c_state;
|
||||
|
||||
/* accept this */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sccp_udt_write_cb(struct msgb *data, void *context)
|
||||
{
|
||||
const u_int8_t *got, *wanted;
|
||||
int i;
|
||||
|
||||
write_called = 1;
|
||||
|
||||
if (send_data[current_test].length != msgb_l2len(data)) {
|
||||
FAIL("Size does not match. Got: %d Wanted: %d\n",
|
||||
msgb_l2len(data), send_data[current_test].length);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
got = &data->l2h[0];
|
||||
wanted = send_data[current_test].data;
|
||||
|
||||
for (i = 0; i < msgb_l2len(data); ++i) {
|
||||
if (got[i] != wanted[i]) {
|
||||
FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n",
|
||||
got[i], wanted[i], i);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
matched = 1;
|
||||
|
||||
exit:
|
||||
msgb_free(data);
|
||||
}
|
||||
|
||||
static void test_sccp_system(void)
|
||||
{
|
||||
sccp_system_init(sccp_write_cb, NULL);
|
||||
sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL);
|
||||
sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL);
|
||||
|
||||
for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) {
|
||||
unsigned int length = test_data[current_test].length;
|
||||
struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__);
|
||||
msg->l2h = msgb_put(msg, length);
|
||||
memcpy(msg->l2h, test_data[current_test].data, length);
|
||||
|
||||
called = matched = write_called = 0;
|
||||
printf("Testing packet: %d\n", current_test);
|
||||
sccp_system_incoming(msg);
|
||||
|
||||
if (!called || !matched || (test_data[current_test].write != write_called))
|
||||
FAIL("current test: %d called: %d matched: %d write: %d\n",
|
||||
current_test, called, matched, write_called);
|
||||
|
||||
msgb_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* test sending of udt */
|
||||
static void test_sccp_send_udt(void)
|
||||
{
|
||||
sccp_system_init(sccp_udt_write_cb, NULL);
|
||||
sccp_set_read(NULL, NULL, NULL);
|
||||
sccp_connection_set_incoming(NULL, NULL, NULL);
|
||||
|
||||
for (current_test = 0; current_test < ARRAY_SIZE(send_data); ++current_test) {
|
||||
const struct test_data *test = &send_data[current_test];
|
||||
|
||||
struct msgb *msg = msgb_alloc(test->payload_length, __func__);
|
||||
msg->l3h = msgb_put(msg, test->payload_length);
|
||||
memcpy(msg->l3h, test->data + test->payload_start, test->payload_length);
|
||||
|
||||
matched = write_called = 0;
|
||||
printf("Testing packet: %d\n", current_test);
|
||||
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
|
||||
|
||||
if (!matched || !write_called)
|
||||
FAIL("current test: %d matched: %d write: %d\n",
|
||||
current_test, matched, write_called);
|
||||
|
||||
msgb_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* send udt from one end to another */
|
||||
static unsigned int test_value = 0x2442;
|
||||
static int sccp_udt_read(struct msgb *data, unsigned int len, void *context)
|
||||
{
|
||||
unsigned int *val;
|
||||
|
||||
if (len != 4) {
|
||||
FAIL("Wrong size: %d\n", msgb_l3len(data));
|
||||
return -1;
|
||||
}
|
||||
|
||||
val = (unsigned int*)data->l3h;
|
||||
matched = test_value == *val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sccp_write_loop(struct msgb *data, void *context)
|
||||
{
|
||||
/* send it back to us */
|
||||
sccp_system_incoming(data);
|
||||
msgb_free(data);
|
||||
}
|
||||
|
||||
static void test_sccp_udt_communication(void)
|
||||
{
|
||||
struct msgb *data;
|
||||
unsigned int *val;
|
||||
|
||||
sccp_system_init(sccp_write_loop, NULL);
|
||||
sccp_set_read(&sccp_ssn_bssap, sccp_udt_read, NULL);
|
||||
sccp_connection_set_incoming(NULL, NULL, NULL);
|
||||
|
||||
|
||||
data = msgb_alloc(4, "test data");
|
||||
data->l3h = &data->data[0];
|
||||
val = (unsigned int *)msgb_put(data, 4);
|
||||
*val = test_value;
|
||||
|
||||
matched = 0;
|
||||
sccp_write(data, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
|
||||
|
||||
if (!matched)
|
||||
FAIL("Talking with us didn't work\n");
|
||||
|
||||
msgb_free(data);
|
||||
}
|
||||
|
||||
|
||||
/* connection testing... open, send, close */
|
||||
static const struct connection_test *current_con_test;
|
||||
static struct sccp_connection *outgoing_con;
|
||||
static struct sccp_connection *incoming_con;
|
||||
static int outgoing_data, incoming_data, incoming_state, outgoing_state;
|
||||
|
||||
static struct msgb *test_data1, *test_data2, *test_data3;
|
||||
|
||||
static void sccp_conn_in_state(struct sccp_connection *conn, int old_state)
|
||||
{
|
||||
printf("\tincome: %d -> %d\n", old_state, conn->connection_state);
|
||||
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
|
||||
if (conn == incoming_con) {
|
||||
sccp_connection_free(conn);
|
||||
incoming_con = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sccp_conn_in_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
|
||||
{
|
||||
/* compare the data */
|
||||
++incoming_data;
|
||||
printf("\tincoming data: %d\n", len);
|
||||
|
||||
/* compare the data */
|
||||
if (len != 4) {
|
||||
FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (incoming_data == 1) {
|
||||
if (memcmp(msg->l3h, test_data1->l3h, len) != 0) {
|
||||
FAIL("Comparing the data failed: %d\n", incoming_data);
|
||||
incoming_state = 0;
|
||||
printf("Got: %s\n", hexdump(msg->l3h, len));
|
||||
printf("Wanted: %s\n", hexdump(test_data1->l3h, len));
|
||||
|
||||
}
|
||||
} else if (incoming_data == 2) {
|
||||
if (memcmp(msg->l3h, test_data2->l3h, len) != 0) {
|
||||
FAIL("Comparing the data failed: %d\n", incoming_data);
|
||||
incoming_state = 0;
|
||||
printf("Got: %s\n", hexdump(msg->l3h, len));
|
||||
printf("Wanted: %s\n", hexdump(test_data2->l3h, len));
|
||||
}
|
||||
}
|
||||
|
||||
/* sending out data */
|
||||
if (incoming_data == 2) {
|
||||
printf("\tReturning data3\n");
|
||||
sccp_connection_write(conn, test_data3);
|
||||
}
|
||||
}
|
||||
|
||||
static int sccp_conn_accept(struct sccp_connection *conn, void *ctx)
|
||||
{
|
||||
printf("\taccept: %p\n", conn);
|
||||
conn->state_cb = sccp_conn_in_state;
|
||||
conn->data_cb = sccp_conn_in_data;
|
||||
|
||||
if (current_con_test->refuse)
|
||||
return -1;
|
||||
|
||||
incoming_con = conn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* callbacks for the outgoing side */
|
||||
static void sccp_conn_out_state(struct sccp_connection *conn, int old_state)
|
||||
{
|
||||
printf("\toutgoing: %p %d -> %d\n", conn, old_state, conn->connection_state);
|
||||
|
||||
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
|
||||
if (conn == outgoing_con) {
|
||||
sccp_connection_free(conn);
|
||||
outgoing_con = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sccp_conn_out_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
|
||||
{
|
||||
++outgoing_data;
|
||||
printf("\toutgoing data: %p %d\n", conn, len);
|
||||
|
||||
if (len != 4)
|
||||
FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len);
|
||||
|
||||
if (outgoing_data == 1) {
|
||||
if (memcmp(msg->l3h, test_data3->l3h, len) != 0) {
|
||||
FAIL("Comparing the data failed\n");
|
||||
outgoing_state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_test_sccp_connection(const struct connection_test *test)
|
||||
{
|
||||
int ret;
|
||||
|
||||
current_con_test = test;
|
||||
outgoing_con = incoming_con = 0;
|
||||
|
||||
outgoing_con = sccp_connection_socket();
|
||||
if (!outgoing_con) {
|
||||
FAIL("Connection is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
outgoing_con->state_cb = sccp_conn_out_state;
|
||||
outgoing_con->data_cb = sccp_conn_out_data;
|
||||
outgoing_data = incoming_data = 0;
|
||||
incoming_state = outgoing_state = 1;
|
||||
|
||||
/* start testing */
|
||||
if (test->with_data) {
|
||||
if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, test_data1) != 0)
|
||||
FAIL("Binding failed\n");
|
||||
} else {
|
||||
++incoming_data;
|
||||
if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, NULL) != 0)
|
||||
FAIL("Binding failed\n");
|
||||
}
|
||||
|
||||
if (test->refuse) {
|
||||
if (outgoing_con)
|
||||
FAIL("Outgoing connection should have been refused.\n");
|
||||
} else {
|
||||
if (!incoming_con)
|
||||
FAIL("Creating incoming didn't work.\n");
|
||||
|
||||
printf("\tWriting test data2\n");
|
||||
sccp_connection_write(outgoing_con, test_data2);
|
||||
sccp_connection_send_it(outgoing_con);
|
||||
|
||||
/* closing connection */
|
||||
if (test->close_side == 0)
|
||||
ret = sccp_connection_close(outgoing_con, 0);
|
||||
else
|
||||
ret = sccp_connection_close(incoming_con, 0);
|
||||
|
||||
if (ret != 0)
|
||||
FAIL("Closing the connection failed\n");
|
||||
}
|
||||
|
||||
/* outgoing should be gone now */
|
||||
if (outgoing_con)
|
||||
FAIL("Outgoing connection was not properly closed\n");
|
||||
|
||||
if (incoming_con)
|
||||
FAIL("Incoming connection was not propery closed.\n");
|
||||
|
||||
if (test->refuse == 0) {
|
||||
if (outgoing_data != 1 || incoming_data != 2) {
|
||||
FAIL("Data sending failed: %d/%d %d/%d\n",
|
||||
outgoing_data, 1,
|
||||
incoming_data, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!incoming_state || !outgoing_state)
|
||||
FAIL("Failure with the state transition. %d %d\n",
|
||||
outgoing_state, incoming_state);
|
||||
}
|
||||
|
||||
static void test_sccp_connection(void)
|
||||
{
|
||||
sccp_system_init(sccp_write_loop, NULL);
|
||||
sccp_set_read(NULL, NULL, NULL);
|
||||
sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_conn_accept, NULL);
|
||||
|
||||
test_data1 = msgb_alloc(4, "data1");
|
||||
test_data1->l3h = msgb_put(test_data1, 4);
|
||||
*((unsigned int*)test_data1->l3h) = 0x23421122;
|
||||
|
||||
test_data2 = msgb_alloc(4, "data2");
|
||||
test_data2->l3h = msgb_put(test_data2, 4);
|
||||
*((unsigned int*)test_data2->l3h) = 0x42232211;
|
||||
|
||||
test_data3 = msgb_alloc(4, "data3");
|
||||
test_data3->l3h = msgb_put(test_data3, 4);
|
||||
*((unsigned int*)test_data3->l3h) = 0x2323ff55;
|
||||
|
||||
|
||||
for (current_test = 0; current_test < ARRAY_SIZE(connection_tests); ++current_test) {
|
||||
printf("Testing %d refuse: %d with_data: %d\n",
|
||||
current_test, connection_tests[current_test].refuse,
|
||||
connection_tests[current_test].with_data);
|
||||
do_test_sccp_connection(&connection_tests[current_test]);
|
||||
}
|
||||
|
||||
msgb_free(test_data1);
|
||||
msgb_free(test_data2);
|
||||
msgb_free(test_data3);
|
||||
}
|
||||
|
||||
/* invalid input */
|
||||
static void test_sccp_system_crash(void)
|
||||
{
|
||||
printf("trying to provoke a crash with invalid input\n");
|
||||
sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL);
|
||||
sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL);
|
||||
|
||||
for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) {
|
||||
int original_length = test_data[current_test].length;
|
||||
int length = original_length + 2;
|
||||
int i;
|
||||
|
||||
printf("Testing packet: %d\n", current_test);
|
||||
|
||||
for (i = length; i >= 0; --i) {
|
||||
unsigned int length = MIN(test_data[current_test].length, i);
|
||||
struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__);
|
||||
msg->l2h = msgb_put(msg, length);
|
||||
memcpy(msg->l2h, test_data[current_test].data, length);
|
||||
sccp_system_incoming(msg);
|
||||
msgb_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
printf("survived\n");
|
||||
}
|
||||
|
||||
static void test_sccp_parsing(void)
|
||||
{
|
||||
for (current_test = 0; current_test < ARRAY_SIZE(parse_result); ++current_test) {
|
||||
struct msgb *msg;
|
||||
struct sccp_parse_result result;
|
||||
|
||||
msg = msgb_alloc_headroom(1024, 128, "parse-test");
|
||||
msgb_put(msg, 1);
|
||||
msg->l2h = msgb_put(msg, parse_result[current_test].input_len);
|
||||
memcpy(msg->l2h, parse_result[current_test].input, msgb_l2len(msg));
|
||||
|
||||
memset(&result, 0, sizeof(result));
|
||||
if (sccp_parse_header(msg, &result) != 0) {
|
||||
fprintf(stderr, "Failed to sccp parse test: %d\n", current_test);
|
||||
} else {
|
||||
if (parse_result[current_test].wanted_len != result.data_len) {
|
||||
fprintf(stderr, "Unexpected data length.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (parse_result[current_test].has_src_ref) {
|
||||
if (memcmp(result.source_local_reference,
|
||||
&parse_result[current_test].src_ref,
|
||||
sizeof(struct sccp_source_reference)) != 0) {
|
||||
fprintf(stderr, "SRC REF did not match\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_result[current_test].has_dst_ref) {
|
||||
if (memcmp(result.destination_local_reference,
|
||||
&parse_result[current_test].dst_ref,
|
||||
sizeof(struct sccp_source_reference)) != 0) {
|
||||
fprintf(stderr, "DST REF did not match\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_result[current_test].src_ssn != -1) {
|
||||
fprintf(stderr, "Not implemented.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (parse_result[current_test].dst_ssn != -1) {
|
||||
fprintf(stderr, "Not implemented.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
msgb_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_sccp_system();
|
||||
test_sccp_send_udt();
|
||||
test_sccp_udt_communication();
|
||||
test_sccp_connection();
|
||||
test_sccp_system_crash();
|
||||
test_sccp_parsing();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void db_store_counter() {}
|
||||
Reference in New Issue
Block a user