mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-10-31 03:53:54 +00:00 
			
		
		
		
	Compare commits
	
		
			100 Commits
		
	
	
		
			stsp/show_
			...
			on-waves/0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 2727909dba | ||
|  | ad9856ec15 | ||
|  | 9d53a8ad2a | ||
|  | 058956e8ee | ||
|  | a34bb9167f | ||
|  | b8ac7ffd7c | ||
|  | b13cf829da | ||
|  | fdc64f6806 | ||
|  | ab46372e2a | ||
|  | ff0a562f9a | ||
|  | 556008d724 | ||
|  | 0094f84f30 | ||
|  | 86069143ff | ||
|  | 44f0be88a3 | ||
|  | 5d88b372d7 | ||
|  | 71c7bf5907 | ||
|  | 869033148c | ||
|  | bc0f7c0988 | ||
|  | 7d06063cfb | ||
|  | 4e42b637fd | ||
|  | f44de9942b | ||
|  | 3a110ae60b | ||
|  | bb84adc465 | ||
|  | 8d123ea3c0 | ||
|  | 88ca894df7 | ||
|  | 42b0d6b494 | ||
|  | 82d8b0457b | ||
|  | 433d6ee1a2 | ||
|  | 203a6eddf8 | ||
|  | 56ef6249e3 | ||
|  | b2a96b1be7 | ||
|  | d4c29c1574 | ||
|  | 3d947e6d67 | ||
|  | b62c9a19cf | ||
|  | ff5957568f | ||
|  | 7d2e1ca4be | ||
|  | 7ce2e0c8b0 | ||
|  | 78d442420b | ||
|  | 8cd2709ebf | ||
|  | 41a1780102 | ||
|  | 2f84715984 | ||
|  | 7253154fc5 | ||
|  | 6c1c76683f | ||
|  | a92fe9a4ca | ||
|  | e83a3f584e | ||
|  | 118ddebc36 | ||
|  | bb53004d47 | ||
|  | 6af20842cb | ||
|  | cc41cb07e7 | ||
|  | d6fb23523a | ||
|  | 2aa0b45cc0 | ||
|  | 619df61ad2 | ||
|  | 893ea65f38 | ||
|  | 64b811f113 | ||
|  | 91fc9bf862 | ||
|  | 111a58dd37 | ||
|  | d1a2563a74 | ||
|  | 7d3ef919ce | ||
|  | cba98d87d6 | ||
|  | 5c18ad0829 | ||
|  | 0d9ed87d5c | ||
|  | ec7be0c969 | ||
|  | 9be3347601 | ||
|  | 3eef7b7d81 | ||
|  | 9de4a6daa9 | ||
|  | 851ace9f33 | ||
|  | d1dd069b48 | ||
|  | 401db32ca2 | ||
|  | 17e03d21d2 | ||
|  | 26a9bff201 | ||
|  | 80fb260a60 | ||
|  | 55a0716da7 | ||
|  | c88fb75616 | ||
|  | d55a4dc326 | ||
|  | a4e6f2e6e1 | ||
|  | 7f71d99cc3 | ||
|  | b92167cf80 | ||
|  | 4b6a6dbe7e | ||
|  | 763e8c7766 | ||
|  | 823ff16088 | ||
|  | 6f93c6a1e0 | ||
|  | f97e48b0de | ||
|  | 761600b0fd | ||
|  | 8549462bc6 | ||
|  | 436e5c6308 | ||
|  | f8b9d844c1 | ||
|  | 58ec07d580 | ||
|  | 71465c21f4 | ||
|  | 16d0a833f8 | ||
|  | ea72b62cac | ||
|  | 49a84ec6e9 | ||
|  | 42c636b6c8 | ||
|  | a0a55f555e | ||
|  | 23ed00e410 | ||
|  | 3fe910b9f1 | ||
|  | 097bdeb77d | ||
|  | 1b85de02e0 | ||
|  | 2281d1835f | ||
|  | fb4433a129 | ||
|  | d954dcf9e1 | 
| @@ -1,7 +1,7 @@ | ||||
| dnl Process this file with autoconf to produce a configure script | ||||
| AC_INIT | ||||
|  | ||||
| AM_INIT_AUTOMAKE(openbsc, 0.0alpha1) | ||||
| AM_INIT_AUTOMAKE(openbsc, 0.3.4onwaves) | ||||
|  | ||||
| dnl kernel style compile messages | ||||
| m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) | ||||
|   | ||||
							
								
								
									
										2
									
								
								openbsc/contrib/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								openbsc/contrib/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| This contains a set of scripts used for the development of the | ||||
| MSC functionality. | ||||
							
								
								
									
										30
									
								
								openbsc/contrib/send_handshake.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										30
									
								
								openbsc/contrib/send_handshake.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| import sys | ||||
|  | ||||
| # packages | ||||
| ACK ="\x00\x01\xfe\x06" | ||||
| RESET_ACK = "\x00\x13\xfd\x09\x00\x03\x07\x0b\x04\x43\x01\x00\xfe\x04\x43\x5c\x00\xfe\x03\x00\x01\x31" | ||||
| PAGE = "\x00\x20\xfd\x09\x00\x03\x07\x0b\x04\x43\x01\x00\xfe\x04\x43\x5c\x00\xfe\x10\x00\x0e\x52\x08\x08\x29\x42\x08\x05\x03\x12\x23\x42\x1a\x01\x06" | ||||
|  | ||||
|  | ||||
| # simple handshake... | ||||
| sys.stdout.write(ACK) | ||||
| sys.stdout.flush() | ||||
| sys.stdin.read(4) | ||||
|  | ||||
| # wait for some data and send reset ack | ||||
| sys.stdin.read(21) | ||||
| sys.stdout.write(RESET_ACK) | ||||
| sys.stdout.flush() | ||||
|  | ||||
| sys.stdout.write(RESET_ACK) | ||||
| sys.stdout.flush() | ||||
|  | ||||
| # page a subscriber | ||||
| sys.stdout.write(PAGE) | ||||
| sys.stdout.flush() | ||||
|  | ||||
| while True: | ||||
|     sys.stdin.read(1) | ||||
|  | ||||
| @@ -5,4 +5,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ | ||||
| 		 gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ | ||||
| 		 bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ | ||||
| 		 silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \ | ||||
| 		 system_information.h handover.h | ||||
| 		 system_information.h handover.h bssap.h bsc_msc.h bsc_nat.h | ||||
|   | ||||
							
								
								
									
										30
									
								
								openbsc/include/openbsc/bsc_msc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								openbsc/include/openbsc/bsc_msc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* Routines to talk to the MSC using the IPA Protocol */ | ||||
| /* | ||||
|  * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2010 by on-waves.com | ||||
|  * All Rights Reserved | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef BSC_MSC_H | ||||
| #define BSC_MSC_H | ||||
|  | ||||
| #include "select.h" | ||||
|  | ||||
| int connect_to_msc(struct bsc_fd *fd, const char *ip, int port); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										33
									
								
								openbsc/include/openbsc/bsc_nat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								openbsc/include/openbsc/bsc_nat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| /* | ||||
|  * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2010 by on-waves.com | ||||
|  * All Rights Reserved | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef BSC_NAT_H | ||||
| #define BSC_NAT_H | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include "msgb.h" | ||||
|  | ||||
| /** | ||||
|  * filter based on IP Access header in both directions | ||||
|  */ | ||||
| int bsc_nat_filter_ipa(struct msgb *msg); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										334
									
								
								openbsc/include/openbsc/bssap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								openbsc/include/openbsc/bssap.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,334 @@ | ||||
| /* From GSM08.08 */ | ||||
|  | ||||
| #ifndef BSSAP_H | ||||
| #define BSSAP_H | ||||
|  | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #include <openbsc/msgb.h> | ||||
| #include <openbsc/gsm_data.h> | ||||
|  | ||||
| /* | ||||
|  * this is from GSM 03.03 CGI but is copied in GSM 08.08 | ||||
|  * in § 3.2.2.27 for Cell Identifier List | ||||
|  */ | ||||
| enum CELL_IDENT { | ||||
| 	CELL_IDENT_WHOLE_GLOBAL		= 0, | ||||
| 	CELL_IDENT_LAC_AND_CI		= 1, | ||||
| 	CELL_IDENT_CI			= 2, | ||||
| 	CELL_IDENT_NO_CELL		= 3, | ||||
| 	CELL_IDENT_LAI_AND_LAC		= 4, | ||||
| 	CELL_IDENT_LAC			= 5, | ||||
| 	CELL_IDENT_BSS			= 6, | ||||
| 	CELL_IDENT_UTRAN_PLMN_LAC_RNC	= 8, | ||||
| 	CELL_IDENT_UTRAN_RNC		= 9, | ||||
| 	CELL_IDENT_UTRAN_LAC_RNC	= 10, | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* GSM 08.06 § 6.3 */ | ||||
| enum BSSAP_MSG_TYPE { | ||||
| 	BSSAP_MSG_BSS_MANAGEMENT    = 0x0, | ||||
| 	BSSAP_MSG_DTAP		    = 0x1, | ||||
| }; | ||||
|  | ||||
| struct bssmap_header { | ||||
| 	u_int8_t type; | ||||
| 	u_int8_t length; | ||||
| } __attribute__((packed)); | ||||
|  | ||||
| struct dtap_header { | ||||
| 	u_int8_t type; | ||||
| 	u_int8_t link_id; | ||||
| 	u_int8_t length; | ||||
| } __attribute__((packed)); | ||||
|  | ||||
|  | ||||
| enum BSS_MAP_MSG_TYPE { | ||||
| 	BSS_MAP_MSG_RESERVED_0		= 0, | ||||
|  | ||||
| 	/* ASSIGNMENT MESSAGES */ | ||||
| 	BSS_MAP_MSG_ASSIGMENT_RQST	= 1, | ||||
| 	BSS_MAP_MSG_ASSIGMENT_COMPLETE	= 2, | ||||
| 	BSS_MAP_MSG_ASSIGMENT_FAILURE	= 3, | ||||
|  | ||||
| 	/*  HANDOVER MESSAGES */ | ||||
| 	BSS_MAP_MSG_HANDOVER_RQST		= 16, | ||||
| 	BSS_MAP_MSG_HANDOVER_REQUIRED		= 17, | ||||
| 	BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE= 18, | ||||
| 	BSS_MAP_MSG_HANDOVER_CMD		= 19, | ||||
| 	BSS_MAP_MSG_HANDOVER_COMPLETE		= 20, | ||||
| 	BSS_MAP_MSG_HANDOVER_SUCCEEDED		= 21, | ||||
| 	BSS_MAP_MSG_HANDOVER_FAILURE		= 22, | ||||
| 	BSS_MAP_MSG_HANDOVER_PERFORMED		= 23, | ||||
| 	BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE	= 24, | ||||
| 	BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE	= 25, | ||||
| 	BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT	= 26, | ||||
| 	BSS_MAP_MSG_HANDOVER_DETECT		= 27, | ||||
|  | ||||
| 	/* RELEASE MESSAGES */ | ||||
| 	BSS_MAP_MSG_CLEAR_CMD		= 32, | ||||
| 	BSS_MAP_MSG_CLEAR_COMPLETE		= 33, | ||||
| 	BSS_MAP_MSG_CLEAR_RQST		= 34, | ||||
| 	BSS_MAP_MSG_RESERVED_1			= 35, | ||||
| 	BSS_MAP_MSG_RESERVED_2			= 36, | ||||
| 	BSS_MAP_MSG_SAPI_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); | ||||
|  | ||||
| struct msgb *bssmap_create_layer3(struct msgb *msg); | ||||
| struct msgb *bssmap_create_reset(void); | ||||
| struct msgb *bssmap_create_clear_complete(void); | ||||
| struct msgb *bssmap_create_cipher_complete(struct msgb *layer3); | ||||
| struct msgb *bssmap_create_cipher_reject(u_int8_t cause); | ||||
| struct msgb *bssmap_create_sapi_reject(u_int8_t link_id); | ||||
| struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, u_int8_t rr_cause); | ||||
| struct msgb *bssmap_create_assignment_failure(u_int8_t cause, u_int8_t *rr_cause); | ||||
| struct msgb *bssmap_create_classmark_update(const u_int8_t *classmark, u_int8_t length); | ||||
|  | ||||
| void gsm0808_send_assignment_failure(struct gsm_lchan *l, u_int8_t cause, u_int8_t *rr_value); | ||||
| void gsm0808_send_assignment_compl(struct gsm_lchan *l, u_int8_t rr_value); | ||||
|  | ||||
| int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length); | ||||
| struct msgb *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id); | ||||
|  | ||||
| void bsc_queue_connection_write(struct sccp_connection *conn, struct msgb *msg); | ||||
| void bsc_free_queued(struct sccp_connection *conn); | ||||
| void bsc_send_queued(struct sccp_connection *conn); | ||||
|  | ||||
| void bts_queue_send(struct msgb *msg, int link_id); | ||||
| void bts_send_queued(struct bss_sccp_connection_data*); | ||||
| void bts_free_queued(struct bss_sccp_connection_data*); | ||||
| void bts_unblock_queue(struct bss_sccp_connection_data*); | ||||
|  | ||||
| #endif | ||||
| @@ -23,6 +23,28 @@ | ||||
|  | ||||
| #include "gsm_subscriber.h" | ||||
|  | ||||
| /* | ||||
|  * Refcounting for the lchan. If the refcount drops to zero | ||||
|  * the channel will send a RSL release request. | ||||
|  */ | ||||
| #define use_lchan(lchan) \ | ||||
| 	do {	lchan->use_count++; \ | ||||
| 		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \ | ||||
| 			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \ | ||||
| 			lchan->nr, lchan->use_count); \ | ||||
| 	} while(0); | ||||
|  | ||||
| #define put_lchan(lchan) \ | ||||
| 	do { lchan->use_count--; \ | ||||
| 		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \ | ||||
| 			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \ | ||||
| 			lchan->nr, lchan->use_count); \ | ||||
| 	    if (lchan->use_count <= 0) \ | ||||
| 		_lchan_release(lchan); \ | ||||
| 	} while(0); | ||||
|  | ||||
|  | ||||
|  | ||||
| /* Special allocator for C0 of BTS */ | ||||
| struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, | ||||
| 				   enum gsm_phys_chan_config pchan); | ||||
| @@ -46,7 +68,7 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type); | ||||
| /* Free a logical channel (SDCCH, TCH, ...) */ | ||||
| void lchan_free(struct gsm_lchan *lchan); | ||||
|  | ||||
| /* Consider releasing the channel */ | ||||
| int lchan_auto_release(struct gsm_lchan *lchan); | ||||
| /* internal.. do not use */ | ||||
| int _lchan_release(struct gsm_lchan *lchan); | ||||
|  | ||||
| #endif /* _CHAN_ALLOC_H */ | ||||
|   | ||||
| @@ -768,7 +768,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan); | ||||
| int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); | ||||
| int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, | ||||
| 			   u_int8_t apdu_len, const u_int8_t *apdu); | ||||
| int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class); | ||||
| int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_class); | ||||
| int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, | ||||
| 		      u_int8_t power_command, u_int8_t ho_ref); | ||||
|  | ||||
|   | ||||
| @@ -93,36 +93,51 @@ typedef int gsm_cbfn(unsigned int hooknum, | ||||
| 		     struct msgb *msg, | ||||
| 		     void *data, void *param); | ||||
|  | ||||
| /* | ||||
|  * Use the channel. As side effect the lchannel recycle timer | ||||
|  * will be started. | ||||
|  */ | ||||
| #define LCHAN_RELEASE_TIMEOUT 20, 0 | ||||
| #define use_lchan(lchan) \ | ||||
| 	do {	lchan->use_count++; \ | ||||
| 		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \ | ||||
| 			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \ | ||||
| 			lchan->nr, lchan->use_count); \ | ||||
| 		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0); | ||||
|  | ||||
| #define put_lchan(lchan) \ | ||||
| 	do { lchan->use_count--; \ | ||||
| 		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \ | ||||
| 			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \ | ||||
| 			lchan->nr, lchan->use_count); \ | ||||
| 	} while(0); | ||||
|  | ||||
|  | ||||
| /* communications link with a BTS */ | ||||
| struct gsm_bts_link { | ||||
| 	struct gsm_bts *bts; | ||||
| }; | ||||
|  | ||||
| struct sccp_connection; | ||||
| struct gsm_lchan; | ||||
| struct gsm_subscriber; | ||||
| struct gsm_mncc; | ||||
| struct rtp_socket; | ||||
|  | ||||
| /* BSC/MSC data holding them together */ | ||||
| struct bss_sccp_connection_data { | ||||
| 	struct gsm_lchan *lchan; | ||||
| 	struct gsm_lchan *secondary_lchan; | ||||
| 	struct sccp_connection *sccp; | ||||
| 	int ciphering_handled : 1; | ||||
|  | ||||
|         /* Timers... */ | ||||
|  | ||||
|         /* for assginment command */ | ||||
|         struct timer_list T10; | ||||
|  | ||||
| 	/* for SCCP ... */ | ||||
| 	struct timer_list sccp_it; | ||||
|  | ||||
| 	/* audio handling */ | ||||
| 	int rtp_port; | ||||
|  | ||||
| 	/* Queue SCCP and GSM0408 messages */ | ||||
| 	int block_gsm; | ||||
| 	struct llist_head gsm_queue; | ||||
| 	unsigned int gsm_queue_size; | ||||
|  | ||||
| 	struct llist_head sccp_queue; | ||||
| 	unsigned int sccp_queue_size; | ||||
| }; | ||||
|  | ||||
| #define GSM0808_T10_VALUE	6, 0 | ||||
| #define sccp_get_lchan(data_ctx) ((struct bss_sccp_connection_data *)data_ctx)->lchan | ||||
| #define lchan_get_sccp(lchan) lchan->msc_data->sccp | ||||
| struct bss_sccp_connection_data *bss_sccp_create_data(); | ||||
| void bss_sccp_free_data(struct bss_sccp_connection_data *); | ||||
|  | ||||
|  | ||||
| /* Network Management State */ | ||||
| struct gsm_nm_state { | ||||
| 	u_int8_t operational; | ||||
| @@ -201,9 +216,6 @@ struct gsm_lchan { | ||||
| 	/* To whom we are allocated at the moment */ | ||||
| 	struct gsm_subscriber *subscr; | ||||
|  | ||||
| 	/* Timer started to release the channel */ | ||||
| 	struct timer_list release_timer; | ||||
|  | ||||
| 	struct timer_list T3101; | ||||
|  | ||||
| 	/* Established data link layer services */ | ||||
| @@ -214,6 +226,12 @@ struct gsm_lchan { | ||||
| 	 */ | ||||
| 	struct gsm_loc_updating_operation *loc_operation; | ||||
|  | ||||
| 	/* | ||||
| 	 * MSC handling... | ||||
| 	 */ | ||||
| 	struct bss_sccp_connection_data *msc_data; | ||||
|  | ||||
|  | ||||
| 	/* use count. how many users use this channel */ | ||||
| 	unsigned int use_count; | ||||
|  | ||||
| @@ -509,6 +527,14 @@ enum gsm_auth_policy { | ||||
| #define GSM_T3101_DEFAULT 10 | ||||
| #define GSM_T3113_DEFAULT 60 | ||||
|  | ||||
| /* | ||||
|  * internal data for audio management | ||||
|  */ | ||||
| struct gsm_audio_support { | ||||
| 	u_int8_t hr  : 1, | ||||
| 		 ver : 7; | ||||
| }; | ||||
|  | ||||
| struct gsm_network { | ||||
| 	/* global parameters */ | ||||
| 	u_int16_t country_code; | ||||
| @@ -539,6 +565,11 @@ struct gsm_network { | ||||
|  | ||||
| 	struct gsmnet_stats stats; | ||||
|  | ||||
| 	struct gsm_audio_support **audio_support; | ||||
| 	int audio_length; | ||||
| 	int rtp_payload; | ||||
| 	int rtp_base_port; | ||||
|  | ||||
| 	/* layer 4 */ | ||||
| 	int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg); | ||||
| 	struct llist_head upqueue; | ||||
| @@ -564,6 +595,10 @@ struct gsm_network { | ||||
| 	struct { | ||||
| 		enum rrlp_mode mode; | ||||
| 	} rrlp; | ||||
|  | ||||
| 	/* a hack for On Waves. It must be signed */ | ||||
| 	int32_t core_country_code; | ||||
| 	int32_t core_network_code; | ||||
| }; | ||||
|  | ||||
| #define SMS_HDR_SIZE	128 | ||||
|   | ||||
| @@ -81,6 +81,8 @@ struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net, | ||||
| 					       const char *ext); | ||||
| struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net, | ||||
| 					unsigned long long id); | ||||
| struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net, | ||||
| 					    const char *imsi); | ||||
| int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason); | ||||
| void subscr_put_channel(struct gsm_lchan *lchan); | ||||
| void subscr_get_channel(struct gsm_subscriber *subscr, | ||||
|   | ||||
| @@ -44,5 +44,6 @@ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa); | ||||
| int ipaccess_rcvmsg_base(struct msgb *msg, struct bsc_fd *bfd); | ||||
| struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error); | ||||
| void ipaccess_prepend_header(struct msgb *msg, int proto); | ||||
| int ipaccess_send_id_ack(int fd); | ||||
|  | ||||
| #endif /* _IPACCESS_H */ | ||||
|   | ||||
| @@ -21,8 +21,6 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| unsigned int rtp_base_port = 4000; | ||||
|  | ||||
| /** | ||||
|  * Calculate the RTP audio port for the given multiplex | ||||
|  * and the direction. This allows a semi static endpoint | ||||
|   | ||||
| @@ -37,6 +37,7 @@ struct msgb { | ||||
| 	unsigned char *l2h; | ||||
| 	unsigned char *l3h; | ||||
| 	unsigned char *smsh; | ||||
| 	unsigned char *l4h; | ||||
|  | ||||
| 	u_int16_t data_len; | ||||
| 	u_int16_t len; | ||||
| @@ -55,6 +56,7 @@ extern void msgb_reset(struct msgb *m); | ||||
|  | ||||
| #define msgb_l2(m)	((void *)(m->l2h)) | ||||
| #define msgb_l3(m)	((void *)(m->l3h)) | ||||
| #define msgb_l4(m)	((void *)(m->l4h)) | ||||
| #define msgb_sms(m)	((void *)(m->smsh)) | ||||
|  | ||||
| static inline unsigned int msgb_l2len(const struct msgb *msgb) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| /* | ||||
|  * SCCP management code | ||||
|  * | ||||
|  * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * | ||||
|  * All Rights Reserved | ||||
|  * | ||||
| @@ -143,4 +143,25 @@ extern const struct sockaddr_sccp sccp_ssn_bssap; | ||||
| 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); | ||||
|  | ||||
| /** | ||||
|  * 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 | ||||
|   | ||||
| @@ -2,21 +2,22 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include | ||||
| AM_CFLAGS=-Wall | ||||
|  | ||||
| sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ | ||||
|                 isdnsync bsc_mgcp | ||||
|                 isdnsync bsc_mgcp bsc_msc_ip bsc_nat | ||||
| noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a | ||||
| noinst_HEADERS = vty/cardshell.h | ||||
|  | ||||
| libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ | ||||
| 		msgb.c select.c chan_alloc.c timer.c debug.c handover_logic.c \ | ||||
| 		msgb.c select.c chan_alloc.c timer.c debug.c \ | ||||
| 		gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ | ||||
| 		trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ | ||||
| 		input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ | ||||
| 		talloc_ctx.c system_information.c bitvec.c rest_octets.c \ | ||||
| 		handover_decision.c meas_rep.c rtp_proxy.c | ||||
| 		rtp_proxy.c telnet_interface.c | ||||
|  | ||||
| libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ | ||||
| libmsc_a_SOURCES = gsm_subscriber.c db.c \ | ||||
| 		mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ | ||||
| 		token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c | ||||
| 		token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \ | ||||
|                 handover_logic.c handover_decision.c meas_rep.c | ||||
|  | ||||
| libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c | ||||
|  | ||||
| @@ -25,6 +26,10 @@ libsccp_a_SOURCES = sccp/sccp.c | ||||
| bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c | ||||
| bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) | ||||
|  | ||||
| bsc_msc_ip_SOURCES = bssap.c bsc_msc_ip.c bsc_init.c vty_interface.c vty_interface_bsc.c \ | ||||
| 		bsc_msc.c | ||||
| bsc_msc_ip_LDADD = libbsc.a libvty.a libsccp.a | ||||
|  | ||||
| bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \ | ||||
| 		      select.c timer.c rs232.c tlv_parser.c signal.c talloc.c | ||||
|  | ||||
| @@ -37,3 +42,6 @@ isdnsync_SOURCES = isdnsync.c | ||||
|  | ||||
| bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c | ||||
| bsc_mgcp_LDADD = libvty.a | ||||
|  | ||||
| bsc_nat_SOURCES = nat/bsc_nat.c nat/bsc_filter.c bsc_msc.c | ||||
| bsc_nat_LDADD = libbsc.a libsccp.a | ||||
|   | ||||
| @@ -630,6 +630,10 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, | ||||
| 	msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power); | ||||
| 	msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); | ||||
|  | ||||
| 	if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) | ||||
| 		msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf), | ||||
| 			     (u_int8_t *) &lchan->mr_conf); | ||||
|  | ||||
| 	msg->trx = lchan->ts->trx; | ||||
|  | ||||
| 	return abis_rsl_sendmsg(msg); | ||||
| @@ -853,6 +857,10 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id) | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	if (msg->lchan->use_count <= 0) { | ||||
| 		DEBUGP(DRSL, "BUG: Trying to send data on unused lchan\n"); | ||||
| 	} | ||||
|  | ||||
| 	/* First push the L3 IE tag and length */ | ||||
| 	msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); | ||||
|  | ||||
| @@ -1477,31 +1485,11 @@ static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) | ||||
| { | ||||
| 	switch (lchan->tch_mode) { | ||||
| 	case GSM48_CMODE_SPEECH_V1: | ||||
| 		switch (lchan->type) { | ||||
| 		case GSM_LCHAN_TCH_F: | ||||
| 		return 0x00; | ||||
| 		case GSM_LCHAN_TCH_H: | ||||
| 			return 0x03; | ||||
| 		default: | ||||
| 			break; | ||||
| 		} | ||||
| 	case GSM48_CMODE_SPEECH_EFR: | ||||
| 		switch (lchan->type) { | ||||
| 		case GSM_LCHAN_TCH_F: | ||||
| 		return 0x01; | ||||
| 		/* there's no half-rate EFR */ | ||||
| 		default: | ||||
| 			break; | ||||
| 		} | ||||
| 	case GSM48_CMODE_SPEECH_AMR: | ||||
| 		switch (lchan->type) { | ||||
| 		case GSM_LCHAN_TCH_F: | ||||
| 		return 0x02; | ||||
| 		case GSM_LCHAN_TCH_H: | ||||
| 			return 0x05; | ||||
| 		default: | ||||
| 			break; | ||||
| 		} | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| @@ -1795,9 +1783,21 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) | ||||
| /* Entry-point where L2 RSL from BTS enters */ | ||||
| int abis_rsl_rcvmsg(struct msgb *msg) | ||||
| { | ||||
| 	struct abis_rsl_common_hdr *rslh = msgb_l2(msg)	; | ||||
| 	struct abis_rsl_common_hdr *rslh; | ||||
| 	int rc = 0; | ||||
|  | ||||
| 	if (!msg) { | ||||
| 		DEBUGP(DRSL, "Empty RSL msg?..\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (msgb_l2len(msg) < sizeof(*rslh)) { | ||||
| 		DEBUGP(DRSL, "Truncated RSL message with l2len: %u\n", msgb_l2len(msg)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	rslh = msgb_l2(msg); | ||||
|  | ||||
| 	switch (rslh->msg_discr & 0xfe) { | ||||
| 	case ABIS_RSL_MDISC_RLL: | ||||
| 		rc = abis_rsl_rx_rll(msg); | ||||
|   | ||||
| @@ -356,12 +356,15 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, | ||||
| 	case NM_OC_SITE_MANAGER: | ||||
| 		bts = container_of(obj, struct gsm_bts, site_mgr); | ||||
| 		if (new_state->operational == 2 && | ||||
| 		    new_state->availability == NM_AVSTATE_OK) | ||||
| 		    new_state->availability == NM_AVSTATE_OK) { | ||||
| 			printf("STARTING SITE MANAGER\n"); | ||||
| 			abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff); | ||||
| 		} | ||||
| 		break; | ||||
| 	case NM_OC_BTS: | ||||
| 		bts = obj; | ||||
| 		if (new_state->availability == NM_AVSTATE_DEPENDENCY) { | ||||
| 			printf("STARTING BTS...\n"); | ||||
| 			patch_nm_tables(bts); | ||||
| 			abis_nm_set_bts_attr(bts, nanobts_attr_bts, | ||||
| 					     sizeof(nanobts_attr_bts)); | ||||
| @@ -377,6 +380,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, | ||||
| 		trx = ts->trx; | ||||
| 		if (new_state->operational == 1 && | ||||
| 		    new_state->availability == NM_AVSTATE_DEPENDENCY) { | ||||
| 			printf("STARTING OC Channel...\n"); | ||||
| 			patch_nm_tables(trx->bts); | ||||
| 			enum abis_nm_chan_comb ccomb = | ||||
| 						abis_nm_chcomb4pchan(ts->pchan); | ||||
|   | ||||
| @@ -63,7 +63,10 @@ static const char *audio_name = "GSM-EFR/8000"; | ||||
| static int audio_payload = 97; | ||||
| static int audio_loop = 0; | ||||
| static int early_bind = 0; | ||||
| static int rtp_base_port = 4000; | ||||
|  | ||||
| static char *forward_ip = NULL; | ||||
| static int forward_port = 0; | ||||
| static char *config_file = "mgcp.cfg"; | ||||
|  | ||||
| /* used by msgb and mgcp */ | ||||
| @@ -95,7 +98,7 @@ struct mgcp_endpoint { | ||||
| 	char *local_options; | ||||
| 	int conn_mode; | ||||
|  | ||||
| 	/* the local rtp port */ | ||||
| 	/* the local rtp port we are binding to */ | ||||
| 	int rtp_port; | ||||
|  | ||||
| 	/* | ||||
| @@ -107,9 +110,10 @@ struct mgcp_endpoint { | ||||
| 	struct bsc_fd local_rtcp; | ||||
|  | ||||
| 	struct in_addr remote; | ||||
| 	struct in_addr bts; | ||||
|  | ||||
| 	/* in network byte order */ | ||||
| 	int rtp, rtcp; | ||||
| 	int net_rtp, net_rtcp; | ||||
| 	int bts_rtp, bts_rtcp; | ||||
| }; | ||||
|  | ||||
| @@ -235,8 +239,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) | ||||
| 	} | ||||
|  | ||||
| 	/* do not forward aynthing... maybe there is a packet from the bts */ | ||||
| 	if (endp->ci == CI_UNUSED) | ||||
| 	if (endp->ci == CI_UNUSED) { | ||||
| 		DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Figure out where to forward it to. This code assumes that we | ||||
| @@ -246,20 +252,22 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) | ||||
| 	 * 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 | ||||
| 	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) { | ||||
| 	if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || forward_ip)) { | ||||
| 		/* it was the BTS... */ | ||||
| 		if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { | ||||
| 		if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { | ||||
| 			if (fd == &endp->local_rtp) { | ||||
| 				endp->bts_rtp = addr.sin_port; | ||||
| 			} else { | ||||
| 				endp->bts_rtcp = addr.sin_port; | ||||
| 			} | ||||
|  | ||||
| 			endp->bts = addr.sin_addr; | ||||
| 			DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n", | ||||
| 				ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); | ||||
| 		} | ||||
| @@ -271,10 +279,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) | ||||
|  | ||||
| 	if (dest == DEST_NETWORK) { | ||||
| 		return _send(fd->fd, &endp->remote, | ||||
| 			     proto == PROTO_RTP ? endp->rtp : endp->rtcp, | ||||
| 			     proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp, | ||||
| 			     buf, rc); | ||||
| 	} else { | ||||
| 		return _send(fd->fd, &bts_in, | ||||
| 		return _send(fd->fd, &endp->bts, | ||||
| 			     proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, | ||||
| 			     buf, rc); | ||||
| 	} | ||||
| @@ -303,9 +311,6 @@ static int create_bind(struct bsc_fd *fd, int port) | ||||
|  | ||||
| static int bind_rtp(struct mgcp_endpoint *endp) | ||||
| { | ||||
| 	/* set to zero until we get the info */ | ||||
| 	memset(&endp->remote, 0, sizeof(endp->remote)); | ||||
|  | ||||
| 	if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { | ||||
| 		DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", | ||||
| 		       endp->rtp_port, ENDPOINT_NUMBER(endp)); | ||||
| @@ -636,7 +641,10 @@ static void handle_create_con(struct msgb *msg, struct sockaddr_in *source) | ||||
| 	MSG_TOKENIZE_END | ||||
|  | ||||
| 	/* initialize */ | ||||
| 	endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; | ||||
| 	endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; | ||||
|  | ||||
| 	/* set to zero until we get the info */ | ||||
| 	memset(&endp->remote, 0, sizeof(endp->remote)); | ||||
|  | ||||
| 	/* bind to the port now */ | ||||
| 	endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); | ||||
| @@ -716,8 +724,8 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source) | ||||
| 		const char *param = (const char *)&msg->l3h[line_start]; | ||||
|  | ||||
| 		if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) { | ||||
| 			endp->rtp = htons(port); | ||||
| 			endp->rtcp = htons(port + 1); | ||||
| 			endp->net_rtp = htons(port); | ||||
| 			endp->net_rtcp = htons(port + 1); | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| @@ -740,7 +748,7 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source) | ||||
|  | ||||
| 	/* modify */ | ||||
| 	DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n", | ||||
| 		ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->rtp); | ||||
| 		ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp); | ||||
| 	return send_with_sdp(endp, "MDCX", trans_id, source); | ||||
|  | ||||
| error: | ||||
| @@ -802,7 +810,7 @@ static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source) | ||||
| 		bsc_unregister_fd(&endp->local_rtcp); | ||||
| 	} | ||||
|  | ||||
| 	endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; | ||||
| 	endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0; | ||||
|  | ||||
| 	return send_response(250, "DLCX", trans_id, source); | ||||
|  | ||||
| @@ -900,6 +908,7 @@ static int config_write_mgcp(struct vty *vty) | ||||
| 	vty_out(vty, "mgcp%s", VTY_NEWLINE); | ||||
| 	if (local_ip) | ||||
| 		vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE); | ||||
| 	if (bts_ip) | ||||
| 		vty_out(vty, "  bts ip %s%s", bts_ip, VTY_NEWLINE); | ||||
| 	vty_out(vty, "  bind ip %s%s", source_addr, VTY_NEWLINE); | ||||
| 	vty_out(vty, "  bind port %u%s", source_port, VTY_NEWLINE); | ||||
| @@ -909,6 +918,10 @@ static int config_write_mgcp(struct vty *vty) | ||||
| 	vty_out(vty, "  sdp audio payload name %s%s", audio_name, VTY_NEWLINE); | ||||
| 	vty_out(vty, "  loop %u%s", !!audio_loop, VTY_NEWLINE); | ||||
| 	vty_out(vty, "  endpoints %u%s", number_endpoints, VTY_NEWLINE); | ||||
| 	if (forward_ip) | ||||
| 		vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE); | ||||
| 	if (forward_port != 0) | ||||
| 		vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE); | ||||
|  | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| @@ -923,7 +936,7 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp", | ||||
| 		struct mgcp_endpoint *endp = &endpoints[i]; | ||||
| 		vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", | ||||
| 			i, endp->ci, | ||||
| 			ntohs(endp->rtp), ntohs(endp->rtcp), | ||||
| 			ntohs(endp->net_rtp), ntohs(endp->net_rtcp), | ||||
| 			ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); | ||||
| 	} | ||||
|  | ||||
| @@ -1055,6 +1068,26 @@ DEFUN(cfg_mgcp_number_endp, | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_mgcp_forward_ip, | ||||
|       cfg_mgcp_forward_ip_cmd, | ||||
|       "forward audio ip IP", | ||||
|       "Forward packets from and to the IP. This disables most of the MGCP feature.") | ||||
| { | ||||
| 	if (forward_ip) | ||||
| 		talloc_free(forward_ip); | ||||
| 	forward_ip = talloc_strdup(tall_bsc_ctx, 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.") | ||||
| { | ||||
| 	forward_port = atoi(argv[0]); | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| int bsc_vty_init(struct gsm_network *dummy) | ||||
| { | ||||
| 	cmd_init(1); | ||||
| @@ -1076,6 +1109,8 @@ int bsc_vty_init(struct gsm_network *dummy) | ||||
| 	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); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @@ -1096,10 +1131,8 @@ int main(int argc, char** argv) | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	if (!bts_ip) { | ||||
| 		fprintf(stderr, "Need to specify the BTS ip address for RTP handling.\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (!bts_ip) | ||||
| 		fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n"); | ||||
|  | ||||
| 	endpoints = _talloc_zero_array(tall_bsc_ctx, | ||||
| 				       sizeof(struct mgcp_endpoint), | ||||
| @@ -1116,7 +1149,36 @@ int main(int argc, char** argv) | ||||
| 		endpoints[i].ci = CI_UNUSED; | ||||
| 	} | ||||
|  | ||||
| 	/* initialize the socket */ | ||||
| 	/* | ||||
| 	 * 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 (forward_ip) { | ||||
| 		int port = rtp_base_port; | ||||
| 		if (forward_port != 0) | ||||
| 			port = forward_port; | ||||
|  | ||||
| 		if (!early_bind) { | ||||
| 			DEBUGP(DMGCP, "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 < number_endpoints; ++i) { | ||||
| 			struct mgcp_endpoint *endp = &endpoints[i]; | ||||
| 			inet_aton(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); | ||||
| 		} | ||||
|  | ||||
| 		DEBUGP(DMGCP, "Configured for Audio Forwarding.\n"); | ||||
| 	} else { | ||||
| 		bfd.when = BSC_FD_READ; | ||||
| 		bfd.cb = read_call_agent; | ||||
| 		bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); | ||||
| @@ -1149,6 +1211,9 @@ int main(int argc, char** argv) | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		DEBUGP(DMGCP, "Configured for MGCP.\n"); | ||||
| 	} | ||||
|  | ||||
| 	/* initialisation */ | ||||
| 	srand(time(NULL)); | ||||
|  | ||||
|   | ||||
							
								
								
									
										72
									
								
								openbsc/src/bsc_msc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								openbsc/src/bsc_msc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| /* Routines to talk to the MSC using the IPA Protocol */ | ||||
| /* | ||||
|  * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2010 by on-waves.com | ||||
|  * All Rights Reserved | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <openbsc/bsc_msc.h> | ||||
|  | ||||
| #include <arpa/inet.h> | ||||
| #include <sys/socket.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| int connect_to_msc(struct bsc_fd *fd, const char *ip, int port) | ||||
| { | ||||
| 	struct sockaddr_in sin; | ||||
| 	int on = 1, ret; | ||||
|  | ||||
| 	printf("Attempting to connect MSC at %s:%d\n", ip, port); | ||||
|  | ||||
| 	fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | ||||
| 	fd->when = BSC_FD_READ; | ||||
| 	fd->data = NULL; | ||||
| 	fd->priv_nr = 1; | ||||
|  | ||||
| 	if (fd->fd < 0) { | ||||
| 		perror("Creating TCP socket failed"); | ||||
| 		return fd->fd; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	memset(&sin, 0, sizeof(sin)); | ||||
| 	sin.sin_family = AF_INET; | ||||
| 	sin.sin_port = htons(port); | ||||
|         inet_aton(ip, &sin.sin_addr); | ||||
|  | ||||
| 	setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | ||||
| 	ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin)); | ||||
|  | ||||
| 	if (ret < 0) { | ||||
| 		perror("Connection failed"); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	ret = bsc_register_fd(fd); | ||||
| 	if (ret < 0) { | ||||
| 		perror("Registering the fd failed"); | ||||
| 		close(fd->fd); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										809
									
								
								openbsc/src/bsc_msc_ip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										809
									
								
								openbsc/src/bsc_msc_ip.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,809 @@ | ||||
| /* A hackish minimal BSC (+MSC +HLR) implementation */ | ||||
|  | ||||
| /* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> | ||||
|  * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2009 by on-waves.com | ||||
|  * All Rights Reserved | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <time.h> | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <arpa/inet.h> | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #include <getopt.h> | ||||
|  | ||||
| #include <openbsc/select.h> | ||||
| #include <openbsc/debug.h> | ||||
| #include <openbsc/e1_input.h> | ||||
| #include <openbsc/talloc.h> | ||||
| #include <openbsc/select.h> | ||||
| #include <openbsc/ipaccess.h> | ||||
| #include <openbsc/bssap.h> | ||||
| #include <openbsc/paging.h> | ||||
| #include <openbsc/signal.h> | ||||
| #include <openbsc/chan_alloc.h> | ||||
| #include <openbsc/bsc_msc.h> | ||||
|  | ||||
| #include <sccp/sccp.h> | ||||
|  | ||||
| /* SCCP helper */ | ||||
| #define SCCP_IT_TIMER 60 | ||||
|  | ||||
| /* MCC and MNC for the Location Area Identifier */ | ||||
| struct gsm_network *bsc_gsmnet = 0; | ||||
| static const char *config_file = "openbsc.cfg"; | ||||
| static char *msc_address = "127.0.0.1"; | ||||
| static struct bsc_fd msc_connection; | ||||
| static struct in_addr local_addr; | ||||
| extern int ipacc_rtp_direct; | ||||
|  | ||||
| extern int bsc_bootstrap_network(int (*layer4)(struct gsm_network *, int, void *), const char *cfg_file); | ||||
| extern int bsc_shutdown_net(struct gsm_network *net); | ||||
|  | ||||
| struct bss_sccp_connection_data *bss_sccp_create_data() | ||||
| { | ||||
| 	struct bss_sccp_connection_data *data; | ||||
|  | ||||
| 	data = _talloc_zero(tall_bsc_ctx, | ||||
| 			    sizeof(struct bss_sccp_connection_data), | ||||
| 			    "bsc<->msc"); | ||||
| 	if (!data) | ||||
| 		return NULL; | ||||
|  | ||||
| 	INIT_LLIST_HEAD(&data->sccp_queue); | ||||
| 	INIT_LLIST_HEAD(&data->gsm_queue); | ||||
| 	return data; | ||||
| } | ||||
|  | ||||
| void bss_sccp_free_data(struct bss_sccp_connection_data *data) | ||||
| { | ||||
| 	bsc_del_timer(&data->T10); | ||||
| 	bsc_del_timer(&data->sccp_it); | ||||
| 	bsc_free_queued(data->sccp); | ||||
| 	bts_free_queued(data); | ||||
| 	talloc_free(data); | ||||
| } | ||||
|  | ||||
| static void sccp_it_fired(void *_data) | ||||
| { | ||||
| 	struct bss_sccp_connection_data *data = | ||||
| 		(struct bss_sccp_connection_data *) _data; | ||||
|  | ||||
| 	sccp_connection_send_it(data->sccp); | ||||
| 	bsc_schedule_timer(&data->sccp_it, SCCP_IT_TIMER, 0); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* GSM subscriber drop-ins */ | ||||
| extern struct llist_head *subscr_bsc_active_subscriber(void); | ||||
| struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string) | ||||
| { | ||||
| 	struct gsm_subscriber *subscr; | ||||
| 	u_int32_t tmsi = GSM_RESERVED_TMSI; | ||||
| 	if (type == GSM_MI_TYPE_TMSI) { | ||||
| 		tmsi = tmsi_from_string(mi_string); | ||||
| 		if (tmsi == GSM_RESERVED_TMSI) { | ||||
| 			DEBUGP(DMSC, "The TMSI is the reserved one.\n"); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) { | ||||
| 		if (type == GSM_MI_TYPE_TMSI && tmsi == subscr->tmsi) { | ||||
| 			return subscr_get(subscr); | ||||
| 		} else if (type == GSM_MI_TYPE_IMSI && strcmp(mi_string, subscr->imsi) == 0) { | ||||
| 			return subscr_get(subscr); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	DEBUGP(DMSC, "No subscriber has been found.\n"); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /* SCCP handling */ | ||||
| void msc_outgoing_sccp_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len) | ||||
| { | ||||
| 	struct bssmap_header *bs; | ||||
|  | ||||
| 	if (len < 1) { | ||||
| 		DEBUGP(DMSC, "The header is too short.\n"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	switch (msg->l3h[0]) { | ||||
| 	case BSSAP_MSG_BSS_MANAGEMENT: | ||||
| 		msg->l4h = &msg->l3h[sizeof(*bs)]; | ||||
| 		msg->lchan = sccp_get_lchan(conn->data_ctx); | ||||
| 		bssmap_rcvmsg_dt1(conn, msg, len - sizeof(*bs)); | ||||
| 		break; | ||||
| 	case BSSAP_MSG_DTAP: | ||||
| 		dtap_rcvmsg(sccp_get_lchan(conn->data_ctx), msg, len); | ||||
| 		break; | ||||
| 	default: | ||||
| 		DEBUGPC(DMSC, "Unimplemented msg type: %d\n", msg->l3h[0]); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state) | ||||
| { | ||||
| 	if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { | ||||
| 		DEBUGP(DMSC, "Freeing sccp conn: %p state: %d\n", conn, conn->connection_state); | ||||
| 		if (sccp_get_lchan(conn->data_ctx) != NULL) { | ||||
| 			struct gsm_lchan *lchan = sccp_get_lchan(conn->data_ctx); | ||||
|  | ||||
| 			DEBUGP(DMSC, "ERROR: The lchan is still associated\n."); | ||||
|  | ||||
| 			lchan->msc_data = NULL; | ||||
| 			put_lchan(lchan); | ||||
| 		} | ||||
|  | ||||
| 		bss_sccp_free_data((struct bss_sccp_connection_data *)conn->data_ctx); | ||||
| 		sccp_connection_free(conn); | ||||
| 		return; | ||||
| 	} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) { | ||||
| 		struct bss_sccp_connection_data *con_data; | ||||
|  | ||||
| 		DEBUGP(DMSC, "Connection established: %p\n", conn); | ||||
|  | ||||
| 		/* start the inactivity test timer */ | ||||
| 		con_data = (struct bss_sccp_connection_data *) conn->data_ctx; | ||||
| 		con_data->sccp_it.cb = sccp_it_fired; | ||||
| 		con_data->sccp_it.data = con_data; | ||||
| 		bsc_schedule_timer(&con_data->sccp_it, SCCP_IT_TIMER, 0); | ||||
|  | ||||
| 		bsc_send_queued(conn); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * General COMPLETE LAYER3 INFORMATION handling for | ||||
|  * PAGING RESPONSE, LOCATION UPDATING REQUEST, CM REESTABLISHMENT REQUEST, | ||||
|  * CM SERVICE REQUEST, IMSI DETACH, IMMEDIATE SETUP. | ||||
|  * | ||||
|  * IMMEDIATE SETUP is coming from GROUP CC that is not yet | ||||
|  * supported... | ||||
|  */ | ||||
| int open_sccp_connection(struct msgb *layer3) | ||||
| { | ||||
| 	struct bss_sccp_connection_data *con_data; | ||||
| 	struct sccp_connection *sccp_connection; | ||||
| 	struct msgb *data; | ||||
|  | ||||
| 	DEBUGP(DMSC, "Opening new layer3 connection\n"); | ||||
| 	sccp_connection = sccp_connection_socket(); | ||||
| 	if (!sccp_connection) { | ||||
| 		DEBUGP(DMSC, "Failed to allocate memory.\n"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
|  | ||||
| 	data = bssmap_create_layer3(layer3); | ||||
| 	if (!data) { | ||||
| 		DEBUGP(DMSC, "Failed to allocate complete layer3.\n"); | ||||
| 		sccp_connection_free(sccp_connection); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
|  | ||||
| 	con_data = bss_sccp_create_data(); | ||||
| 	if (!con_data) { | ||||
| 		DEBUGP(DMSC, "Failed to allocate bss<->msc data.\n"); | ||||
| 		sccp_connection_free(sccp_connection); | ||||
| 		msgb_free(data); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
|  | ||||
| 	/* initialize the bridge */ | ||||
| 	con_data->lchan = layer3->lchan; | ||||
| 	con_data->sccp = sccp_connection; | ||||
|  | ||||
| 	sccp_connection->state_cb = msc_outgoing_sccp_state; | ||||
| 	sccp_connection->data_cb = msc_outgoing_sccp_data; | ||||
| 	sccp_connection->data_ctx = con_data; | ||||
| 	layer3->lchan->msc_data = con_data; | ||||
|  | ||||
| 	/* FIXME: Use transaction for this */ | ||||
| 	use_lchan(layer3->lchan); | ||||
| 	sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data); | ||||
| 	msgb_free(data); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* figure out if this is the inial layer3 message */ | ||||
| static int send_dtap_or_open_connection(struct msgb *msg) | ||||
| { | ||||
| 	if (msg->lchan->msc_data) { | ||||
| 		struct msgb *dtap = dtap_create_msg(msg, 0); | ||||
| 		if (!dtap) { | ||||
| 			DEBUGP(DMSC, "Creating a DTAP message failed.\n"); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		bsc_queue_connection_write(lchan_get_sccp(msg->lchan), dtap); | ||||
| 		return 1; | ||||
| 	} else { | ||||
| 		return open_sccp_connection(msg); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Receive a PAGING RESPONSE message from the MS */ | ||||
| static int handle_paging_response(struct msgb *msg) | ||||
| { | ||||
| 	struct gsm_subscriber *subscr; | ||||
| 	char mi_string[GSM48_MI_SIZE]; | ||||
| 	u_int8_t mi_type; | ||||
|  | ||||
| 	gsm48_paging_extract_mi(msg, mi_string, &mi_type); | ||||
| 	DEBUGP(DMSC, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n", | ||||
| 		mi_type, mi_string); | ||||
|  | ||||
| 	subscr = find_subscriber(mi_type, mi_string); | ||||
| 	if (!subscr) | ||||
| 		return -EINVAL; | ||||
|  | ||||
| 	/* force the paging to stop at every bts */ | ||||
| 	subscr->lac = GSM_LAC_RESERVED_ALL_BTS; | ||||
| 	if (gsm48_handle_paging_resp(msg, subscr) != 0) { | ||||
| 		DEBUGP(DMSC, "Paging failed.\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* open a new transaction and SCCP connection */ | ||||
| 	return send_dtap_or_open_connection(msg); | ||||
| } | ||||
|  | ||||
| /* Receive a CIPHER MODE COMPLETE from the MS */ | ||||
| static int handle_cipher_m_complete(struct msgb *msg) | ||||
| { | ||||
| 	struct msgb *resp; | ||||
|  | ||||
| 	DEBUGP(DMSC, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n"); | ||||
| 	resp = bssmap_create_cipher_complete(msg); | ||||
| 	if (!resp) { | ||||
| 		DEBUGP(DMSC, "Creating MSC response failed.\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	/* handled this message */ | ||||
| 	bts_unblock_queue(msg->lchan->msc_data); | ||||
| 	bsc_queue_connection_write(lchan_get_sccp(msg->lchan), resp); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Receive a ASSIGNMENT COMPLETE */ | ||||
| static int handle_ass_compl(struct msgb *msg) | ||||
| { | ||||
| 	struct gsm_lchan *old_chan; | ||||
| 	struct gsm48_hdr *gh = msgb_l3(msg); | ||||
|  | ||||
| 	DEBUGP(DMSC, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n"); | ||||
|  | ||||
| 	if (!msg->lchan->msc_data) { | ||||
| 		DEBUGP(DMSC, "No MSC data\n"); | ||||
| 		put_lchan(msg->lchan); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (msg->lchan->msc_data->secondary_lchan != msg->lchan) { | ||||
| 		LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n"); | ||||
| 		put_lchan(msg->lchan); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (msgb_l3len(msg) - sizeof(*gh) != 1) { | ||||
| 		DEBUGP(DMSC, "assignment failure invalid: %d\n", | ||||
| 			msgb_l3len(msg) - sizeof(*gh)); | ||||
| 		put_lchan(msg->lchan); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* swap the channels and release the old */ | ||||
| 	old_chan = msg->lchan->msc_data->lchan; | ||||
| 	msg->lchan->msc_data->lchan = msg->lchan; | ||||
| 	msg->lchan->msc_data->secondary_lchan = NULL; | ||||
| 	old_chan->msc_data = NULL; | ||||
|  | ||||
| 	/* give up the old channel to not do a SACCH deactivate */ | ||||
| 	subscr_put(old_chan->subscr); | ||||
| 	old_chan->subscr = NULL; | ||||
| 	put_lchan(old_chan); | ||||
|  | ||||
| 	/* activate audio on it... */ | ||||
| 	if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && msg->lchan->tch_mode != GSM48_CMODE_SIGN) | ||||
| 		rsl_ipacc_crcx(msg->lchan); | ||||
|  | ||||
| 	gsm0808_send_assignment_compl(msg->lchan, gh->data[0]); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Receive a ASSIGNMENT FAILURE. If the message is failed | ||||
|  * to be parsed the T10 timer will send the failure. | ||||
|  */ | ||||
| static int handle_ass_fail(struct msgb *msg) | ||||
| { | ||||
| 	struct gsm48_hdr *gh = msgb_l3(msg); | ||||
|  | ||||
| 	DEBUGP(DMSC, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n"); | ||||
| 	if (!msg->lchan->msc_data) { | ||||
| 		DEBUGP(DMSC, "No MSC data\n"); | ||||
| 		put_lchan(msg->lchan); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (msg->lchan->msc_data->secondary_lchan != msg->lchan) { | ||||
| 		LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n"); | ||||
| 		put_lchan(msg->lchan); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (msgb_l3len(msg) - sizeof(*gh) != 1) { | ||||
| 		DEBUGP(DMSC, "assignment failure invalid: %d\n", | ||||
| 			msgb_l3len(msg) - sizeof(*gh)); | ||||
| 		put_lchan(msg->lchan); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	gsm0808_send_assignment_failure(msg->lchan, | ||||
| 		GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, &gh->data[0]); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Receive a GSM04.08 MODIFY ACK. Actually we have to check | ||||
|  * the content to see if this was a success or not. | ||||
|  */ | ||||
| static int handle_modify_ack(struct msgb *msg) | ||||
| { | ||||
| 	int rc; | ||||
|  | ||||
| 	/* modify RSL */ | ||||
| 	rc = gsm48_rx_rr_modif_ack(msg); | ||||
| 	if (rc < 0) | ||||
| 		gsm0808_send_assignment_failure(msg->lchan, | ||||
| 			GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); | ||||
| 	else | ||||
| 		gsm0808_send_assignment_compl(msg->lchan, 0); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Receive a GSM 04.08 Radio Resource (RR) message */ | ||||
| static int gsm0408_rcv_rr(struct msgb *msg) | ||||
| { | ||||
| 	struct gsm48_hdr *gh = msgb_l3(msg); | ||||
| 	int rc = 0; | ||||
|  | ||||
| 	switch (gh->msg_type) { | ||||
| 	case GSM48_MT_RR_PAG_RESP: | ||||
| 		rc = handle_paging_response(msg); | ||||
| 		break; | ||||
| 	case GSM48_MT_RR_MEAS_REP: | ||||
| 		/* ignore measurement for now */ | ||||
| 		rc = -1; | ||||
| 		break; | ||||
| 	case GSM48_MT_RR_CIPH_M_COMPL: | ||||
| 		rc = handle_cipher_m_complete(msg); | ||||
| 		break; | ||||
| 	case GSM48_MT_RR_ASS_COMPL: | ||||
| 		rc = handle_ass_compl(msg); | ||||
| 		break; | ||||
| 	case GSM48_MT_RR_ASS_FAIL: | ||||
| 		rc = handle_ass_fail(msg); | ||||
| 		break; | ||||
| 	case GSM48_MT_RR_CHAN_MODE_MODIF_ACK: | ||||
| 		rc = handle_modify_ack(msg); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| /* Receive a GSM 04.08 Mobility Management (MM) message */ | ||||
| static int gsm0408_rcv_mm(struct msgb *msg) | ||||
| { | ||||
| 	struct gsm48_hdr *gh = msgb_l3(msg); | ||||
| 	int rc = 0; | ||||
|  | ||||
| 	switch (gh->msg_type & 0xbf) { | ||||
| 	case GSM48_MT_MM_LOC_UPD_REQUEST: | ||||
| 	case GSM48_MT_MM_CM_REEST_REQ: | ||||
| 	case GSM48_MT_MM_CM_SERV_REQ: | ||||
| 	case GSM48_MT_MM_IMSI_DETACH_IND: | ||||
| 		rc = send_dtap_or_open_connection(msg); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id) | ||||
| { | ||||
| 	struct gsm48_hdr *gh = msgb_l3(msg); | ||||
| 	u_int8_t pdisc = gh->proto_discr & 0x0f; | ||||
| 	int rc = 0; | ||||
|  | ||||
| 	switch (pdisc) { | ||||
| 	case GSM48_PDISC_RR: | ||||
| 		rc = gsm0408_rcv_rr(msg); | ||||
| 		break; | ||||
| 	case GSM48_PDISC_MM: | ||||
| 		rc = gsm0408_rcv_mm(msg); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * if we have a sccp connection and didn't handle the message | ||||
| 	 * forward it to the MSC using DTAP | ||||
| 	 */ | ||||
| 	if (rc == 0 && msg->lchan->msc_data && lchan_get_sccp(msg->lchan)) { | ||||
| 		struct msgb *dtap = dtap_create_msg(msg, link_id); | ||||
| 		if (!dtap) { | ||||
| 			DEBUGP(DMSC, "Creating a DTAP message failed.\n"); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		bsc_queue_connection_write(lchan_get_sccp(msg->lchan), dtap); | ||||
| 	} | ||||
|  | ||||
| 	return rc; | ||||
| } | ||||
|  | ||||
| /* handle ipaccess signals */ | ||||
| static int handle_abisip_signal(unsigned int subsys, unsigned int signal, | ||||
| 				 void *handler_data, void *signal_data) | ||||
| { | ||||
| 	struct gsm_lchan *lchan = signal_data; | ||||
| 	struct gsm_bts_trx_ts *ts; | ||||
| 	int rc; | ||||
|  | ||||
| 	if (subsys != SS_ABISIP) | ||||
| 		return 0; | ||||
|  | ||||
| 	ts = lchan->ts; | ||||
|  | ||||
| 	switch (signal) { | ||||
| 	case S_ABISIP_CRCX_ACK: | ||||
| 		/* we can ask it to connect now */ | ||||
| 		if (lchan->msc_data) { | ||||
| 			DEBUGP(DMSC, "Connecting BTS to port: %d conn: %d\n", | ||||
| 				lchan->msc_data->rtp_port, lchan->abis_ip.conn_id); | ||||
|  | ||||
| 			int rtp_payload = ts->trx->bts->network->rtp_payload; | ||||
| 			if (rtp_payload == 0) | ||||
| 				rtp_payload = lchan->abis_ip.rtp_payload2; | ||||
|  | ||||
| 			rc = rsl_ipacc_mdcx(lchan, ntohl(local_addr.s_addr), | ||||
| 					    lchan->msc_data->rtp_port, | ||||
| 					    rtp_payload); | ||||
| 			if (rc < 0) { | ||||
| 				DEBUGP(DMSC, "Failed to send connect: %d\n", rc); | ||||
| 				return rc; | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
| 	case S_ABISIP_DLCX_IND: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void print_usage() | ||||
| { | ||||
| 	printf("Usage: bsc_hack\n"); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * SCCP handling | ||||
|  */ | ||||
| static int msc_sccp_write_ipa(struct msgb *msg, void *data) | ||||
| { | ||||
| 	int ret; | ||||
|  | ||||
| 	DEBUGP(DMSC, "Sending SCCP to MSC: %u\n", msgb_l2len(msg)); | ||||
| 	ipaccess_prepend_header(msg, IPAC_PROTO_SCCP); | ||||
|  | ||||
|  | ||||
| 	DEBUGP(DMI, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg))); | ||||
| 	ret = write(msc_connection.fd, msg->data, msg->len); | ||||
|  | ||||
| 	if (ret <= 0) { | ||||
| 		perror("MSC: Failed to send SCCP"); | ||||
| 		return -1; | ||||
|         } | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int msc_sccp_accept(struct sccp_connection *connection, void *data) | ||||
| { | ||||
| 	DEBUGP(DMSC, "Rejecting incoming SCCP connection.\n"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data) | ||||
| { | ||||
| 	struct bssmap_header *bs; | ||||
|  | ||||
| 	DEBUGP(DMSC, "Incoming SCCP message ftom MSC: %s\n", hexdump(msgb->l3h, length)); | ||||
|  | ||||
| 	if (length < sizeof(*bs)) { | ||||
| 		DEBUGP(DMSC, "The header is too short.\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	bs = (struct bssmap_header *) msgb->l3h; | ||||
| 	if (bs->length < length - sizeof(*bs)) | ||||
| 		return -1; | ||||
|  | ||||
| 	switch (bs->type) { | ||||
| 	case BSSAP_MSG_BSS_MANAGEMENT: | ||||
| 		msgb->l4h = &msgb->l3h[sizeof(*bs)]; | ||||
| 		bssmap_rcvmsg_udt(bsc_gsmnet, msgb, length - sizeof(*bs)); | ||||
| 		break; | ||||
| 	default: | ||||
| 		DEBUGPC(DMSC, "Unimplemented msg type: %d\n", bs->type); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * network initialisation | ||||
|  */ | ||||
| static void initialize_if_needed(void) | ||||
| { | ||||
| 	if (!bsc_gsmnet) { | ||||
| 		int rc; | ||||
| 		struct msgb *msg; | ||||
|  | ||||
| 		fprintf(stderr, "Bootstraping the network. Sending GSM08.08 reset.\n"); | ||||
| 		rc = bsc_bootstrap_network(NULL, config_file); | ||||
| 		if (rc < 0) { | ||||
| 			fprintf(stderr, "Bootstrapping the network failed. exiting.\n"); | ||||
| 			exit(1); | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		/* send a gsm 08.08 reset message from here */ | ||||
| 		msg = bssmap_create_reset(); | ||||
| 		if (!msg) { | ||||
| 			DEBUGP(DMSC, "Failed to create the reset message.\n"); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0); | ||||
| 		msgb_free(msg); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * callback with IP access data | ||||
|  */ | ||||
| static int ipaccess_a_fd_cb(struct bsc_fd *bfd, unsigned int what) | ||||
| { | ||||
| 	int error; | ||||
| 	struct msgb *msg = ipaccess_read_msg(bfd, &error); | ||||
| 	struct ipaccess_head *hh; | ||||
|  | ||||
| 	if (!msg) { | ||||
| 		if (error == 0) { | ||||
| 			fprintf(stderr, "The connection to the MSC was lost, exiting\n"); | ||||
| 			exit(-2); | ||||
| 		} | ||||
|  | ||||
| 		fprintf(stderr, "Failed to parse ip access message: %d\n", error); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGP(DMSC, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]); | ||||
|  | ||||
| 	/* handle base message handling */ | ||||
| 	hh = (struct ipaccess_head *) msg->data; | ||||
| 	ipaccess_rcvmsg_base(msg, bfd); | ||||
|  | ||||
| 	/* initialize the networking. This includes sending a GSM08.08 message */ | ||||
| 	if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK) | ||||
| 		initialize_if_needed(); | ||||
| 	else if (hh->proto == IPAC_PROTO_SCCP) | ||||
| 		sccp_system_incoming(msg); | ||||
|  | ||||
| 	msgb_free(msg); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void print_help() | ||||
| { | ||||
| 	printf("  Some useful help...\n"); | ||||
| 	printf("  -h --help this text\n"); | ||||
| 	printf("  -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n"); | ||||
| 	printf("  -s --disable-color\n"); | ||||
| 	printf("  -c --config-file filename The config file to use.\n"); | ||||
| 	printf("  -m --msc=IP. The address of the MSC.\n"); | ||||
| 	printf("  -l --local=IP. The local address of the MGCP.\n"); | ||||
| } | ||||
|  | ||||
| static void handle_options(int argc, char** argv) | ||||
| { | ||||
| 	while (1) { | ||||
| 		int option_index = 0, c; | ||||
| 		static struct option long_options[] = { | ||||
| 			{"help", 0, 0, 'h'}, | ||||
| 			{"debug", 1, 0, 'd'}, | ||||
| 			{"config-file", 1, 0, 'c'}, | ||||
| 			{"disable-color", 0, 0, 's'}, | ||||
| 			{"timestamp", 0, 0, 'T'}, | ||||
| 			{"rtp-proxy", 0, 0, 'P'}, | ||||
| 			{"msc", 1, 0, 'm'}, | ||||
| 			{"local", 1, 0, 'l'}, | ||||
| 			{0, 0, 0, 0} | ||||
| 		}; | ||||
|  | ||||
| 		c = getopt_long(argc, argv, "hd:sTPc:m:l:", | ||||
| 				long_options, &option_index); | ||||
| 		if (c == -1) | ||||
| 			break; | ||||
|  | ||||
| 		switch (c) { | ||||
| 		case 'h': | ||||
| 			print_usage(); | ||||
| 			print_help(); | ||||
| 			exit(0); | ||||
| 		case 's': | ||||
| 			debug_use_color(0); | ||||
| 			break; | ||||
| 		case 'd': | ||||
| 			debug_parse_category_mask(optarg); | ||||
| 			break; | ||||
| 		case 'c': | ||||
| 			config_file = strdup(optarg); | ||||
| 			break; | ||||
| 		case 'T': | ||||
| 			debug_timestamp(1); | ||||
| 			break; | ||||
| 		case 'P': | ||||
| 			ipacc_rtp_direct = 0; | ||||
| 			break; | ||||
| 		case 'm': | ||||
| 			msc_address = strdup(optarg); | ||||
| 			break; | ||||
| 		case 'l': | ||||
| 			inet_aton(optarg, &local_addr); | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* ignore */ | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void signal_handler(int signal) | ||||
| { | ||||
| 	fprintf(stdout, "signal %u received\n", signal); | ||||
|  | ||||
| 	switch (signal) { | ||||
| 	case SIGINT: | ||||
| 		bsc_shutdown_net(bsc_gsmnet); | ||||
| 		sleep(3); | ||||
| 		exit(0); | ||||
| 		break; | ||||
| 	case SIGABRT: | ||||
| 		/* in case of abort, we want to obtain a talloc report | ||||
| 		 * and then return to the caller, who will abort the process */ | ||||
| 	case SIGUSR1: | ||||
| 		talloc_report_full(tall_bsc_ctx, stderr); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void test_mode() | ||||
| { | ||||
| 	static const u_int8_t assignment_req[] = { 0x01, 0x0b, 0x03, 0x01, 0x0b, 0x25, 0x01, 0x00, 0x01 }; | ||||
| 	struct gsm_lchan lchan; | ||||
| 	struct sccp_connection conn; | ||||
| 	struct bss_sccp_connection_data data; | ||||
|  | ||||
| 	struct gsm_bts_trx_ts trx_ts; | ||||
| 	struct gsm_bts_trx trx; | ||||
| 	struct gsm_bts bts; | ||||
| 	int rc; | ||||
|  | ||||
| 	/* initialize */ | ||||
| 	fprintf(stderr, "Bootstraping the network. Sending GSM08.08 reset.\n"); | ||||
| 	rc = bsc_bootstrap_network(NULL, config_file); | ||||
| 	if (rc < 0) { | ||||
| 		fprintf(stderr, "Bootstrapping the network failed. exiting.\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	bts.network = bsc_gsmnet; | ||||
| 	trx.bts = &bts; | ||||
| 	trx_ts.trx = &trx; | ||||
| 	lchan.ts = &trx_ts; | ||||
|  | ||||
| 	/* create fake data connection */ | ||||
| 	data.lchan = &lchan; | ||||
| 	data.sccp = &conn; | ||||
| 	lchan.msc_data = &data; | ||||
| 	conn.data_ctx = &data; | ||||
|  | ||||
|  | ||||
| 	struct msgb *msg = msgb_alloc(400, "test-msg"); | ||||
| 	msg->lchan = &lchan; | ||||
|  | ||||
| 	msg->l4h = msgb_put(msg, ARRAY_SIZE(assignment_req)); | ||||
| 	memcpy(msg->l4h, assignment_req, ARRAY_SIZE(assignment_req)); | ||||
| 	bssmap_rcvmsg_dt1(&conn, msg, ARRAY_SIZE(assignment_req)); | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	int rc; | ||||
|  | ||||
| 	tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc"); | ||||
|  | ||||
| 	/* parse options */ | ||||
| 	handle_options(argc, argv); | ||||
|  | ||||
| 	/* seed the PRNG */ | ||||
| 	srand(time(NULL)); | ||||
|  | ||||
| 	/* initialize sccp */ | ||||
| 	sccp_system_init(msc_sccp_write_ipa, NULL); | ||||
| 	sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL); | ||||
| 	sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, NULL); | ||||
|  | ||||
| 	/* initialize ipaccess handling */ | ||||
| 	register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL); | ||||
|  | ||||
| 	msc_connection.cb = ipaccess_a_fd_cb; | ||||
| 	rc = connect_to_msc(&msc_connection, msc_address, 5000); | ||||
| 	if (rc < 0) { | ||||
| 		fprintf(stderr, "Opening the MSC connection failed.\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	signal(SIGINT, &signal_handler); | ||||
| 	signal(SIGABRT, &signal_handler); | ||||
| 	signal(SIGUSR1, &signal_handler); | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
|  | ||||
| 	while (1) { | ||||
| 		bsc_select_main(0); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										1299
									
								
								openbsc/src/bssap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1299
									
								
								openbsc/src/bssap.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -33,8 +33,6 @@ | ||||
| #include <openbsc/debug.h> | ||||
| #include <openbsc/signal.h> | ||||
|  | ||||
| static void auto_release_channel(void *_lchan); | ||||
|  | ||||
| struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, | ||||
| 				   enum gsm_phys_chan_config pchan) | ||||
| { | ||||
| @@ -223,10 +221,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) | ||||
| 		/* clear multi rate config */ | ||||
| 		memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf)); | ||||
|  | ||||
| 		/* Configure the time and start it so it will be closed */ | ||||
| 		lchan->release_timer.cb = auto_release_channel; | ||||
| 		lchan->release_timer.data = lchan; | ||||
| 		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); | ||||
| 		/* clear any msc reference */ | ||||
| 		lchan->msc_data = NULL; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return lchan; | ||||
| @@ -249,8 +246,6 @@ void lchan_free(struct gsm_lchan *lchan) | ||||
| 		lchan->use_count = 0; | ||||
| 	} | ||||
|  | ||||
| 	/* stop the timer */ | ||||
| 	bsc_del_timer(&lchan->release_timer); | ||||
| 	bsc_del_timer(&lchan->T3101); | ||||
|  | ||||
| 	/* clear cached measuement reports */ | ||||
| @@ -261,21 +256,23 @@ void lchan_free(struct gsm_lchan *lchan) | ||||
| 	} | ||||
| 	for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++) | ||||
| 		lchan->neigh_meas[i].arfcn = 0; | ||||
|  | ||||
| 	/* FIXME: ts_free() the timeslot, if we're the last logical | ||||
| 	 * channel using it */ | ||||
| } | ||||
|  | ||||
| /* Consider releasing the channel now */ | ||||
| int lchan_auto_release(struct gsm_lchan *lchan) | ||||
| int _lchan_release(struct gsm_lchan *lchan) | ||||
| { | ||||
| 	if (lchan->use_count > 0) { | ||||
| 		DEBUGP(DRLL, "BUG: _lchan_release called without zero use_count.\n"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Assume we have GSM04.08 running and send a release */ | ||||
| 	if (lchan->subscr) { | ||||
| 		++lchan->use_count; | ||||
| 		gsm48_send_rr_release(lchan); | ||||
| 		--lchan->use_count; | ||||
| 	} | ||||
|  | ||||
| 	/* spoofed? message */ | ||||
| @@ -288,15 +285,6 @@ int lchan_auto_release(struct gsm_lchan *lchan) | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* Auto release the channel when the use count is zero */ | ||||
| static void auto_release_channel(void *_lchan) | ||||
| { | ||||
| 	struct gsm_lchan *lchan = _lchan; | ||||
|  | ||||
| 	if (!lchan_auto_release(lchan)) | ||||
| 		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); | ||||
| } | ||||
|  | ||||
| struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) { | ||||
| 	struct gsm_bts_trx *trx; | ||||
| 	int ts_no, lchan_no;  | ||||
|   | ||||
| @@ -232,7 +232,6 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg) | ||||
| 		int rc; | ||||
|  | ||||
| 		db_subscriber_alloc_tmsi(lchan->subscr); | ||||
| 		release_loc_updating_req(lchan); | ||||
| 		rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi); | ||||
| 		if (lchan->ts->trx->bts->network->send_mm_info) { | ||||
| 			/* send MM INFO with network name */ | ||||
| @@ -244,8 +243,7 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg) | ||||
| 		 * trigger further action like SMS delivery */ | ||||
| 		subscr_update(lchan->subscr, msg->trx->bts, | ||||
| 			      GSM_SUBSCRIBER_UPDATE_ATTACHED); | ||||
| 		/* try to close channel ASAP */ | ||||
| 		lchan_auto_release(lchan); | ||||
| 		release_loc_updating_req(lchan); | ||||
| 		return rc; | ||||
| 	} | ||||
|  | ||||
| @@ -931,9 +929,8 @@ static void loc_upd_rej_cb(void *data) | ||||
| 	struct gsm_lchan *lchan = data; | ||||
| 	struct gsm_bts *bts = lchan->ts->trx->bts; | ||||
|  | ||||
| 	release_loc_updating_req(lchan); | ||||
| 	gsm0408_loc_upd_rej(lchan, bts->network->reject_cause); | ||||
| 	lchan_auto_release(lchan); | ||||
| 	release_loc_updating_req(lchan); | ||||
| } | ||||
|  | ||||
| static void schedule_reject(struct gsm_lchan *lchan) | ||||
| @@ -1355,8 +1352,6 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) | ||||
| 	 * imagine an IMSI DETACH happening during an active call! */ | ||||
|  | ||||
| 	/* subscriber is detached: should we release lchan? */ | ||||
| 	lchan_auto_release(msg->lchan); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @@ -2698,7 +2693,6 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg) | ||||
| 					  MNCC_REL_CNF, &rel); | ||||
| 			/* FIXME: in case of multiple calls, we can't simply | ||||
| 			 * hang up here ! */ | ||||
| 			lchan_auto_release(msg->lchan); | ||||
| 			break; | ||||
| 		default: | ||||
| 			rc = mncc_recvmsg(trans->subscr->net, trans, | ||||
|   | ||||
| @@ -567,7 +567,7 @@ int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, | ||||
| } | ||||
|  | ||||
| /* Chapter 9.1.2: Assignment Command */ | ||||
| int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) | ||||
| int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_command) | ||||
| { | ||||
| 	struct msgb *msg = gsm48_msgb_alloc(); | ||||
| 	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); | ||||
| @@ -576,7 +576,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) | ||||
|  | ||||
| 	DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode); | ||||
|  | ||||
| 	msg->lchan = lchan; | ||||
| 	msg->lchan = dest_lchan; | ||||
| 	gh->proto_discr = GSM48_PDISC_RR; | ||||
| 	gh->msg_type = GSM48_MT_RR_ASS_CMD; | ||||
|  | ||||
| @@ -591,6 +591,8 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) | ||||
| 	gsm48_chan_desc(&ass->chan_desc, lchan); | ||||
| 	ass->power_command = power_command; | ||||
|  | ||||
| 	msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode); | ||||
|  | ||||
| 	/* in case of multi rate we need to attach a config */ | ||||
| 	if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { | ||||
| 		if (lchan->mr_conf.ver == 0) { | ||||
|   | ||||
| @@ -224,6 +224,10 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c | ||||
|  | ||||
| 	net->mncc_recv = mncc_recv; | ||||
|  | ||||
| 	net->core_country_code = -1; | ||||
| 	net->core_network_code = -1; | ||||
| 	net->rtp_base_port = 4000; | ||||
|  | ||||
| 	return net; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -32,6 +32,7 @@ | ||||
| #include <openbsc/paging.h> | ||||
| #include <openbsc/debug.h> | ||||
| #include <openbsc/paging.h> | ||||
| #include <openbsc/chan_alloc.h> | ||||
|  | ||||
| LLIST_HEAD(active_subscribers); | ||||
| void *tall_subscr_ctx; | ||||
| @@ -89,6 +90,7 @@ static int subscr_paging_cb(unsigned int hooknum, unsigned int event, | ||||
| 	request->cbfn(hooknum, event, msg, data, request->param); | ||||
| 	subscr->in_callback = 0; | ||||
|  | ||||
| 	subscr_put(request->subscr); | ||||
| 	talloc_free(request); | ||||
| 	return 0; | ||||
| } | ||||
| @@ -166,7 +168,7 @@ void subscr_get_channel(struct gsm_subscriber *subscr, | ||||
| 	} | ||||
|  | ||||
| 	memset(request, 0, sizeof(*request)); | ||||
| 	request->subscr = subscr; | ||||
| 	request->subscr = subscr_get(subscr); | ||||
| 	request->channel_type = type; | ||||
| 	request->cbfn = cbfn; | ||||
| 	request->param = param; | ||||
| @@ -212,3 +214,22 @@ void subscr_put_channel(struct gsm_lchan *lchan) | ||||
| 		subscr_send_paging_request(lchan->subscr); | ||||
| } | ||||
|  | ||||
| struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net, | ||||
| 					    const char *imsi) | ||||
| { | ||||
| 	struct gsm_subscriber *subscr; | ||||
|  | ||||
| 	llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) { | ||||
| 		if (strcmp(subscr->imsi, imsi) == 0 && subscr->net == net) | ||||
| 			return subscr_get(subscr); | ||||
| 	} | ||||
|  | ||||
| 	subscr = subscr_alloc(); | ||||
| 	if (!subscr) | ||||
| 		return NULL; | ||||
|  | ||||
| 	strcpy(subscr->imsi, imsi); | ||||
| 	subscr->net = net; | ||||
| 	return subscr; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -223,7 +223,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) | ||||
| 	trans_lchan_change(ho->old_lchan, new_lchan); | ||||
|  | ||||
| 	ho->old_lchan->state = LCHAN_S_INACTIVE; | ||||
| 	lchan_auto_release(ho->old_lchan); | ||||
|  | ||||
| 	/* do something to re-route the actual speech frames ! */ | ||||
|  | ||||
|   | ||||
| @@ -164,6 +164,12 @@ static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id, | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* send the id ack */ | ||||
| int ipaccess_send_id_ack(int fd) | ||||
| { | ||||
| 	return write(fd, id_ack, sizeof(id_ack)); | ||||
| } | ||||
|  | ||||
| /* base handling of the ip.access protocol */ | ||||
| int ipaccess_rcvmsg_base(struct msgb *msg, | ||||
| 			 struct bsc_fd *bfd) | ||||
| @@ -180,7 +186,7 @@ int ipaccess_rcvmsg_base(struct msgb *msg, | ||||
| 		break; | ||||
| 	case IPAC_MSGT_ID_ACK: | ||||
| 		DEBUGP(DMI, "ID_ACK? -> ACK!\n"); | ||||
| 		ret = write(bfd->fd, id_ack, sizeof(id_ack)); | ||||
| 		ret = ipaccess_send_id_ack(bfd->fd); | ||||
| 		break; | ||||
| 	} | ||||
| 	return 0; | ||||
| @@ -236,6 +242,14 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, | ||||
| 			trx->rsl_link = e1inp_sign_link_create(e1i_ts, | ||||
| 							E1INP_SIGN_RSL, trx, | ||||
| 							trx->rsl_tei, 0); | ||||
|  | ||||
| 			if (newbfd->fd >= 0) { | ||||
| 				LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n"); | ||||
| 				bsc_unregister_fd(newbfd); | ||||
| 				close(newbfd->fd); | ||||
| 				newbfd->fd = -1; | ||||
| 			} | ||||
|  | ||||
| 			/* get rid of our old temporary bfd */ | ||||
| 			memcpy(newbfd, bfd, sizeof(*newbfd)); | ||||
| 			newbfd->priv_nr = 2+trx_id; | ||||
| @@ -478,6 +492,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) | ||||
| { | ||||
| 	int ret; | ||||
| 	int idx = 0; | ||||
| 	int i; | ||||
| 	struct e1inp_line *line; | ||||
| 	struct e1inp_ts *e1i_ts; | ||||
| 	struct bsc_fd *bfd; | ||||
| @@ -504,6 +519,10 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) | ||||
| 	/* create virrtual E1 timeslots for signalling */ | ||||
| 	e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN); | ||||
|  | ||||
| 	/* initialize the fds */ | ||||
| 	for (i = 0; i < ARRAY_SIZE(line->ts); ++i) | ||||
| 		line->ts[i].driver.ipaccess.fd.fd = -1; | ||||
|  | ||||
| 	e1i_ts = &line->ts[idx]; | ||||
|  | ||||
| 	bfd = &e1i_ts->driver.ipaccess.fd; | ||||
|   | ||||
| @@ -95,6 +95,7 @@ void msgb_reset(struct msgb *msg) | ||||
| 	msg->l2h = NULL; | ||||
| 	msg->l3h = NULL; | ||||
| 	msg->smsh = NULL; | ||||
| 	msg->l4h = NULL; | ||||
| } | ||||
|  | ||||
| static __attribute__((constructor)) void on_dso_load_trau_msgb(void) | ||||
|   | ||||
							
								
								
									
										34
									
								
								openbsc/src/nat/bsc_filter.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								openbsc/src/nat/bsc_filter.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| /* BSC Multiplexer/NAT */ | ||||
|  | ||||
| /* | ||||
|  * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2010 by on-waves.com | ||||
|  * All Rights Reserved | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License along | ||||
|  * with this program; if not, write to the Free Software Foundation, Inc., | ||||
|  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <openbsc/bsc_nat.h> | ||||
| #include <openbsc/ipaccess.h> | ||||
|  | ||||
| int bsc_nat_filter_ipa(struct msgb *msg) | ||||
| { | ||||
| 	struct ipaccess_head *hh; | ||||
|  | ||||
| 	/* handle base message handling */ | ||||
| 	hh = (struct ipaccess_head *) msg->data; | ||||
| 	return hh->proto == IPAC_PROTO_IPACCESS; | ||||
| } | ||||
							
								
								
									
										412
									
								
								openbsc/src/nat/bsc_nat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										412
									
								
								openbsc/src/nat/bsc_nat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,412 @@ | ||||
| /* BSC Multiplexer/NAT */ | ||||
|  | ||||
| /* | ||||
|  * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2010 by on-waves.com | ||||
|  * (C) 2009 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 <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <arpa/inet.h> | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #define _GNU_SOURCE | ||||
| #include <getopt.h> | ||||
|  | ||||
| #include <openbsc/debug.h> | ||||
| #include <openbsc/msgb.h> | ||||
| #include <openbsc/bsc_msc.h> | ||||
| #include <openbsc/bsc_nat.h> | ||||
| #include <openbsc/ipaccess.h> | ||||
| #include <openbsc/abis_nm.h> | ||||
| #include <openbsc/talloc.h> | ||||
| #include <openbsc/linuxlist.h> | ||||
|  | ||||
| #include <sccp/sccp.h> | ||||
|  | ||||
| static const char *config_file = "openbsc.cfg"; | ||||
| static char *msc_address = "127.0.0.1"; | ||||
| static struct in_addr local_addr; | ||||
| static struct bsc_fd msc_connection; | ||||
| static struct bsc_fd bsc_connection; | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Per BSC data structure | ||||
|  */ | ||||
| struct bsc_connection { | ||||
| 	struct llist_head list_entry; | ||||
|  | ||||
| 	/* do we know anything about this BSC? */ | ||||
| 	int authenticated; | ||||
|  | ||||
| 	/* the fd we use to communicate */ | ||||
| 	struct bsc_fd bsc_fd; | ||||
| }; | ||||
|  | ||||
| static LLIST_HEAD(bsc_connections); | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * below are stubs we need to link | ||||
|  */ | ||||
| int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, | ||||
| 		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state) | ||||
| { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) | ||||
| {} | ||||
|  | ||||
| int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id) | ||||
| { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Below is the handling of messages coming | ||||
|  * from the MSC and need to be forwarded to | ||||
|  * a real BSC. | ||||
|  */ | ||||
| static void initialize_msc_if_needed() | ||||
| { | ||||
| 	static int init = 0; | ||||
| 	init = 1; | ||||
|  | ||||
| 	/* do we need to send a GSM 08.08 message here? */ | ||||
| } | ||||
|  | ||||
| static void forward_sccp_to_bts(struct msgb *msg) | ||||
| { | ||||
| 	struct bsc_connection *bsc; | ||||
| 	int rc; | ||||
|  | ||||
| 	/* filter, drop, patch the message? */ | ||||
|  | ||||
| 	/* drop packets with the wrong IPA header */ | ||||
| 	if (bsc_nat_filter_ipa(msg)) | ||||
| 		return; | ||||
|  | ||||
| 	/* currently send this to every BSC connected */ | ||||
| 	llist_for_each_entry(bsc, &bsc_connections, list_entry) { | ||||
| 		rc = write(bsc->bsc_fd.fd, msg->data, msg->len); | ||||
|  | ||||
| 		/* try the next one */ | ||||
| 		if (rc < msg->len) | ||||
| 			fprintf(stderr, "Failed to write message to BTS.\n"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int ipaccess_msc_cb(struct bsc_fd *bfd, unsigned int what) | ||||
| { | ||||
| 	int error; | ||||
| 	struct msgb *msg = ipaccess_read_msg(bfd, &error); | ||||
| 	struct ipaccess_head *hh; | ||||
|  | ||||
| 	if (!msg) { | ||||
| 		if (error == 0) { | ||||
| 			fprintf(stderr, "The connection to the MSC was lost, exiting\n"); | ||||
| 			exit(-2); | ||||
| 		} | ||||
|  | ||||
| 		fprintf(stderr, "Failed to parse ip access message: %d\n", error); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGP(DMSC, "MSG from MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]); | ||||
|  | ||||
| 	/* handle base message handling */ | ||||
| 	hh = (struct ipaccess_head *) msg->data; | ||||
| 	ipaccess_rcvmsg_base(msg, bfd); | ||||
|  | ||||
| 	/* initialize the networking. This includes sending a GSM08.08 message */ | ||||
| 	if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK) | ||||
| 		initialize_msc_if_needed(); | ||||
| 	else if (hh->proto == IPAC_PROTO_SCCP) | ||||
| 		forward_sccp_to_bts(msg); | ||||
|  | ||||
| 	msgb_free(msg); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Below is the handling of messages coming | ||||
|  * from the BSC and need to be forwarded to | ||||
|  * a real BSC. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Remove the connection from the connections list, | ||||
|  * remove it from the patching of SCCP header lists | ||||
|  * as well. Maybe in the future even close connection.. | ||||
|  */ | ||||
| static void remove_bsc_connection(struct bsc_connection *connection) | ||||
| { | ||||
| 	bsc_unregister_fd(&connection->bsc_fd); | ||||
| 	llist_del(&connection->list_entry); | ||||
| 	talloc_free(connection); | ||||
| } | ||||
|  | ||||
| static int forward_sccp_to_msc(struct msgb *msg) | ||||
| { | ||||
| 	/* FIXME: We need to filter out certain messages */ | ||||
|  | ||||
| 	/* drop packets with the wrong IPA header */ | ||||
| 	if (bsc_nat_filter_ipa(msg)) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* send the non-filtered but maybe modified msg */ | ||||
| 	return write(msc_connection.fd, msg->data, msg->len); | ||||
| } | ||||
|  | ||||
| static int ipaccess_bsc_cb(struct bsc_fd *bfd, unsigned int what) | ||||
| { | ||||
| 	int error; | ||||
| 	struct msgb *msg = ipaccess_read_msg(bfd, &error); | ||||
|  | ||||
| 	if (!msg) { | ||||
| 		if (error == 0) { | ||||
| 			fprintf(stderr, "The connection to the BSC was lost. Cleaning it\n"); | ||||
| 			remove_bsc_connection((struct bsc_connection *) bfd->data); | ||||
| 		} | ||||
|  | ||||
| 		fprintf(stderr, "Failed to parse ip access message: %d\n", error); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	DEBUGP(DMSC, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]); | ||||
|  | ||||
| 	/* Handle messages from the BSC */ | ||||
| 	/* FIXME: Currently no PONG is sent to the BSC */ | ||||
| 	/* FIXME: Currently no ID ACK is sent to the BSC */ | ||||
| 	forward_sccp_to_msc(msg); | ||||
| 	msgb_free(msg); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what) | ||||
| { | ||||
| 	struct bsc_connection *bsc; | ||||
| 	int ret; | ||||
| 	struct sockaddr_in sa; | ||||
| 	socklen_t sa_len = sizeof(sa); | ||||
|  | ||||
| 	if (!(what & BSC_FD_READ)) | ||||
| 		return 0; | ||||
|  | ||||
| 	ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len); | ||||
| 	if (ret < 0) { | ||||
| 		perror("accept"); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	/* todo... do something with the connection */ | ||||
| 	/* todo... use GNUtls to see if we want to trust this as a BTS */ | ||||
|  | ||||
| 	/* | ||||
| 	 * | ||||
| 	 */ | ||||
| 	bsc = talloc_zero(tall_bsc_ctx, struct bsc_connection); | ||||
| 	if (!bsc) { | ||||
| 		DEBUGP(DMSC, "Failed to allocate BSC struct.\n"); | ||||
| 		close(ret); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	bsc->bsc_fd.data = bsc; | ||||
| 	bsc->bsc_fd.fd = ret; | ||||
| 	bsc->bsc_fd.cb = ipaccess_bsc_cb; | ||||
| 	bsc->bsc_fd.when = BSC_FD_READ; | ||||
| 	if (bsc_register_fd(&bsc->bsc_fd) < 0) { | ||||
| 		DEBUGP(DMSC, "Failed to register BSC fd.\n"); | ||||
| 		close(ret); | ||||
| 		talloc_free(bsc); | ||||
| 		return -2; | ||||
| 	} | ||||
|  | ||||
| 	DEBUGP(DMSC, "Registered new BSC\n"); | ||||
| 	llist_add(&bsc->list_entry, &bsc_connections); | ||||
| 	ipaccess_send_id_ack(ret); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port) | ||||
| { | ||||
| 	struct sockaddr_in addr; | ||||
| 	int ret, on = 1; | ||||
|  | ||||
| 	bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | ||||
| 	bfd->cb = ipaccess_listen_bsc_cb; | ||||
| 	bfd->when = BSC_FD_READ; | ||||
|  | ||||
| 	memset(&addr, 0, sizeof(addr)); | ||||
| 	addr.sin_family = AF_INET; | ||||
| 	addr.sin_port = htons(port); | ||||
| 	addr.sin_addr.s_addr = in_addr->s_addr; | ||||
|  | ||||
| 	setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | ||||
|  | ||||
| 	ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); | ||||
| 	if (ret < 0) { | ||||
| 		fprintf(stderr, "Could not bind the BSC socket %s\n", | ||||
| 			strerror(errno)); | ||||
| 		return -EIO; | ||||
| 	} | ||||
|  | ||||
| 	ret = listen(bfd->fd, 1); | ||||
| 	if (ret < 0) { | ||||
| 		perror("listen"); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	ret = bsc_register_fd(bfd); | ||||
| 	if (ret < 0) { | ||||
| 		perror("register_listen_fd"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void print_usage() | ||||
| { | ||||
| 	printf("Usage: bsc_nat\n"); | ||||
| } | ||||
|  | ||||
| static void print_help() | ||||
| { | ||||
| 	printf("  Some useful help...\n"); | ||||
| 	printf("  -h --help this text\n"); | ||||
| 	printf("  -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n"); | ||||
| 	printf("  -s --disable-color\n"); | ||||
| 	printf("  -c --config-file filename The config file to use.\n"); | ||||
| 	printf("  -m --msc=IP. The address of the MSC.\n"); | ||||
| 	printf("  -l --local=IP. The local address of this BSC.\n"); | ||||
| } | ||||
|  | ||||
| static void handle_options(int argc, char** argv) | ||||
| { | ||||
| 	while (1) { | ||||
| 		int option_index = 0, c; | ||||
| 		static struct option long_options[] = { | ||||
| 			{"help", 0, 0, 'h'}, | ||||
| 			{"debug", 1, 0, 'd'}, | ||||
| 			{"config-file", 1, 0, 'c'}, | ||||
| 			{"disable-color", 0, 0, 's'}, | ||||
| 			{"timestamp", 0, 0, 'T'}, | ||||
| 			{"msc", 1, 0, 'm'}, | ||||
| 			{"local", 1, 0, 'l'}, | ||||
| 			{0, 0, 0, 0} | ||||
| 		}; | ||||
|  | ||||
| 		c = getopt_long(argc, argv, "hd:sTPc:m:l:", | ||||
| 				long_options, &option_index); | ||||
| 		if (c == -1) | ||||
| 			break; | ||||
|  | ||||
| 		switch (c) { | ||||
| 		case 'h': | ||||
| 			print_usage(); | ||||
| 			print_help(); | ||||
| 			exit(0); | ||||
| 		case 's': | ||||
| 			debug_use_color(0); | ||||
| 			break; | ||||
| 		case 'd': | ||||
| 			debug_parse_category_mask(optarg); | ||||
| 			break; | ||||
| 		case 'c': | ||||
| 			config_file = strdup(optarg); | ||||
| 			break; | ||||
| 		case 'T': | ||||
| 			debug_timestamp(1); | ||||
| 			break; | ||||
| 		case 'm': | ||||
| 			msc_address = strdup(optarg); | ||||
| 			break; | ||||
| 		case 'l': | ||||
| 			inet_aton(optarg, &local_addr); | ||||
| 			break; | ||||
| 		default: | ||||
| 			/* ignore */ | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void signal_handler(int signal) | ||||
| { | ||||
| 	fprintf(stdout, "signal %u received\n", signal); | ||||
|  | ||||
| 	switch (signal) { | ||||
| 	case SIGABRT: | ||||
| 		/* in case of abort, we want to obtain a talloc report | ||||
| 		 * and then return to the caller, who will abort the process */ | ||||
| 	case SIGUSR1: | ||||
| 		talloc_report_full(tall_bsc_ctx, stderr); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	int rc; | ||||
|  | ||||
| 	/* parse options */ | ||||
| 	local_addr.s_addr = INADDR_ANY; | ||||
| 	handle_options(argc, argv); | ||||
|  | ||||
| 	/* seed the PRNG */ | ||||
| 	srand(time(NULL)); | ||||
|  | ||||
| 	/* connect to the MSC */ | ||||
| 	msc_connection.cb = ipaccess_msc_cb; | ||||
| 	rc = connect_to_msc(&msc_connection, msc_address, 5000); | ||||
| 	if (rc < 0) { | ||||
| 		fprintf(stderr, "Opening the MSC connection failed.\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	/* wait for the BSC */ | ||||
| 	if (listen_for_bsc(&bsc_connection, &local_addr, 5000) < 0) { | ||||
| 		fprintf(stderr, "Failed to listen for BSC.\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	signal(SIGINT, &signal_handler); | ||||
| 	signal(SIGABRT, &signal_handler); | ||||
| 	signal(SIGUSR1, &signal_handler); | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
|  | ||||
| 	while (1) { | ||||
| 		bsc_select_main(0); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -160,7 +160,7 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b | ||||
| 	} while (paging_bts->available_slots > 0 | ||||
| 		    &&  initial_request != current_request); | ||||
|  | ||||
| 	bsc_schedule_timer(&paging_bts->work_timer, 1, 0); | ||||
| 	bsc_schedule_timer(&paging_bts->work_timer, 2, 0); | ||||
| } | ||||
|  | ||||
| static void paging_worker(void *data) | ||||
| @@ -245,7 +245,7 @@ static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr, | ||||
| 	llist_add_tail(&req->entry, &bts_entry->pending_requests); | ||||
|  | ||||
| 	if (!bsc_timer_pending(&bts_entry->work_timer)) | ||||
| 		bsc_schedule_timer(&bts_entry->work_timer, 1, 0); | ||||
| 		bsc_schedule_timer(&bts_entry->work_timer, 2, 0); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|   | ||||
| @@ -37,7 +37,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos) | ||||
|  | ||||
| 	memset(&bv, 0, sizeof(bv)); | ||||
| 	bv.data = data; | ||||
| 	bv.data_len = 2; | ||||
| 	bv.data_len = 1; | ||||
|  | ||||
| 	if (nch_pos) { | ||||
| 		bitvec_set_bit(&bv, H); | ||||
| @@ -45,7 +45,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos) | ||||
| 	} else | ||||
| 		bitvec_set_bit(&bv, L); | ||||
|  | ||||
| 	bitvec_spare_padding(&bv, 15); | ||||
| 	bitvec_spare_padding(&bv, 7); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @@ -95,7 +95,7 @@ int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3) | ||||
|  | ||||
| 	memset(&bv, 0, sizeof(bv)); | ||||
| 	bv.data = data; | ||||
| 	bv.data_len = 5; | ||||
| 	bv.data_len = 4; | ||||
|  | ||||
| 	/* Optional Selection Parameters */ | ||||
| 	append_selection_params(&bv, &si3->selection_params); | ||||
| @@ -141,7 +141,7 @@ int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4) | ||||
|  | ||||
| 	memset(&bv, 0, sizeof(bv)); | ||||
| 	bv.data = data; | ||||
| 	bv.data_len = 11; /* FIXME: up to ? */ | ||||
| 	bv.data_len = 10; /* FIXME: up to ? */ | ||||
|  | ||||
| 	/* SI4 Rest Octets O */ | ||||
| 	append_selection_params(&bv, &si4->selection_params); | ||||
| @@ -340,7 +340,7 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13) | ||||
|  | ||||
| 	memset(&bv, 0, sizeof(bv)); | ||||
| 	bv.data = data; | ||||
| 	bv.data_len = 21; | ||||
| 	bv.data_len = 20; | ||||
|  | ||||
| 	if (0) { | ||||
| 		/* No rest octets */ | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| /* | ||||
|  * SCCP management code | ||||
|  * | ||||
|  * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2009 by on-waves.com | ||||
|  * (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||
|  * (C) 2009, 2010 by on-waves.com | ||||
|  * | ||||
|  * All Rights Reserved | ||||
|  * | ||||
| @@ -199,6 +199,134 @@ static int _sccp_parse_optional_data(const int offset, | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *result) | ||||
| { | ||||
| 	static const u_int32_t header_size = | ||||
| 			sizeof(struct sccp_connection_request); | ||||
| 	static const u_int32_t optional_offset = | ||||
| 			offsetof(struct sccp_connection_request, optional_start); | ||||
| 	static const u_int32_t called_offset = | ||||
| 			offsetof(struct sccp_connection_request, variable_called); | ||||
|  | ||||
| 	struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data; | ||||
| 	struct sccp_optional_data optional_data; | ||||
|  | ||||
| 	/* header check */ | ||||
| 	if (msgb_l2len(msgb) < header_size) { | ||||
| 		DEBUGP(DSCCP, "msgb < header_size %u %u\n", | ||||
| 		        msgb_l2len(msgb), header_size); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* copy out the calling and called address. Add the offset */ | ||||
| 	if (copy_address(&result->called, called_offset + req->variable_called, msgb) != 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (check_address(&result->called) != 0) { | ||||
| 		DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", | ||||
| 			*(u_int8_t *)&result->called.address, result->called.ssn); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	result->source_local_reference = &req->source_local_reference; | ||||
|  | ||||
| 	/* | ||||
| 	 * parse optional data. | ||||
| 	 */ | ||||
| 	memset(&optional_data, 0, sizeof(optional_data)); | ||||
| 	if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) { | ||||
| 		DEBUGP(DSCCP, "parsing of optional data failed.\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (optional_data.data_len != 0) { | ||||
| 		msgb->l3h = &msgb->l2h[optional_data.data_start]; | ||||
| 		result->data_len = optional_data.data_len; | ||||
| 	} else { | ||||
| 		result->data_len = 0; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int _sccp_parse_connection_released(struct msgb *msg, struct sccp_parse_result *result) | ||||
| { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int _sccp_parse_connection_refused(struct msgb *msg, struct sccp_parse_result *result) | ||||
| { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int _sccp_parse_connection_confirm(struct msgb *msg, struct sccp_parse_result *result) | ||||
| { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int _sccp_parse_connection_release_complete(struct msgb *msg, struct sccp_parse_result *result) | ||||
| { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int _sccp_parse_connection_dt1(struct msgb *msg, struct sccp_parse_result *result) | ||||
| { | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result) | ||||
| { | ||||
| 	static const u_int32_t header_size = sizeof(struct sccp_data_unitdata); | ||||
| 	static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called); | ||||
| 	static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling); | ||||
| 	static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data); | ||||
|  | ||||
| 	struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h; | ||||
|  | ||||
| 	if (msgb_l2len(msgb) < header_size) { | ||||
| 		DEBUGP(DSCCP, "msgb < header_size %u %u\n", | ||||
| 		        msgb_l2len(msgb), header_size); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* copy out the calling and called address. Add the off */ | ||||
| 	if (copy_address(&result->called, called_offset + udt->variable_called, msgb) != 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (check_address(&result->called) != 0) { | ||||
| 		DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", | ||||
| 			*(u_int8_t *)&result->called.address, result->called.ssn); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (copy_address(&result->calling, calling_offset + udt->variable_calling, msgb) != 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (check_address(&result->calling) != 0) { | ||||
| 		DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", | ||||
| 			*(u_int8_t *)&result->called.address, result->called.ssn); | ||||
| 	} | ||||
|  | ||||
| 	/* we don't have enough size for the data */ | ||||
| 	if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) { | ||||
| 		DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n", | ||||
| 			msgb_l2len(msgb), header_size, udt->variable_data); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	msgb->l3h = &udt->data[udt->variable_data]; | ||||
|  | ||||
| 	if (msgb_l3len(msgb) !=  msgb->l3h[-1]) { | ||||
| 		DEBUGP(DSCCP, "msgb is truncated %u %u\n", | ||||
| 			msgb_l3len(msgb), msgb->l3h[-1]); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Send UDT. Currently we have a fixed address... | ||||
|  */ | ||||
| @@ -249,59 +377,15 @@ static int _sccp_send_data(int class, const struct sockaddr_sccp *in, | ||||
|  | ||||
| static int _sccp_handle_read(struct msgb *msgb) | ||||
| { | ||||
| 	static const u_int32_t header_size = sizeof(struct sccp_data_unitdata); | ||||
| 	static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called); | ||||
| 	static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling); | ||||
| 	static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data); | ||||
|  | ||||
| 	struct sccp_data_callback *cb; | ||||
| 	struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h; | ||||
| 	struct sccp_address called, calling; | ||||
| 	struct sccp_parse_result result; | ||||
|  | ||||
| 	/* we don't have enough size for the struct */ | ||||
| 	if (msgb_l2len(msgb) < header_size) { | ||||
| 		DEBUGP(DSCCP, "msgb < header_size %u %u\n", | ||||
| 		        msgb_l2len(msgb), header_size); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* copy out the calling and called address. Add the off */ | ||||
| 	if (copy_address(&called, called_offset + udt->variable_called, msgb) != 0) | ||||
| 	if (_sccp_parse_udt(msgb, &result) != 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (check_address(&called) != 0) { | ||||
| 		DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", | ||||
| 			*(u_int8_t *)&called.address, called.ssn); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	cb = _find_ssn(called.ssn); | ||||
| 	cb = _find_ssn(result.called.ssn); | ||||
| 	if (!cb || !cb->read_cb) { | ||||
| 		DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", called.ssn); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (copy_address(&calling, calling_offset + udt->variable_calling, msgb) != 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (check_address(&calling) != 0) { | ||||
| 		DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", | ||||
| 			*(u_int8_t *)&called.address, called.ssn); | ||||
| 	} | ||||
|  | ||||
| 	/* we don't have enough size for the data */ | ||||
| 	if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) { | ||||
| 		DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n", | ||||
| 			msgb_l2len(msgb), header_size, udt->variable_data); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	msgb->l3h = &udt->data[udt->variable_data]; | ||||
|  | ||||
| 	if (msgb_l3len(msgb) !=  msgb->l3h[-1]) { | ||||
| 		DEBUGP(DSCCP, "msgb is truncated %u %u\n", | ||||
| 			msgb_l3len(msgb), msgb->l3h[-1]); | ||||
| 		DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", result.called.ssn); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| @@ -374,7 +458,7 @@ static void _sccp_set_connection_state(struct sccp_connection *connection, int n | ||||
| 		connection->state_cb(connection, old_state); | ||||
| } | ||||
|  | ||||
| static int _sccp_send_refuse(struct sccp_connection_request *req, int cause) | ||||
| static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause) | ||||
| { | ||||
| 	struct msgb *msgb; | ||||
| 	struct sccp_connection_refused *ref; | ||||
| @@ -387,7 +471,7 @@ static int _sccp_send_refuse(struct sccp_connection_request *req, int cause) | ||||
|  | ||||
| 	ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref)); | ||||
| 	ref->type = SCCP_MSG_TYPE_CREF; | ||||
| 	memcpy(&ref->destination_local_reference, &req->source_local_reference, | ||||
| 	memcpy(&ref->destination_local_reference, src_ref, | ||||
| 	       sizeof(struct sccp_source_reference)); | ||||
| 	ref->cause = cause; | ||||
| 	ref->optional_start = 1; | ||||
| @@ -601,39 +685,17 @@ static int _sccp_send_connection_released(struct sccp_connection *conn, int caus | ||||
|  */ | ||||
| static int _sccp_handle_connection_request(struct msgb *msgb) | ||||
| { | ||||
| 	static const u_int32_t header_size = | ||||
| 			sizeof(struct sccp_connection_request); | ||||
| 	static const u_int32_t optional_offset = | ||||
| 			offsetof(struct sccp_connection_request, optional_start); | ||||
| 	static const u_int32_t called_offset = | ||||
| 			offsetof(struct sccp_connection_request, variable_called); | ||||
| 	struct sccp_parse_result result; | ||||
|  | ||||
| 	struct sccp_data_callback *cb; | ||||
| 	struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data; | ||||
| 	struct sccp_address called; | ||||
| 	struct sccp_connection *connection; | ||||
| 	struct sccp_optional_data optional_data; | ||||
|  | ||||
| 	/* header check */ | ||||
| 	if (msgb_l2len(msgb) < header_size) { | ||||
| 		DEBUGP(DSCCP, "msgb < header_size %u %u\n", | ||||
| 		        msgb_l2len(msgb), header_size); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* copy out the calling and called address. Add the offset */ | ||||
| 	if (copy_address(&called, called_offset + req->variable_called, msgb) != 0) | ||||
| 	if (_sccp_parse_connection_request(msgb, &result) != 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (check_address(&called) != 0) { | ||||
| 		DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", | ||||
| 			*(u_int8_t *)&called.address, called.ssn); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	cb = _find_ssn(called.ssn); | ||||
| 	cb = _find_ssn(result.called.ssn); | ||||
| 	if (!cb || !cb->accept_cb) { | ||||
| 		DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", called.ssn); | ||||
| 		DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", result.called.ssn); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| @@ -651,28 +713,18 @@ static int _sccp_handle_connection_request(struct msgb *msgb) | ||||
| 	 * and send a connection confirm, otherwise we will send a refuseed | ||||
| 	 * one.... | ||||
| 	 */ | ||||
| 	if (destination_local_reference_is_free(&req->source_local_reference) != 0) { | ||||
| 	if (destination_local_reference_is_free(result.source_local_reference) != 0) { | ||||
| 		DEBUGP(DSCCP, "Need to reject connection with existing reference\n"); | ||||
| 		_sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE); | ||||
| 		_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE); | ||||
| 		talloc_free(connection); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	connection->incoming = 1; | ||||
| 	connection->destination_local_reference = req->source_local_reference; | ||||
|  | ||||
| 	/* | ||||
| 	 * parse optional data. | ||||
| 	 */ | ||||
| 	memset(&optional_data, 0, sizeof(optional_data)); | ||||
| 	if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) { | ||||
| 		DEBUGP(DSCCP, "parsing of optional data failed.\n"); | ||||
| 		talloc_free(connection); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	connection->destination_local_reference = *result.source_local_reference; | ||||
|  | ||||
| 	if (cb->accept_cb(connection, cb->accept_context) != 0) { | ||||
| 		_sccp_send_refuse(req, SCCP_REFUSAL_END_USER_ORIGINATED); | ||||
| 		_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_END_USER_ORIGINATED); | ||||
| 		_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); | ||||
| 		talloc_free(connection); | ||||
| 		return 0; | ||||
| @@ -684,7 +736,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb) | ||||
| 	if (_sccp_send_connection_confirm(connection) != 0) { | ||||
| 		DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n"); | ||||
|  | ||||
| 		_sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE); | ||||
| 		_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE); | ||||
| 		_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); | ||||
| 		llist_del(&connection->list); | ||||
| 		talloc_free(connection); | ||||
| @@ -695,9 +747,8 @@ static int _sccp_handle_connection_request(struct msgb *msgb) | ||||
| 	/* | ||||
| 	 * If we have data let us forward things. | ||||
| 	 */ | ||||
| 	if (optional_data.data_len != 0 && connection->data_cb) { | ||||
| 		msgb->l3h = &msgb->l2h[optional_data.data_start]; | ||||
| 		connection->data_cb(connection, msgb, optional_data.data_len); | ||||
| 	if (result.data_len != 0 && connection->data_cb) { | ||||
| 		connection->data_cb(connection, msgb, result.data_len); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| @@ -1160,6 +1211,14 @@ struct sccp_source_reference sccp_src_ref_from_int(u_int32_t int_ref) | ||||
| 	return ref; | ||||
| } | ||||
|  | ||||
| int sccp_determine_msg_type(struct msgb *msg) | ||||
| { | ||||
| 	if (msgb_l2len(msg) < 1) | ||||
| 		return -1; | ||||
|  | ||||
| 	return msg->l2h[0]; | ||||
| } | ||||
|  | ||||
| static __attribute__((constructor)) void on_dso_load(void) | ||||
| { | ||||
| 	tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp"); | ||||
|   | ||||
| @@ -319,6 +319,8 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts) | ||||
| 	struct gsm48_system_information_type_5 *si5; | ||||
| 	int rc, l2_plen = 18; | ||||
|  | ||||
| 	memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); | ||||
|  | ||||
| 	/* ip.access nanoBTS needs l2_plen!! */ | ||||
| 	if (is_ipaccess_bts(bts)) { | ||||
| 		*output++ = (l2_plen << 2) | 1; | ||||
| @@ -326,7 +328,6 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts) | ||||
| 	} | ||||
|  | ||||
| 	si5 = (struct gsm48_system_information_type_5 *) output; | ||||
| 	memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); | ||||
|  | ||||
| 	/* l2 pseudo length, not part of msg: 18 */ | ||||
| 	si5->rr_protocol_discriminator = GSM48_PDISC_RR; | ||||
| @@ -345,6 +346,8 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts) | ||||
| 	struct gsm48_system_information_type_6 *si6; | ||||
| 	int l2_plen = 11; | ||||
|  | ||||
| 	memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); | ||||
|  | ||||
| 	/* ip.access nanoBTS needs l2_plen!! */ | ||||
| 	if (is_ipaccess_bts(bts)) { | ||||
| 		*output++ = (l2_plen << 2) | 1; | ||||
| @@ -352,7 +355,6 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts) | ||||
| 	} | ||||
|  | ||||
| 	si6 = (struct gsm48_system_information_type_6 *) output; | ||||
| 	memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); | ||||
|  | ||||
| 	/* l2 pseudo length, not part of msg: 11 */ | ||||
| 	si6->rr_protocol_discriminator = GSM48_PDISC_RR; | ||||
|   | ||||
| @@ -28,6 +28,7 @@ | ||||
| #include <openbsc/gsm_04_08.h> | ||||
| #include <openbsc/mncc.h> | ||||
| #include <openbsc/paging.h> | ||||
| #include <openbsc/chan_alloc.h> | ||||
|  | ||||
| void *tall_trans_ctx; | ||||
|  | ||||
| @@ -95,14 +96,14 @@ void trans_free(struct gsm_trans *trans) | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if (trans->lchan) | ||||
| 		put_lchan(trans->lchan); | ||||
|  | ||||
| 	if (!trans->lchan && trans->subscr && trans->subscr->net) { | ||||
| 		/* Stop paging on all bts' */ | ||||
| 		paging_request_stop(NULL, trans->subscr, NULL); | ||||
| 	} | ||||
|  | ||||
| 	if (trans->lchan) | ||||
| 		put_lchan(trans->lchan); | ||||
|  | ||||
| 	if (trans->subscr) | ||||
| 		subscr_put(trans->subscr); | ||||
|  | ||||
|   | ||||
| @@ -76,6 +76,8 @@ static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms) | ||||
|  | ||||
| static void net_dump_vty(struct vty *vty, struct gsm_network *net) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	vty_out(vty, "BSC is on Country Code %u, Network Code %u " | ||||
| 		"and has %u BTS%s", net->country_code, net->network_code, | ||||
| 		net->num_bts, VTY_NEWLINE); | ||||
| @@ -97,6 +99,11 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) | ||||
| 		VTY_NEWLINE); | ||||
| 	vty_out(vty, "  Handover: %s%s", net->handover.active ? "On" : "Off", | ||||
| 		VTY_NEWLINE); | ||||
| 	vty_out(vty, "  Allowed Audio Codecs: "); | ||||
| 	for (i = 0; i < net->audio_length; ++i) | ||||
| 		vty_out(vty, "hr: %d ver: %d, ", | ||||
| 			net->audio_support[i]->hr, net->audio_support[i]->ver); | ||||
| 	vty_out(vty, "%s", VTY_NEWLINE); | ||||
| } | ||||
|  | ||||
| DEFUN(show_net, show_net_cmd, "show network", | ||||
| @@ -287,7 +294,11 @@ static int config_write_net(struct vty *vty) | ||||
| { | ||||
| 	vty_out(vty, "network%s", VTY_NEWLINE); | ||||
| 	vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE); | ||||
| 	if (gsmnet->core_country_code > 0) | ||||
| 		vty_out(vty, " core network country code %u%s", gsmnet->core_country_code, VTY_NEWLINE); | ||||
| 	vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE); | ||||
| 	if (gsmnet->core_network_code > 0) | ||||
| 		vty_out(vty, " core mobile network code %u%s", gsmnet->core_network_code, VTY_NEWLINE); | ||||
| 	vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE); | ||||
| 	vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE); | ||||
| 	vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE); | ||||
| @@ -322,6 +333,25 @@ static int config_write_net(struct vty *vty) | ||||
| 	vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE); | ||||
| 	vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE); | ||||
| 	vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE); | ||||
| 	vty_out(vty, " ipacc rtp_payload %u%s", gsmnet->rtp_payload, VTY_NEWLINE); | ||||
| 	vty_out(vty, " rtp base %u%s", gsmnet->rtp_base_port, VTY_NEWLINE); | ||||
|  | ||||
| 	if (gsmnet->audio_length != 0) { | ||||
| 		int i; | ||||
|  | ||||
| 		vty_out(vty, " codec_list "); | ||||
| 		for (i = 0; i < gsmnet->audio_length; ++i) { | ||||
| 			printf("I... %d %d\n", i, gsmnet->audio_length); | ||||
| 			if (i != 0) | ||||
| 				vty_out(vty, ", "); | ||||
|  | ||||
| 			if (gsmnet->audio_support[i]->hr) | ||||
| 				vty_out(vty, "hr%.1u", gsmnet->audio_support[i]->ver); | ||||
| 			else | ||||
| 				vty_out(vty, "fr%.1u", gsmnet->audio_support[i]->ver); | ||||
| 		} | ||||
| 		vty_out(vty, "%s", VTY_NEWLINE); | ||||
| 	} | ||||
|  | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
| @@ -818,6 +848,16 @@ DEFUN(cfg_net_ncc, | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_core_net_ncc, | ||||
|       cfg_core_net_ncc_cmd, | ||||
|       "core network country code <1-999>", | ||||
|       "Set the GSM country code to be used in the MSC connection") | ||||
| { | ||||
| 	gsmnet->core_country_code = atoi(argv[0]); | ||||
|  | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_net_mnc, | ||||
|       cfg_net_mnc_cmd, | ||||
|       "mobile network code <1-999>", | ||||
| @@ -828,6 +868,16 @@ DEFUN(cfg_net_mnc, | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_core_net_mnc, | ||||
|       cfg_core_net_mnc_cmd, | ||||
|       "core mobile network code <1-999>", | ||||
|       "Set the GSM mobile network code to be used in the MSC connection") | ||||
| { | ||||
| 	gsmnet->core_network_code = atoi(argv[0]); | ||||
|  | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_net_name_short, | ||||
|       cfg_net_name_short_cmd, | ||||
|       "short name NAME", | ||||
| @@ -976,6 +1026,90 @@ DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_net_supported_codecs, | ||||
|       cfg_net_supported_codecs_cmd, | ||||
|       "codec_list .LIST", | ||||
|       "Set the three preferred audio codecs.\n" | ||||
|       "Codec List") | ||||
| { | ||||
| 	int saw_fr, saw_hr; | ||||
| 	int i; | ||||
|  | ||||
| 	saw_fr = saw_hr = 0; | ||||
|  | ||||
| 	/* free the old list... if it exists */ | ||||
| 	if (gsmnet->audio_support) { | ||||
| 		talloc_free(gsmnet->audio_support); | ||||
| 		gsmnet->audio_support = NULL; | ||||
| 		gsmnet->audio_length = 0; | ||||
| 	} | ||||
|  | ||||
| 	/* create a new array */ | ||||
| 	gsmnet->audio_support = | ||||
| 			talloc_zero_array(gsmnet, struct gsm_audio_support *, argc); | ||||
| 	gsmnet->audio_length = argc; | ||||
|  | ||||
| 	for (i = 0; i < argc; ++i) { | ||||
| 		/* check for hrX or frX */ | ||||
| 		if (strlen(argv[i]) != 3 | ||||
| 		    || argv[i][1] != 'r' | ||||
| 		    || (argv[i][0] != 'h' && argv[i][0] != 'f') | ||||
| 		    || argv[i][2] < 0x30 | ||||
| 		    || argv[i][2] > 0x39) | ||||
| 			goto error; | ||||
|  | ||||
| 		gsmnet->audio_support[i] = talloc_zero(gsmnet->audio_support, | ||||
| 						       struct gsm_audio_support); | ||||
| 		gsmnet->audio_support[i]->ver = atoi(argv[i] + 2); | ||||
|  | ||||
| 		if (strncmp("hr", argv[i], 2) == 0) { | ||||
| 			gsmnet->audio_support[i]->hr = 1; | ||||
| 			saw_hr = 1; | ||||
| 		} else if (strncmp("fr", argv[i], 2) == 0) { | ||||
| 			gsmnet->audio_support[i]->hr = 0; | ||||
| 			saw_fr = 1; | ||||
| 		} | ||||
|  | ||||
| 		if (saw_hr && saw_fr) { | ||||
| 			vty_out(vty, "Can not have full-rate and half-rate codec.%s", | ||||
| 				VTY_NEWLINE); | ||||
| 			return CMD_ERR_INCOMPLETE; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return CMD_SUCCESS; | ||||
|  | ||||
| error: | ||||
| 	vty_out(vty, "Codec name must be hrX or frX. Was '%s'%s", | ||||
| 		argv[i], VTY_NEWLINE); | ||||
| 	return CMD_ERR_INCOMPLETE; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_net_ipacc_rtp_payload, | ||||
|       cfg_net_ipacc_rtp_payload_cmd, | ||||
|       "ipacc rtp_payload <0-256>", | ||||
|       "Override the RTP payload to use") | ||||
| { | ||||
| 	gsmnet->rtp_payload = atoi(argv[0]) & 0xff; | ||||
|  | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_net_rtp_base_port, | ||||
|       cfg_net_rtp_base_port_cmd, | ||||
|       "rtp base <0-65534>", | ||||
|       "Base port to use for MGCP RTP") | ||||
| { | ||||
| 	unsigned int port = atoi(argv[0]); | ||||
| 	if (port > 65534) { | ||||
| 		vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE); | ||||
| 		return CMD_WARNING; | ||||
| 	} | ||||
|  | ||||
| 	gsmnet->rtp_base_port = port; | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| #define DECLARE_TIMER(number) \ | ||||
|     DEFUN(cfg_net_T##number,					\ | ||||
|       cfg_net_T##number##_cmd,					\ | ||||
| @@ -1006,7 +1140,6 @@ DECLARE_TIMER(3117) | ||||
| DECLARE_TIMER(3119) | ||||
| DECLARE_TIMER(3141) | ||||
|  | ||||
|  | ||||
| /* per-BTS configuration */ | ||||
| DEFUN(cfg_bts, | ||||
|       cfg_bts_cmd, | ||||
| @@ -1476,7 +1609,9 @@ int bsc_vty_init(struct gsm_network *net) | ||||
| 	install_node(&net_node, config_write_net); | ||||
| 	install_default(GSMNET_NODE); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_ncc_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_core_net_ncc_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_mnc_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_core_net_mnc_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_name_short_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_name_long_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd); | ||||
| @@ -1492,6 +1627,9 @@ int bsc_vty_init(struct gsm_network *net) | ||||
| 	install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_supported_codecs_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_ipacc_rtp_payload_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_rtp_base_port_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_T3101_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_T3103_cmd); | ||||
| 	install_element(GSMNET_NODE, &cfg_net_T3105_cmd); | ||||
|   | ||||
							
								
								
									
										48
									
								
								openbsc/src/vty_interface_bsc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								openbsc/src/vty_interface_bsc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| /* OpenBSC interface to quagga VTY - BSC options */ | ||||
| /* (C) 2009 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 <sys/types.h> | ||||
|  | ||||
| #include <vty/command.h> | ||||
| #include <vty/buffer.h> | ||||
| #include <vty/vty.h> | ||||
|  | ||||
| #include <openbsc/gsm_data.h> | ||||
|  | ||||
| static struct gsmnet *gsmnet = NULL; | ||||
|  | ||||
| DEFUN(show_bsc, show_bsc_cmd, "show bsc", | ||||
| 	SHOW_STR "Display information about the BSC\n") | ||||
| { | ||||
| 	vty_out(vty, "BSC... not implemented yet%s", VTY_NEWLINE); | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| int bsc_vty_init_extra(struct gsm_network *net) | ||||
| { | ||||
| 	gsmnet = net; | ||||
|  | ||||
| 	/* get runtime information */ | ||||
| 	install_element(VIEW_NODE, &show_bsc_cmd); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -76,4 +76,5 @@ int main(int argc, char** argv) | ||||
| void nm_state_event() {} | ||||
| void input_event() {} | ||||
| void sms_alloc() {} | ||||
| void _lchan_release() {} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user