mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	Compare commits
	
		
			91 Commits
		
	
	
		
			35c3
			...
			fairwaves/
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					6984250742 | ||
| 
						 | 
					683e60db73 | ||
| 
						 | 
					785e8b8533 | ||
| 
						 | 
					bd6784dbe8 | ||
| 
						 | 
					5788904242 | ||
| 
						 | 
					362a757f56 | ||
| 
						 | 
					444a9b9304 | ||
| 
						 | 
					8d8bedff4c | ||
| 
						 | 
					084a35588f | ||
| 
						 | 
					03bf40f6a5 | ||
| 
						 | 
					842e599c5c | ||
| 
						 | 
					16e9c4a70f | ||
| 
						 | 
					fdee81b35f | ||
| 
						 | 
					582242d2f5 | ||
| 
						 | 
					fb5a18db4b | ||
| 
						 | 
					8a8703e06c | ||
| 
						 | 
					d68abba3d0 | ||
| 
						 | 
					bbd3c7cd46 | ||
| 
						 | 
					0a2a92a4f5 | ||
| 
						 | 
					a52726dae8 | ||
| 
						 | 
					8af593e4e4 | ||
| 
						 | 
					fb11fc1a7a | ||
| 
						 | 
					0904c1de19 | ||
| 
						 | 
					c301ef4ea7 | ||
| 
						 | 
					59dc70462b | ||
| 
						 | 
					e7dc282b51 | ||
| 
						 | 
					45fdb6a728 | ||
| 
						 | 
					32906636f1 | ||
| 
						 | 
					b314380065 | ||
| 
						 | 
					8bb11c90fc | ||
| 
						 | 
					933de8cb48 | ||
| 
						 | 
					1bcfaa7119 | ||
| 
						 | 
					6c079bb981 | ||
| 
						 | 
					c572ac8733 | ||
| 
						 | 
					53d1a9186c | ||
| 
						 | 
					2f749ef103 | ||
| 
						 | 
					17276417ef | ||
| 
						 | 
					234f6714a7 | ||
| 
						 | 
					3e7a48c475 | ||
| 
						 | 
					9d53708f58 | ||
| 
						 | 
					da8c96e097 | ||
| 
						 | 
					d4839fe14a | ||
| 
						 | 
					db0e216845 | ||
| 
						 | 
					2d9f39ec43 | ||
| 
						 | 
					e5e251c396 | ||
| 
						 | 
					991691f8df | ||
| 
						 | 
					955d8800e5 | ||
| 
						 | 
					9a4936a234 | ||
| 
						 | 
					012c9203e4 | ||
| 
						 | 
					5087f994fd | ||
| 
						 | 
					420e4d445c | ||
| 
						 | 
					a8f56961be | ||
| 
						 | 
					b2679b822e | ||
| 
						 | 
					0ce3516a47 | ||
| 
						 | 
					2b5eb8ddb0 | ||
| 
						 | 
					fd245fcfa8 | ||
| 
						 | 
					9f24671589 | ||
| 
						 | 
					acddb2a632 | ||
| 
						 | 
					800369d258 | ||
| 
						 | 
					236d81fa0c | ||
| 
						 | 
					8e58f575e7 | ||
| 
						 | 
					da0864dfde | ||
| 
						 | 
					fc969503e1 | ||
| 
						 | 
					1e4a954c73 | ||
| 
						 | 
					2f4878a90f | ||
| 
						 | 
					70e6f2ec74 | ||
| 
						 | 
					be9419881c | ||
| 
						 | 
					a363aa3fc0 | ||
| 
						 | 
					9cddaeafd5 | ||
| 
						 | 
					9fe68b0fbc | ||
| 
						 | 
					1c30463e76 | ||
| 
						 | 
					bcc2567579 | ||
| 
						 | 
					924292977f | ||
| 
						 | 
					a317e334c2 | ||
| 
						 | 
					76c7cec298 | ||
| 
						 | 
					c70110945a | ||
| 
						 | 
					f5fe345dbb | ||
| 
						 | 
					07a5b120e9 | ||
| 
						 | 
					dfeabbbff6 | ||
| 
						 | 
					1371303689 | ||
| 
						 | 
					f7cb56572a | ||
| 
						 | 
					014316f514 | ||
| 
						 | 
					b96f1912da | ||
| 
						 | 
					adc681331e | ||
| 
						 | 
					8516d533db | ||
| 
						 | 
					c6e735fd00 | ||
| 
						 | 
					cc75a7f014 | ||
| 
						 | 
					1c33b89886 | ||
| 
						 | 
					077e62cded | ||
| 
						 | 
					a78396dcb3 | ||
| 
						 | 
					e9c81d2581 | 
							
								
								
									
										13
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,16 @@
 | 
				
			|||||||
 | 
					openbsc (0.15.1-fw.2) UNRELEASED; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * Fixed rebase issues.
 | 
				
			||||||
 | 
					  * New release of openbsc for fairwaves build.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Ivan Klyuchnikov <kluchnikovi@gmail.com>  Wed, 15 Feb 2017 17:03:24 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					openbsc (0.15.1-fw.1) UNRELEASED; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  * New release of openbsc for fairwaves build.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 -- Ivan Klyuchnikov <kluchnikovi@gmail.com>  Tue, 14 Feb 2017 15:12:30 +0200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
openbsc (0.15.1) UNRELEASED; urgency=medium
 | 
					openbsc (0.15.1) UNRELEASED; urgency=medium
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * Move forward toward a new release.
 | 
					  * Move forward toward a new release.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										153
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										153
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -6,7 +6,6 @@ Build-Depends: debhelper (>= 9),
 | 
				
			|||||||
               autotools-dev,
 | 
					               autotools-dev,
 | 
				
			||||||
               autoconf-archive,
 | 
					               autoconf-archive,
 | 
				
			||||||
               pkg-config,
 | 
					               pkg-config,
 | 
				
			||||||
               libgtp-dev,
 | 
					 | 
				
			||||||
               libosmocore-dev,
 | 
					               libosmocore-dev,
 | 
				
			||||||
               libosmo-sccp-dev,
 | 
					               libosmo-sccp-dev,
 | 
				
			||||||
               libdbi0-dev,
 | 
					               libdbi0-dev,
 | 
				
			||||||
@@ -17,23 +16,16 @@ Build-Depends: debhelper (>= 9),
 | 
				
			|||||||
               libpcap-dev,
 | 
					               libpcap-dev,
 | 
				
			||||||
               libssl-dev,
 | 
					               libssl-dev,
 | 
				
			||||||
               libc-ares-dev,
 | 
					               libc-ares-dev,
 | 
				
			||||||
               libsmpp34-dev
 | 
					               libsmpp34-dev,
 | 
				
			||||||
 | 
					               libcdk5-dev,
 | 
				
			||||||
 | 
					               libsqlite3-dev,
 | 
				
			||||||
 | 
					               libosip2-dev,
 | 
				
			||||||
 | 
					               libsofia-sip-ua-dev
 | 
				
			||||||
Standards-Version: 3.9.8
 | 
					Standards-Version: 3.9.8
 | 
				
			||||||
Vcs-Git: git://bs11-abis.gnumonks.org/openbsc.git
 | 
					Vcs-Git: git://bs11-abis.gnumonks.org/openbsc.git
 | 
				
			||||||
Vcs-Browser: http://openbsc.osmocom.org/trac/browser
 | 
					Vcs-Browser: http://openbsc.osmocom.org/trac/browser
 | 
				
			||||||
Homepage: https://projects.osmocom.org/projects/openbsc
 | 
					Homepage: https://projects.osmocom.org/projects/openbsc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmocom-bsc
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Depends: ${shlibs:Depends},
 | 
					 | 
				
			||||||
         ${misc:Depends}
 | 
					 | 
				
			||||||
Description: GSM Base Station Controller
 | 
					 | 
				
			||||||
 This is the BSC-only version of OpenBSC. It requires a Mobile Switching Center
 | 
					 | 
				
			||||||
 (MSC) to operate.
 | 
					 | 
				
			||||||
 .
 | 
					 | 
				
			||||||
 You might rather prefer to use osmocom-nitb which is considered a
 | 
					 | 
				
			||||||
 "GSM Network-in-a-Box" and does not depend on a MSC.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmocom-nitb
 | 
					Package: osmocom-nitb
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Depends: ${shlibs:Depends},
 | 
					Depends: ${shlibs:Depends},
 | 
				
			||||||
@@ -44,138 +36,45 @@ Description: GSM Network-in-a-Box, implements BSC, MSC, SMSC, HLR, VLR
 | 
				
			|||||||
 components bundled together. When using osmocom-nitb, there is no need for a
 | 
					 components bundled together. When using osmocom-nitb, there is no need for a
 | 
				
			||||||
 Mobile Switching Center (MSC) which is needed when using osmocom-bsc.
 | 
					 Mobile Switching Center (MSC) which is needed when using osmocom-bsc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmocom-ipaccess-utils
 | 
					Package: osmocom-meas-utils
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Depends: ${shlibs:Depends},
 | 
					Depends: ${shlibs:Depends},
 | 
				
			||||||
         ${misc:Depends}
 | 
					         ${misc:Depends},
 | 
				
			||||||
Description: Command line utilities for ip.access nanoBTS
 | 
					         libcdk5,
 | 
				
			||||||
 This package contains utilities that are specific for nanoBTS when being used
 | 
					         sqlite3
 | 
				
			||||||
 together with OpenBSC. It contains mainly three tools: ipaccess-find,
 | 
					Description: Measurement utilities for the OpenBSC
 | 
				
			||||||
 ipaccess-config and ipaccess-proxy.
 | 
					 Measurement utilities for the OpenBSC.
 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmocom-bs11-utils
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Depends: ${shlibs:Depends},
 | 
					 | 
				
			||||||
         ${misc:Depends}
 | 
					 | 
				
			||||||
Description: Command line utilities for Siemens BS-11 BTS
 | 
					 | 
				
			||||||
 There is a tool in this package for configuring the Siemens BS-11 BTS.
 | 
					 | 
				
			||||||
 Additionally, it contains one tool for making use of an ISDN-card and the
 | 
					 | 
				
			||||||
 public telephone network as frequency standard for the E1 line.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmocom-sgsn
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Depends: ${shlibs:Depends},
 | 
					 | 
				
			||||||
         ${misc:Depends}
 | 
					 | 
				
			||||||
Suggests: osmocom-bsc
 | 
					 | 
				
			||||||
Description: Osmocom Serving GPRS Support Node
 | 
					 | 
				
			||||||
 This is an implementation of the GPRS Serving GPRS Support Node (SGSN). As
 | 
					 | 
				
			||||||
 such it implements the GPRS Mobility Management (GMM) and SM (Session
 | 
					 | 
				
			||||||
 Management).
 | 
					 | 
				
			||||||
 .
 | 
					 | 
				
			||||||
 The SGSN connects via the Gb-interface to the BSS (like the osmo-pcu or an
 | 
					 | 
				
			||||||
 ip.access nanoBTS), and it connects via the GTP protocol to a Gateway GPRS
 | 
					 | 
				
			||||||
 Support Node (GGSN) like openggsn.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmocom-gbproxy
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Depends: ${shlibs:Depends},
 | 
					 | 
				
			||||||
         ${misc:Depends}
 | 
					 | 
				
			||||||
Recommends: osmocom-sgsn
 | 
					 | 
				
			||||||
Description: Osmocom GPRS Gb Interface Proxy
 | 
					 | 
				
			||||||
 The purpose of the Gb proxy is to aggregate the Gb links of multiple
 | 
					 | 
				
			||||||
 BSS's and present them in one Gb link to the SGSN.
 | 
					 | 
				
			||||||
 .
 | 
					 | 
				
			||||||
 This package is part of OpenBSC and closely related to osmocom-sgsn.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmocom-bsc-nat
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Depends: ${shlibs:Depends},
 | 
					 | 
				
			||||||
         ${misc:Depends}
 | 
					 | 
				
			||||||
Recommends: osmocom-bsc
 | 
					 | 
				
			||||||
Description: Osmocom Base Station Controller Network Address Translation
 | 
					 | 
				
			||||||
 This NAT is useful for masquerading multiple BSCs behind one. It listens
 | 
					 | 
				
			||||||
 for incoming BSCs on port 5000 and connects to a specified Mobile Switching
 | 
					 | 
				
			||||||
 Center (MSC).
 | 
					 | 
				
			||||||
 .
 | 
					 | 
				
			||||||
 This package is part of OpenBSC and closely related to osmocom-bsc.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: openbsc-dev
 | 
					 | 
				
			||||||
Architecture: all
 | 
					 | 
				
			||||||
Depends: ${misc:Depends}
 | 
					 | 
				
			||||||
Description: Header file needed by tools tightly integrated
 | 
					 | 
				
			||||||
 Some other programs depend on gsm_data_shared.h and gsm_data_shared.c
 | 
					 | 
				
			||||||
 from OpenBSC. This package installs these files to your file system so
 | 
					 | 
				
			||||||
 that the other packages can build-depend on this package.
 | 
					 | 
				
			||||||
 .
 | 
					 | 
				
			||||||
 The directory structure is copied after the structure in the repository
 | 
					 | 
				
			||||||
 and the header and .c file are installed into /usr/src/osmocom/openbsc/.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmo-gtphub
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
 | 
					 | 
				
			||||||
Description: Osmocom GTP Hub
 | 
					 | 
				
			||||||
 Proxy for comms between multiple SGSNs and GGSNs.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmocom-bsc-dbg
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Section: debug
 | 
					 | 
				
			||||||
Priority: extra
 | 
					 | 
				
			||||||
Depends: osmocom-bsc (= ${binary:Version}), ${misc:Depends}
 | 
					 | 
				
			||||||
Description: Debug symbols for the OpenBSC BSC
 | 
					 | 
				
			||||||
 Make debugging possible
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmocom-nitb-dbg
 | 
					Package: osmocom-nitb-dbg
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Section: debug
 | 
					Section: debug
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Depends: osmocom-nitb (= ${binary:Version}), ${misc:Depends}
 | 
					Depends: osmocom-nitb (= ${binary:Version}),
 | 
				
			||||||
 | 
					         ${misc:Depends}
 | 
				
			||||||
Description: Debug symbols for the OpenBSC NITB
 | 
					Description: Debug symbols for the OpenBSC NITB
 | 
				
			||||||
 Make debugging possible
 | 
					 Make debugging possible
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmocom-ipaccess-utils-dbg
 | 
					Package: osmocom-meas-utils-dbg
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Section: debug
 | 
					Section: debug
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Depends: osmocom-ipaccess-utils (= ${binary:Version}), ${misc:Depends}
 | 
					Depends: osmocom-meas-utils (= ${binary:Version}),
 | 
				
			||||||
Description: Debug symbols for the OpenBSC ip.access utils
 | 
					         ${misc:Depends}
 | 
				
			||||||
 | 
					Description: Debug symbols for the OpenBSC measurement utilities
 | 
				
			||||||
 Make debugging possible
 | 
					 Make debugging possible
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmocom-bs11-utils-dbg
 | 
					Package: osmocom-proxy
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Section: debug
 | 
					Depends: ${shlibs:Depends},
 | 
				
			||||||
Priority: extra
 | 
					         ${misc:Depends}
 | 
				
			||||||
Depends: osmocom-bs11-utils (= ${binary:Version}), ${misc:Depends}
 | 
					Description: GSM Network-in-a-Box, implements BSC, MSC, SMSC, HLR, VLR
 | 
				
			||||||
Description: Debug symbols for the OpenBSC BS11 utils
 | 
					 reg and ussd proxies
 | 
				
			||||||
 Make debugging possible
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Package: osmocom-sgsn-dbg
 | 
					Package: osmocom-proxy-dbg
 | 
				
			||||||
Architecture: any
 | 
					Architecture: any
 | 
				
			||||||
Section: debug
 | 
					Section: debug
 | 
				
			||||||
Priority: extra
 | 
					Priority: extra
 | 
				
			||||||
Depends: osmocom-sgsn (= ${binary:Version}), ${misc:Depends}
 | 
					Depends: osmocom-nitb (= ${binary:Version}),
 | 
				
			||||||
Description: Debug symbols for the OpenBSC Serving GPRS Support Node
 | 
					         ${misc:Depends}
 | 
				
			||||||
 Make debugging possible
 | 
					Description: Debug symbols for the OpenBSC Proxies
 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmocom-gbproxy-dbg
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Section: debug
 | 
					 | 
				
			||||||
Priority: extra
 | 
					 | 
				
			||||||
Depends: osmocom-gbproxy (= ${binary:Version}), ${misc:Depends}
 | 
					 | 
				
			||||||
Description: Debug symbols for the OpenBSC GPRS GBProxy
 | 
					 | 
				
			||||||
 Make debugging possible
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmocom-bsc-nat-dbg
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Section: debug
 | 
					 | 
				
			||||||
Priority: extra
 | 
					 | 
				
			||||||
Depends: osmocom-bsc-nat (= ${binary:Version}), ${misc:Depends}
 | 
					 | 
				
			||||||
Description: Debug symbols for the OpenBSC Network Address Translation
 | 
					 | 
				
			||||||
 Make debugging possible
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Package: osmo-gtphub-dbg
 | 
					 | 
				
			||||||
Architecture: any
 | 
					 | 
				
			||||||
Section: debug
 | 
					 | 
				
			||||||
Priority: extra
 | 
					 | 
				
			||||||
Depends: osmo-gtphub (= ${binary:Version}), ${misc:Depends}
 | 
					 | 
				
			||||||
Description: Debug symbols for Osmocom GTP Hub
 | 
					 | 
				
			||||||
 Make debugging possible
 | 
					 Make debugging possible
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								debian/osmocom-meas-utils.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								debian/osmocom-meas-utils.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					/usr/bin/osmo-meas-udp2db
 | 
				
			||||||
 | 
					/usr/bin/osmo-meas-pcap2db
 | 
				
			||||||
 | 
					/usr/bin/meas_vis
 | 
				
			||||||
 | 
					/usr/bin/meas_json
 | 
				
			||||||
							
								
								
									
										9
									
								
								debian/osmocom-proxy.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								debian/osmocom-proxy.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					usr/bin/reg-proxy
 | 
				
			||||||
 | 
					etc/sv/reg-proxy
 | 
				
			||||||
 | 
					etc/service/reg-proxy
 | 
				
			||||||
 | 
					etc/reg-proxy.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					usr/bin/ussd-proxy
 | 
				
			||||||
 | 
					etc/sv/ussd-proxy
 | 
				
			||||||
 | 
					etc/service/ussd-proxy
 | 
				
			||||||
 | 
					etc/ussd-proxy.config
 | 
				
			||||||
							
								
								
									
										12
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -17,16 +17,10 @@ override_dh_autoreconf:
 | 
				
			|||||||
	cd openbsc && autoreconf --install --force
 | 
						cd openbsc && autoreconf --install --force
 | 
				
			||||||
 | 
					
 | 
				
			||||||
override_dh_strip:
 | 
					override_dh_strip:
 | 
				
			||||||
	dh_strip -posmocom-bsc --dbg-package=osmocom-bsc-dbg
 | 
					 | 
				
			||||||
	dh_strip -posmocom-nitb --dbg-package=osmocom-nitb-dbg
 | 
						dh_strip -posmocom-nitb --dbg-package=osmocom-nitb-dbg
 | 
				
			||||||
	dh_strip -posmocom-ipaccess-utils --dbg-package=osmocom-ipaccess-utils-dbg
 | 
						dh_strip -posmocom-meas-utils --dbg-package=osmocom-meas-utils-dbg
 | 
				
			||||||
	dh_strip -posmocom-bs11-utils --dbg-package=osmocom-bs11-utils-dbg
 | 
					    dh_strip -posmocom-proxy --dbg-package=osmocom-proxy-dbg
 | 
				
			||||||
	dh_strip -posmocom-sgsn --dbg-package=osmocom-sgsn-dbg
 | 
					 | 
				
			||||||
	dh_strip -posmocom-gbproxy --dbg-package=osmocom-gbproxy-dbg
 | 
					 | 
				
			||||||
	dh_strip -posmocom-bsc-nat --dbg-package=osmocom-bsc-nat-dbg
 | 
					 | 
				
			||||||
	dh_strip -posmo-gtphub --dbg-package=osmo-gtphub-dbg
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
override_dh_auto_configure:
 | 
					override_dh_auto_configure:
 | 
				
			||||||
	echo $(VERSION) > openbsc/.tarball-version
 | 
						echo $(VERSION) > openbsc/.tarball-version
 | 
				
			||||||
	dh_auto_configure --sourcedirectory=openbsc -- --enable-nat --enable-osmo-bsc --enable-smpp
 | 
						dh_auto_configure --sourcedirectory=openbsc -- --enable-smpp --enable-ussd-proxy
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								etc/reg-proxy.config
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								etc/reg-proxy.config
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMAND_LINE="-S 172.31.0.16 -s 5040 -D 172.31.0.10 -d 5040"
 | 
				
			||||||
							
								
								
									
										1
									
								
								etc/service/reg-proxy
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								etc/service/reg-proxy
									
									
									
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					../sv/reg-proxy
 | 
				
			||||||
							
								
								
									
										1
									
								
								etc/service/ussd-proxy
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								etc/service/ussd-proxy
									
									
									
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					../sv/ussd-proxy/
 | 
				
			||||||
							
								
								
									
										4
									
								
								etc/sv/reg-proxy/log/run
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								etc/sv/reg-proxy/log/run
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					LOG_FOLDER=/var/log/reg-proxy
 | 
				
			||||||
 | 
					mkdir -p $LOG_FOLDER
 | 
				
			||||||
 | 
					exec svlogd -tt $LOG_FOLDER
 | 
				
			||||||
							
								
								
									
										6
									
								
								etc/sv/reg-proxy/run
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								etc/sv/reg-proxy/run
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					. /etc/reg-proxy.config
 | 
				
			||||||
 | 
					exec 2>&1
 | 
				
			||||||
 | 
					echo "reg-proxy restart" | /usr/bin/ts >> /var/log/runsv.log
 | 
				
			||||||
 | 
					exec reg-proxy $COMMAND_LINE
 | 
				
			||||||
							
								
								
									
										4
									
								
								etc/sv/ussd-proxy/log/run
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								etc/sv/ussd-proxy/log/run
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					LOG_FOLDER=/var/log/ussd-proxy
 | 
				
			||||||
 | 
					mkdir -p $LOG_FOLDER
 | 
				
			||||||
 | 
					exec svlogd -tt $LOG_FOLDER
 | 
				
			||||||
							
								
								
									
										6
									
								
								etc/sv/ussd-proxy/run
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								etc/sv/ussd-proxy/run
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					. /etc/ussd-proxy.config
 | 
				
			||||||
 | 
					exec 2>&1
 | 
				
			||||||
 | 
					echo "ussd-proxy restart" | /usr/bin/ts >> /var/log/runsv.log
 | 
				
			||||||
 | 
					exec ussd-proxy $COMMAND_LINE
 | 
				
			||||||
							
								
								
									
										3
									
								
								etc/ussd-proxy.config
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								etc/ussd-proxy.config
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMAND_LINE="-t sip:172.31.0.6:5060 -u sip:172.31.0.29:5090 -l8"
 | 
				
			||||||
@@ -211,6 +211,18 @@ AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
 | 
				
			|||||||
AC_MSG_RESULT([$enable_ext_tests])
 | 
					AC_MSG_RESULT([$enable_ext_tests])
 | 
				
			||||||
AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
 | 
					AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Enable/disable ussd_proxy utility
 | 
				
			||||||
 | 
					AC_ARG_ENABLE([ussd_proxy], [AS_HELP_STRING([--enable-ussd-proxy], [Build the USSD MAP SUP to SIP proxy])],
 | 
				
			||||||
 | 
					    [osmo_ac_build_ussd_proxy="$enableval"],[osmo_ac_build_ussd_proxy="no"])
 | 
				
			||||||
 | 
					if test "$osmo_ac_build_ussd_proxy" = "yes" ; then
 | 
				
			||||||
 | 
					    PKG_CHECK_MODULES(LIBSOFIA_SIP_UA, sofia-sip-ua >= 1.10)
 | 
				
			||||||
 | 
					    AC_DEFINE(BUILD_USSD_PROXY, 1, [Define if we want to build ussd_proxy])
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					AM_CONDITIONAL(BUILD_USSD_PROXY, test "x$osmo_ac_build_ussd_proxy" = "xyes")
 | 
				
			||||||
 | 
					AC_SUBST(osmo_ac_build_smpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl Generate the output
 | 
					dnl Generate the output
 | 
				
			||||||
AM_CONFIG_HEADER(bscconfig.h)
 | 
					AM_CONFIG_HEADER(bscconfig.h)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -234,6 +246,8 @@ AC_OUTPUT(
 | 
				
			|||||||
    src/ipaccess/Makefile
 | 
					    src/ipaccess/Makefile
 | 
				
			||||||
    src/utils/Makefile
 | 
					    src/utils/Makefile
 | 
				
			||||||
    src/gprs/Makefile
 | 
					    src/gprs/Makefile
 | 
				
			||||||
 | 
					    src/reg-proxy/Makefile
 | 
				
			||||||
 | 
					    src/ussd-proxy/Makefile
 | 
				
			||||||
    tests/Makefile
 | 
					    tests/Makefile
 | 
				
			||||||
    tests/atlocal
 | 
					    tests/atlocal
 | 
				
			||||||
    tests/gsm0408/Makefile
 | 
					    tests/gsm0408/Makefile
 | 
				
			||||||
@@ -258,6 +272,7 @@ AC_OUTPUT(
 | 
				
			|||||||
    tests/slhc/Makefile
 | 
					    tests/slhc/Makefile
 | 
				
			||||||
    tests/v42bis/Makefile
 | 
					    tests/v42bis/Makefile
 | 
				
			||||||
    tests/nanobts_omlattr/Makefile
 | 
					    tests/nanobts_omlattr/Makefile
 | 
				
			||||||
 | 
					    tests/ussd/Makefile
 | 
				
			||||||
    doc/Makefile
 | 
					    doc/Makefile
 | 
				
			||||||
    doc/examples/Makefile
 | 
					    doc/examples/Makefile
 | 
				
			||||||
    Makefile)
 | 
					    Makefile)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
#define _AUTH_H
 | 
					#define _AUTH_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/utils.h>
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_data.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gsm_auth_tuple;
 | 
					struct gsm_auth_tuple;
 | 
				
			||||||
struct gsm_subscriber;
 | 
					struct gsm_subscriber;
 | 
				
			||||||
@@ -20,7 +21,8 @@ static inline const char *auth_action_str(enum auth_action a)
 | 
				
			|||||||
	return get_value_string(auth_action_names, a);
 | 
						return get_value_string(auth_action_names, a);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
 | 
					int auth_get_tuple_for_subscr(enum gsm_auth_policy auth_policy,
 | 
				
			||||||
 | 
					                              struct gsm_auth_tuple *atuple,
 | 
				
			||||||
                              struct gsm_subscriber *subscr, int key_seq);
 | 
					                              struct gsm_subscriber *subscr, int key_seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _AUTH_H */
 | 
					#endif /* _AUTH_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,8 @@ enum {
 | 
				
			|||||||
	DRANAP,
 | 
						DRANAP,
 | 
				
			||||||
	DSUA,
 | 
						DSUA,
 | 
				
			||||||
	DV42BIS,
 | 
						DV42BIS,
 | 
				
			||||||
 | 
						DSUP,
 | 
				
			||||||
 | 
						DSS,
 | 
				
			||||||
	Debug_LastEntry,
 | 
						Debug_LastEntry,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,4 +94,8 @@ void allocate_security_operation(struct gsm_subscriber_connection *conn);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, struct amr_mode *modes);
 | 
					int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, struct amr_mode *modes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb *msg);
 | 
				
			||||||
 | 
					int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause);
 | 
				
			||||||
 | 
					void release_loc_updating_req(struct gsm_subscriber_connection *conn, int release);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,5 +38,8 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn,
 | 
				
			|||||||
		    struct gsm_sms *sms);
 | 
							    struct gsm_sms *sms);
 | 
				
			||||||
void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn);
 | 
					void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gsm411_send_rp_msg_subscr(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
							    struct msgb *rp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref);
 | 
					uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,12 +7,17 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct gsm_subscriber_connection;
 | 
					struct gsm_subscriber_connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
 | 
					int gsm0480_send_component(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
			       const struct msgb *in_msg, const char* response_text, 
 | 
								   struct msgb *msg,
 | 
				
			||||||
			       const struct ss_request *req);
 | 
								   struct ss_header* reqhdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
 | 
					int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
			     const struct msgb *msg, 
 | 
								     uint8_t invoke_id,
 | 
				
			||||||
			     const struct ss_request *request);
 | 
								     uint8_t transaction_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb *gsm0480_compose_ussd_component(struct ss_request* req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level,
 | 
					int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level,
 | 
				
			||||||
			 const char *text);
 | 
								 const char *text);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <openbsc/rest_octets.h>
 | 
					#include <openbsc/rest_octets.h>
 | 
				
			||||||
#include <openbsc/common_cs.h>
 | 
					#include <openbsc/common_cs.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsup_client.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** annotations for msgb ownership */
 | 
					/** annotations for msgb ownership */
 | 
				
			||||||
#define __uses
 | 
					#define __uses
 | 
				
			||||||
@@ -70,6 +71,7 @@ struct gsm_loc_updating_operation {
 | 
				
			|||||||
        struct osmo_timer_list updating_timer;
 | 
					        struct osmo_timer_list updating_timer;
 | 
				
			||||||
	unsigned int waiting_for_imsi : 1;
 | 
						unsigned int waiting_for_imsi : 1;
 | 
				
			||||||
	unsigned int waiting_for_imei : 1;
 | 
						unsigned int waiting_for_imei : 1;
 | 
				
			||||||
 | 
						unsigned int waiting_for_remote_accept : 1;
 | 
				
			||||||
	unsigned int key_seq : 4;
 | 
						unsigned int key_seq : 4;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -266,6 +268,8 @@ enum gsm_auth_policy {
 | 
				
			|||||||
	GSM_AUTH_POLICY_ACCEPT_ALL, /* accept everyone, even if not authorized in DB */
 | 
						GSM_AUTH_POLICY_ACCEPT_ALL, /* accept everyone, even if not authorized in DB */
 | 
				
			||||||
	GSM_AUTH_POLICY_TOKEN, /* accept first, send token per sms, then revoke authorization */
 | 
						GSM_AUTH_POLICY_TOKEN, /* accept first, send token per sms, then revoke authorization */
 | 
				
			||||||
	GSM_AUTH_POLICY_REGEXP, /* accept IMSIs matching given regexp */
 | 
						GSM_AUTH_POLICY_REGEXP, /* accept IMSIs matching given regexp */
 | 
				
			||||||
 | 
						GSM_AUTH_POLICY_REMOTE,
 | 
				
			||||||
 | 
						GSM_AUTH_POLICY_REMOTE_CLOSED
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define GSM_T3101_DEFAULT 10
 | 
					#define GSM_T3101_DEFAULT 10
 | 
				
			||||||
@@ -320,6 +324,9 @@ struct gsm_network {
 | 
				
			|||||||
	struct llist_head upqueue;
 | 
						struct llist_head upqueue;
 | 
				
			||||||
	struct llist_head trans_list;
 | 
						struct llist_head trans_list;
 | 
				
			||||||
	struct bsc_api *bsc_api;
 | 
						struct bsc_api *bsc_api;
 | 
				
			||||||
 | 
						struct gsup_client *hlr_sup_client;
 | 
				
			||||||
 | 
						struct gsup_client *ussd_sup_client;
 | 
				
			||||||
 | 
						struct gsup_client *sms_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int num_bts;
 | 
						unsigned int num_bts;
 | 
				
			||||||
	struct llist_head bts_list;
 | 
						struct llist_head bts_list;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								openbsc/include/openbsc/gsm_sup.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								openbsc/include/openbsc/gsm_sup.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					#ifndef _GSM_SUP_H
 | 
				
			||||||
 | 
					#define _GSM_SUP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_subscriber.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm0480.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/protocol/gsm_04_11.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGGSUBSCRP(level, subscr, fmt, args...) \
 | 
				
			||||||
 | 
						LOGP(DSUP, level, "SUBSCR(%s) " fmt, \
 | 
				
			||||||
 | 
						     (subscr) ? (subscr)->imsi : "---", \
 | 
				
			||||||
 | 
						     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Callback for both HLR/auth and USSD SUP sockets */
 | 
				
			||||||
 | 
					int sup_read_cb(struct gsup_client *sup_client, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					int subscr_query_auth_info(struct gsm_subscriber *subscr);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int subscr_location_update(struct gsm_subscriber *subscr);
 | 
				
			||||||
 | 
					int subscr_purge_ms(struct gsm_subscriber *subscr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int subscr_tx_sms_message(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
					                          struct gsm411_rp_hdr *rph);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _GSM_SUP_H */
 | 
				
			||||||
							
								
								
									
										14
									
								
								openbsc/include/openbsc/gsm_ussd_map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								openbsc/include/openbsc/gsm_ussd_map.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					#ifndef _GSM_USSD_MAP_H
 | 
				
			||||||
 | 
					#define _GSM_USSD_MAP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/gsup_client.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_subscriber.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_ussd_map_proto.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ussd_map_read_cb(struct gsup_client *sup_client,
 | 
				
			||||||
 | 
							     struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ussd_map_tx_message(struct gsm_network *net, struct ss_header *req,
 | 
				
			||||||
 | 
								const char *extension, uint32_t ref, const uint8_t *component_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _GSM_USSD_MAP_H */
 | 
				
			||||||
							
								
								
									
										25
									
								
								openbsc/include/openbsc/gsm_ussd_map_proto.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								openbsc/include/openbsc/gsm_ussd_map_proto.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					#ifndef _GSM_USSD_MAP_PROTO_H
 | 
				
			||||||
 | 
					#define _GSM_USSD_MAP_PROTO_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm0480.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
					    FMAP_MSISDN        = 0x80
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int subscr_uss_message(struct msgb *msg,
 | 
				
			||||||
 | 
							       struct ss_header *req,
 | 
				
			||||||
 | 
							       const char* extension,
 | 
				
			||||||
 | 
							       uint32_t ref,
 | 
				
			||||||
 | 
							       const uint8_t *component_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int rx_uss_message_parse(const uint8_t* data,
 | 
				
			||||||
 | 
								 size_t len,
 | 
				
			||||||
 | 
								 struct ss_header *ss,
 | 
				
			||||||
 | 
								 uint32_t *ref,
 | 
				
			||||||
 | 
								 char* extention,
 | 
				
			||||||
 | 
								 size_t extention_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _GSM_USSD_MAP_PROTO_H */
 | 
				
			||||||
@@ -47,6 +47,7 @@ struct gsup_client {
 | 
				
			|||||||
	struct osmo_timer_list connect_timer;
 | 
						struct osmo_timer_list connect_timer;
 | 
				
			||||||
	int is_connected;
 | 
						int is_connected;
 | 
				
			||||||
	int got_ipa_pong;
 | 
						int got_ipa_pong;
 | 
				
			||||||
 | 
						struct gsm_network *net;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gsup_client *gsup_client_create(const char *ip_addr,
 | 
					struct gsup_client *gsup_client_create(const char *ip_addr,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								openbsc/include/openbsc/reg_proxy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								openbsc/include/openbsc/reg_proxy.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					#ifndef _REG_PROXY_H
 | 
				
			||||||
 | 
					#define _REG_PROXY_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/sup_server.h>
 | 
				
			||||||
 | 
					#include <openbsc/sip_client.h>
 | 
				
			||||||
 | 
					#include <osip2/osip.h>
 | 
				
			||||||
 | 
					void *tall_reg_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct reg_proxy {
 | 
				
			||||||
 | 
						struct gsm_sup_server *sup_server;
 | 
				
			||||||
 | 
						struct sip_client *sip_client;
 | 
				
			||||||
 | 
						osip_t *osip;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _REG_PROXY_H */
 | 
				
			||||||
							
								
								
									
										16
									
								
								openbsc/include/openbsc/sip.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								openbsc/include/openbsc/sip.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					#ifndef _SIP_H
 | 
				
			||||||
 | 
					#define _SIP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/sip_client.h>
 | 
				
			||||||
 | 
					#include <openbsc/reg_proxy.h>
 | 
				
			||||||
 | 
					#include <osip2/osip.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm0480.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tx_ss_handle(struct sip_client *sip_client, osip_t *osip, struct ss_request *ss,
 | 
				
			||||||
 | 
							 const char *extention);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tx_sip_register(struct sip_client *sip_client, osip_t *osip, char *imsi, int expires_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sip_client_init(struct reg_proxy *reg, const char *src_ip, u_int16_t src_port,
 | 
				
			||||||
 | 
											 const char *dst_ip, u_int16_t dst_port, int expires_time);
 | 
				
			||||||
 | 
					#endif /* _SIP_H */
 | 
				
			||||||
							
								
								
									
										36
									
								
								openbsc/include/openbsc/sip_client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								openbsc/include/openbsc/sip_client.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SIP_RECONNECT_INTERVAL 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb;
 | 
				
			||||||
 | 
					struct ipa_client_conn;
 | 
				
			||||||
 | 
					struct sip_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Expects message in msg->l2h */
 | 
				
			||||||
 | 
					typedef int (*sip_read_cb_t)(struct sip_client *sip_client, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sip_client {
 | 
				
			||||||
 | 
						struct tcp_client_conn	*link;
 | 
				
			||||||
 | 
						sip_read_cb_t	read_cb;
 | 
				
			||||||
 | 
						void			*data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct osmo_timer_list	connect_timer;
 | 
				
			||||||
 | 
						int			is_connected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *src_ip;
 | 
				
			||||||
 | 
						char *dst_ip;
 | 
				
			||||||
 | 
						u_int16_t src_port;
 | 
				
			||||||
 | 
						u_int16_t dst_port;
 | 
				
			||||||
 | 
						int expires_time;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sip_client *sip_client_create(const char *src_ip, u_int16_t src_port,
 | 
				
			||||||
 | 
					                                     const char *dst_ip, u_int16_t dst_port,
 | 
				
			||||||
 | 
					                                     int expires_time, sip_read_cb_t read_cb,
 | 
				
			||||||
 | 
					                                                                 void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_client_destroy(struct sip_client *sip_client);
 | 
				
			||||||
 | 
					int sip_client_send(struct sip_client *sip_client, struct msgb *msg);
 | 
				
			||||||
 | 
					struct msgb *sip_msgb_alloc(void);
 | 
				
			||||||
							
								
								
									
										19
									
								
								openbsc/include/openbsc/sup.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								openbsc/include/openbsc/sup.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#ifndef _SUP_H
 | 
				
			||||||
 | 
					#define _SUP_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/reg_proxy.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LOGGSUPP(level, sup, fmt, args...) \
 | 
				
			||||||
 | 
						LOGP(DGPRS, level, "SUP(%s) " fmt, \
 | 
				
			||||||
 | 
						     (sup)->imsi, \
 | 
				
			||||||
 | 
						     ## args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sup_server_init(struct reg_proxy *reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int handle_location_update_result(struct gsm_sup_server *sup_server,
 | 
				
			||||||
 | 
													 char *imsi, char *msisdn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int handle_purge_ms_result(struct gsm_sup_server *sup_server,
 | 
				
			||||||
 | 
													 char *imsi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _SUP_H */
 | 
				
			||||||
							
								
								
									
										29
									
								
								openbsc/include/openbsc/sup_server.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								openbsc/include/openbsc/sup_server.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					#ifndef _SUP_SERVER_H
 | 
				
			||||||
 | 
					#define _SUP_SERVER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/abis/ipa.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//struct msgb;
 | 
				
			||||||
 | 
					struct ipa_server_conn;
 | 
				
			||||||
 | 
					struct gsm_sup_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Expects message in msg->l2h */
 | 
				
			||||||
 | 
					typedef int (*sup_read_cb_t)(struct gsm_sup_server *sup_server, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct gsm_sup_server {
 | 
				
			||||||
 | 
						struct ipa_server_link	*link;
 | 
				
			||||||
 | 
						sup_read_cb_t	read_cb;
 | 
				
			||||||
 | 
						void			*data;
 | 
				
			||||||
 | 
						struct osmo_fd fd;
 | 
				
			||||||
 | 
						struct ipa_server_conn *server_conn;
 | 
				
			||||||
 | 
						void *app;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct gsm_sup_server *sup_server_create(const char *ip_addr,
 | 
				
			||||||
 | 
											 unsigned int tcp_port,
 | 
				
			||||||
 | 
											 sup_read_cb_t read_cb,
 | 
				
			||||||
 | 
											 void *app);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sup_server_send(struct gsm_sup_server *sup_server, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _SUP_SERVER_H */
 | 
				
			||||||
							
								
								
									
										51
									
								
								openbsc/include/openbsc/tcp_client.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								openbsc/include/openbsc/tcp_client.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					#ifndef _TCP_CLIENT_H_
 | 
				
			||||||
 | 
					#define _TCP_CLIENT_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/timer.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum tcp_client_conn_state {
 | 
				
			||||||
 | 
						TCP_CLIENT_LINK_STATE_NONE         = 0,
 | 
				
			||||||
 | 
						TCP_CLIENT_LINK_STATE_CONNECTING   = 1,
 | 
				
			||||||
 | 
						TCP_CLIENT_LINK_STATE_CONNECTED    = 2,
 | 
				
			||||||
 | 
						TCP_CLIENT_LINK_STATE_MAX
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tcp_client_conn {
 | 
				
			||||||
 | 
						struct osmo_fd			*ofd;
 | 
				
			||||||
 | 
						struct llist_head		tx_queue;
 | 
				
			||||||
 | 
						struct osmo_timer_list		timer;
 | 
				
			||||||
 | 
						enum tcp_client_conn_state	state;
 | 
				
			||||||
 | 
						const char			*src_addr;
 | 
				
			||||||
 | 
						uint16_t			src_port;
 | 
				
			||||||
 | 
						const char			*dst_addr;
 | 
				
			||||||
 | 
						uint16_t			dst_port;
 | 
				
			||||||
 | 
						void (*updown_cb)(struct tcp_client_conn *link, int up);
 | 
				
			||||||
 | 
						int (*read_cb)(struct tcp_client_conn *link, struct msgb *msg);
 | 
				
			||||||
 | 
						int (*write_cb)(struct tcp_client_conn *link);
 | 
				
			||||||
 | 
						void				*data;
 | 
				
			||||||
 | 
						struct msgb			*pending_msg;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tcp_client_conn *
 | 
				
			||||||
 | 
					tcp_client_conn_create(void *ctx, int priv_nr,
 | 
				
			||||||
 | 
								const char *dst_addr, uint16_t dst_port,
 | 
				
			||||||
 | 
								const char *src_addr, uint16_t src_port,
 | 
				
			||||||
 | 
								void (*updown)(struct tcp_client_conn *link, int),
 | 
				
			||||||
 | 
								int (*read_cb)(struct tcp_client_conn *link, struct msgb *msgb),
 | 
				
			||||||
 | 
								int (*write_cb)(struct tcp_client_conn *link),
 | 
				
			||||||
 | 
								void *data);
 | 
				
			||||||
 | 
					void tcp_client_conn_destroy(struct tcp_client_conn *link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tcp_client_conn_open(struct tcp_client_conn *link);
 | 
				
			||||||
 | 
					void tcp_client_conn_close(struct tcp_client_conn *link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tcp_client_conn_send(struct tcp_client_conn *link, struct msgb *msg);
 | 
				
			||||||
 | 
					size_t tcp_client_conn_clear_queue(struct tcp_client_conn *link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@@ -32,6 +32,11 @@ struct gsm_trans {
 | 
				
			|||||||
	/* reference from MNCC or other application */
 | 
						/* reference from MNCC or other application */
 | 
				
			||||||
	uint32_t callref;
 | 
						uint32_t callref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* SMS RP message reference */
 | 
				
			||||||
 | 
						uint8_t msg_ref;
 | 
				
			||||||
 | 
						/* handle SMS local */
 | 
				
			||||||
 | 
						uint8_t sms_local;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* if traffic channel receive was requested */
 | 
						/* if traffic channel receive was requested */
 | 
				
			||||||
	int tch_recv;
 | 
						int tch_recv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -56,6 +61,11 @@ struct gsm_trans {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			struct gsm_sms *sms;
 | 
								struct gsm_sms *sms;
 | 
				
			||||||
		} sms;
 | 
							} sms;
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								uint8_t invoke_id;
 | 
				
			||||||
 | 
								uint8_t mo;
 | 
				
			||||||
 | 
								uint8_t dirty;
 | 
				
			||||||
 | 
							} ss;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,6 +75,8 @@ struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
 | 
				
			|||||||
				   uint8_t proto, uint8_t trans_id);
 | 
									   uint8_t proto, uint8_t trans_id);
 | 
				
			||||||
struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
 | 
					struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
 | 
				
			||||||
					uint32_t callref);
 | 
										uint32_t callref);
 | 
				
			||||||
 | 
					struct gsm_trans *trans_find_by_msgref(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
 | 
										uint8_t msg_ref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gsm_trans *trans_alloc(struct gsm_network *net,
 | 
					struct gsm_trans *trans_alloc(struct gsm_network *net,
 | 
				
			||||||
			      struct gsm_subscriber *subscr,
 | 
								      struct gsm_subscriber *subscr,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define USSD_MO 1
 | 
				
			||||||
 | 
					#define USSD_MT 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg);
 | 
					int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int on_ussd_response(struct gsm_network *net,
 | 
				
			||||||
 | 
							     uint32_t ref,
 | 
				
			||||||
 | 
							     struct ss_header *reqhdr,
 | 
				
			||||||
 | 
							     const uint8_t *component,
 | 
				
			||||||
 | 
							     const char* extention);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _ussd_trans_free(struct gsm_trans *trans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,8 @@ SUBDIRS += \
 | 
				
			|||||||
	utils \
 | 
						utils \
 | 
				
			||||||
	ipaccess \
 | 
						ipaccess \
 | 
				
			||||||
	gprs \
 | 
						gprs \
 | 
				
			||||||
 | 
						reg-proxy \
 | 
				
			||||||
 | 
						ussd-proxy \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Conditional Programs
 | 
					# Conditional Programs
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2115,9 +2115,17 @@ DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
 | 
				
			|||||||
      "Maximum transmit power of the MS in dBm")
 | 
					      "Maximum transmit power of the MS in dBm")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gsm_bts *bts = vty->index;
 | 
						struct gsm_bts *bts = vty->index;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bts->ms_max_power = atoi(argv[0]);
 | 
						bts->ms_max_power = atoi(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Apply setting to the BTS */
 | 
				
			||||||
 | 
						rc = gsm_bts_set_system_infos(bts);
 | 
				
			||||||
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% Failed updating SYSTEM INFORMATION for the BTS%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3383,27 +3391,42 @@ DEFUN(cfg_trx_max_power_red,
 | 
				
			|||||||
      "Reduction of maximum BS RF Power (relative to nominal power)\n"
 | 
					      "Reduction of maximum BS RF Power (relative to nominal power)\n"
 | 
				
			||||||
      "Reduction of maximum BS RF Power in dB\n")
 | 
					      "Reduction of maximum BS RF Power in dB\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						int ret = CMD_SUCCESS;
 | 
				
			||||||
	int maxpwr_r = atoi(argv[0]);
 | 
						int maxpwr_r = atoi(argv[0]);
 | 
				
			||||||
	struct gsm_bts_trx *trx = vty->index;
 | 
						struct gsm_bts_trx *trx = vty->index;
 | 
				
			||||||
 | 
						/* FIXME: check if our BTS type supports more than 24 */
 | 
				
			||||||
	int upper_limit = 24;	/* default 12.21 max power red. */
 | 
						int upper_limit = 24;	/* default 12.21 max power red. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: check if our BTS type supports more than 12 */
 | 
						if (maxpwr_r < 0) {
 | 
				
			||||||
	if (maxpwr_r < 0 || maxpwr_r > upper_limit) {
 | 
							vty_out(vty, "%% Power %d dB can not be negative%s",
 | 
				
			||||||
		vty_out(vty, "%% Power %d dB is not in the valid range%s",
 | 
					 | 
				
			||||||
			maxpwr_r, VTY_NEWLINE);
 | 
								maxpwr_r, VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							return CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (maxpwr_r > upper_limit) {
 | 
				
			||||||
 | 
							vty_out(vty, "%% Power %d dB is more than %d dB maximum power reduction"
 | 
				
			||||||
 | 
								" defined by GSM 12.21. BTS may not support it.%s",
 | 
				
			||||||
 | 
								maxpwr_r, upper_limit, VTY_NEWLINE);
 | 
				
			||||||
 | 
							ret = CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (maxpwr_r & 1) {
 | 
						if (maxpwr_r & 1) {
 | 
				
			||||||
		vty_out(vty, "%% Power %d dB is not an even value%s",
 | 
							maxpwr_r = (maxpwr_r/2)*2;
 | 
				
			||||||
 | 
							vty_out(vty, "%% Power is not an even value, rounding it to %d dB%s",
 | 
				
			||||||
			maxpwr_r, VTY_NEWLINE);
 | 
								maxpwr_r, VTY_NEWLINE);
 | 
				
			||||||
		return CMD_WARNING;
 | 
							ret = CMD_WARNING;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Update the value if it's changed */
 | 
				
			||||||
 | 
						if (trx->max_power_red != maxpwr_r) {
 | 
				
			||||||
		trx->max_power_red = maxpwr_r;
 | 
							trx->max_power_red = maxpwr_r;
 | 
				
			||||||
 | 
							vty_out(vty, "%% Updating max_pwr_red to %d dB for %s%s",
 | 
				
			||||||
 | 
								trx->max_power_red, gsm_trx_name(trx), VTY_NEWLINE);
 | 
				
			||||||
 | 
							abis_nm_update_max_power_red(trx);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							vty_out(vty, "%% max_pwr_red is not changed for %s%s",
 | 
				
			||||||
 | 
								gsm_trx_name(trx), VTY_NEWLINE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* FIXME: make sure we update this using OML */
 | 
						return ret;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_trx_rsl_e1,
 | 
					DEFUN(cfg_trx_rsl_e1,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,13 +105,15 @@ DEFUN(cfg_net_name_long,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DEFUN(cfg_net_auth_policy,
 | 
					DEFUN(cfg_net_auth_policy,
 | 
				
			||||||
      cfg_net_auth_policy_cmd,
 | 
					      cfg_net_auth_policy_cmd,
 | 
				
			||||||
      "auth policy (closed|accept-all|regexp|token)",
 | 
					      "auth policy (closed|accept-all|regexp|token|remote|remote-closed)",
 | 
				
			||||||
	"Authentication (not cryptographic)\n"
 | 
						"Authentication (not cryptographic)\n"
 | 
				
			||||||
	"Set the GSM network authentication policy\n"
 | 
						"Set the GSM network authentication policy\n"
 | 
				
			||||||
	"Require the MS to be activated in HLR\n"
 | 
						"Require the MS to be activated in HLR\n"
 | 
				
			||||||
	"Accept all MS, whether in HLR or not\n"
 | 
						"Accept all MS, whether in HLR or not\n"
 | 
				
			||||||
	"Use regular expression for IMSI authorization decision\n"
 | 
						"Use regular expression for IMSI authorization decision\n"
 | 
				
			||||||
	"Use SMS-token based authentication\n")
 | 
						"Use SMS-token based authentication\n"
 | 
				
			||||||
 | 
						"Use remote subscription data only (HLR)\n"
 | 
				
			||||||
 | 
						"Use remote subscription data if the MS is activated in local HLR\n")
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
 | 
						enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
 | 
				
			||||||
	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 | 
						struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -160,6 +160,11 @@ static const struct log_info_cat default_categories[] = {
 | 
				
			|||||||
		.description = "SMPP interface for external SMS apps",
 | 
							.description = "SMPP interface for external SMS apps",
 | 
				
			||||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
							.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						[DSUP] = {
 | 
				
			||||||
 | 
							.name = "DSUP",
 | 
				
			||||||
 | 
							.description = "SUP interface for external HLR",
 | 
				
			||||||
 | 
							.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	[DFILTER] = {
 | 
						[DFILTER] = {
 | 
				
			||||||
		.name = "DFILTER",
 | 
							.name = "DFILTER",
 | 
				
			||||||
		.description = "BSC/NAT IMSI based filtering",
 | 
							.description = "BSC/NAT IMSI based filtering",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -163,6 +163,8 @@ static const struct value_string auth_policy_names[] = {
 | 
				
			|||||||
	{ GSM_AUTH_POLICY_ACCEPT_ALL,	"accept-all" },
 | 
						{ GSM_AUTH_POLICY_ACCEPT_ALL,	"accept-all" },
 | 
				
			||||||
	{ GSM_AUTH_POLICY_TOKEN,	"token" },
 | 
						{ GSM_AUTH_POLICY_TOKEN,	"token" },
 | 
				
			||||||
	{ GSM_AUTH_POLICY_REGEXP,	"regexp" },
 | 
						{ GSM_AUTH_POLICY_REGEXP,	"regexp" },
 | 
				
			||||||
 | 
						{ GSM_AUTH_POLICY_REMOTE,	"remote" },
 | 
				
			||||||
 | 
						{ GSM_AUTH_POLICY_REMOTE_CLOSED,	"remote-closed" },
 | 
				
			||||||
	{ 0,				NULL }
 | 
						{ 0,				NULL }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,7 @@ libmsc_a_SOURCES = \
 | 
				
			|||||||
	gsm_04_08.c \
 | 
						gsm_04_08.c \
 | 
				
			||||||
	gsm_04_11.c \
 | 
						gsm_04_11.c \
 | 
				
			||||||
	gsm_04_80.c \
 | 
						gsm_04_80.c \
 | 
				
			||||||
 | 
						gsm_sup.c \
 | 
				
			||||||
	gsm_subscriber.c \
 | 
						gsm_subscriber.c \
 | 
				
			||||||
	mncc.c \
 | 
						mncc.c \
 | 
				
			||||||
	mncc_builtin.c \
 | 
						mncc_builtin.c \
 | 
				
			||||||
@@ -42,6 +43,8 @@ libmsc_a_SOURCES = \
 | 
				
			|||||||
	osmo_msc.c \
 | 
						osmo_msc.c \
 | 
				
			||||||
	ctrl_commands.c \
 | 
						ctrl_commands.c \
 | 
				
			||||||
	meas_feed.c \
 | 
						meas_feed.c \
 | 
				
			||||||
 | 
						gsm_ussd_map_proto.c \
 | 
				
			||||||
 | 
						gsm_ussd_map.c \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if BUILD_SMPP
 | 
					if BUILD_SMPP
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,20 +82,23 @@ _use_comp128_v1(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
 | 
				
			|||||||
 *   1 -> Tuple returned, need to do auth, then enable cipher
 | 
					 *   1 -> Tuple returned, need to do auth, then enable cipher
 | 
				
			||||||
 *   2 -> Tuple returned, need to enable cipher
 | 
					 *   2 -> Tuple returned, need to enable cipher
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
 | 
					int auth_get_tuple_for_subscr(enum gsm_auth_policy auth_policy,
 | 
				
			||||||
 | 
					                              struct gsm_auth_tuple *atuple,
 | 
				
			||||||
                              struct gsm_subscriber *subscr, int key_seq)
 | 
					                              struct gsm_subscriber *subscr, int key_seq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gsm_auth_info ainfo;
 | 
						struct gsm_auth_info ainfo;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (auth_policy != GSM_AUTH_POLICY_REMOTE &&
 | 
				
			||||||
 | 
						    auth_policy != GSM_AUTH_POLICY_REMOTE_CLOSED) {
 | 
				
			||||||
		/* Get subscriber info (if any) */
 | 
							/* Get subscriber info (if any) */
 | 
				
			||||||
		rc = db_get_authinfo_for_subscr(&ainfo, subscr);
 | 
							rc = db_get_authinfo_for_subscr(&ainfo, subscr);
 | 
				
			||||||
		if (rc < 0) {
 | 
							if (rc < 0) {
 | 
				
			||||||
			LOGP(DMM, LOGL_NOTICE,
 | 
								LOGP(DMM, LOGL_NOTICE,
 | 
				
			||||||
		     "No retrievable Ki for subscriber %s, skipping auth\n",
 | 
									"No retrievable Ki for subscriber %s, skipping auth\n");
 | 
				
			||||||
		     subscr_name(subscr));
 | 
					 | 
				
			||||||
			return rc == -ENOENT ? AUTH_NOT_AVAIL : AUTH_ERROR;
 | 
								return rc == -ENOENT ? AUTH_NOT_AVAIL : AUTH_ERROR;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If possible, re-use the last tuple and skip auth */
 | 
						/* If possible, re-use the last tuple and skip auth */
 | 
				
			||||||
	rc = db_get_lastauthtuple_for_subscr(atuple, subscr);
 | 
						rc = db_get_lastauthtuple_for_subscr(atuple, subscr);
 | 
				
			||||||
@@ -110,6 +113,12 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
 | 
				
			|||||||
		return AUTH_DO_CIPH;
 | 
							return AUTH_DO_CIPH;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (auth_policy == GSM_AUTH_POLICY_REMOTE ||
 | 
				
			||||||
 | 
						    auth_policy == GSM_AUTH_POLICY_REMOTE_CLOSED) {
 | 
				
			||||||
 | 
							/* Request a new tuple from remote HLR */
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Generate a new one */
 | 
						/* Generate a new one */
 | 
				
			||||||
	if (rc != 0) {
 | 
						if (rc != 0) {
 | 
				
			||||||
		/* If db_get_lastauthtuple_for_subscr() returned nothing, make
 | 
							/* If db_get_lastauthtuple_for_subscr() returned nothing, make
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,7 @@
 | 
				
			|||||||
#include <openbsc/osmo_msc.h>
 | 
					#include <openbsc/osmo_msc.h>
 | 
				
			||||||
#include <openbsc/handover.h>
 | 
					#include <openbsc/handover.h>
 | 
				
			||||||
#include <openbsc/mncc_int.h>
 | 
					#include <openbsc/mncc_int.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_sup.h>
 | 
				
			||||||
#include <osmocom/abis/e1_input.h>
 | 
					#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
#include <osmocom/core/bitvec.h>
 | 
					#include <osmocom/core/bitvec.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,7 +213,18 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* If not done yet, try to get info for this user */
 | 
						/* If not done yet, try to get info for this user */
 | 
				
			||||||
	if (status < 0) {
 | 
						if (status < 0) {
 | 
				
			||||||
		rc = auth_get_tuple_for_subscr(&atuple, subscr, key_seq);
 | 
							rc = auth_get_tuple_for_subscr(net->auth_policy, &atuple, subscr, key_seq);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
							if ((rc == 0) && (net->auth_policy == GSM_AUTH_POLICY_REMOTE ||
 | 
				
			||||||
 | 
							                  net->auth_policy == GSM_AUTH_POLICY_REMOTE_CLOSED)) {
 | 
				
			||||||
 | 
								allocate_security_operation(conn);
 | 
				
			||||||
 | 
								conn->sec_operation->cb = cb;
 | 
				
			||||||
 | 
								conn->sec_operation->cb_data = cb_data;
 | 
				
			||||||
 | 
								return subscr_query_auth_info(subscr);
 | 
				
			||||||
 | 
							} else if (rc <= 0) {
 | 
				
			||||||
 | 
								status = GSM_SECURITY_NOAVAIL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
		if (rc <= 0)
 | 
							if (rc <= 0)
 | 
				
			||||||
			status = GSM_SECURITY_NOAVAIL;
 | 
								status = GSM_SECURITY_NOAVAIL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -290,12 +302,23 @@ static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
 | 
				
			|||||||
		return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT);
 | 
							return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT);
 | 
				
			||||||
	case GSM_AUTH_POLICY_ACCEPT_ALL:
 | 
						case GSM_AUTH_POLICY_ACCEPT_ALL:
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
 | 
						case GSM_AUTH_POLICY_REMOTE_CLOSED:
 | 
				
			||||||
 | 
							if (!subscriber->authorized) {
 | 
				
			||||||
 | 
								return subscriber->authorized;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case GSM_AUTH_POLICY_REMOTE:
 | 
				
			||||||
 | 
							if (loc->waiting_for_remote_accept) {
 | 
				
			||||||
 | 
								subscr_location_update(subscriber);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void release_loc_updating_req(struct gsm_subscriber_connection *conn, int release)
 | 
					void release_loc_updating_req(struct gsm_subscriber_connection *conn, int release)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!conn->loc_operation)
 | 
						if (!conn->loc_operation)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -384,7 +407,7 @@ static int _gsm0408_authorize_sec_cb(unsigned int hooknum, unsigned int event,
 | 
				
			|||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb *msg)
 | 
					int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!conn->loc_operation)
 | 
						if (!conn->loc_operation)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@@ -602,7 +625,7 @@ static void schedule_reject(struct gsm_subscriber_connection *conn)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	conn->loc_operation->updating_timer.cb = loc_upd_rej_cb;
 | 
						conn->loc_operation->updating_timer.cb = loc_upd_rej_cb;
 | 
				
			||||||
	conn->loc_operation->updating_timer.data = conn;
 | 
						conn->loc_operation->updating_timer.data = conn;
 | 
				
			||||||
	osmo_timer_schedule(&conn->loc_operation->updating_timer, 5, 0);
 | 
						osmo_timer_schedule(&conn->loc_operation->updating_timer, 10, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct value_string lupd_names[] = {
 | 
					static const struct value_string lupd_names[] = {
 | 
				
			||||||
@@ -703,6 +726,8 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb
 | 
				
			|||||||
	/* schedule the reject timer */
 | 
						/* schedule the reject timer */
 | 
				
			||||||
	schedule_reject(conn);
 | 
						schedule_reject(conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn->loc_operation->waiting_for_remote_accept = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!subscr) {
 | 
						if (!subscr) {
 | 
				
			||||||
		DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
 | 
							DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
 | 
				
			||||||
		/* FIXME: request id? close channel? */
 | 
							/* FIXME: request id? close channel? */
 | 
				
			||||||
@@ -1060,6 +1085,12 @@ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct m
 | 
				
			|||||||
			_gsm48_rx_mm_serv_req_sec_cb, NULL);
 | 
								_gsm48_rx_mm_serv_req_sec_cb, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void gsm0408_purge_ms(struct gsm_subscriber *subscr) {
 | 
				
			||||||
 | 
						if (subscr->group->net->auth_policy == GSM_AUTH_POLICY_REMOTE) {
 | 
				
			||||||
 | 
							subscr_purge_ms(subscr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, struct msgb *msg)
 | 
					static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gsm_network *network = conn->network;
 | 
						struct gsm_network *network = conn->network;
 | 
				
			||||||
@@ -1098,6 +1129,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, s
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (subscr) {
 | 
						if (subscr) {
 | 
				
			||||||
 | 
							gsm0408_purge_ms(subscr);
 | 
				
			||||||
		subscr_update(subscr, conn->bts,
 | 
							subscr_update(subscr, conn->bts,
 | 
				
			||||||
			      GSM_SUBSCRIBER_UPDATE_DETACHED);
 | 
								      GSM_SUBSCRIBER_UPDATE_DETACHED);
 | 
				
			||||||
		DEBUGP(DMM, "Subscriber: %s\n", subscr_name(subscr));
 | 
							DEBUGP(DMM, "Subscriber: %s\n", subscr_name(subscr));
 | 
				
			||||||
@@ -3669,7 +3701,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
 | 
				
			|||||||
			/* Temporarily out of order */
 | 
								/* Temporarily out of order */
 | 
				
			||||||
			return mncc_release_ind(net, NULL, data->callref,
 | 
								return mncc_release_ind(net, NULL, data->callref,
 | 
				
			||||||
						GSM48_CAUSE_LOC_PRN_S_LU,
 | 
											GSM48_CAUSE_LOC_PRN_S_LU,
 | 
				
			||||||
						GSM48_CC_CAUSE_DEST_OOO);
 | 
											GSM48_CC_CAUSE_USER_NOTRESPOND);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* Create transaction */
 | 
							/* Create transaction */
 | 
				
			||||||
		trans = trans_alloc(net, subscr, GSM48_PDISC_CC, 0xff, data->callref);
 | 
							trans = trans_alloc(net, subscr, GSM48_PDISC_CC, 0xff, data->callref);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,7 @@
 | 
				
			|||||||
#include <openbsc/bsc_rll.h>
 | 
					#include <openbsc/bsc_rll.h>
 | 
				
			||||||
#include <openbsc/chan_alloc.h>
 | 
					#include <openbsc/chan_alloc.h>
 | 
				
			||||||
#include <openbsc/bsc_api.h>
 | 
					#include <openbsc/bsc_api.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_sup.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef BUILD_SMPP
 | 
					#ifdef BUILD_SMPP
 | 
				
			||||||
#include "smpp_smsc.h"
 | 
					#include "smpp_smsc.h"
 | 
				
			||||||
@@ -361,6 +362,36 @@ try_local:
 | 
				
			|||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int gsm340_tpdu_dst_addr(struct msgb *msg, struct gsm_sms_addr* dst_addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t *smsp = msgb_sms(msg);
 | 
				
			||||||
 | 
						uint8_t da_len_bytes;
 | 
				
			||||||
 | 
						uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* skip two first octets*/
 | 
				
			||||||
 | 
						smsp += 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* length in bytes of the destination address */
 | 
				
			||||||
 | 
						da_len_bytes = 2 + *smsp/2 + *smsp%2;
 | 
				
			||||||
 | 
						if (da_len_bytes > 12) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "Destination Address > 12 bytes ?!?\n");
 | 
				
			||||||
 | 
							return GSM411_RP_CAUSE_SEMANT_INC_MSG;
 | 
				
			||||||
 | 
						} else if (da_len_bytes < 4) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "Destination Address < 4 bytes ?!?\n");
 | 
				
			||||||
 | 
							return GSM411_RP_CAUSE_SEMANT_INC_MSG;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						memset(address_lv, 0, sizeof(address_lv));
 | 
				
			||||||
 | 
						memcpy(address_lv, smsp, da_len_bytes);
 | 
				
			||||||
 | 
						/* mangle first byte to reflect length in bytes, not digits */
 | 
				
			||||||
 | 
						address_lv[0] = da_len_bytes - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dst_addr->ton = (address_lv[1] >> 4) & 7;
 | 
				
			||||||
 | 
						dst_addr->npi = address_lv[1] & 0xF;
 | 
				
			||||||
 | 
						/* convert to real number */
 | 
				
			||||||
 | 
						gsm48_decode_bcd_number(dst_addr->addr,
 | 
				
			||||||
 | 
									sizeof(dst_addr->addr), address_lv, 1);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* process an incoming TPDU (called from RP-DATA)
 | 
					/* process an incoming TPDU (called from RP-DATA)
 | 
				
			||||||
 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
 | 
					 * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
 | 
				
			||||||
@@ -553,6 +584,24 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	DEBUGP(DLSMS, "DST(%u,%s)\n", dst_len, osmo_hexdump(dst, dst_len));
 | 
						DEBUGP(DLSMS, "DST(%u,%s)\n", dst_len, osmo_hexdump(dst, dst_len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct gsm_sms_addr dst_addr;
 | 
				
			||||||
 | 
						int res = gsm340_tpdu_dst_addr(msg, &dst_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!res) {
 | 
				
			||||||
 | 
							DEBUGP(DLSMS, "DA(%d,%s)\n", strlen(dst_addr.addr), dst_addr.addr);
 | 
				
			||||||
 | 
							DEBUGP(DLSMS, "OA(%d,%s)\n", strlen(trans->conn->subscr->extension), trans->conn->subscr->extension);
 | 
				
			||||||
 | 
							if ((strlen(trans->conn->subscr->extension) == 5) ||
 | 
				
			||||||
 | 
							    (strlen(dst_addr.addr) == 5)) {
 | 
				
			||||||
 | 
								trans->sms_local = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((trans->net->sms_client) && (trans->sms_local == 0)) {
 | 
				
			||||||
 | 
							rate_ctr_inc(&trans->conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED]);
 | 
				
			||||||
 | 
							trans->msg_ref = rph->msg_ref;
 | 
				
			||||||
 | 
							return subscr_tx_sms_message(trans->subscr, rph);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = gsm340_rx_tpdu(trans->conn, msg);
 | 
						rc = gsm340_rx_tpdu(trans->conn, msg);
 | 
				
			||||||
	if (rc == 0)
 | 
						if (rc == 0)
 | 
				
			||||||
		return gsm411_send_rp_ack(trans, rph->msg_ref);
 | 
							return gsm411_send_rp_ack(trans, rph->msg_ref);
 | 
				
			||||||
@@ -594,6 +643,10 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct gsm_sms *sms = trans->sms.sms;
 | 
						struct gsm_sms *sms = trans->sms.sms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((trans->net->sms_client) && (trans->sms_local == 0)) {
 | 
				
			||||||
 | 
							return subscr_tx_sms_message(trans->subscr, rph);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
 | 
						/* Acnkowledgement to MT RP_DATA, i.e. the MS confirms it
 | 
				
			||||||
	 * successfully received a SMS.  We can now safely mark it as
 | 
						 * successfully received a SMS.  We can now safely mark it as
 | 
				
			||||||
	 * transmitted */
 | 
						 * transmitted */
 | 
				
			||||||
@@ -631,6 +684,15 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
 | 
				
			|||||||
	     subscr_name(trans->conn->subscr), cause_len, cause,
 | 
						     subscr_name(trans->conn->subscr), cause_len, cause,
 | 
				
			||||||
	     get_value_string(gsm411_rp_cause_strs, cause));
 | 
						     get_value_string(gsm411_rp_cause_strs, cause));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((trans->net->sms_client) && (trans->sms_local == 0)) {
 | 
				
			||||||
 | 
							if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) {
 | 
				
			||||||
 | 
								rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_MEM]);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								rate_ctr_inc(&net->msc_ctrs->ctr[MSC_CTR_SMS_RP_ERR_OTHER]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return subscr_tx_sms_message(trans->subscr, rph);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!sms) {
 | 
						if (!sms) {
 | 
				
			||||||
		LOGP(DLSMS, LOGL_ERROR,
 | 
							LOGP(DLSMS, LOGL_ERROR,
 | 
				
			||||||
			"RX RP-ERR, but no sms in transaction?!?\n");
 | 
								"RX RP-ERR, but no sms in transaction?!?\n");
 | 
				
			||||||
@@ -911,6 +973,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
 | 
				
			|||||||
	trans->sms.sms = sms;
 | 
						trans->sms.sms = sms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trans->conn = conn;
 | 
						trans->conn = conn;
 | 
				
			||||||
 | 
						trans->sms_local = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Hardcode SMSC Originating Address for now */
 | 
						/* Hardcode SMSC Originating Address for now */
 | 
				
			||||||
	data = (uint8_t *)msgb_put(msg, 8);
 | 
						data = (uint8_t *)msgb_put(msg, 8);
 | 
				
			||||||
@@ -1062,3 +1125,136 @@ void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int gsm411_send_rp_data(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
 | 
					                        struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_trans *trans;
 | 
				
			||||||
 | 
						struct gsm411_rp_hdr *rp;
 | 
				
			||||||
 | 
						rp = (struct gsm411_rp_hdr *)msgb_data(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int transaction_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						transaction_id =
 | 
				
			||||||
 | 
							trans_assign_trans_id(conn->bts->network, conn->subscr,
 | 
				
			||||||
 | 
								      GSM48_PDISC_SMS, 0);
 | 
				
			||||||
 | 
						if (transaction_id == -1) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "No available transaction ids\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -EBUSY;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* FIXME: allocate transaction with message reference */
 | 
				
			||||||
 | 
						trans = trans_alloc(conn->bts->network, conn->subscr,
 | 
				
			||||||
 | 
								    GSM48_PDISC_SMS,
 | 
				
			||||||
 | 
								    transaction_id, new_callref++);
 | 
				
			||||||
 | 
						if (!trans) {
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "No memory for trans\n");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							/* FIXME: send some error message */
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						gsm411_smc_init(&trans->sms.smc_inst, 0, 1,
 | 
				
			||||||
 | 
							gsm411_mn_recv, gsm411_mm_send);
 | 
				
			||||||
 | 
						gsm411_smr_init(&trans->sms.smr_inst, 0, 1,
 | 
				
			||||||
 | 
							gsm411_rl_recv, gsm411_mn_send);
 | 
				
			||||||
 | 
						trans->msg_ref = rp->msg_ref;
 | 
				
			||||||
 | 
						trans->conn = conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[MSC_CTR_SMS_DELIVERED]);
 | 
				
			||||||
 | 
						return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_DATA_REQ, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int gsm411_send_rp_resp(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
					                            struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_subscriber_connection *conn;
 | 
				
			||||||
 | 
						struct gsm_trans *trans;
 | 
				
			||||||
 | 
						struct gsm411_rp_hdr *rp;
 | 
				
			||||||
 | 
						rp = (struct gsm411_rp_hdr *)msgb_data(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conn = connection_for_subscr(subscr);
 | 
				
			||||||
 | 
						if (!conn) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						trans = trans_find_by_msgref(conn, rp->msg_ref);
 | 
				
			||||||
 | 
						if (!trans) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gsm411_smr_send(&trans->sms.smr_inst, GSM411_SM_RL_REPORT_REQ, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* paging callback. Here we get called if paging a subscriber has
 | 
				
			||||||
 | 
					 * succeeded or failed. */
 | 
				
			||||||
 | 
					static int paging_cb_send_rp_data(unsigned int hooknum, unsigned int event,
 | 
				
			||||||
 | 
								      struct msgb *msg, void *_conn, void *_rp_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_subscriber_connection *conn = _conn;
 | 
				
			||||||
 | 
						struct msgb *rp_data = _rp_data;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DEBUGP(DLSMS, "paging_cb_send_sms(hooknum=%u, event=%u, msg=%p,"
 | 
				
			||||||
 | 
							"conn=%p, rp_data=%p)\n", hooknum, event, msg, conn, rp_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hooknum != GSM_HOOK_RR_PAGING)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (event) {
 | 
				
			||||||
 | 
						case GSM_PAGING_SUCCEEDED:
 | 
				
			||||||
 | 
							gsm411_send_rp_data(conn, rp_data);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case GSM_PAGING_EXPIRED:
 | 
				
			||||||
 | 
						case GSM_PAGING_OOM:
 | 
				
			||||||
 | 
						case GSM_PAGING_BUSY:
 | 
				
			||||||
 | 
							msgb_free(rp_data);
 | 
				
			||||||
 | 
							rc = -ETIMEDOUT;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOGP(DLSMS, LOGL_ERROR, "Unhandled paging event: %d\n", event);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int gsm411_send_rp_req(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
					                           struct msgb *rp_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_subscriber_connection *conn;
 | 
				
			||||||
 | 
						conn = connection_for_subscr(subscr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn) {
 | 
				
			||||||
 | 
							return gsm411_send_rp_data(conn, rp_data);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *res;
 | 
				
			||||||
 | 
						res = subscr_request_channel(subscr, RSL_CHANNEED_SDCCH,
 | 
				
			||||||
 | 
										paging_cb_send_rp_data, rp_data);
 | 
				
			||||||
 | 
						if (!res) {
 | 
				
			||||||
 | 
							msgb_free(rp_data);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gsm411_send_rp_msg_subscr(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
					                       struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm411_rp_hdr *rp;
 | 
				
			||||||
 | 
						msgb_push(msg, 1);
 | 
				
			||||||
 | 
						rp = (struct gsm411_rp_hdr *)msgb_data(msg);
 | 
				
			||||||
 | 
						rp->len = msg->len - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (rp->msg_type) {
 | 
				
			||||||
 | 
						case GSM411_MT_RP_ACK_MT:
 | 
				
			||||||
 | 
						case GSM411_MT_RP_ERROR_MT:
 | 
				
			||||||
 | 
							return gsm411_send_rp_resp(subscr, msg);
 | 
				
			||||||
 | 
						case GSM411_MT_RP_DATA_MT:
 | 
				
			||||||
 | 
							return gsm411_send_rp_req(subscr, msg);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,22 @@
 | 
				
			|||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/gsm/tlv.h>
 | 
					#include <osmocom/gsm/tlv.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This function can handle ASN1 length up to 255 which is enough for USSD */
 | 
				
			||||||
 | 
					static inline unsigned char *msgb_wrap_with_ASN1_TL(struct msgb *msgb, uint8_t tag)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint16_t origlen = msgb->len;
 | 
				
			||||||
 | 
						uint8_t *data = msgb_push(msgb, (origlen > 0x7f) ? 3 : 2);
 | 
				
			||||||
 | 
						data[0] = tag;
 | 
				
			||||||
 | 
						if (origlen > 0x7f) {
 | 
				
			||||||
 | 
							data[1] = 0x81;
 | 
				
			||||||
 | 
							data[2] = origlen;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							data[1] = origlen;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag)
 | 
					static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t *data = msgb_push(msgb, 2);
 | 
						uint8_t *data = msgb_push(msgb, 2);
 | 
				
			||||||
@@ -59,83 +75,201 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
 | 
				
			|||||||
	return data;
 | 
						return data;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline unsigned char *msgb_wrap_with_L(struct msgb *msgb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t *data = msgb_push(msgb, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Send response to a mobile-originated ProcessUnstructuredSS-Request */
 | 
						data[0] = msgb->len - 1;
 | 
				
			||||||
int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
 | 
						return data;
 | 
				
			||||||
			       const struct msgb *in_msg, const char *response_text,
 | 
					}
 | 
				
			||||||
			       const struct ss_request *req)
 | 
					
 | 
				
			||||||
 | 
					/* Compose universial USSD packet invoke/return_result payload */
 | 
				
			||||||
 | 
					struct msgb *gsm0480_compose_ussd_component(struct ss_request* req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD RSP");
 | 
						struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD RSP");
 | 
				
			||||||
	struct gsm48_hdr *gh;
 | 
					 | 
				
			||||||
	uint8_t *ptr8;
 | 
						uint8_t *ptr8;
 | 
				
			||||||
	int response_len;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* First put the payload text into the message */
 | 
						/* First put the payload text into the message */
 | 
				
			||||||
	ptr8 = msgb_put(msg, 0);
 | 
						ptr8 = msgb_put(msg, 0);
 | 
				
			||||||
	gsm_7bit_encode_n_ussd(ptr8, msgb_tailroom(msg), response_text, &response_len);
 | 
					
 | 
				
			||||||
	msgb_put(msg, response_len);
 | 
						memcpy(ptr8, req->ussd_text, req->ussd_text_len);
 | 
				
			||||||
 | 
						msgb_put(msg, req->ussd_text_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Then wrap it as an Octet String */
 | 
						/* Then wrap it as an Octet String */
 | 
				
			||||||
	msgb_wrap_with_TL(msg, ASN1_OCTET_STRING_TAG);
 | 
						msgb_wrap_with_ASN1_TL(msg, ASN1_OCTET_STRING_TAG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Pre-pend the DCS octet string */
 | 
						/* Pre-pend the DCS octet string */
 | 
				
			||||||
	msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, 0x0F);
 | 
						msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_language);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Then wrap these as a Sequence */
 | 
						/* Then wrap these as a Sequence */
 | 
				
			||||||
	msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG);
 | 
						msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (req->component_type == GSM0480_CTYPE_RETURN_RESULT) {
 | 
				
			||||||
		/* Pre-pend the operation code */
 | 
							/* Pre-pend the operation code */
 | 
				
			||||||
	msgb_push_TLV1(msg, GSM0480_OPERATION_CODE,
 | 
							msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
 | 
				
			||||||
			GSM0480_OP_CODE_PROCESS_USS_REQ);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Wrap the operation code and IA5 string as a sequence */
 | 
							/* Wrap the operation code and IA5 string as a sequence */
 | 
				
			||||||
	msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG);
 | 
							msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Pre-pend the invoke ID */
 | 
							/* Pre-pend the invoke ID */
 | 
				
			||||||
		msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
 | 
							msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
 | 
				
			||||||
 | 
						} else if (req->component_type == GSM0480_CTYPE_INVOKE) {
 | 
				
			||||||
 | 
							/* Pre-pend the operation code */
 | 
				
			||||||
 | 
							msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Wrap this up as a Return Result component */
 | 
							/* Pre-pend the invoke ID */
 | 
				
			||||||
	msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT);
 | 
							msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							abort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Wrap the component in a Facility message */
 | 
						/* Wrap this up as an Invoke or a Return Result component */
 | 
				
			||||||
 | 
						msgb_wrap_with_ASN1_TL(msg, req->component_type);
 | 
				
			||||||
 | 
						return msg;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef NO_GSM0480_SEND_FUNC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int gsm0480_send_component(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
 | 
								   struct msgb *msg,
 | 
				
			||||||
 | 
								   struct ss_header* reqhdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						struct msgb *msg = gsm48_msgb_alloc();
 | 
				
			||||||
 | 
						struct gsm48_hdr *gh;
 | 
				
			||||||
 | 
						uint8_t *ptr8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ptr8 = msgb_put(msg, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(ptr8, component, reqhdr->component_length);
 | 
				
			||||||
 | 
						msgb_put(msg, reqhdr->component_length);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						struct gsm48_hdr *gh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (reqhdr->message_type == GSM0480_MTYPE_REGISTER ||
 | 
				
			||||||
 | 
							reqhdr->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
 | 
				
			||||||
 | 
							/* Wrap the component in a Facility message, it's not ASN1 */
 | 
				
			||||||
		msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
 | 
							msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
 | 
				
			||||||
 | 
						} else if (reqhdr->message_type == GSM0480_MTYPE_FACILITY) {
 | 
				
			||||||
 | 
							/* For GSM0480_MTYPE_FACILITY it's LV not TLV */
 | 
				
			||||||
 | 
							msgb_wrap_with_L(msg);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							abort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* And finally pre-pend the L3 header */
 | 
				
			||||||
 | 
						gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
 | 
				
			||||||
 | 
						gh->proto_discr = GSM48_PDISC_NC_SS | reqhdr->transaction_id
 | 
				
			||||||
 | 
										| (1<<7);  /* TI direction = 1 */
 | 
				
			||||||
 | 
						gh->msg_type = reqhdr->message_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DEBUGP(DSS, "Sending SS to mobile: %s\n", msgb_hexdump(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gsm0808_submit_dtap(conn, msg, 0, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					/* Compose universial SS packet except Reject opcodes */
 | 
				
			||||||
 | 
					int gsm0480_send_ussd(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
 | 
							      struct ss_request* req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = gsm48_msgb_alloc();
 | 
				
			||||||
 | 
						struct gsm48_hdr *gh;
 | 
				
			||||||
 | 
						uint8_t *ptr8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* First put the payload text into the message */
 | 
				
			||||||
 | 
						ptr8 = msgb_put(msg, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(ptr8, req->ussd_text, req->ussd_text_len);
 | 
				
			||||||
 | 
						msgb_put(msg, req->ussd_text_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Then wrap it as an Octet String */
 | 
				
			||||||
 | 
						msgb_wrap_with_ASN1_TL(msg, ASN1_OCTET_STRING_TAG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Pre-pend the DCS octet string */
 | 
				
			||||||
 | 
						msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_language);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Then wrap these as a Sequence */
 | 
				
			||||||
 | 
						msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (req->component_type == GSM0480_CTYPE_RETURN_RESULT) {
 | 
				
			||||||
 | 
							/* Pre-pend the operation code */
 | 
				
			||||||
 | 
							msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Wrap the operation code and IA5 string as a sequence */
 | 
				
			||||||
 | 
							msgb_wrap_with_ASN1_TL(msg, GSM_0480_SEQUENCE_TAG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Pre-pend the invoke ID */
 | 
				
			||||||
 | 
							msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
 | 
				
			||||||
 | 
						} else if (req->component_type == GSM0480_CTYPE_INVOKE) {
 | 
				
			||||||
 | 
							/* Pre-pend the operation code */
 | 
				
			||||||
 | 
							msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Pre-pend the invoke ID */
 | 
				
			||||||
 | 
							msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							abort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Wrap this up as an Invoke or a Return Result component */
 | 
				
			||||||
 | 
						msgb_wrap_with_ASN1_TL(msg, req->component_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (req->message_type == GSM0480_MTYPE_REGISTER ||
 | 
				
			||||||
 | 
							req->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
 | 
				
			||||||
 | 
							/* Wrap the component in a Facility message, it's not ASN1 */
 | 
				
			||||||
 | 
							msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
 | 
				
			||||||
 | 
						} else if (req->message_type == GSM0480_MTYPE_FACILITY) {
 | 
				
			||||||
 | 
							/* For GSM0480_MTYPE_FACILITY it's LV not TLV */
 | 
				
			||||||
 | 
							msgb_wrap_with_L(msg);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							abort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* And finally pre-pend the L3 header */
 | 
						/* And finally pre-pend the L3 header */
 | 
				
			||||||
	gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
 | 
						gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
 | 
				
			||||||
	gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id
 | 
						gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id
 | 
				
			||||||
					| (1<<7);  /* TI direction = 1 */
 | 
										| (1<<7);  /* TI direction = 1 */
 | 
				
			||||||
	gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
						gh->msg_type = req->message_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DEBUGP(DSS, "Sending USSD to mobile: %s\n", msgb_hexdump(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return gsm0808_submit_dtap(conn, msg, 0, 0);
 | 
						return gsm0808_submit_dtap(conn, msg, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
 | 
					int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
			     const struct msgb *in_msg,
 | 
								     uint8_t invoke_id,
 | 
				
			||||||
			     const struct ss_request *req)
 | 
								     uint8_t transaction_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REJ");
 | 
						struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REJ");
 | 
				
			||||||
	struct gsm48_hdr *gh;
 | 
						struct ss_header ssh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* First insert the problem code */
 | 
						/* First insert the problem code */
 | 
				
			||||||
	msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL,
 | 
						msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL,
 | 
				
			||||||
			GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
 | 
								GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Before it insert the invoke ID */
 | 
						/* Before it insert the invoke ID */
 | 
				
			||||||
	msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
 | 
						msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Wrap this up as a Reject component */
 | 
						/* Wrap this up as a Reject component */
 | 
				
			||||||
	msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT);
 | 
						msgb_wrap_with_ASN1_TL(msg, GSM0480_CTYPE_REJECT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Prepare data for L3 header */
 | 
				
			||||||
 | 
						ssh.transaction_id = transaction_id;
 | 
				
			||||||
 | 
						ssh.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
				
			||||||
 | 
						return gsm0480_send_component(conn, msg, &ssh);
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
	/* Wrap the component in a Facility message */
 | 
						/* Wrap the component in a Facility message */
 | 
				
			||||||
	msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
 | 
						msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* And finally pre-pend the L3 header */
 | 
						/* And finally pre-pend the L3 header */
 | 
				
			||||||
	gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
 | 
						gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
 | 
				
			||||||
	gh->proto_discr = GSM48_PDISC_NC_SS;
 | 
						gh->proto_discr = GSM48_PDISC_NC_SS;
 | 
				
			||||||
	gh->proto_discr |= req->transaction_id | (1<<7);  /* TI direction = 1 */
 | 
						gh->proto_discr |= transaction_id | (1<<7);  /* TI direction = 1 */
 | 
				
			||||||
	gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
						gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return gsm0808_submit_dtap(conn, msg, 0, 0);
 | 
						return gsm0808_submit_dtap(conn, msg, 0, 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level, const char *text)
 | 
					int msc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level, const char *text)
 | 
				
			||||||
@@ -153,3 +287,5 @@ int msc_send_ussd_release_complete(struct gsm_subscriber_connection *conn)
 | 
				
			|||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	return gsm0808_submit_dtap(conn, msg, 0, 0);
 | 
						return gsm0808_submit_dtap(conn, msg, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,7 @@ extern struct llist_head *subscr_bsc_active_subscribers(void);
 | 
				
			|||||||
int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
 | 
					int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
 | 
				
			||||||
                         gsm_cbfn *cb, void *cb_data);
 | 
					                         gsm_cbfn *cb, void *cb_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void gsm0408_purge_ms(struct gsm_subscriber *subscr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Struct for pending channel requests. This is managed in the
 | 
					 * Struct for pending channel requests. This is managed in the
 | 
				
			||||||
@@ -364,6 +365,7 @@ static void subscr_expire_callback(void *data, long long unsigned int id)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGP(DMM, LOGL_NOTICE, "Expiring inactive subscriber %s (ID %llu)\n",
 | 
						LOGP(DMM, LOGL_NOTICE, "Expiring inactive subscriber %s (ID %llu)\n",
 | 
				
			||||||
			subscr_name(s), id);
 | 
								subscr_name(s), id);
 | 
				
			||||||
 | 
						gsm0408_purge_ms(s);
 | 
				
			||||||
	s->lac = GSM_LAC_RESERVED_DETACHED;
 | 
						s->lac = GSM_LAC_RESERVED_DETACHED;
 | 
				
			||||||
	db_sync_subscriber(s);
 | 
						db_sync_subscriber(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										628
									
								
								openbsc/src/libmsc/gsm_sup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										628
									
								
								openbsc/src/libmsc/gsm_sup.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,628 @@
 | 
				
			|||||||
 | 
					/* GSM Subscriber Update Protocol */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (C) 2015 by Ivan Klyuchnikov <kluchnikovi@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/gsm_sup.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/tlv.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_subscriber.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_04_08.h>
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					#include <openbsc/db.h>
 | 
				
			||||||
 | 
					#include <openbsc/chan_alloc.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsup.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsup_client.h>
 | 
				
			||||||
 | 
					#include <openbsc/osmo_msc.h>
 | 
				
			||||||
 | 
					#include <openbsc/gprs_utils.h>
 | 
				
			||||||
 | 
					#include <openbsc/ussd.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_04_11.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/protocol/gsm_04_11.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm0411_utils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
					    FMAP_MSISDN        = 0x80
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int subscr_uss_message(struct msgb *msg,
 | 
				
			||||||
 | 
								      struct ss_request *req,
 | 
				
			||||||
 | 
								      const char* extention)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t bcd_len = 0;
 | 
				
			||||||
 | 
						uint8_t *gsup_indicator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_indicator = msgb_put(msg, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* First byte should always be OSMO_GSUP_MSGT_MAP */
 | 
				
			||||||
 | 
						gsup_indicator[0] = OSMO_GSUP_MSGT_MAP;
 | 
				
			||||||
 | 
						gsup_indicator[1] = req->message_type;
 | 
				
			||||||
 | 
						/* TODO ADD tid */
 | 
				
			||||||
 | 
						gsup_indicator[2] = req->component_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* invokeId */
 | 
				
			||||||
 | 
						msgb_tlv_put(msg, GSM0480_COMPIDTAG_INVOKE_ID, 1, &req->invoke_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* opCode */
 | 
				
			||||||
 | 
						msgb_tlv_put(msg, GSM0480_OPERATION_CODE, 1, &req->opcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (req->ussd_text_len > 0) {
 | 
				
			||||||
 | 
							msgb_tlv_put(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_len + 1, &req->ussd_text_language);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (extention) {
 | 
				
			||||||
 | 
							uint8_t bcd_buf[32];
 | 
				
			||||||
 | 
							bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0,
 | 
				
			||||||
 | 
											  extention);
 | 
				
			||||||
 | 
							msgb_tlv_put(msg, FMAP_MSISDN, bcd_len - 1, &bcd_buf[1]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* fill actual length */
 | 
				
			||||||
 | 
						gsup_indicator[3] = 3 + 3 + (req->ussd_text_len + 1 + 2) + (bcd_len + 2);;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* wrap with GSM0480_CTYPE_INVOKE */
 | 
				
			||||||
 | 
						// gsm0480_wrap_invoke(msg, req->opcode, invoke_id);
 | 
				
			||||||
 | 
						// gsup_indicator = msgb_push(msgb, 1);
 | 
				
			||||||
 | 
						// gsup_indicator[0] = OSMO_GSUP_MSGT_MAP;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int subscr_tx_uss_message(struct ss_request *req,
 | 
				
			||||||
 | 
								  struct gsm_subscriber *subscr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = gsup_client_msgb_alloc();
 | 
				
			||||||
 | 
						if (!msg)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//GSM0480_OP_CODE_PROCESS_USS_REQ
 | 
				
			||||||
 | 
						subscr_uss_message(msg, req, subscr->extension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gsup_client_send(subscr->group->net->ussd_sup_client, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_uss_message_parse(struct ss_request *ss,
 | 
				
			||||||
 | 
									const uint8_t* data,
 | 
				
			||||||
 | 
									size_t len,
 | 
				
			||||||
 | 
									char* extention,
 | 
				
			||||||
 | 
									size_t extention_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const uint8_t* const_data = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len < 1 + 2 + 3 + 3)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* skip OSMO_GSUP_MSGT_MAP */
 | 
				
			||||||
 | 
						ss->message_type = *(++const_data);
 | 
				
			||||||
 | 
						ss->component_type = *(++const_data);
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						if (*const_data != GSM0480_COMPIDTAG_INVOKE_ID) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
						ss->invoke_id = *const_data;
 | 
				
			||||||
 | 
						const_data++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						if (*const_data != GSM0480_OPERATION_CODE) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
						ss->opcode = *const_data;
 | 
				
			||||||
 | 
						const_data++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (const_data - data < len) {
 | 
				
			||||||
 | 
							uint8_t len;
 | 
				
			||||||
 | 
							switch (*const_data) {
 | 
				
			||||||
 | 
							case ASN1_OCTET_STRING_TAG:
 | 
				
			||||||
 | 
								ss->ussd_text_len = len = (*(++const_data) - 1);
 | 
				
			||||||
 | 
								ss->ussd_text_language = *(++const_data);
 | 
				
			||||||
 | 
								memcpy(ss->ussd_text,
 | 
				
			||||||
 | 
									++const_data,
 | 
				
			||||||
 | 
									(len > MAX_LEN_USSD_STRING) ? MAX_LEN_USSD_STRING : len);
 | 
				
			||||||
 | 
								const_data += len;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case FMAP_MSISDN:
 | 
				
			||||||
 | 
								len = *(++const_data);
 | 
				
			||||||
 | 
								gsm48_decode_bcd_number(extention,
 | 
				
			||||||
 | 
											extention_len,
 | 
				
			||||||
 | 
											const_data,
 | 
				
			||||||
 | 
											0);
 | 
				
			||||||
 | 
								const_data += len + 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								DEBUGP(DMM, "Unknown code: %d\n", *const_data);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_uss_message(const uint8_t* data, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char extention[32] = {0};
 | 
				
			||||||
 | 
						struct ss_request ss;
 | 
				
			||||||
 | 
						memset(&ss, 0, sizeof(ss));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rx_uss_message_parse(&ss, data, len, extention, sizeof(extention))) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "Can't parse uss message\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DSUP, LOGL_ERROR, "Got invoke_id=0x%02x opcode=0x%02x facility=0x%02x text=%s\n",
 | 
				
			||||||
 | 
						     ss.invoke_id, ss.opcode, ss.component_type, ss.ussd_text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return on_ussd_response(&ss, extention);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int subscr_tx_sms_message(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
					                          struct gsm411_rp_hdr *rph)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t *data;
 | 
				
			||||||
 | 
						struct msgb *msg = gsup_client_msgb_alloc();
 | 
				
			||||||
 | 
						if (!msg)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_put_u8(msg, OSMO_GSUP_MSGT_SMS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (subscr->extension) {
 | 
				
			||||||
 | 
							uint8_t bcd_buf[32];
 | 
				
			||||||
 | 
							int bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf),
 | 
				
			||||||
 | 
							                                      0, subscr->extension);
 | 
				
			||||||
 | 
							msgb_tlv_put(msg, 0x82, bcd_len - 1, &bcd_buf[1]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						msgb_put_u8(msg, rph->msg_type);
 | 
				
			||||||
 | 
						msgb_put_u8(msg, rph->msg_ref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = msgb_put(msg, rph->len - 2);
 | 
				
			||||||
 | 
						memcpy(data, rph->data, rph->len - 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gsup_client_send(subscr->group->net->sms_client, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_sms_message(struct gsup_client *sup_client,
 | 
				
			||||||
 | 
					                          const uint8_t* data, size_t data_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						char extension[15];
 | 
				
			||||||
 | 
						uint8_t *value;
 | 
				
			||||||
 | 
						size_t value_len;
 | 
				
			||||||
 | 
						int offset = 1;
 | 
				
			||||||
 | 
						uint8_t *rp_hdr = (uint8_t*)data + offset;
 | 
				
			||||||
 | 
						data_len -= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc =  osmo_match_shift_tlv(&rp_hdr, &data_len, 0x82, &value, &value_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc <= 0)
 | 
				
			||||||
 | 
							return -GMM_CAUSE_INV_MAND_INFO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (value_len * 2 + 1 > ARRAY_SIZE(extension))
 | 
				
			||||||
 | 
							return -GMM_CAUSE_INV_MAND_INFO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Note that gsm48_decode_bcd_number expects the number of encoded MSISDN
 | 
				
			||||||
 | 
						 * octets in the first octet. By coincidence (the TLV encoding) the byte
 | 
				
			||||||
 | 
						 * before the value part already contains this length so we can use it
 | 
				
			||||||
 | 
						 * here.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						OSMO_ASSERT(value[-1] == value_len);
 | 
				
			||||||
 | 
						gsm48_decode_bcd_number(extension, ARRAY_SIZE(extension), value - 1, 0);
 | 
				
			||||||
 | 
						offset += 2 + value_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct msgb *msg = gsm411_msgb_alloc();
 | 
				
			||||||
 | 
						uint8_t *rp_msg;
 | 
				
			||||||
 | 
						rp_msg = (uint8_t *)msgb_put(msg, data_len);
 | 
				
			||||||
 | 
						memcpy(rp_msg, data + offset, data_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct gsm_subscriber *subscr;
 | 
				
			||||||
 | 
						struct gsm_network *net = sup_client->net;
 | 
				
			||||||
 | 
						subscr = subscr_get_by_extension(net->subscr_group, extension);
 | 
				
			||||||
 | 
						if (!subscr) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -GMM_CAUSE_IMSI_UNKNOWN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return gsm411_send_rp_msg_subscr(subscr, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int subscr_tx_sup_message(struct gsup_client *sup_client,
 | 
				
			||||||
 | 
													 struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
													 struct osmo_gsup_message *gsup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = gsup_client_msgb_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strlen(gsup_msg->imsi) == 0 && subscr)
 | 
				
			||||||
 | 
							strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_gsup_encode(msg, gsup_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUBSCRP(LOGL_INFO, subscr,
 | 
				
			||||||
 | 
							    "Sending SUP, will send: %s\n", msgb_hexdump(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sup_client) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOTSUP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gsup_client_send(sup_client, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					int subscr_query_auth_info(struct gsm_subscriber *subscr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_gsup_message gsup_msg = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUBSCRP(LOGL_INFO, subscr,
 | 
				
			||||||
 | 
							"subscriber auth info is not available\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_msg.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
 | 
				
			||||||
 | 
						return subscr_tx_sup_message(subscr->group->net->hlr_sup_client, subscr, &gsup_msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					int subscr_location_update(struct gsm_subscriber *subscr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_gsup_message gsup_msg = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUBSCRP(LOGL_INFO, subscr,
 | 
				
			||||||
 | 
							"subscriber data is not available\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
 | 
				
			||||||
 | 
						return subscr_tx_sup_message(subscr->group->net->hlr_sup_client, subscr, &gsup_msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int subscr_purge_ms(struct gsm_subscriber *subscr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_gsup_message gsup_msg = {0};
 | 
				
			||||||
 | 
						gsup_msg.message_type = OSMO_GSUP_MSGT_PURGE_MS_REQUEST;
 | 
				
			||||||
 | 
						return subscr_tx_sup_message(subscr->group->net->hlr_sup_client, subscr, &gsup_msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int subscr_tx_sup_error_reply(struct gsup_client *sup_client,
 | 
				
			||||||
 | 
														 struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
														 struct osmo_gsup_message *gsup_orig,
 | 
				
			||||||
 | 
														 enum gsm48_gmm_cause cause)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_gsup_message gsup_reply = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
 | 
				
			||||||
 | 
						gsup_reply.cause = cause;
 | 
				
			||||||
 | 
						gsup_reply.message_type =
 | 
				
			||||||
 | 
							OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return subscr_tx_sup_message(sup_client, subscr, &gsup_reply);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					static int subscr_handle_sup_auth_res(struct gsup_client *sup_client,
 | 
				
			||||||
 | 
														   struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
														   struct osmo_gsup_message *gsup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
 | 
				
			||||||
 | 
						struct gsm_security_operation *op;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUBSCRP(LOGL_INFO, subscr,
 | 
				
			||||||
 | 
							"Got SendAuthenticationInfoResult, num_auth_vectors = %zu\n",
 | 
				
			||||||
 | 
							gsup_msg->num_auth_vectors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gsup_msg->num_auth_vectors > 0) {
 | 
				
			||||||
 | 
							op = conn->sec_operation;
 | 
				
			||||||
 | 
							memcpy(&op->atuple, gsup_msg->auth_vectors, sizeof(struct gsm_auth_vectors));
 | 
				
			||||||
 | 
							db_sync_lastauthtuple_for_subscr(&op->atuple, subscr);
 | 
				
			||||||
 | 
							gsm48_tx_mm_auth_req(conn, op->atuple.rand, op->atuple.key_seq);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int subscr_handle_sup_upd_loc_res(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
														struct osmo_gsup_message *gsup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t msisdn_lv[10];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!subscr->group) {
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_ERROR, subscr,
 | 
				
			||||||
 | 
								"Update location result was received, but LUR procedure timedout.\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gsup_msg->msisdn_enc) {
 | 
				
			||||||
 | 
							if (gsup_msg->msisdn_enc_len > sizeof(msisdn_lv) - 1) {
 | 
				
			||||||
 | 
								LOGP(DSUP, LOGL_ERROR, "MSISDN too long (%zu)\n",
 | 
				
			||||||
 | 
									gsup_msg->msisdn_enc_len);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								msisdn_lv[0] = gsup_msg->msisdn_enc_len;
 | 
				
			||||||
 | 
								memcpy(msisdn_lv+1, gsup_msg->msisdn_enc,
 | 
				
			||||||
 | 
									gsup_msg->msisdn_enc_len);
 | 
				
			||||||
 | 
								gsm48_decode_bcd_number(subscr->extension, sizeof(subscr->extension),
 | 
				
			||||||
 | 
																						msisdn_lv,0);
 | 
				
			||||||
 | 
								db_sync_subscriber(subscr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn) {
 | 
				
			||||||
 | 
							if (conn->loc_operation)
 | 
				
			||||||
 | 
								conn->loc_operation->waiting_for_remote_accept = 0;
 | 
				
			||||||
 | 
							gsm0408_authorize(conn,NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int subscr_handle_sup_purge_ms_res(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
														struct osmo_gsup_message *gsup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						LOGP(DSUP, LOGL_INFO, "SUP PURGE MS result OK for IMSI:%s\n", subscr->imsi);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int check_cause(int cause)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (cause) {
 | 
				
			||||||
 | 
						case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
 | 
				
			||||||
 | 
						case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
 | 
				
			||||||
 | 
							return EACCES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
 | 
				
			||||||
 | 
							return EHOSTUNREACH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int subscr_handle_sup_upd_loc_err(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
														struct osmo_gsup_message *gsup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int cause_err;
 | 
				
			||||||
 | 
						struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cause_err = check_cause(gsup_msg->cause);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUBSCRP(LOGL_DEBUG, subscr,
 | 
				
			||||||
 | 
							"Update location has failed with cause %d, handled as: %s\n",
 | 
				
			||||||
 | 
							gsup_msg->cause, strerror(cause_err));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (cause_err) {
 | 
				
			||||||
 | 
						case EACCES:
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_NOTICE, subscr,
 | 
				
			||||||
 | 
								"GSM update location failed, access denied, "
 | 
				
			||||||
 | 
								"MM cause = '%s' (%d)\n",
 | 
				
			||||||
 | 
								get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
 | 
				
			||||||
 | 
								gsup_msg->cause);
 | 
				
			||||||
 | 
							gsm0408_loc_upd_rej(conn, gsup_msg->cause);
 | 
				
			||||||
 | 
							release_loc_updating_req(conn, 0);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case EHOSTUNREACH:
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_NOTICE, subscr,
 | 
				
			||||||
 | 
								"GSM update location failed, MM cause = '%s' (%d)\n",
 | 
				
			||||||
 | 
								get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
 | 
				
			||||||
 | 
								gsup_msg->cause);
 | 
				
			||||||
 | 
							// TODO: Try to find subscriber in local HLR?
 | 
				
			||||||
 | 
							gsm0408_loc_upd_rej(conn, gsup_msg->cause);
 | 
				
			||||||
 | 
							release_loc_updating_req(conn, 0);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
						case EINVAL:
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_ERROR, subscr,
 | 
				
			||||||
 | 
								"SUP protocol remote error, MM cause = '%s' (%d)\n",
 | 
				
			||||||
 | 
								get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
 | 
				
			||||||
 | 
								gsup_msg->cause);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -gsup_msg->cause;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					static int subscr_handle_sup_auth_err(struct gsm_subscriber *subscr,
 | 
				
			||||||
 | 
										    struct osmo_gsup_message *gsup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int cause_err;
 | 
				
			||||||
 | 
						struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
 | 
				
			||||||
 | 
						gsm_cbfn *cb = conn->sec_operation->cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cause_err = check_cause(gsup_msg->cause);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUBSCRP(LOGL_DEBUG, subscr,
 | 
				
			||||||
 | 
							"Send authentication info has failed with cause %d, "
 | 
				
			||||||
 | 
							"handled as: %s\n",
 | 
				
			||||||
 | 
							gsup_msg->cause, strerror(cause_err));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (cause_err) {
 | 
				
			||||||
 | 
						case EACCES:
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_NOTICE, subscr,
 | 
				
			||||||
 | 
								"GSM send auth info req failed, access denied, "
 | 
				
			||||||
 | 
								"MM cause = '%s' (%d)\n",
 | 
				
			||||||
 | 
								get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
 | 
				
			||||||
 | 
								gsup_msg->cause);
 | 
				
			||||||
 | 
							if (cb)
 | 
				
			||||||
 | 
								cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED,
 | 
				
			||||||
 | 
								   NULL, conn, conn->sec_operation->cb_data);
 | 
				
			||||||
 | 
							release_security_operation(conn);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case EHOSTUNREACH:
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_NOTICE, subscr,
 | 
				
			||||||
 | 
								"GSM send auth info req failed, MM cause = '%s' (%d)\n",
 | 
				
			||||||
 | 
								get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
 | 
				
			||||||
 | 
								gsup_msg->cause);
 | 
				
			||||||
 | 
							// TODO: Try to resend auth request?
 | 
				
			||||||
 | 
							if (cb)
 | 
				
			||||||
 | 
								cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED,
 | 
				
			||||||
 | 
								   NULL, conn, conn->sec_operation->cb_data);
 | 
				
			||||||
 | 
							release_security_operation(conn);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
						case EINVAL:
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_ERROR, subscr,
 | 
				
			||||||
 | 
								"SUP protocol remote error, MM cause = '%s' (%d)\n",
 | 
				
			||||||
 | 
								get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
 | 
				
			||||||
 | 
								gsup_msg->cause);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -gsup_msg->cause;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static int subscr_handle_unknown_imsi(struct gsup_client *sup_client,
 | 
				
			||||||
 | 
														  struct osmo_gsup_message *gsup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
 | 
				
			||||||
 | 
							subscr_tx_sup_error_reply(sup_client, NULL, gsup_msg,
 | 
				
			||||||
 | 
											GMM_CAUSE_IMSI_UNKNOWN);
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_NOTICE,
 | 
				
			||||||
 | 
							     "Unknown IMSI %s, discarding SUP request "
 | 
				
			||||||
 | 
							     "of type 0x%02x\n",
 | 
				
			||||||
 | 
							     gsup_msg->imsi, gsup_msg->message_type);
 | 
				
			||||||
 | 
						} else if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_NOTICE,
 | 
				
			||||||
 | 
							     "Unknown IMSI %s, discarding SUP error "
 | 
				
			||||||
 | 
							     "of type 0x%02x, cause '%s' (%d)\n",
 | 
				
			||||||
 | 
							     gsup_msg->imsi, gsup_msg->message_type,
 | 
				
			||||||
 | 
							     get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
 | 
				
			||||||
 | 
							     gsup_msg->cause);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_NOTICE,
 | 
				
			||||||
 | 
							     "Unknown IMSI %s, discarding SUP response "
 | 
				
			||||||
 | 
							     "of type 0x%02x\n",
 | 
				
			||||||
 | 
							     gsup_msg->imsi, gsup_msg->message_type);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -GMM_CAUSE_IMSI_UNKNOWN;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int subscr_rx_sup_message(struct gsup_client *sup_client, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t *data = msgb_l2(msg);
 | 
				
			||||||
 | 
						size_t data_len = msgb_l2len(msg);
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct osmo_gsup_message gsup_msg = {0};
 | 
				
			||||||
 | 
						struct gsm_subscriber *subscr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*data == OSMO_GSUP_MSGT_SMS) {
 | 
				
			||||||
 | 
							return rx_sms_message(sup_client, data, data_len);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rc = osmo_gsup_decode(data, data_len, &gsup_msg);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "decoding SUP message fails with error '%s' (%d)\n",
 | 
				
			||||||
 | 
							     get_value_string(gsm48_gmm_cause_names, -rc), -rc);
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!gsup_msg.imsi[0]) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "Missing IMSI in SUP message\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
 | 
				
			||||||
 | 
								subscr_tx_sup_error_reply(sup_client, NULL, &gsup_msg,
 | 
				
			||||||
 | 
												GMM_CAUSE_INV_MAND_INFO);
 | 
				
			||||||
 | 
							return -GMM_CAUSE_INV_MAND_INFO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!gsup_msg.cause && OSMO_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
 | 
				
			||||||
 | 
							gsup_msg.cause = GMM_CAUSE_NET_FAIL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						subscr = subscr_get_by_imsi(NULL, gsup_msg.imsi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!subscr) {
 | 
				
			||||||
 | 
							return subscr_handle_unknown_imsi(sup_client, &gsup_msg);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUBSCRP(LOGL_INFO, subscr,
 | 
				
			||||||
 | 
							"Received SUP message of type 0x%02x\n", gsup_msg.message_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (gsup_msg.message_type) {
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
 | 
				
			||||||
 | 
							rc = subscr_handle_sup_auth_res(sup_client, subscr, &gsup_msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
 | 
				
			||||||
 | 
							rc = subscr_handle_sup_auth_err(subscr, &gsup_msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT:
 | 
				
			||||||
 | 
							rc = subscr_handle_sup_upd_loc_res(subscr, &gsup_msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR:
 | 
				
			||||||
 | 
							rc = subscr_handle_sup_upd_loc_err(subscr, &gsup_msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_PURGE_MS_ERROR:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
 | 
				
			||||||
 | 
							rc = subscr_handle_sup_purge_ms_res(subscr, &gsup_msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_DELETE_DATA_REQUEST:
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_ERROR, subscr,
 | 
				
			||||||
 | 
								"Rx SUP message type %d not yet implemented\n",
 | 
				
			||||||
 | 
								gsup_msg.message_type);
 | 
				
			||||||
 | 
							subscr_tx_sup_error_reply(sup_client, subscr, &gsup_msg,
 | 
				
			||||||
 | 
											GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
 | 
				
			||||||
 | 
							rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOGGSUBSCRP(LOGL_ERROR, subscr,
 | 
				
			||||||
 | 
								"Rx SUP message type %d not valid at SGSN\n",
 | 
				
			||||||
 | 
								gsup_msg.message_type);
 | 
				
			||||||
 | 
							if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
 | 
				
			||||||
 | 
								subscr_tx_sup_error_reply(sup_client, subscr, &gsup_msg,
 | 
				
			||||||
 | 
												GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
 | 
				
			||||||
 | 
							rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						subscr_put(subscr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sup_read_cb(struct gsup_client *sup_client, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = subscr_rx_sup_message(sup_client, msg);
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										93
									
								
								openbsc/src/libmsc/gsm_ussd_map.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								openbsc/src/libmsc/gsm_ussd_map.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
				
			|||||||
 | 
					/* GSM USSD external MAP interface */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (C) 2015 by Sergey Kostanbaev <sergey.kostanbaev@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/gsm_ussd_map.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_subscriber.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_04_08.h>
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					#include <openbsc/db.h>
 | 
				
			||||||
 | 
					#include <openbsc/chan_alloc.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsup.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsup_client.h>
 | 
				
			||||||
 | 
					#include <openbsc/osmo_msc.h>
 | 
				
			||||||
 | 
					#include <openbsc/gprs_utils.h>
 | 
				
			||||||
 | 
					#include <openbsc/ussd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ussd_map_tx_message(struct gsm_network* net,
 | 
				
			||||||
 | 
								struct ss_header *req,
 | 
				
			||||||
 | 
								const char* extension,
 | 
				
			||||||
 | 
								uint32_t ref,
 | 
				
			||||||
 | 
								const uint8_t* component_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = gsup_client_msgb_alloc();
 | 
				
			||||||
 | 
						if (!msg)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						subscr_uss_message(msg, req, extension, ref, component_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gsup_client_send(net->ussd_sup_client, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ussd_map_rx_message_int(struct gsm_network *net, const uint8_t* data, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char extension[32] = {0};
 | 
				
			||||||
 | 
						uint32_t ref;
 | 
				
			||||||
 | 
						struct ss_header ss;
 | 
				
			||||||
 | 
						memset(&ss, 0, sizeof(ss));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rx_uss_message_parse(data, len, &ss, &ref, extension, sizeof(extension))) {
 | 
				
			||||||
 | 
							LOGP(DSS, LOGL_ERROR, "Can't parse SUP MAP SS message\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DSS, LOGL_ERROR, "Got type=0x%02x len=%d\n",
 | 
				
			||||||
 | 
						     ss.message_type, ss.component_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return on_ussd_response(net, ref, &ss, data + ss.component_offset, extension);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ussd_map_rx_message(struct gsup_client *sup_client, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t *data = msgb_l2(msg);
 | 
				
			||||||
 | 
						size_t data_len = msgb_l2len(msg);
 | 
				
			||||||
 | 
						struct gsm_network *gsmnet = (struct gsm_network *)sup_client->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*data != OSMO_GSUP_MSGT_USSD_MAP) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ussd_map_rx_message_int(gsmnet, data, data_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ussd_map_read_cb(struct gsup_client *sup_client, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ussd_map_rx_message(sup_client, msg);
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										211
									
								
								openbsc/src/libmsc/gsm_ussd_map_proto.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								openbsc/src/libmsc/gsm_ussd_map_proto.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,211 @@
 | 
				
			|||||||
 | 
					/* GSM USSD external MAP protocol on pseudo TCAP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (C) 2015 by Sergey Kostanbaev <sergey.kostanbaev@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/gsm_ussd_map.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_ussd_map_proto.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_subscriber.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_04_08.h>
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					#include <openbsc/db.h>
 | 
				
			||||||
 | 
					#include <openbsc/chan_alloc.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsup.h>
 | 
				
			||||||
 | 
					#include <openbsc/osmo_msc.h>
 | 
				
			||||||
 | 
					#include <openbsc/gprs_utils.h>
 | 
				
			||||||
 | 
					#include <openbsc/ussd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* 0 - OSMO_GSUP_MSGT_USSD_MAP constant
 | 
				
			||||||
 | 
					* 1 - LEN
 | 
				
			||||||
 | 
					* 2 - message_type [ REGISTER / FACILITY / RELEASE COMPLETE ]
 | 
				
			||||||
 | 
					* 3,4,5,6 - tid          ID associated with the session
 | 
				
			||||||
 | 
					* 7 - FMAP_MSISDN constant
 | 
				
			||||||
 | 
					* 8 - extention_len
 | 
				
			||||||
 | 
					* 9..x -  extention
 | 
				
			||||||
 | 
					* x+1 .. original MAP message
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int subscr_uss_message(struct msgb *msg,
 | 
				
			||||||
 | 
							       struct ss_header *req,
 | 
				
			||||||
 | 
							       const char* extension,
 | 
				
			||||||
 | 
							       uint32_t ref,
 | 
				
			||||||
 | 
							       const uint8_t* component_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t bcd_lvlen;
 | 
				
			||||||
 | 
						uint8_t offset = 0;
 | 
				
			||||||
 | 
						uint8_t *gsup_indicator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_indicator = msgb_put(msg, 7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* First byte should always be OSMO_GSUP_MSGT_USSD_MAP */
 | 
				
			||||||
 | 
						gsup_indicator[offset++] = OSMO_GSUP_MSGT_USSD_MAP;
 | 
				
			||||||
 | 
						gsup_indicator[offset++] = 0; // Total length
 | 
				
			||||||
 | 
						gsup_indicator[offset++] = req->message_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_indicator[offset++] = ref >> 24;
 | 
				
			||||||
 | 
						gsup_indicator[offset++] = ref >> 16;
 | 
				
			||||||
 | 
						gsup_indicator[offset++] = ref >> 8;
 | 
				
			||||||
 | 
						gsup_indicator[offset++] = ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (extension) {
 | 
				
			||||||
 | 
							gsup_indicator[offset++] = FMAP_MSISDN;
 | 
				
			||||||
 | 
							bcd_lvlen = gsm48_encode_bcd_number(gsup_indicator + offset,
 | 
				
			||||||
 | 
											    32, 0, extension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							offset += bcd_lvlen;
 | 
				
			||||||
 | 
							msgb_put(msg, bcd_lvlen + 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (component_data) {
 | 
				
			||||||
 | 
							msgb_put(msg, req->component_length);
 | 
				
			||||||
 | 
							memcpy(gsup_indicator + offset, component_data, req->component_length);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_indicator[1] = offset + req->component_length - 2; //except OSMO_GSUP_MSGT_USSD_MAP and length field
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						gsup_indicator[6] = req->component_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* invokeId */
 | 
				
			||||||
 | 
						msgb_tlv_put(msg, GSM0480_COMPIDTAG_INVOKE_ID, 1, &req->invoke_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* opCode */
 | 
				
			||||||
 | 
						msgb_tlv_put(msg, GSM0480_OPERATION_CODE, 1, &req->opcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (req->ussd_text_len > 0) {
 | 
				
			||||||
 | 
							msgb_tlv_put(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_len + 1, &req->ussd_text_language);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (extension) {
 | 
				
			||||||
 | 
							uint8_t bcd_buf[32];
 | 
				
			||||||
 | 
							bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0,
 | 
				
			||||||
 | 
											  extension);
 | 
				
			||||||
 | 
							msgb_tlv_put(msg, FMAP_MSISDN, bcd_len - 1, &bcd_buf[1]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* fill actual length */
 | 
				
			||||||
 | 
						gsup_indicator[7] = 3 + 3 + (req->ussd_text_len + 1 + 2) + (bcd_len + 2);;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* wrap with GSM0480_CTYPE_INVOKE */
 | 
				
			||||||
 | 
						// gsm0480_wrap_invoke(msg, req->opcode, invoke_id);
 | 
				
			||||||
 | 
						// gsup_indicator = msgb_push(msgb, 1);
 | 
				
			||||||
 | 
						// gsup_indicator[0] = OSMO_GSUP_MSGT_MAP;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int rx_uss_message_parse(const uint8_t* data,
 | 
				
			||||||
 | 
								 size_t len,
 | 
				
			||||||
 | 
								 struct ss_header *ss,
 | 
				
			||||||
 | 
								 uint32_t *pref,
 | 
				
			||||||
 | 
								 char* extention,
 | 
				
			||||||
 | 
								 size_t extention_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t ext_len;
 | 
				
			||||||
 | 
						const uint8_t* const_data = data + 1; // Skip constant
 | 
				
			||||||
 | 
						uint32_t ref;
 | 
				
			||||||
 | 
						int total_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len < 7)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* skip OSMO_GSUP_MSGT_MAP */
 | 
				
			||||||
 | 
						total_len        = *(const_data++);
 | 
				
			||||||
 | 
						ss->message_type = *(const_data++);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ref = ((uint32_t)(*(const_data++))) << 24;
 | 
				
			||||||
 | 
						ref |= ((uint32_t)(*(const_data++))) << 16;
 | 
				
			||||||
 | 
						ref |= ((uint32_t)(*(const_data++))) << 8;
 | 
				
			||||||
 | 
						ref |= ((uint32_t)(*(const_data++)));
 | 
				
			||||||
 | 
						if (pref)
 | 
				
			||||||
 | 
							*pref = ref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						total_len -= 4 + 1; // ref + sizeof(len)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*const_data == FMAP_MSISDN) {
 | 
				
			||||||
 | 
							ext_len = *(++const_data);
 | 
				
			||||||
 | 
							if (extention) {
 | 
				
			||||||
 | 
								gsm48_decode_bcd_number(extention,
 | 
				
			||||||
 | 
											extention_len,
 | 
				
			||||||
 | 
											const_data,
 | 
				
			||||||
 | 
											0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							const_data += ext_len + 1;
 | 
				
			||||||
 | 
							total_len -= ext_len + 2; // tag FMAP_MSISDN + sizeof(len)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ss->component_offset = const_data - data;
 | 
				
			||||||
 | 
						ss->component_length = total_len; //data[ss->component_offset + 1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						ss->component_type = *(++const_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* skip full len and move to component id */
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*const_data != GSM0480_COMPIDTAG_INVOKE_ID) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
						ss->invoke_id = *const_data;
 | 
				
			||||||
 | 
						const_data++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						if (*const_data != GSM0480_OPERATION_CODE) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
						ss->opcode = *const_data;
 | 
				
			||||||
 | 
						const_data++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (const_data - data < len) {
 | 
				
			||||||
 | 
							uint8_t len;
 | 
				
			||||||
 | 
							switch (*const_data) {
 | 
				
			||||||
 | 
							case ASN1_OCTET_STRING_TAG:
 | 
				
			||||||
 | 
								ss->ussd_text_len = len = (*(++const_data) - 1);
 | 
				
			||||||
 | 
								ss->ussd_text_language = *(++const_data);
 | 
				
			||||||
 | 
								memcpy(ss->ussd_text,
 | 
				
			||||||
 | 
									++const_data,
 | 
				
			||||||
 | 
									(len > MAX_LEN_USSD_STRING) ? MAX_LEN_USSD_STRING : len);
 | 
				
			||||||
 | 
								const_data += len;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case FMAP_MSISDN:
 | 
				
			||||||
 | 
								len = *(++const_data);
 | 
				
			||||||
 | 
								gsm48_decode_bcd_number(extention,
 | 
				
			||||||
 | 
											extention_len,
 | 
				
			||||||
 | 
											const_data,
 | 
				
			||||||
 | 
											0);
 | 
				
			||||||
 | 
								const_data += len + 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								DEBUGP(DSS, "Unknown code: %d\n", *const_data);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -61,6 +61,22 @@ struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
 | 
				
			|||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct gsm_trans *trans_find_by_msgref(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
 | 
										uint8_t msg_ref)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_trans *trans;
 | 
				
			||||||
 | 
						struct gsm_network *net = conn->bts->network;
 | 
				
			||||||
 | 
						struct gsm_subscriber *subscr = conn->subscr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llist_for_each_entry(trans, &net->trans_list, entry) {
 | 
				
			||||||
 | 
							if (trans->subscr == subscr &&
 | 
				
			||||||
 | 
							    trans->protocol == GSM48_PDISC_SMS &&
 | 
				
			||||||
 | 
							    trans->msg_ref == msg_ref)
 | 
				
			||||||
 | 
								return trans;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gsm_trans *trans_alloc(struct gsm_network *net,
 | 
					struct gsm_trans *trans_alloc(struct gsm_network *net,
 | 
				
			||||||
			      struct gsm_subscriber *subscr,
 | 
								      struct gsm_subscriber *subscr,
 | 
				
			||||||
			      uint8_t protocol, uint8_t trans_id,
 | 
								      uint8_t protocol, uint8_t trans_id,
 | 
				
			||||||
@@ -80,6 +96,7 @@ struct gsm_trans *trans_alloc(struct gsm_network *net,
 | 
				
			|||||||
	trans->protocol = protocol;
 | 
						trans->protocol = protocol;
 | 
				
			||||||
	trans->transaction_id = trans_id;
 | 
						trans->transaction_id = trans_id;
 | 
				
			||||||
	trans->callref = callref;
 | 
						trans->callref = callref;
 | 
				
			||||||
 | 
						trans->sms_local = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trans->net = net;
 | 
						trans->net = net;
 | 
				
			||||||
	llist_add_tail(&trans->entry, &net->trans_list);
 | 
						llist_add_tail(&trans->entry, &net->trans_list);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,49 +33,83 @@
 | 
				
			|||||||
#include <openbsc/gsm_subscriber.h>
 | 
					#include <openbsc/gsm_subscriber.h>
 | 
				
			||||||
#include <openbsc/debug.h>
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
#include <openbsc/osmo_msc.h>
 | 
					#include <openbsc/osmo_msc.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_ussd_map.h>
 | 
				
			||||||
 | 
					#include <openbsc/ussd.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm_utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm0480.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/protocol/gsm_04_08.h>
 | 
				
			||||||
 | 
					#include <openbsc/transaction.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Last uniq generated session id */
 | 
				
			||||||
 | 
					static uint32_t s_uniq_ussd_sessiod_id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Forward declaration of USSD handler for USSD MAP interface */
 | 
				
			||||||
 | 
					static int handle_rcv_ussd_sup(struct gsm_subscriber_connection *conn, struct msgb *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Declarations of USSD strings to be recognised */
 | 
					/* Declarations of USSD strings to be recognised */
 | 
				
			||||||
const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
 | 
					const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Forward declarations of network-specific handler functions */
 | 
					/* Forward declarations of network-specific handler functions */
 | 
				
			||||||
static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req);
 | 
					static int send_own_number(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
 | 
								   const struct ss_header *reqhdr,
 | 
				
			||||||
 | 
								   const struct ss_request *req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Entrypoint - handler function common to all mobile-originated USSDs */
 | 
					/* Entrypoint - handler function common to all mobile-originated USSDs */
 | 
				
			||||||
int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
 | 
					int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
						struct ss_header reqhdr;
 | 
				
			||||||
	struct ss_request req;
 | 
						struct ss_request req;
 | 
				
			||||||
 | 
						char request_string[MAX_LEN_USSD_STRING + 1];
 | 
				
			||||||
	struct gsm48_hdr *gh;
 | 
						struct gsm48_hdr *gh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (conn->subscr->group->net->ussd_sup_client)
 | 
				
			||||||
 | 
							return handle_rcv_ussd_sup(conn, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&req, 0, sizeof(req));
 | 
						memset(&req, 0, sizeof(req));
 | 
				
			||||||
 | 
						memset(&reqhdr, 0, sizeof(reqhdr));
 | 
				
			||||||
	gh = msgb_l3(msg);
 | 
						gh = msgb_l3(msg);
 | 
				
			||||||
	rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
 | 
						rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &reqhdr);
 | 
				
			||||||
	if (!rc) {
 | 
						if (!rc) {
 | 
				
			||||||
		DEBUGP(DMM, "Unhandled SS\n");
 | 
							DEBUGP(DSS, "Incorrect SS header\n");
 | 
				
			||||||
		rc = gsm0480_send_ussd_reject(conn, msg, &req);
 | 
					 | 
				
			||||||
		msc_release_connection(conn);
 | 
							msc_release_connection(conn);
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Interrogation or releaseComplete? */
 | 
						rc = gsm0480_parse_ss_facility(gh->data + reqhdr.component_offset,
 | 
				
			||||||
	if (req.ussd_text[0] == '\0' || req.ussd_text[0] == 0xFF) {
 | 
									       reqhdr.component_length,
 | 
				
			||||||
		if (req.ss_code > 0) {
 | 
									       &req);
 | 
				
			||||||
			/* Assume interrogateSS or modification of it and reject */
 | 
						if (!rc) {
 | 
				
			||||||
			rc = gsm0480_send_ussd_reject(conn, msg, &req);
 | 
							DEBUGP(DSS, "Unhandled SS\n");
 | 
				
			||||||
 | 
							// TODO req.invoke_id may not be set!!!
 | 
				
			||||||
 | 
							rc = gsm0480_send_ussd_reject(conn, req.invoke_id, reqhdr.transaction_id);
 | 
				
			||||||
		msc_release_connection(conn);
 | 
							msc_release_connection(conn);
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		/* Still assuming a Release-Complete and returning */
 | 
					
 | 
				
			||||||
 | 
						if (reqhdr.message_type == GSM0480_MTYPE_RELEASE_COMPLETE)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (reqhdr.message_type != GSM0480_MTYPE_REGISTER ||
 | 
				
			||||||
 | 
								req.component_type != GSM0480_CTYPE_INVOKE ||
 | 
				
			||||||
 | 
								req.opcode != GSM0480_OP_CODE_PROCESS_USS_REQ ||
 | 
				
			||||||
 | 
								req.ussd_text_language != 0x0f)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							DEBUGP(DSS, "Unexpected SS\n");
 | 
				
			||||||
 | 
							rc = gsm0480_send_ussd_reject(conn, req.invoke_id, reqhdr.transaction_id);
 | 
				
			||||||
 | 
							msc_release_connection(conn);
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.ussd_text)) {
 | 
						gsm_7bit_decode_n_ussd(request_string, MAX_LEN_USSD_STRING, req.ussd_text, req.ussd_text_len);
 | 
				
			||||||
		DEBUGP(DMM, "USSD: Own number requested\n");
 | 
					
 | 
				
			||||||
		rc = send_own_number(conn, msg, &req);
 | 
						if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)request_string)) {
 | 
				
			||||||
 | 
							DEBUGP(DSS, "USSD: Own number requested\n");
 | 
				
			||||||
 | 
							rc = send_own_number(conn, &reqhdr, &req);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		DEBUGP(DMM, "Unhandled USSD %s\n", req.ussd_text);
 | 
							DEBUGP(DSS, "Unhandled USSD %s\n", request_string);
 | 
				
			||||||
		rc = gsm0480_send_ussd_reject(conn, msg, &req);
 | 
							rc = gsm0480_send_ussd_reject(conn, req.invoke_id, reqhdr.transaction_id);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check if we can release it */
 | 
						/* check if we can release it */
 | 
				
			||||||
@@ -84,12 +118,258 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* A network-specific handler function */
 | 
					/* A network-specific handler function */
 | 
				
			||||||
static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req)
 | 
					static int send_own_number(struct gsm_subscriber_connection *conn,
 | 
				
			||||||
 | 
								   const struct ss_header *reqhdr,
 | 
				
			||||||
 | 
								   const struct ss_request *req)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct ss_request rss;
 | 
				
			||||||
 | 
						struct ss_header rssh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *own_number = conn->subscr->extension;
 | 
						char *own_number = conn->subscr->extension;
 | 
				
			||||||
	char response_string[GSM_EXTENSION_LENGTH + 20];
 | 
						char response_string[GSM_EXTENSION_LENGTH + 20];
 | 
				
			||||||
 | 
						int response_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Need trailing CR as EOT character */
 | 
						/* Need trailing CR as EOT character */
 | 
				
			||||||
	snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
 | 
						snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
 | 
				
			||||||
	return gsm0480_send_ussd_response(conn, msg, response_string, req);
 | 
					
 | 
				
			||||||
 | 
						memset(&rss, 0, sizeof(rss));
 | 
				
			||||||
 | 
						gsm_7bit_encode_n_ussd(rss.ussd_text, MAX_LEN_USSD_STRING, response_string, &response_len);
 | 
				
			||||||
 | 
						rss.ussd_text_len = response_len;
 | 
				
			||||||
 | 
						rss.ussd_text_language = 0x0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rss.component_type = GSM0480_CTYPE_RETURN_RESULT;
 | 
				
			||||||
 | 
						rss.invoke_id = req->invoke_id;
 | 
				
			||||||
 | 
						rss.opcode = GSM0480_OP_CODE_PROCESS_USS_REQ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rssh.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
				
			||||||
 | 
						rssh.transaction_id = reqhdr->transaction_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gsm0480_send_component(conn,
 | 
				
			||||||
 | 
									      gsm0480_compose_ussd_component(&rss),
 | 
				
			||||||
 | 
									      &rssh);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ussd_sup_send_reject(struct gsm_network *conn, uint32_t ref)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ss_header rej;
 | 
				
			||||||
 | 
						rej.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
				
			||||||
 | 
						rej.component_length = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						rej.component_type = GSM0480_CTYPE_REJECT;
 | 
				
			||||||
 | 
						rej.invoke_id = invokeid;
 | 
				
			||||||
 | 
						rej.opcode = opcode;
 | 
				
			||||||
 | 
						rej.ussd_text_len = 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return ussd_map_tx_message(conn, &rej, NULL, ref, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Callback from USSD MAP interface */
 | 
				
			||||||
 | 
					int on_ussd_response(struct gsm_network *net,
 | 
				
			||||||
 | 
							     uint32_t ref,
 | 
				
			||||||
 | 
							     struct ss_header *reqhdr,
 | 
				
			||||||
 | 
							     const uint8_t* component,
 | 
				
			||||||
 | 
							     const char *extention)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_trans *trans = trans_find_by_callref(net, ref);
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
						uint8_t *ptr8;
 | 
				
			||||||
 | 
						struct ss_header ssrep = *reqhdr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (reqhdr->message_type) {
 | 
				
			||||||
 | 
						case GSM0480_MTYPE_REGISTER:
 | 
				
			||||||
 | 
							DEBUGP(DSS, "Network originated USSD messages isn't supported yet!\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ussd_sup_send_reject(net, ref);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case GSM0480_MTYPE_FACILITY:
 | 
				
			||||||
 | 
						case GSM0480_MTYPE_RELEASE_COMPLETE:
 | 
				
			||||||
 | 
							if (!trans) {
 | 
				
			||||||
 | 
								DEBUGP(DSS, "No session was found for ref: %d!\n",
 | 
				
			||||||
 | 
								       ref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ussd_sup_send_reject(net, ref);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							DEBUGP(DSS, "Unknown message type 0x%02x\n", reqhdr->message_type);
 | 
				
			||||||
 | 
							ussd_sup_send_reject(net, ref);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						req->invoke_id = trans->ss.invoke_id;
 | 
				
			||||||
 | 
						req->transaction_id = (trans->transaction_id << 4) ^ 0x80;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (req->component_type != GSM0480_CTYPE_REJECT) {
 | 
				
			||||||
 | 
							rc = gsm0480_send_ussd(trans->conn, req);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							rc = gsm0480_send_ussd_reject(trans->conn, req);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						msg = gsm48_msgb_alloc_name("");
 | 
				
			||||||
 | 
						ptr8 = msgb_put(msg, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(ptr8, component, reqhdr->component_length);
 | 
				
			||||||
 | 
						msgb_put(msg, reqhdr->component_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ssrep.transaction_id = (trans->transaction_id << 4) ^ 0x80;
 | 
				
			||||||
 | 
						rc = gsm0480_send_component(trans->conn, msg, &ssrep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (reqhdr->message_type == GSM0480_MTYPE_RELEASE_COMPLETE) {
 | 
				
			||||||
 | 
							struct gsm_subscriber_connection* conn = trans->conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							trans_free(trans);
 | 
				
			||||||
 | 
							msc_release_connection(conn);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int get_invoke_id(const uint8_t* data, uint8_t len, uint8_t* pinvoke_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* 0:    CTYPE tag
 | 
				
			||||||
 | 
						 * 1..x: CTYPE len
 | 
				
			||||||
 | 
						 * x:    INVOKE_ID tag
 | 
				
			||||||
 | 
						 * x+1:  INVOKE_ID len
 | 
				
			||||||
 | 
						 * x+2:  INVOKE_ID value
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (len < 5)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned inv_offset = 2;
 | 
				
			||||||
 | 
						switch (data[0]) {
 | 
				
			||||||
 | 
						case GSM0480_CTYPE_INVOKE:
 | 
				
			||||||
 | 
						case GSM0480_CTYPE_RETURN_RESULT:
 | 
				
			||||||
 | 
							if (data[1] > 0x80)
 | 
				
			||||||
 | 
								inv_offset += data[1] & 0x7f;
 | 
				
			||||||
 | 
							if (inv_offset + 2 >= len)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							if (data[inv_offset] != GSM0480_COMPIDTAG_INVOKE_ID)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							*pinvoke_id = data[inv_offset + 2];
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Handler function common to all mobile-originated USSDs in case if USSD MAP enabled  */
 | 
				
			||||||
 | 
					static int handle_rcv_ussd_sup(struct gsm_subscriber_connection *conn, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						struct gsm48_hdr *gh = msgb_l3(msg);
 | 
				
			||||||
 | 
						struct ss_header reqhdr;
 | 
				
			||||||
 | 
						struct gsm_trans *trans = NULL;
 | 
				
			||||||
 | 
						uint8_t transaction_id = ((gh->proto_discr >> 4) ^ 0x8); /* flip */
 | 
				
			||||||
 | 
						uint8_t invoke_id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!conn->subscr)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&reqhdr, 0, sizeof(reqhdr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DEBUGP(DSS, "handle ussd tid=%d: %s\n", transaction_id, msgb_hexdump(msg));
 | 
				
			||||||
 | 
						trans = trans_find_by_id(conn, GSM48_PDISC_NC_SS, transaction_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &reqhdr);
 | 
				
			||||||
 | 
						if (!rc) {
 | 
				
			||||||
 | 
							DEBUGP(DSS, "Incorrect SS header\n");
 | 
				
			||||||
 | 
							if (!trans) {
 | 
				
			||||||
 | 
								goto release_conn;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* don't know how to process */
 | 
				
			||||||
 | 
							goto failed_transaction;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (reqhdr.message_type) {
 | 
				
			||||||
 | 
						case GSM0480_MTYPE_REGISTER:
 | 
				
			||||||
 | 
							if (trans) {
 | 
				
			||||||
 | 
								/* we already have a transaction, ignore this message */
 | 
				
			||||||
 | 
								goto release_conn;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!get_invoke_id(gh->data + reqhdr.component_offset,
 | 
				
			||||||
 | 
									   reqhdr.component_length,
 | 
				
			||||||
 | 
									   &invoke_id)) {
 | 
				
			||||||
 | 
								DEBUGP(DSS, "Incorrect InvokeID in transaction\n");
 | 
				
			||||||
 | 
								goto release_conn;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							trans = trans_alloc(conn->bts->network, conn->subscr,
 | 
				
			||||||
 | 
									    GSM48_PDISC_NC_SS,
 | 
				
			||||||
 | 
									    transaction_id, s_uniq_ussd_sessiod_id++);
 | 
				
			||||||
 | 
							if (!trans) {
 | 
				
			||||||
 | 
								DEBUGP(DSS, "Failed to create new ussd transaction\n");
 | 
				
			||||||
 | 
								goto transaction_not_found;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							trans->conn = conn;
 | 
				
			||||||
 | 
							trans->ss.invoke_id = invoke_id;
 | 
				
			||||||
 | 
							trans->ss.mo = 1;
 | 
				
			||||||
 | 
							trans->ss.dirty = 1;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case GSM0480_MTYPE_FACILITY:
 | 
				
			||||||
 | 
							if (!trans) {
 | 
				
			||||||
 | 
								DEBUGP(DSS, "No session found tid=%d\n",
 | 
				
			||||||
 | 
								       transaction_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!get_invoke_id(gh->data + reqhdr.component_offset,
 | 
				
			||||||
 | 
										   reqhdr.component_length,
 | 
				
			||||||
 | 
										   &invoke_id)) {
 | 
				
			||||||
 | 
									DEBUGP(DSS, "Incorrect InvokeID in transaction\n");
 | 
				
			||||||
 | 
									goto release_conn;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								goto transaction_not_found;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case GSM0480_MTYPE_RELEASE_COMPLETE:
 | 
				
			||||||
 | 
							if (!trans) {
 | 
				
			||||||
 | 
								DEBUGP(DSS, "RELEASE_COMPLETE to non-existing transaction!\n");
 | 
				
			||||||
 | 
								goto release_conn;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							trans_free(trans);
 | 
				
			||||||
 | 
							goto release_conn;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = ussd_map_tx_message(conn->subscr->group->net, &reqhdr,
 | 
				
			||||||
 | 
									 conn->subscr->extension, trans->callref,
 | 
				
			||||||
 | 
									 gh->data + reqhdr.component_offset);
 | 
				
			||||||
 | 
						if (rc) {
 | 
				
			||||||
 | 
							/* do not send reject if we failed with the message */
 | 
				
			||||||
 | 
							trans->ss.dirty = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							DEBUGP(DSS, "Unable tp send uss over sup reason: %d\n", rc);
 | 
				
			||||||
 | 
							goto failed_transaction;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					failed_transaction:
 | 
				
			||||||
 | 
						trans_free(trans);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					transaction_not_found:
 | 
				
			||||||
 | 
						gsm0480_send_ussd_reject(conn, invoke_id, transaction_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					release_conn:
 | 
				
			||||||
 | 
						msc_release_connection(conn);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void _ussd_trans_free(struct gsm_trans *trans)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (trans->ss.dirty) {
 | 
				
			||||||
 | 
							trans->ss.dirty = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//ussd_sup_send_reject(trans->net, trans->callref, trans->ss.invoke_id, 0);
 | 
				
			||||||
 | 
							ussd_sup_send_reject(trans->net, trans->callref);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,8 +50,11 @@
 | 
				
			|||||||
#include <openbsc/sms_queue.h>
 | 
					#include <openbsc/sms_queue.h>
 | 
				
			||||||
#include <openbsc/mncc_int.h>
 | 
					#include <openbsc/mncc_int.h>
 | 
				
			||||||
#include <openbsc/handover.h>
 | 
					#include <openbsc/handover.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsup_client.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_ussd_map.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/vty/logging.h>
 | 
					#include <osmocom/vty/logging.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_sup.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "meas_feed.h"
 | 
					#include "meas_feed.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1027,6 +1030,53 @@ DEFUN(meas_feed_scenario, meas_feed_scenario_cmd,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(sup_ussd_destination, sup_ussd_destination_cmd,
 | 
				
			||||||
 | 
						"sup-ussd destination ADDR <0-65535>",
 | 
				
			||||||
 | 
						"Enable SUP USSD socket to a given address/port" "destination\n" "address or hostname\n" "port number\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gsmnet->ussd_sup_client) {
 | 
				
			||||||
 | 
							LOGP(DSS, LOGL_FATAL, "Can't create two USSD SUP clients\n");
 | 
				
			||||||
 | 
							vty_out(vty, "%%USSD SUP client already configured%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsmnet->ussd_sup_client = gsup_client_create(
 | 
				
			||||||
 | 
							argv[0], atoi(argv[1]), &ussd_map_read_cb, NULL);
 | 
				
			||||||
 | 
						if (!gsmnet->ussd_sup_client) {
 | 
				
			||||||
 | 
							LOGP(DSS, LOGL_FATAL, "Cannot set up USSD SUP socket\n");
 | 
				
			||||||
 | 
							vty_out(vty, "%%Cannot set up USSD SUP socket%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsmnet->ussd_sup_client->data = gsmnet;
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(sms_destination, sms_destination_cmd,
 | 
				
			||||||
 | 
						"sms destination ADDR <0-65535>",
 | 
				
			||||||
 | 
						"Enable SMS socket to a given address/port" "destination\n" "address or hostname\n" "port number\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gsmnet->sms_client) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_FATAL, "Can't create two SMS clients\n");
 | 
				
			||||||
 | 
							vty_out(vty, "%%SMS client already configured%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsmnet->sms_client = gsup_client_create(
 | 
				
			||||||
 | 
							argv[0], atoi(argv[1]), &sup_read_cb, NULL);
 | 
				
			||||||
 | 
						if (!gsmnet->sms_client) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_FATAL, "Cannot set up SMS socket\n");
 | 
				
			||||||
 | 
							vty_out(vty, "%%Cannot set up SMS socket%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
							return CMD_WARNING;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						gsmnet->sms_client->net = gsmnet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(logging_fltr_imsi,
 | 
					DEFUN(logging_fltr_imsi,
 | 
				
			||||||
      logging_fltr_imsi_cmd,
 | 
					      logging_fltr_imsi_cmd,
 | 
				
			||||||
@@ -1199,6 +1249,8 @@ int bsc_vty_init_extra(void)
 | 
				
			|||||||
	install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd);
 | 
						install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd);
 | 
				
			||||||
	install_element(NITB_NODE, &cfg_nitb_assign_tmsi_cmd);
 | 
						install_element(NITB_NODE, &cfg_nitb_assign_tmsi_cmd);
 | 
				
			||||||
	install_element(NITB_NODE, &cfg_nitb_no_assign_tmsi_cmd);
 | 
						install_element(NITB_NODE, &cfg_nitb_no_assign_tmsi_cmd);
 | 
				
			||||||
 | 
						install_element(NITB_NODE, &sup_ussd_destination_cmd);
 | 
				
			||||||
 | 
						install_element(NITB_NODE, &sms_destination_cmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,6 +53,7 @@
 | 
				
			|||||||
#include <openbsc/ctrl.h>
 | 
					#include <openbsc/ctrl.h>
 | 
				
			||||||
#include <openbsc/osmo_bsc_rf.h>
 | 
					#include <openbsc/osmo_bsc_rf.h>
 | 
				
			||||||
#include <openbsc/smpp.h>
 | 
					#include <openbsc/smpp.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_sup.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../../bscconfig.h"
 | 
					#include "../../bscconfig.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -367,6 +368,18 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	printf("DB: Database prepared.\n");
 | 
						printf("DB: Database prepared.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Prepare HLR SUP socket if auth policy is "remote" or "remote-closed"*/
 | 
				
			||||||
 | 
						if (bsc_gsmnet->auth_policy == GSM_AUTH_POLICY_REMOTE ||
 | 
				
			||||||
 | 
						    bsc_gsmnet->auth_policy == GSM_AUTH_POLICY_REMOTE_CLOSED) {
 | 
				
			||||||
 | 
							bsc_gsmnet->hlr_sup_client = gsup_client_create(
 | 
				
			||||||
 | 
								"127.0.0.1", 8183,
 | 
				
			||||||
 | 
								&sup_read_cb, NULL);
 | 
				
			||||||
 | 
							if (!bsc_gsmnet->hlr_sup_client) {
 | 
				
			||||||
 | 
								LOGP(DSUP, LOGL_FATAL, "Cannot set up subscriber management\n");
 | 
				
			||||||
 | 
								exit(2);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* setup the timer */
 | 
						/* setup the timer */
 | 
				
			||||||
	db_sync_timer.cb = db_sync_timer_cb;
 | 
						db_sync_timer.cb = db_sync_timer_cb;
 | 
				
			||||||
	db_sync_timer.data = NULL;
 | 
						db_sync_timer.data = NULL;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								openbsc/src/reg-proxy/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								openbsc/src/reg-proxy/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
 | 
				
			||||||
 | 
					AM_CFLAGS=-Wall	$(COVERAGE_CFLAGS)			\
 | 
				
			||||||
 | 
					  	$(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS)
 | 
				
			||||||
 | 
					AM_LDFLAGS = $(COVERAGE_LDFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bin_PROGRAMS = reg-proxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					reg_proxy_SOURCES = \
 | 
				
			||||||
 | 
							../gprs/gprs_utils.c \
 | 
				
			||||||
 | 
							tcp_client.c sup_server.c sup.c sip.c sip_client.c reg_proxy.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					reg_proxy_LDADD = \
 | 
				
			||||||
 | 
							-losipparser2 -losip2 \
 | 
				
			||||||
 | 
							$(top_builddir)/src/libcommon/libcommon.a \
 | 
				
			||||||
 | 
							-ldbi $(LIBCRYPT)				   \
 | 
				
			||||||
 | 
							$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS)  \
 | 
				
			||||||
 | 
							$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										330
									
								
								openbsc/src/reg-proxy/reg_proxy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								openbsc/src/reg-proxy/reg_proxy.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,330 @@
 | 
				
			|||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define _GNU_SOURCE
 | 
				
			||||||
 | 
					#include <getopt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <sys/time.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ENABLE_TRACE
 | 
				
			||||||
 | 
					#include <osip2/osip.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//#define _GNU_SOURCE
 | 
				
			||||||
 | 
					//#include <getopt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//#include <openbsc/db.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					//#include <osmocom/abis/abis.h>
 | 
				
			||||||
 | 
					//#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
 | 
					#include <openbsc/signal.h>
 | 
				
			||||||
 | 
					//#include <openbsc/osmo_msc.h>
 | 
				
			||||||
 | 
					//#include <openbsc/osmo_msc_data.h>
 | 
				
			||||||
 | 
					//#include <openbsc/sms_queue.h>
 | 
				
			||||||
 | 
					//#include <openbsc/vty.h>
 | 
				
			||||||
 | 
					//#include <openbsc/bss.h>
 | 
				
			||||||
 | 
					//#include <openbsc/mncc.h>
 | 
				
			||||||
 | 
					//#include <openbsc/token_auth.h>
 | 
				
			||||||
 | 
					//#include <openbsc/handover_decision.h>
 | 
				
			||||||
 | 
					//#include <openbsc/rrlp.h>
 | 
				
			||||||
 | 
					//#include <osmocom/ctrl/control_if.h>
 | 
				
			||||||
 | 
					//#include <osmocom/ctrl/ports.h>
 | 
				
			||||||
 | 
					//#include <openbsc/ctrl.h>
 | 
				
			||||||
 | 
					//#include <openbsc/osmo_bsc_rf.h>
 | 
				
			||||||
 | 
					//#include <openbsc/smpp.h>
 | 
				
			||||||
 | 
					#include <openbsc/reg_proxy.h>
 | 
				
			||||||
 | 
					#include <openbsc/sup.h>
 | 
				
			||||||
 | 
					#include <openbsc/sip.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DIPA_PROXY_TEST 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *sip_src_ip = "127.0.0.1";
 | 
				
			||||||
 | 
					static const char *sip_dst_ip = "127.0.0.1";
 | 
				
			||||||
 | 
					static u_int16_t src_port = 5150;
 | 
				
			||||||
 | 
					static u_int16_t dst_port = 5060;
 | 
				
			||||||
 | 
					static int expires_time = 3600;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct log_info_cat ipa_proxy_test_cat[] = {
 | 
				
			||||||
 | 
						[DIPA_PROXY_TEST] = {
 | 
				
			||||||
 | 
							.name = "DLINP_IPA_PROXY_TEST",
 | 
				
			||||||
 | 
							.description = "IPA proxy test",
 | 
				
			||||||
 | 
							.color = "\033[1;35m",
 | 
				
			||||||
 | 
							.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct log_info ipa_proxy_test_log_info = {
 | 
				
			||||||
 | 
						.filter_fn = NULL,
 | 
				
			||||||
 | 
						.cat = ipa_proxy_test_cat,
 | 
				
			||||||
 | 
						.num_cat = ARRAY_SIZE(ipa_proxy_test_cat),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_usage()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("Usage: reg-proxy\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_help()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("  Some useful help...\n");
 | 
				
			||||||
 | 
						printf("  -h --help this text\n");
 | 
				
			||||||
 | 
						printf("  -S --sip-src-ip ip-addr Sip client IP address (source).\n");
 | 
				
			||||||
 | 
						printf("  -s --src-port port Sip client port (source).\n");
 | 
				
			||||||
 | 
						printf("  -D --sip-dst-ip ip-addr Sip server IP address (destination).\n");
 | 
				
			||||||
 | 
						printf("  -d --dst-port port Sip server port (destination).\n");
 | 
				
			||||||
 | 
						printf("  -t --expires-time Registration expiry time in seconds.\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'},
 | 
				
			||||||
 | 
								{"sip-src-ip", 1, 0, 'S'},
 | 
				
			||||||
 | 
								{"src-port", 1, 0, 's'},
 | 
				
			||||||
 | 
								{"sip-dst-ip", 1, 0, 'D'},
 | 
				
			||||||
 | 
								{"dst-port", 1, 0, 'd'},
 | 
				
			||||||
 | 
								{"expires-time", 1, 0, 't'},
 | 
				
			||||||
 | 
								{0, 0, 0, 0}
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							c = getopt_long(argc, argv, "hS:s:D:d:t:",
 | 
				
			||||||
 | 
									long_options, &option_index);
 | 
				
			||||||
 | 
							if (c == -1)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (c) {
 | 
				
			||||||
 | 
							case 'h':
 | 
				
			||||||
 | 
								print_usage();
 | 
				
			||||||
 | 
								print_help();
 | 
				
			||||||
 | 
								exit(0);
 | 
				
			||||||
 | 
							case 'S':
 | 
				
			||||||
 | 
								sip_src_ip = optarg;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 's':
 | 
				
			||||||
 | 
								src_port = atoi(optarg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'D':
 | 
				
			||||||
 | 
								sip_dst_ip = optarg;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'd':
 | 
				
			||||||
 | 
								dst_port = atoi(optarg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 't':
 | 
				
			||||||
 | 
								expires_time = atoi(optarg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								/* ignore */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct reg_proxy *reg_proxy_init()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct reg_proxy *reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = talloc_zero(tall_reg_ctx, struct reg_proxy);
 | 
				
			||||||
 | 
						if (!reg)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return reg;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void signal_handler(int signal)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						fprintf(stdout, "signal %u received\n", signal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (signal) {
 | 
				
			||||||
 | 
						case SIGINT:
 | 
				
			||||||
 | 
							//bsc_shutdown_net(bsc_gsmnet);
 | 
				
			||||||
 | 
							//osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
 | 
				
			||||||
 | 
							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(tall_reg_ctx, stderr);
 | 
				
			||||||
 | 
							talloc_report_full(tall_reg_ctx, stderr);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SIGUSR2:
 | 
				
			||||||
 | 
							talloc_report_full(tall_reg_ctx, stderr);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void printf_trace_func (char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const char* desc = "       ";
 | 
				
			||||||
 | 
					    switch(level)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    case OSIP_FATAL:
 | 
				
			||||||
 | 
					        desc = " FATAL ";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case OSIP_BUG:
 | 
				
			||||||
 | 
					        desc = "  BUG  ";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case OSIP_ERROR:
 | 
				
			||||||
 | 
					        desc = " ERROR ";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case OSIP_WARNING:
 | 
				
			||||||
 | 
					        desc = "WARNING";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case OSIP_INFO1:
 | 
				
			||||||
 | 
					        desc = " INFO1 ";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case OSIP_INFO2:
 | 
				
			||||||
 | 
					        desc = " INFO2 ";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case OSIP_INFO3:
 | 
				
			||||||
 | 
					        desc = " INFO3 ";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case OSIP_INFO4:
 | 
				
			||||||
 | 
					        desc = " INFO4 ";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        desc = "       ";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    printf ("|%s| <%s: %i> | ", desc, fi, li);
 | 
				
			||||||
 | 
					    vprintf(chfr, ap);
 | 
				
			||||||
 | 
					    printf ("\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void nict_trans_free(osip_t * osip)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int pos = 0;
 | 
				
			||||||
 | 
						while (!osip_list_eol(&osip->osip_nict_transactions, pos)) {
 | 
				
			||||||
 | 
							osip_transaction_t *tr = (osip_transaction_t*) osip_list_get(&osip->osip_nict_transactions, pos);
 | 
				
			||||||
 | 
							if (tr->state== NICT_TERMINATED)
 | 
				
			||||||
 | 
								osip_transaction_free(tr);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								pos++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						struct reg_proxy *reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tall_reg_ctx = talloc_named_const(NULL, 1, "reg_proxy");
 | 
				
			||||||
 | 
						//talloc_ctx_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//libosmo_abis_init(tall_reg_ctx);
 | 
				
			||||||
 | 
						osmo_init_logging(&log_info);
 | 
				
			||||||
 | 
						printf("Initializing OSIP\n");
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// use custom function
 | 
				
			||||||
 | 
						osip_trace_initialize_func(END_TRACE_LEVEL, &printf_trace_func);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//osmo_init_logging(&ipa_proxy_test_log_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* seed the PRNG */
 | 
				
			||||||
 | 
						//srand(time(NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
						if (db_init(database_name)) {
 | 
				
			||||||
 | 
							printf("DB: Failed to init database. Please check the option settings.\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("DB: Database initialized.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (db_prepare()) {
 | 
				
			||||||
 | 
							printf("DB: Failed to prepare database.\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("DB: Database prepared.\n");
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
						/* parse options */
 | 
				
			||||||
 | 
						handle_options(argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = reg_proxy_init();
 | 
				
			||||||
 | 
						if (!reg) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_FATAL, "Cannot create reg_proxy struck\n");
 | 
				
			||||||
 | 
							exit(2);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rc = sup_server_init(reg);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_FATAL, "Cannot set up subscriber management\n");
 | 
				
			||||||
 | 
							exit(2);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					////////////////////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = sip_client_init(reg, sip_src_ip, src_port, sip_dst_ip, dst_port, expires_time);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_FATAL, "Cannot set up SIP\n");
 | 
				
			||||||
 | 
							exit(2);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* setup the timer */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
						db_sync_timer.cb = db_sync_timer_cb;
 | 
				
			||||||
 | 
						db_sync_timer.data = NULL;
 | 
				
			||||||
 | 
						if (use_db_counter)
 | 
				
			||||||
 | 
							osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bsc_gsmnet->subscr_expire_timer.cb = subscr_expire_cb;
 | 
				
			||||||
 | 
						bsc_gsmnet->subscr_expire_timer.data = NULL;
 | 
				
			||||||
 | 
						osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
						signal(SIGINT, &signal_handler);
 | 
				
			||||||
 | 
						signal(SIGABRT, &signal_handler);
 | 
				
			||||||
 | 
						signal(SIGUSR1, &signal_handler);
 | 
				
			||||||
 | 
						signal(SIGUSR2, &signal_handler);
 | 
				
			||||||
 | 
						osmo_init_ignore_signals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
						if (daemonize) {
 | 
				
			||||||
 | 
							rc = osmo_daemonize();
 | 
				
			||||||
 | 
							if (rc < 0) {
 | 
				
			||||||
 | 
								perror("Error during daemonize");
 | 
				
			||||||
 | 
								exit(1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
						printf("Entering Main loop 1\n");
 | 
				
			||||||
 | 
						OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Check OSIP_TRACE init\n"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							log_reset_context();
 | 
				
			||||||
 | 
							osmo_select_main(0); //<-- TIMER handling
 | 
				
			||||||
 | 
							osip_nict_execute(reg->osip);
 | 
				
			||||||
 | 
							osip_timers_nict_execute(reg->osip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							osip_ict_execute(reg->osip);
 | 
				
			||||||
 | 
							osip_timers_ict_execute(reg->osip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							osip_nist_execute(reg->osip);
 | 
				
			||||||
 | 
							osip_timers_nist_execute(reg->osip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							osip_ist_execute(reg->osip);
 | 
				
			||||||
 | 
							osip_timers_ist_execute(reg->osip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							osip_retransmissions_execute(reg->osip);
 | 
				
			||||||
 | 
							nict_trans_free(reg->osip);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										623
									
								
								openbsc/src/reg-proxy/sip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										623
									
								
								openbsc/src/reg-proxy/sip.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,623 @@
 | 
				
			|||||||
 | 
					#include <openbsc/sip_client.h>
 | 
				
			||||||
 | 
					#include <openbsc/reg_proxy.h>
 | 
				
			||||||
 | 
					#include <openbsc/sup.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm0480.h>
 | 
				
			||||||
 | 
					#include <osip2/osip.h>
 | 
				
			||||||
 | 
					#include <osip2/osip_dialog.h>
 | 
				
			||||||
 | 
					#include <osip2/osip_fifo.h>
 | 
				
			||||||
 | 
					#include <osip2/osip_time.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MESSAGE_MAX_LENGTH 4000
 | 
				
			||||||
 | 
					#define MAX_ADDR_STR 128
 | 
				
			||||||
 | 
					#define MESSAGE_ENTRY_MAX_LENGTH 256
 | 
				
			||||||
 | 
					#define SIP_URI_SCHEME "sip"
 | 
				
			||||||
 | 
					#define SIP_VERSION "SIP/2.0"
 | 
				
			||||||
 | 
					#define EXPIRES_TIME_INSECS 3600
 | 
				
			||||||
 | 
					#define SIP_ALLOW "REGISTER, INVITE, INFO, ACK, CANCEL, BYE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int get_seqnum(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static int seq_num = 1;
 | 
				
			||||||
 | 
						if (seq_num < (1<<30)) {
 | 
				
			||||||
 | 
							seq_num++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							seq_num = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return seq_num;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sip_send(struct sip_client *sip_client, osip_t *osip,
 | 
				
			||||||
 | 
					             osip_message_t *msg, osip_fsm_type_t transaction_type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
						osip_transaction_t *transaction;
 | 
				
			||||||
 | 
						osip_event_t *sip_event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = osip_transaction_init(&transaction, transaction_type, osip, msg);
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							printf("Failed to init transaction %d",status);
 | 
				
			||||||
 | 
							osip_message_free(msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_transaction_set_your_instance(transaction, sip_client);
 | 
				
			||||||
 | 
						osip_transaction_set_reserved6(transaction, osip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_event = osip_new_outgoing_sipmessage(msg);
 | 
				
			||||||
 | 
						if (!sip_event) {
 | 
				
			||||||
 | 
							printf("Can't allocate message");
 | 
				
			||||||
 | 
							osip_message_free(msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_event->transactionid = transaction->transactionid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = osip_message_force_update(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							printf("Failed force update %d",status);
 | 
				
			||||||
 | 
							osip_message_free(msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						status = osip_transaction_add_event(transaction, sip_event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							printf("Can't add event %d",status);
 | 
				
			||||||
 | 
							osip_message_free(msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Event added, waiting message to send ..... %d\n",status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tx_sip_register(struct sip_client *sip_client, osip_t *osip, char *imsi,
 | 
				
			||||||
 | 
					                    int expires_time)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osip_message_t *reg_msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char *call_id_num = NULL;
 | 
				
			||||||
 | 
						char *seq_num_str = NULL;
 | 
				
			||||||
 | 
						osip_call_id_t *call_id;
 | 
				
			||||||
 | 
						char tmp[MESSAGE_ENTRY_MAX_LENGTH];
 | 
				
			||||||
 | 
						osip_cseq_t *cseq;
 | 
				
			||||||
 | 
						char src_port[6];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_message_init(®_msg)) {
 | 
				
			||||||
 | 
							OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Can't init message!\n"));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						osip_message_set_method(reg_msg, osip_strdup("REGISTER"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/////
 | 
				
			||||||
 | 
						osip_uri_init(&(reg_msg->req_uri));
 | 
				
			||||||
 | 
						osip_uri_set_scheme(reg_msg->req_uri, osip_strdup(SIP_URI_SCHEME));
 | 
				
			||||||
 | 
						osip_uri_set_host(reg_msg->req_uri, osip_strdup(sip_client->dst_ip));
 | 
				
			||||||
 | 
						//if (osip_uri_parse(reg_msg->req_uri, SIP_SERVER)) {
 | 
				
			||||||
 | 
						//	OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"uri parse failed!\n"));
 | 
				
			||||||
 | 
						//	osip_message_free(reg_msg);
 | 
				
			||||||
 | 
						//	return -1;
 | 
				
			||||||
 | 
						//}
 | 
				
			||||||
 | 
						////////
 | 
				
			||||||
 | 
						osip_message_set_version(reg_msg, osip_strdup(SIP_VERSION));
 | 
				
			||||||
 | 
						//osip_message_set_status_code(reg_msg, 0);
 | 
				
			||||||
 | 
						//osip_message_set_reason_phrase(reg_msg, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(tmp, "<sip:%s@%s>", imsi, sip_client->dst_ip);
 | 
				
			||||||
 | 
						osip_message_set_to(reg_msg, tmp);
 | 
				
			||||||
 | 
						sprintf(tmp, "<sip:%s@%s>;tag=%u", imsi, sip_client->dst_ip, osip_build_random_number());
 | 
				
			||||||
 | 
						osip_message_set_from(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_call_id_init(&call_id)) {
 | 
				
			||||||
 | 
							OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"call id failed!\n"));
 | 
				
			||||||
 | 
							osip_message_free(reg_msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						call_id_num = (char *)osip_malloc(MAX_ADDR_STR);
 | 
				
			||||||
 | 
						sprintf(call_id_num, "%u", osip_build_random_number());
 | 
				
			||||||
 | 
						osip_call_id_set_number(call_id, call_id_num);
 | 
				
			||||||
 | 
						reg_msg->call_id = call_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_cseq_init(&cseq)) {
 | 
				
			||||||
 | 
							OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"seq init failed!\n"));
 | 
				
			||||||
 | 
							osip_message_free(reg_msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seq_num_str = (char *)osip_malloc(11);
 | 
				
			||||||
 | 
						sprintf(seq_num_str,"%i", get_seqnum());
 | 
				
			||||||
 | 
						osip_cseq_set_number(cseq, seq_num_str);
 | 
				
			||||||
 | 
						osip_cseq_set_method(cseq, osip_strdup("REGISTER"));
 | 
				
			||||||
 | 
						reg_msg->cseq = cseq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_max_forwards(reg_msg, "70");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(src_port, "%u", sip_client->src_port);
 | 
				
			||||||
 | 
						sprintf(tmp, "SIP/2.0/%s %s:%s;branch=z9hG4bK%u", "TCP", sip_client->src_ip,
 | 
				
			||||||
 | 
					                                          src_port, osip_build_random_number());
 | 
				
			||||||
 | 
						osip_message_set_via(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(tmp, "<sip:%s@%s:%s>", imsi, sip_client->src_ip, src_port);
 | 
				
			||||||
 | 
						osip_message_set_contact(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(tmp, "%i",  expires_time);
 | 
				
			||||||
 | 
						osip_message_set_expires(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_content_length(reg_msg, "0");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_allow(reg_msg, SIP_ALLOW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("REG message ready, try to send\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sip_send(sip_client, osip, reg_msg, NICT)) {
 | 
				
			||||||
 | 
							printf("Error sending message!");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int rx_sip_message(struct sip_client *sip_client, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char sip_msg[MESSAGE_MAX_LENGTH];
 | 
				
			||||||
 | 
						osip_event_t *sipevent;
 | 
				
			||||||
 | 
						struct reg_proxy *reg = sip_client->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("processSipMsg: RECEIVED MSG\n");
 | 
				
			||||||
 | 
						strncpy(sip_msg, (char*)msg->data,msg->data_len);
 | 
				
			||||||
 | 
						printf("processSipMsg: sip_msg = %s\n", sip_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sipevent= osip_parse(sip_msg,msg->data_len);
 | 
				
			||||||
 | 
						if((sipevent==NULL)||(sipevent->sip==NULL)) {
 | 
				
			||||||
 | 
							printf("Could not parse SIP message\n");
 | 
				
			||||||
 | 
							osip_event_free(sipevent);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_find_transaction_and_add_event(reg->osip,sipevent)) {
 | 
				
			||||||
 | 
							printf("New transaction!\n");
 | 
				
			||||||
 | 
							if (MSG_IS_REQUEST(sipevent->sip)) {
 | 
				
			||||||
 | 
								printf("Got New Request:%s\n",sip_msg);
 | 
				
			||||||
 | 
							} else if (MSG_IS_RESPONSE(sipevent->sip)) {
 | 
				
			||||||
 | 
								printf("Got New Response:%s\n",sip_msg);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								printf("Unsupported message:%s\n",sip_msg);
 | 
				
			||||||
 | 
								osip_event_free(sipevent);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sip_read_cb(struct sip_client *sip_client, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						rc = rx_sip_message(sip_client, msg);
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sip_cb_send(osip_transaction_t *tr, osip_message_t *sip_msg, char *host, int port, int out_socket)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t msg_len;
 | 
				
			||||||
 | 
						char *msg_p;
 | 
				
			||||||
 | 
						struct msgb *msg = sip_msgb_alloc();
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						struct sip_client *sip_client = osip_transaction_get_your_instance(tr);
 | 
				
			||||||
 | 
						printf("SIP Send Msg\n");
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if ((err = osip_message_to_str(sip_msg, &msg_p, &msg_len)) != 0){
 | 
				
			||||||
 | 
							osip_message_free(sip_msg);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							printf("SIP failed to convert message: %d\n", err);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("SIP convert message ok\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!msg_p) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							osip_message_free(sip_msg);
 | 
				
			||||||
 | 
							printf("SIP msg_p = NULL fail!\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sip_client == NULL) {
 | 
				
			||||||
 | 
							osip_dialog_t* diag = (osip_dialog_t* )sip_msg->application_data;
 | 
				
			||||||
 | 
							if (diag == NULL) {
 | 
				
			||||||
 | 
								msgb_free(msg);
 | 
				
			||||||
 | 
								osip_free(msg_p);
 | 
				
			||||||
 | 
								osip_message_free(sip_msg);
 | 
				
			||||||
 | 
								printf("Unable to send:\n%s\n", msg_p);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							sip_client = (struct sip_client *)diag->your_instance;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("SIP msg_p != NULL OK!, msg_len = %d\n", msg_len);
 | 
				
			||||||
 | 
						memcpy(msg->data, (uint8_t*)msg_p, msg_len);
 | 
				
			||||||
 | 
						msg->data_len = msg_len;
 | 
				
			||||||
 | 
						msg->len += msg_len;
 | 
				
			||||||
 | 
						printf("SIP ready to send msg via IPA\n");
 | 
				
			||||||
 | 
						osip_free(msg_p);
 | 
				
			||||||
 | 
						return sip_client_send(sip_client, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_cb_rcv1xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_NICT_STATUS_1XX_RECEIVED\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_cb_rcv2xx(int type, osip_transaction_t *tr, osip_message_t *sip_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_NICT_STATUS_2XX_RECEIVED\n");
 | 
				
			||||||
 | 
						osip_contact_t *contact;
 | 
				
			||||||
 | 
						osip_to_t* to;
 | 
				
			||||||
 | 
						struct sip_client *sip_client = osip_transaction_get_your_instance(tr);
 | 
				
			||||||
 | 
						struct reg_proxy *reg = sip_client->data;
 | 
				
			||||||
 | 
						char imsi[16];
 | 
				
			||||||
 | 
						char msisdn[16];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						to = osip_message_get_to(sip_msg);
 | 
				
			||||||
 | 
						memcpy(imsi, to->url->username, 16);
 | 
				
			||||||
 | 
						printf("OSIP_NICT_STATUS_2XX_RECEIVED imsi = %s \n", imsi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_message_get_contact(sip_msg, 0, &contact) < 0) {
 | 
				
			||||||
 | 
							handle_purge_ms_result(reg->sup_server, imsi);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							memcpy(msisdn, contact->url->username, 16);
 | 
				
			||||||
 | 
							printf("OSIP_NICT_STATUS_2XX_RECEIVED msisdn = %s \n", msisdn);
 | 
				
			||||||
 | 
							handle_location_update_result(reg->sup_server, imsi, msisdn);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_cb_rcv2xx_again(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_cb_rcv3xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_NICT_STATUS_3XX_RECEIVED\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_cb_rcv4xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_NICT_STATUS_4XX_RECEIVED\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void sip_cb_rcv5xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_NICT_STATUS_5XX_RECEIVED\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void sip_cb_rcv6xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_NICT_STATUS_6XX_RECEIVED\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_cb_ict_rcv2xx(int type, osip_transaction_t *tr, osip_message_t *sip_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_ICT_STATUS_2XX_RECEIVED\n");
 | 
				
			||||||
 | 
						//osip_contact_t *contact;
 | 
				
			||||||
 | 
						osip_to_t* to;
 | 
				
			||||||
 | 
						osip_from_t* from;
 | 
				
			||||||
 | 
						struct sip_client *sip_client = osip_transaction_get_your_instance(tr);
 | 
				
			||||||
 | 
						osip_t* osip = osip_transaction_get_reserved6(tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//struct reg_proxy *reg = sip_client->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//char request[32];
 | 
				
			||||||
 | 
						char from_str[32];
 | 
				
			||||||
 | 
						char to_str[32];
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//osip_message_get_contact(sip_msg, 0, &contact);
 | 
				
			||||||
 | 
						//strncpy(request, contact->url->username, sizeof(request));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						from = osip_message_get_from(sip_msg);
 | 
				
			||||||
 | 
						strncpy(from_str, from->url->username, sizeof(from_str));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						to = osip_message_get_to(sip_msg);
 | 
				
			||||||
 | 
						strncpy(to_str, to->url->username, sizeof(to_str));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("FROM: %s TO: %s\n", from_str, to_str);
 | 
				
			||||||
 | 
						osip_dialog_t *dialog;
 | 
				
			||||||
 | 
						if (MSG_IS_RESPONSE_FOR(sip_msg, "INVITE")) {
 | 
				
			||||||
 | 
							//dialog = my_application_search_existing_dialog(sip_msg);
 | 
				
			||||||
 | 
							//if (dialog == NULL) //NO EXISTING DIALOG
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								int err = osip_dialog_init_as_uac(&dialog, sip_msg);
 | 
				
			||||||
 | 
								if (err) {
 | 
				
			||||||
 | 
									printf("Can't osip_dialog_init_as_uac %d\n", err);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								//my_application_add_existing_dialog(dialog);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dialog->your_instance = sip_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_t *ack_msg;
 | 
				
			||||||
 | 
						if (osip_message_init(&ack_msg)) {
 | 
				
			||||||
 | 
							OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Can't init message!\n"));
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_method(ack_msg, osip_strdup("ACK"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_uri_init(&(ack_msg->req_uri));
 | 
				
			||||||
 | 
						osip_uri_set_scheme(ack_msg->req_uri, osip_strdup(SIP_URI_SCHEME));
 | 
				
			||||||
 | 
						osip_uri_set_username(ack_msg->req_uri, osip_strdup(to_str));
 | 
				
			||||||
 | 
						osip_uri_set_host(ack_msg->req_uri, osip_strdup(sip_client->dst_ip));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_version(ack_msg, osip_strdup(SIP_VERSION));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//osip_message_set_to(ack_msg, to->displayname);
 | 
				
			||||||
 | 
						//osip_message_set_from(ack_msg, from->displayname);
 | 
				
			||||||
 | 
						osip_from_clone(from, &ack_msg->from);
 | 
				
			||||||
 | 
						osip_to_clone(to, &ack_msg->to);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = osip_call_id_clone(sip_msg->call_id, &(ack_msg->call_id));
 | 
				
			||||||
 | 
						assert (rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_cseq_t* cseq;
 | 
				
			||||||
 | 
						rc = osip_cseq_init(&cseq);
 | 
				
			||||||
 | 
						assert (rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//char* seq_num_str = (char *)osip_malloc(11);
 | 
				
			||||||
 | 
						//sprintf(seq_num_str,"%i", atoi(sip_msg->cseq->number) + 1); // Hardcoded
 | 
				
			||||||
 | 
						osip_cseq_set_number(cseq, osip_strdup(sip_msg->cseq->number));
 | 
				
			||||||
 | 
						osip_cseq_set_method(cseq, osip_strdup("ACK"));
 | 
				
			||||||
 | 
						ack_msg->cseq = cseq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_max_forwards(ack_msg, "70");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char tmp[MESSAGE_ENTRY_MAX_LENGTH];
 | 
				
			||||||
 | 
						snprintf(tmp, sizeof(tmp), "SIP/2.0/%s %s:%s;branch=z9hG4bK-%u",
 | 
				
			||||||
 | 
							 "TCP",
 | 
				
			||||||
 | 
							 //from->url->host,
 | 
				
			||||||
 | 
							 //from->url->port,
 | 
				
			||||||
 | 
							 "127.0.0.1",
 | 
				
			||||||
 | 
							 "5150",
 | 
				
			||||||
 | 
							 osip_build_random_number());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_via(ack_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char src_port[7];
 | 
				
			||||||
 | 
						snprintf(src_port, sizeof(src_port), "%u", sip_client->src_port);
 | 
				
			||||||
 | 
						snprintf(tmp, sizeof(tmp), "<sip:ussd_sip@%s:%s>", sip_client->src_ip, src_port);
 | 
				
			||||||
 | 
						osip_message_set_contact(ack_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(tmp, sizeof(tmp), "%i", EXPIRES_TIME_INSECS);
 | 
				
			||||||
 | 
						osip_message_set_expires(ack_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_content_length(ack_msg, "0");
 | 
				
			||||||
 | 
						ack_msg->application_data = dialog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
						osip_transaction_t *transaction;
 | 
				
			||||||
 | 
						status = osip_transaction_init(&transaction, ICT, osip, ack_msg);
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							printf("Failed to init transaction %d\n", status);
 | 
				
			||||||
 | 
							return ;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_transaction_set_your_instance(transaction, sip_client);
 | 
				
			||||||
 | 
						osip_transaction_set_reserved5(transaction, dialog);
 | 
				
			||||||
 | 
						osip_transaction_set_reserved6(transaction, osip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_event_t *sip_event = osip_new_outgoing_sipmessage(ack_msg);
 | 
				
			||||||
 | 
						if (!sip_event) {
 | 
				
			||||||
 | 
							printf("Can't allocate message\n");
 | 
				
			||||||
 | 
							osip_message_free(ack_msg);
 | 
				
			||||||
 | 
							return ;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_event->transactionid = transaction->transactionid;
 | 
				
			||||||
 | 
						status = osip_message_force_update(ack_msg);
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							printf("Failed force update %d\n",status);
 | 
				
			||||||
 | 
							osip_message_free(ack_msg);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status = osip_transaction_add_event(transaction, sip_event);
 | 
				
			||||||
 | 
						if (status) {
 | 
				
			||||||
 | 
							printf("Can't add event %d\n",status);
 | 
				
			||||||
 | 
							osip_message_free(ack_msg);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_ict_execute(osip);
 | 
				
			||||||
 | 
					//	osip_start_ack_retransmissions(transaction,
 | 
				
			||||||
 | 
					//				       dialog, ack_msg, to->url->host,
 | 
				
			||||||
 | 
					//				       (to->url->port) ? atoi(to->url->port) : 5060, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_cb_ict_rcv1xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_ICT_STATUS_1XX_RECEIVED\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void sip_cb_ict_rcv2xx_again(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_ICT_STATUS_2XX_RECEIVED_AGAIN\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void sip_cb_ict_rcv3456xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_ICT_STATUS_3456XX_RECEIVED\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_cb_ict_kill_transaction(int type, osip_transaction_t *tr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_ICT_KILL_TRANSACTION\n");
 | 
				
			||||||
 | 
						//int i = osip_remove_transaction (osip_transaction_get_reserved6(tr), tr);
 | 
				
			||||||
 | 
						//i = osip_transaction_free2(tr);
 | 
				
			||||||
 | 
						//if (i != 0) fprintf(stderr, "cannot remove transaction\n");
 | 
				
			||||||
 | 
						printf("KILLED TRANSACTION\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void cb_transport_error(int type, osip_transaction_t *a, int error)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("OSIP_ICT_TRANSPORT_ERROR trnasaction: %p error: %d\n",
 | 
				
			||||||
 | 
						       a, error);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_set_cbs(osip_t *osip)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osip_set_cb_send_message(osip, sip_cb_send);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_NICT_STATUS_1XX_RECEIVED, sip_cb_rcv1xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_NICT_STATUS_2XX_RECEIVED, sip_cb_rcv2xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN, sip_cb_rcv2xx_again);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_NICT_STATUS_3XX_RECEIVED, sip_cb_rcv3xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_NICT_STATUS_4XX_RECEIVED, sip_cb_rcv4xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_NICT_STATUS_5XX_RECEIVED, sip_cb_rcv5xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_NICT_STATUS_6XX_RECEIVED, sip_cb_rcv6xx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_ICT_STATUS_1XX_RECEIVED, sip_cb_ict_rcv1xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_ICT_STATUS_2XX_RECEIVED, sip_cb_ict_rcv2xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_ICT_STATUS_2XX_RECEIVED_AGAIN, sip_cb_ict_rcv2xx_again);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_ICT_STATUS_3XX_RECEIVED, sip_cb_ict_rcv3456xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_ICT_STATUS_4XX_RECEIVED, sip_cb_ict_rcv3456xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_ICT_STATUS_5XX_RECEIVED, sip_cb_ict_rcv3456xx);
 | 
				
			||||||
 | 
						osip_set_message_callback (osip, OSIP_ICT_STATUS_6XX_RECEIVED, sip_cb_ict_rcv3456xx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_set_kill_transaction_callback(osip, OSIP_ICT_KILL_TRANSACTION, sip_cb_ict_kill_transaction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_set_transport_error_callback(osip, OSIP_ICT_TRANSPORT_ERROR, cb_transport_error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//osip_set_kill_transaction_callback(osip ,OSIP_NIST_KILL_TRANSACTION, &cb_ist_kill_transaction);
 | 
				
			||||||
 | 
						//osip_set_kill_transaction_callback(osip ,OSIP_NICT_KILL_TRANSACTION, &cb_nict_kill_transaction);
 | 
				
			||||||
 | 
						//osip_set_kill_transaction_callback(osip ,OSIP_NIST_KILL_TRANSACTION, &cb_nist_kill_transaction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sip_client_init(struct reg_proxy *reg, const char *src_ip, u_int16_t src_port,
 | 
				
			||||||
 | 
											 const char *dst_ip, u_int16_t dst_port, int expires_time)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg->sip_client = sip_client_create(src_ip, src_port, dst_ip, dst_port, expires_time,
 | 
				
			||||||
 | 
					                                                        &sip_read_cb, reg);
 | 
				
			||||||
 | 
						if (!reg->sip_client)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_init(®->osip)!=0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_set_cbs(reg->osip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// USSD part
 | 
				
			||||||
 | 
					#define MAX_USSD_CONTENT 1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tx_ss_handle(struct sip_client *sip_client, osip_t *osip, struct ss_request *ss,
 | 
				
			||||||
 | 
							 const char *extention)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osip_message_t *reg_msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//static int seq_num = 1;
 | 
				
			||||||
 | 
						char *call_id_num = NULL;
 | 
				
			||||||
 | 
						char *seq_num_str = NULL;
 | 
				
			||||||
 | 
						osip_call_id_t *call_id;
 | 
				
			||||||
 | 
						char tmp[MESSAGE_ENTRY_MAX_LENGTH];
 | 
				
			||||||
 | 
						osip_cseq_t *cseq;
 | 
				
			||||||
 | 
						char src_port[6];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_message_init(®_msg)) {
 | 
				
			||||||
 | 
							OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Can't init message!\n"));
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						osip_message_set_method(reg_msg, osip_strdup("INVITE"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/////
 | 
				
			||||||
 | 
						osip_uri_init(&(reg_msg->req_uri));
 | 
				
			||||||
 | 
						osip_uri_set_scheme(reg_msg->req_uri, osip_strdup(SIP_URI_SCHEME));
 | 
				
			||||||
 | 
						osip_uri_set_username(reg_msg->req_uri, osip_strdup(ss->ussd_text));
 | 
				
			||||||
 | 
						osip_uri_set_host(reg_msg->req_uri, osip_strdup(sip_client->dst_ip));
 | 
				
			||||||
 | 
						osip_message_set_version(reg_msg, osip_strdup(SIP_VERSION));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(tmp, "<sip:%s@%s>", ss->ussd_text, sip_client->dst_ip);
 | 
				
			||||||
 | 
						osip_message_set_to(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(tmp, "<sip:%s@%s>;tag=%u", extention, sip_client->dst_ip, osip_build_random_number());
 | 
				
			||||||
 | 
						osip_message_set_from(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_call_id_init(&call_id)) {
 | 
				
			||||||
 | 
							OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"call id failed!\n"));
 | 
				
			||||||
 | 
							osip_message_free(reg_msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						call_id_num = (char *)osip_malloc(MAX_ADDR_STR);
 | 
				
			||||||
 | 
						sprintf(call_id_num, "%u", osip_build_random_number());
 | 
				
			||||||
 | 
						osip_call_id_set_number(call_id, call_id_num);
 | 
				
			||||||
 | 
						reg_msg->call_id = call_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osip_cseq_init(&cseq)) {
 | 
				
			||||||
 | 
							OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"seq init failed!\n"));
 | 
				
			||||||
 | 
							osip_message_free(reg_msg);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seq_num_str = (char *)osip_malloc(11);
 | 
				
			||||||
 | 
						sprintf(seq_num_str,"%i", 1); // Hardcoded
 | 
				
			||||||
 | 
						osip_cseq_set_number(cseq, seq_num_str);
 | 
				
			||||||
 | 
						osip_cseq_set_method(cseq, osip_strdup("INVITE"));
 | 
				
			||||||
 | 
						reg_msg->cseq = cseq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_max_forwards(reg_msg, "70");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(src_port, sizeof(src_port), "%u", sip_client->src_port);
 | 
				
			||||||
 | 
						snprintf(tmp, sizeof(tmp), "SIP/2.0/%s %s:%s;branch=z9hG4bK-%u", "TCP", sip_client->src_ip,
 | 
				
			||||||
 | 
										  src_port, osip_build_random_number());
 | 
				
			||||||
 | 
						osip_message_set_via(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(tmp, sizeof(tmp), "<sip:ussd_sip@%s:%s>", sip_client->src_ip, src_port);
 | 
				
			||||||
 | 
						osip_message_set_contact(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(tmp, sizeof(tmp), "%i", EXPIRES_TIME_INSECS);
 | 
				
			||||||
 | 
						osip_message_set_expires(reg_msg, tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Content
 | 
				
			||||||
 | 
						char content[MAX_USSD_CONTENT];
 | 
				
			||||||
 | 
						int content_len = snprintf(content, sizeof(content),
 | 
				
			||||||
 | 
									   "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 | 
				
			||||||
 | 
									   "<ussd-data>\n"
 | 
				
			||||||
 | 
									   " <language>%s</language>\n"
 | 
				
			||||||
 | 
									   " <ussd-string>%s</ussd-string>\n"
 | 
				
			||||||
 | 
									   "</ussd-data>",
 | 
				
			||||||
 | 
									   "en",
 | 
				
			||||||
 | 
									   ss->ussd_text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(tmp, sizeof(tmp), "%i", content_len);
 | 
				
			||||||
 | 
						osip_message_set_content_length(reg_msg, tmp);
 | 
				
			||||||
 | 
						osip_message_set_content_type(reg_msg, "application/vnd.3gpp.ussd+xml");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osip_message_set_body(reg_msg, content, content_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//osip_message_set_allow(reg_msg, SIP_ALLOW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("REG message ready, try to send\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sip_send(sip_client, osip, reg_msg, ICT)) {
 | 
				
			||||||
 | 
							printf("Error sending message!");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										277
									
								
								openbsc/src/reg-proxy/sip_client.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								openbsc/src/reg-proxy/sip_client.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,277 @@
 | 
				
			|||||||
 | 
					#include <openbsc/reg_proxy.h>
 | 
				
			||||||
 | 
					#include <openbsc/sip_client.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//#include <osmocom/abis/ipa.h>
 | 
				
			||||||
 | 
					//#include <osmocom/gsm/protocol/ipaccess.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <sys/fcntl.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/tcp_client.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//extern void *tall_reg_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//static void start_test_procedure(struct gsup_client *gsupc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					static void gsup_client_send_ping(struct gsup_client *gsupc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = gsup_client_msgb_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg->l2h = msgb_put(msg, 1);
 | 
				
			||||||
 | 
						msg->l2h[0] = IPAC_MSGT_PING;
 | 
				
			||||||
 | 
						ipa_msg_push_header(msg, IPAC_PROTO_IPACCESS);
 | 
				
			||||||
 | 
						ipa_client_conn_send(gsupc->link, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sip_client_connect(struct sip_client *sip_client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sip_client->is_connected)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (osmo_timer_pending(&sip_client->connect_timer)) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_DEBUG,
 | 
				
			||||||
 | 
							     "SIP connect: connect timer already running\n");
 | 
				
			||||||
 | 
							osmo_timer_del(&sip_client->connect_timer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tcp_client_conn_clear_queue(sip_client->link) > 0)
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_DEBUG, "SIP connect: discarded stored messages\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = tcp_client_conn_open(sip_client->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc >= 0) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_INFO, "SIP connecting to %s:%d\n",
 | 
				
			||||||
 | 
							     sip_client->link->dst_addr, sip_client->link->dst_port);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DSUP, LOGL_INFO, "SIP failed to connect to %s:%d: %s\n",
 | 
				
			||||||
 | 
						     sip_client->link->dst_addr, sip_client->link->dst_port, strerror(-rc));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc == -EBADF || rc == -ENOTSOCK || rc == -EAFNOSUPPORT ||
 | 
				
			||||||
 | 
						    rc == -EINVAL)
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_timer_schedule(&sip_client->connect_timer, SIP_RECONNECT_INTERVAL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DSUP, LOGL_INFO, "Scheduled timer to retry SIP connect to %s:%d\n",
 | 
				
			||||||
 | 
						     sip_client->link->dst_addr, sip_client->link->dst_port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void connect_timer_cb(void *sip_client_)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sip_client *sip_client = sip_client_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sip_client->is_connected)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_client_connect(sip_client);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sip_client_updown_cb(struct tcp_client_conn *link, int up)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sip_client *sip_client = link->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DSUP, LOGL_INFO, "SIP link to %s:%d %s\n",
 | 
				
			||||||
 | 
							     link->dst_addr, link->dst_port, up ? "UP" : "DOWN");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_client->is_connected = up;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (up) {
 | 
				
			||||||
 | 
							osmo_timer_del(&sip_client->connect_timer);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							osmo_timer_schedule(&sip_client->connect_timer,
 | 
				
			||||||
 | 
									    SIP_RECONNECT_INTERVAL, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sip_client_read_cb(struct tcp_client_conn *link, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
 | 
				
			||||||
 | 
						//struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
 | 
				
			||||||
 | 
						printf("Recv sip message! len = %d\n", msg->data_len);
 | 
				
			||||||
 | 
					    struct sip_client *sip_client = (struct sip_client *)link->data;
 | 
				
			||||||
 | 
						//int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//msg->l2h = &hh->data[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OSMO_ASSERT(sip_client->read_cb != NULL);
 | 
				
			||||||
 | 
					    sip_client->read_cb(sip_client, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Not freeing msg here, because that must be done by the read_cb. */
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					static void ping_timer_cb(void *gsupc_)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsup_client *gsupc = gsupc_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DGPRS, LOGL_INFO, "GSUP ping callback (%s, %s PONG)\n",
 | 
				
			||||||
 | 
						     gsupc->is_connected ? "connected" : "not connected",
 | 
				
			||||||
 | 
						     gsupc->got_ipa_pong ? "got" : "didn't get");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (gsupc->got_ipa_pong) {
 | 
				
			||||||
 | 
							start_test_procedure(gsupc);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DGPRS, LOGL_NOTICE, "GSUP ping timed out, reconnecting\n");
 | 
				
			||||||
 | 
						ipa_client_conn_close(gsupc->link);
 | 
				
			||||||
 | 
						gsupc->is_connected = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_client_connect(gsupc);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					static void start_test_procedure(struct gsup_client *gsupc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						gsupc->ping_timer.data = gsupc;
 | 
				
			||||||
 | 
						gsupc->ping_timer.cb = &ping_timer_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsupc->got_ipa_pong = 0;
 | 
				
			||||||
 | 
						osmo_timer_schedule(&gsupc->ping_timer, OSMO_GSUP_PING_INTERVAL, 0);
 | 
				
			||||||
 | 
						LOGP(DGPRS, LOGL_DEBUG, "GSUP sending PING\n");
 | 
				
			||||||
 | 
						gsup_client_send_ping(gsupc);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					int ipa_client_write_cb(struct ipa_client_conn *link)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_fd *ofd = link->ofd;
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
						struct llist_head *lh;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLINP, LOGL_DEBUG, "sending data\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (llist_empty(&link->tx_queue)) {
 | 
				
			||||||
 | 
							ofd->when &= ~BSC_FD_WRITE;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lh = link->tx_queue.next;
 | 
				
			||||||
 | 
						llist_del(lh);
 | 
				
			||||||
 | 
						msg = llist_entry(lh, struct msgb, list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("ipa_client_write_cb sending data... msg->len= %d\n",  msg->len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = send(link->ofd->fd, msg->data, msg->len, 0);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							if (errno == EPIPE || errno == ENOTCONN) {
 | 
				
			||||||
 | 
								ipa_client_conn_close(link);
 | 
				
			||||||
 | 
								if (link->updown_cb)
 | 
				
			||||||
 | 
									link->updown_cb(link, 0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							LOGP(DLINP, LOGL_ERROR, "error to send\n");
 | 
				
			||||||
 | 
							printf("ipa_client_write_cb error to send!!!! ret = %d errno = %d\n", ret, errno);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						printf("ipa_client_write_cb send OK ret = %d\n", ret);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					struct sip_client *sip_client_create(const char *src_ip, u_int16_t src_port,
 | 
				
			||||||
 | 
					                                     const char *dst_ip, u_int16_t dst_port,
 | 
				
			||||||
 | 
					                                     int expires_time, sip_read_cb_t read_cb,
 | 
				
			||||||
 | 
					                                                                  void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sip_client *sip_client;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_client = talloc_zero(tall_reg_ctx, struct sip_client);
 | 
				
			||||||
 | 
						OSMO_ASSERT(sip_client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_client->link = tcp_client_conn_create(sip_client,
 | 
				
			||||||
 | 
										     0,
 | 
				
			||||||
 | 
										     dst_ip, dst_port,
 | 
				
			||||||
 | 
										     src_ip, src_port,
 | 
				
			||||||
 | 
										     sip_client_updown_cb,
 | 
				
			||||||
 | 
										     sip_client_read_cb,
 | 
				
			||||||
 | 
										     NULL,
 | 
				
			||||||
 | 
										     sip_client);
 | 
				
			||||||
 | 
						if (!sip_client->link)
 | 
				
			||||||
 | 
							goto failed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_client->connect_timer.data = sip_client;
 | 
				
			||||||
 | 
						sip_client->connect_timer.cb = &connect_timer_cb;
 | 
				
			||||||
 | 
						sip_client->dst_ip = dst_ip;
 | 
				
			||||||
 | 
						sip_client->src_ip = src_ip;
 | 
				
			||||||
 | 
						sip_client->dst_port = dst_port;
 | 
				
			||||||
 | 
						sip_client->src_port = src_port;
 | 
				
			||||||
 | 
						sip_client->expires_time = expires_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = sip_client_connect(sip_client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							goto failed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sip_client->read_cb = read_cb;
 | 
				
			||||||
 | 
						sip_client->data = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sip_client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					failed:
 | 
				
			||||||
 | 
						sip_client_destroy(sip_client);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sip_client_destroy(struct sip_client *sip_client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osmo_timer_del(&sip_client->connect_timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sip_client->link) {
 | 
				
			||||||
 | 
							tcp_client_conn_close(sip_client->link);
 | 
				
			||||||
 | 
							tcp_client_conn_destroy(sip_client->link);
 | 
				
			||||||
 | 
							sip_client->link = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						talloc_free(sip_client);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sip_client_send(struct sip_client *sip_client, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!sip_client) {
 | 
				
			||||||
 | 
							printf(" sip_client == NULL ");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOTCONN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sip_client->is_connected) {
 | 
				
			||||||
 | 
							printf(" !sip_client->is_connected ");
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -EAGAIN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_GSUP);
 | 
				
			||||||
 | 
						//ipa_msg_push_header(msg, IPAC_PROTO_OSMO);
 | 
				
			||||||
 | 
						printf(" TRY tcp_client_conn_send\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcp_client_conn_send(sip_client->link, msg);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						printf(" DONE tcp_client_conn_send\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb *sip_msgb_alloc(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return msgb_alloc_headroom(400000, 64, __func__);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										137
									
								
								openbsc/src/reg-proxy/sip_parser.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								openbsc/src/reg-proxy/sip_parser.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					################################################################################
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Stand-alone VoIP honeypot client (preparation for Dionaea integration)
 | 
				
			||||||
 | 
					# Copyright (c) 2010 Tobias Wulff (twu200 at gmail)
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					################################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SIP headers have short forms
 | 
				
			||||||
 | 
					shortHeaders = {"call-id": "i",
 | 
				
			||||||
 | 
					                "contact": "m",
 | 
				
			||||||
 | 
					                "content-encoding": "e",
 | 
				
			||||||
 | 
					                "content-length": "l",
 | 
				
			||||||
 | 
					                "content-type": "c",
 | 
				
			||||||
 | 
					                "from": "f",
 | 
				
			||||||
 | 
					                "subject": "s",
 | 
				
			||||||
 | 
					                "to": "t",
 | 
				
			||||||
 | 
					                "via": "v",
 | 
				
			||||||
 | 
					                                "cseq": "cseq",
 | 
				
			||||||
 | 
					                                "accept": "accept",
 | 
				
			||||||
 | 
					                                "user-agent": "user-agent",
 | 
				
			||||||
 | 
					                                "max-forwards": "max-forwards",
 | 
				
			||||||
 | 
					                                "www-authentication": "www-authentication",
 | 
				
			||||||
 | 
					                                "authorization": "authorization",
 | 
				
			||||||
 | 
					                                "allow": "allow",
 | 
				
			||||||
 | 
					                                "recv-info": "recv-info",
 | 
				
			||||||
 | 
					                                "supported": "supported"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					longHeaders = {}
 | 
				
			||||||
 | 
					for k, v in shortHeaders.items():
 | 
				
			||||||
 | 
					    longHeaders[v] = k
 | 
				
			||||||
 | 
					del k, v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SipParsingError(Exception):
 | 
				
			||||||
 | 
					        """Exception class for errors occuring during SIP message parsing"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def parseSipMessage(msg):
 | 
				
			||||||
 | 
					        """Parses a SIP message (string), returns a tupel (type, firstLine, header,
 | 
				
			||||||
 | 
					        body)"""
 | 
				
			||||||
 | 
					        # Sanitize input: remove superfluous leading and trailing newlines and
 | 
				
			||||||
 | 
					        # spaces
 | 
				
			||||||
 | 
					        msg = msg.strip("\n\r\t ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Split request/status line plus headers and body: we don't care about the
 | 
				
			||||||
 | 
					        # body in the SIP parser
 | 
				
			||||||
 | 
					        parts = msg.split("\n\r\n", 1)
 | 
				
			||||||
 | 
					        if len(parts) < 1:
 | 
				
			||||||
 | 
					                raise SipParsingError("Message too short")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        msg = parts[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Python way of doing a ? b : c
 | 
				
			||||||
 | 
					        body = len(parts) == 2 and parts[1] or parts[len(parts)-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Normalize line feed and carriage return to \n
 | 
				
			||||||
 | 
					        msg = msg.replace("\n\r", "\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Split lines into a list, each item containing one line
 | 
				
			||||||
 | 
					        lines = msg.split('\n')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Get message type (first word, smallest possible one is "ACK" or "BYE")
 | 
				
			||||||
 | 
					        sep = lines[0].find(' ')
 | 
				
			||||||
 | 
					        if sep < 3:
 | 
				
			||||||
 | 
					                raise SipParsingError("Malformed request or status line")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        msgType = lines[0][:sep]
 | 
				
			||||||
 | 
					        firstLine = lines[0][sep+1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Done with first line: delete from list of lines
 | 
				
			||||||
 | 
					        del lines[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Parse header
 | 
				
			||||||
 | 
					        headers = {}
 | 
				
			||||||
 | 
					        for i in range(len(lines)):
 | 
				
			||||||
 | 
					                # Take first line and remove from list of lines
 | 
				
			||||||
 | 
					                line = lines.pop(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Strip each line of leading and trailing whitespaces
 | 
				
			||||||
 | 
					                line = line.strip("\n\r\t ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Break on empty line (end of headers)
 | 
				
			||||||
 | 
					                if len(line.strip(' ')) == 0:
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Parse header lines
 | 
				
			||||||
 | 
					                sep = line.find(':')
 | 
				
			||||||
 | 
					                if sep < 1:
 | 
				
			||||||
 | 
					                        raise SipParsingError("Malformed header line (no ':')")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Get header identifier (word before the ':')
 | 
				
			||||||
 | 
					                identifier = line[:sep]
 | 
				
			||||||
 | 
					                identifier = identifier.lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Check for valid header
 | 
				
			||||||
 | 
					                if identifier not in shortHeaders.keys() and \
 | 
				
			||||||
 | 
					                        identifier not in longHeaders.keys():
 | 
				
			||||||
 | 
					                        raise SipParsingError("Unknown header type: {}".format(identifier))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Get long header identifier if necessary
 | 
				
			||||||
 | 
					                if identifier in longHeaders.keys():
 | 
				
			||||||
 | 
					                        identifier = longHeaders[identifier]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Get header value (line after ':')
 | 
				
			||||||
 | 
					                value = line[sep+1:].strip(' ')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # The Via header can occur multiple times
 | 
				
			||||||
 | 
					                if identifier == "via":
 | 
				
			||||||
 | 
					                        if identifier not in headers:
 | 
				
			||||||
 | 
					                                headers["via"] = [value]
 | 
				
			||||||
 | 
					                        else:
 | 
				
			||||||
 | 
					                                headers["via"].append(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Assign any other header value directly to the header key
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                        headers[identifier] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Return message type, header dictionary, and body string
 | 
				
			||||||
 | 
					        return (msgType, firstLine, headers, body)
 | 
				
			||||||
							
								
								
									
										408
									
								
								openbsc/src/reg-proxy/sup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										408
									
								
								openbsc/src/reg-proxy/sup.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,408 @@
 | 
				
			|||||||
 | 
					#include <openbsc/sup_server.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsup_client.h>
 | 
				
			||||||
 | 
					#include <openbsc/reg_proxy.h>
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsup.h>
 | 
				
			||||||
 | 
					#include <openbsc/sip.h>
 | 
				
			||||||
 | 
					#include <openbsc/sup.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_04_08.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm0480.h>
 | 
				
			||||||
 | 
					#include <openbsc/ussd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int handle_sup_upd_loc_req(struct gsm_sup_server *sup_server,
 | 
				
			||||||
 | 
														struct osmo_gsup_message *sup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						struct reg_proxy *reg = sup_server->app;
 | 
				
			||||||
 | 
						struct sip_client *sip_client = reg->sip_client;
 | 
				
			||||||
 | 
						osip_t *osip = reg->osip;
 | 
				
			||||||
 | 
						LOGGSUPP(LOGL_INFO, sup_msg,
 | 
				
			||||||
 | 
							"Try to send sip_register 0x%02x\n", sup_msg->message_type);
 | 
				
			||||||
 | 
						rc = tx_sip_register(sip_client, osip, sup_msg->imsi, sip_client->expires_time);
 | 
				
			||||||
 | 
						LOGGSUPP(LOGL_INFO, sup_msg,
 | 
				
			||||||
 | 
							"Sip_register was send 0x%02x\n", sup_msg->message_type);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int handle_sup_purge_ms_req(struct gsm_sup_server *sup_server,
 | 
				
			||||||
 | 
														struct osmo_gsup_message *sup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						struct reg_proxy *reg = sup_server->app;
 | 
				
			||||||
 | 
						struct sip_client *sip_client = reg->sip_client;
 | 
				
			||||||
 | 
						osip_t *osip = reg->osip;
 | 
				
			||||||
 | 
						LOGGSUPP(LOGL_INFO, sup_msg,
 | 
				
			||||||
 | 
							"Try to send sip_register (cancellation) 0x%02x\n", sup_msg->message_type);
 | 
				
			||||||
 | 
						rc = tx_sip_register(sip_client, osip, sup_msg->imsi, 0);
 | 
				
			||||||
 | 
						LOGGSUPP(LOGL_INFO, sup_msg,
 | 
				
			||||||
 | 
							"Sip_register (cancellation) was send 0x%02x\n", sup_msg->message_type);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					static int handle_sup_ss(struct gsm_sup_server *sup_server,
 | 
				
			||||||
 | 
								 struct ss_request *ss,
 | 
				
			||||||
 | 
								 const char* extention)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						struct reg_proxy *reg = sup_server->app;
 | 
				
			||||||
 | 
						struct sip_client *sip_client = reg->sip_client;
 | 
				
			||||||
 | 
						osip_t *osip = reg->osip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DGPRS, LOGL_INFO,
 | 
				
			||||||
 | 
							"Try to send sip_register 0x%02x\n", ss->message_type);
 | 
				
			||||||
 | 
						rc = tx_ss_handle(sip_client, osip, ss, extention);
 | 
				
			||||||
 | 
						LOGP(DGPRS, LOGL_INFO,
 | 
				
			||||||
 | 
							"Sip_register was send 0x%02x\n", ss->message_type);
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
					    FMAP_MSISDN        = 0x80
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					static int rx_uss_message_parse(struct ss_request *ss,
 | 
				
			||||||
 | 
									const uint8_t* data,
 | 
				
			||||||
 | 
									size_t len,
 | 
				
			||||||
 | 
									char* extention,
 | 
				
			||||||
 | 
									size_t extention_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const uint8_t* const_data = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len < 1 + 2 + 3 + 3)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* skip OSMO_GSUP_MSGT_MAP */
 | 
				
			||||||
 | 
						ss->message_type = *(++const_data);
 | 
				
			||||||
 | 
						ss->component_type = *(++const_data);
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						if (*const_data != GSM0480_COMPIDTAG_INVOKE_ID) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
						ss->invoke_id = *const_data;
 | 
				
			||||||
 | 
						const_data++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						if (*const_data != GSM0480_OPERATION_CODE) {
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const_data += 2;
 | 
				
			||||||
 | 
						ss->opcode = *const_data;
 | 
				
			||||||
 | 
						const_data++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (const_data - data < len) {
 | 
				
			||||||
 | 
							uint8_t len;
 | 
				
			||||||
 | 
							switch (*const_data) {
 | 
				
			||||||
 | 
							case ASN1_OCTET_STRING_TAG:
 | 
				
			||||||
 | 
								len = *(++const_data);
 | 
				
			||||||
 | 
								strncpy((char*)ss->ussd_text,
 | 
				
			||||||
 | 
									(const char*)++const_data,
 | 
				
			||||||
 | 
									(len > MAX_LEN_USSD_STRING) ? MAX_LEN_USSD_STRING : len);
 | 
				
			||||||
 | 
								const_data += len;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case FMAP_MSISDN:
 | 
				
			||||||
 | 
								len = *(++const_data);
 | 
				
			||||||
 | 
								gsm48_decode_bcd_number(extention,
 | 
				
			||||||
 | 
											extention_len,
 | 
				
			||||||
 | 
											const_data,
 | 
				
			||||||
 | 
											0);
 | 
				
			||||||
 | 
								const_data += len + 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								DEBUGP(DMM, "Unknown code: %d\n", *const_data);
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int subscr_uss_message(struct msgb *msg,
 | 
				
			||||||
 | 
								      struct ss_request *req,
 | 
				
			||||||
 | 
								      const char* extention)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t bcd_len = 0;
 | 
				
			||||||
 | 
						uint8_t *gsup_indicator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_indicator = msgb_put(msg, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* First byte should always be OSMO_GSUP_MSGT_MAP */
 | 
				
			||||||
 | 
						gsup_indicator[0] = OSMO_GSUP_MSGT_MAP;
 | 
				
			||||||
 | 
						gsup_indicator[1] = req->message_type;
 | 
				
			||||||
 | 
						/* TODO ADD tid */
 | 
				
			||||||
 | 
						gsup_indicator[2] = req->component_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* invokeId */
 | 
				
			||||||
 | 
						msgb_tlv_put(msg, GSM0480_COMPIDTAG_INVOKE_ID, 1, &req->invoke_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* opCode */
 | 
				
			||||||
 | 
						msgb_tlv_put(msg, GSM0480_OPERATION_CODE, 1, &req->opcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (req->ussd_text_len > 0) {
 | 
				
			||||||
 | 
							//msgb_tlv_put(msg, ASN1_OCTET_STRING_TAG, 1, &req->ussd_text_language);
 | 
				
			||||||
 | 
							msgb_tlv_put(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_len, req->ussd_text);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (extention) {
 | 
				
			||||||
 | 
							uint8_t bcd_buf[32];
 | 
				
			||||||
 | 
							bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0,
 | 
				
			||||||
 | 
											  extention);
 | 
				
			||||||
 | 
							msgb_tlv_put(msg, FMAP_MSISDN, bcd_len - 1, &bcd_buf[1]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* fill actual length */
 | 
				
			||||||
 | 
						gsup_indicator[3] = 3 + 3 + (req->ussd_text_len + 2) + (bcd_len + 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* wrap with GSM0480_CTYPE_INVOKE */
 | 
				
			||||||
 | 
						// gsm0480_wrap_invoke(msg, req->opcode, invoke_id);
 | 
				
			||||||
 | 
						// gsup_indicator = msgb_push(msgb, 1);
 | 
				
			||||||
 | 
						// gsup_indicator[0] = OSMO_GSUP_MSGT_MAP;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rx_sup_uss_message(struct gsm_sup_server *sup_server, const uint8_t* data, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char extention[32] = {0};
 | 
				
			||||||
 | 
						struct ss_request ss;
 | 
				
			||||||
 | 
						memset(&ss, 0, sizeof(ss));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rx_uss_message_parse(&ss, data, len, extention, sizeof(extention))) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "Can't parse uss message\n");
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DSUP, LOGL_ERROR, "Got mtype=0x%02x invoke_id=0x%02x opcode=0x%02x component_type=0x%02x text=%s\n",
 | 
				
			||||||
 | 
						     ss.message_type, ss.invoke_id, ss.opcode, ss.component_type, ss.ussd_text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handle_sup_ss(sup_server, &ss, extention);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
						if (strcmp((const char*)ss.ussd_text, "*#100#") == 0) {
 | 
				
			||||||
 | 
							ss.ussd_text_len = snprintf(ss.ussd_text,
 | 
				
			||||||
 | 
										    sizeof(ss.ussd_text),
 | 
				
			||||||
 | 
										    "Your extention is %s",
 | 
				
			||||||
 | 
										    extention);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Last message in the transaction */
 | 
				
			||||||
 | 
							ss.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
				
			||||||
 | 
							ss.component_type = GSM0480_CTYPE_RETURN_RESULT;
 | 
				
			||||||
 | 
						} else if (strcmp((const char*)ss.ussd_text, "*#101#") == 0) {
 | 
				
			||||||
 | 
							ss.ussd_text_len = snprintf(ss.ussd_text,
 | 
				
			||||||
 | 
										    sizeof(ss.ussd_text),
 | 
				
			||||||
 | 
										    "Select option:\n1) Option 1\n2) Option 2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ss.message_type = GSM0480_MTYPE_FACILITY;
 | 
				
			||||||
 | 
							ss.component_type = GSM0480_CTYPE_INVOKE;
 | 
				
			||||||
 | 
							ss.opcode = GSM0480_OP_CODE_USS_REQUEST;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (ss.component_type == GSM0480_CTYPE_RETURN_RESULT &&
 | 
				
			||||||
 | 
									ss.opcode == GSM0480_OP_CODE_USS_REQUEST) {
 | 
				
			||||||
 | 
								// Menu selected
 | 
				
			||||||
 | 
								char buffer[160];
 | 
				
			||||||
 | 
								strncpy(buffer, ss.ussd_text, sizeof(buffer));
 | 
				
			||||||
 | 
								ss.ussd_text_len = snprintf(ss.ussd_text,
 | 
				
			||||||
 | 
											    sizeof(ss.ussd_text),
 | 
				
			||||||
 | 
											    "You've selected \"%s\"",
 | 
				
			||||||
 | 
											    buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ss.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
				
			||||||
 | 
								ss.component_type = GSM0480_CTYPE_RETURN_RESULT;
 | 
				
			||||||
 | 
								ss.opcode = GSM0480_OP_CODE_PROCESS_USS_REQ;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ss.ussd_text_len = 0;
 | 
				
			||||||
 | 
								ss.message_type = GSM0480_MTYPE_RELEASE_COMPLETE;
 | 
				
			||||||
 | 
								ss.component_type = GSM0480_CTYPE_REJECT;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ss.ussd_text_len > sizeof(ss.ussd_text))
 | 
				
			||||||
 | 
							ss.ussd_text_len = sizeof(ss.ussd_text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct msgb *msg = gsup_client_msgb_alloc();
 | 
				
			||||||
 | 
						subscr_uss_message(msg,
 | 
				
			||||||
 | 
								   &ss,
 | 
				
			||||||
 | 
								   (extention[0] == 0) ? NULL : extention);
 | 
				
			||||||
 | 
						LOGP(DGPRS, LOGL_INFO,
 | 
				
			||||||
 | 
						     "Sending USS, will send: %s\n", msgb_hexdump(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sup_server) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOTSUP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sup_server_send(sup_server, msg);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int rx_sup_message(struct gsm_sup_server *sup_server, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t *data = msgb_l2(msg);
 | 
				
			||||||
 | 
						size_t data_len = msgb_l2len(msg);
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct osmo_gsup_message sup_msg = {0};
 | 
				
			||||||
 | 
						//struct gsm_subscriber *subscr;
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    if (*data == OSMO_GSUP_MSGT_MAP) {
 | 
				
			||||||
 | 
						LOGP(DSUP, LOGL_INFO,
 | 
				
			||||||
 | 
							   "Receive USS: %s\n", msgb_hexdump(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rx_sup_uss_message(sup_server, data, data_len);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						rc = osmo_gsup_decode(data, data_len, &sup_msg);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR,
 | 
				
			||||||
 | 
							     "decoding SUP message fails with error '%s' (%d)\n",
 | 
				
			||||||
 | 
							     get_value_string(gsm48_gmm_cause_names, -rc), -rc);
 | 
				
			||||||
 | 
							return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sup_msg.imsi[0]) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "Missing IMSI in SUP message\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//		if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
 | 
				
			||||||
 | 
					//			subscr_tx_sup_error_reply(sup_client, NULL, &gsup_msg,
 | 
				
			||||||
 | 
					//							GMM_CAUSE_INV_MAND_INFO);
 | 
				
			||||||
 | 
							return -GMM_CAUSE_INV_MAND_INFO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	if (!gsup_msg.cause && OSMO_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
 | 
				
			||||||
 | 
					//		gsup_msg.cause = GMM_CAUSE_NET_FAIL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	subscr = subscr_get_by_imsi(NULL, gsup_msg.imsi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	if (!subscr) {
 | 
				
			||||||
 | 
					//		return subscr_handle_unknown_imsi(sup_client, &gsup_msg);
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUPP(LOGL_INFO, &sup_msg,
 | 
				
			||||||
 | 
							"Received SUP message of type 0x%02x\n", sup_msg.message_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (sup_msg.message_type) {
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
 | 
				
			||||||
 | 
							rc = handle_sup_upd_loc_req(sup_server, &sup_msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
 | 
				
			||||||
 | 
							//FIXME!!!!
 | 
				
			||||||
 | 
							//rc = subscr_handle_sup_auth_req(sup_server, &sup_msg);
 | 
				
			||||||
 | 
							rc = handle_sup_upd_loc_req(sup_server, &sup_msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_PURGE_MS_REQUEST:
 | 
				
			||||||
 | 
							rc = handle_sup_purge_ms_req(sup_server, &sup_msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
 | 
				
			||||||
 | 
						case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:
 | 
				
			||||||
 | 
							LOGGSUPP(LOGL_ERROR, &sup_msg,
 | 
				
			||||||
 | 
								"Rx SUP message type %d not yet implemented\n",
 | 
				
			||||||
 | 
								sup_msg.message_type);
 | 
				
			||||||
 | 
							//tx_sup_error_reply(sup_server, &sup_msg,
 | 
				
			||||||
 | 
							//				GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
 | 
				
			||||||
 | 
							rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOGGSUPP(LOGL_ERROR, &sup_msg,
 | 
				
			||||||
 | 
								"Rx SUP message type %d not valid\n",
 | 
				
			||||||
 | 
								sup_msg.message_type);
 | 
				
			||||||
 | 
							rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//subscr_put(subscr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tx_sup_message(struct gsm_sup_server *sup_server,
 | 
				
			||||||
 | 
													 struct osmo_gsup_message *sup_msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg = gsup_client_msgb_alloc();
 | 
				
			||||||
 | 
						printf("tx_sup_message \n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_gsup_encode(msg, sup_msg);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						printf("tx_sup_message encoded\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGGSUPP(LOGL_INFO, sup_msg,
 | 
				
			||||||
 | 
							    "Sending SUP, will send: %s\n", msgb_hexdump(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sup_server) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOTSUP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("tx_sup_message lets try to send\n");
 | 
				
			||||||
 | 
						return sup_server_send(sup_server, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int handle_location_update_result(struct gsm_sup_server *sup_server,
 | 
				
			||||||
 | 
													 char *imsi, char *msisdn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_gsup_message gsup_msg = {0};
 | 
				
			||||||
 | 
						u_int8_t msisdn_enc[9];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT;
 | 
				
			||||||
 | 
						printf("handle_location_update_result 1\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(gsup_msg.imsi, imsi, 17);
 | 
				
			||||||
 | 
						printf("handle_location_update_result %d  len = %d 2\n", gsup_msg.msisdn_enc, strlen(msisdn));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(imsi, msisdn) != 0) {
 | 
				
			||||||
 | 
							gsm48_encode_bcd_number(msisdn_enc, 9, 0, msisdn);
 | 
				
			||||||
 | 
							(&gsup_msg)->msisdn_enc = msisdn_enc + 1;
 | 
				
			||||||
 | 
							gsup_msg.msisdn_enc_len = msisdn_enc[0];
 | 
				
			||||||
 | 
							printf("handle_location_update_result %d %d\n", gsup_msg.msisdn_enc_len, gsup_msg.msisdn_enc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return tx_sup_message(sup_server, &gsup_msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int handle_purge_ms_result(struct gsm_sup_server *sup_server,
 | 
				
			||||||
 | 
													 char *imsi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_gsup_message gsup_msg = {0};
 | 
				
			||||||
 | 
						gsup_msg.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT;
 | 
				
			||||||
 | 
						memcpy(gsup_msg.imsi, imsi, 17);
 | 
				
			||||||
 | 
						return tx_sup_message(sup_server, &gsup_msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sup_read_cb(struct gsm_sup_server *sup_server, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Got message from nitb!\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = rx_sup_message(sup_server, msg);
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sup_server_init(struct reg_proxy *reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *addr_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr_str = "127.0.0.1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg->sup_server = sup_server_create(addr_str, 8183, &sup_read_cb, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!reg->sup_server)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										164
									
								
								openbsc/src/reg-proxy/sup_server.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								openbsc/src/reg-proxy/sup_server.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					/* GSM Subscriber Update Protocol server */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (C) 2015 by Ivan Klyuchnikov <kluchnikovi@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/abis/ipa.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/protocol/ipaccess.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/sup_server.h>
 | 
				
			||||||
 | 
					#include <openbsc/reg_proxy.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ipa_sock_server_cb(struct ipa_server_conn *conn, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_sup_server *sup_server = conn->data;
 | 
				
			||||||
 | 
						struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
 | 
				
			||||||
 | 
						struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg->l2h = &hh->data[0];	/* Handle IPA PING, PONG and ID_ACK messages. */
 | 
				
			||||||
 | 
						ret = ipa_ccm_rcvmsg_base(msg, &conn->ofd);
 | 
				
			||||||
 | 
						switch(ret) {
 | 
				
			||||||
 | 
						case -1:
 | 
				
			||||||
 | 
							/* error in IPA control message handling */
 | 
				
			||||||
 | 
							goto invalid;
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							/* this is an IPA control message, skip further processing */
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
							/* this is not an IPA control message, continue */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "Unexpected return from "
 | 
				
			||||||
 | 
										"ipa_ccm_rcvmsg_base "
 | 
				
			||||||
 | 
										"(ret=%d)\n", ret);
 | 
				
			||||||
 | 
							goto invalid;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hh->proto != IPAC_PROTO_OSMO)
 | 
				
			||||||
 | 
							goto invalid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!he || msgb_l2len(msg) < sizeof(*he) ||
 | 
				
			||||||
 | 
						    he->proto != IPAC_PROTO_EXT_GSUP)
 | 
				
			||||||
 | 
							goto invalid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg->l2h = &he->data[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(sup_server->read_cb != NULL);
 | 
				
			||||||
 | 
						sup_server->read_cb(sup_server, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Not freeing msg here, because that must be done by the read_cb. */
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					invalid:
 | 
				
			||||||
 | 
						LOGP(DSUP, LOGL_NOTICE,
 | 
				
			||||||
 | 
						     "SUP received an invalid IPA message from %s:%d, size = %d\n",
 | 
				
			||||||
 | 
						     sup_server->link->addr, sup_server->link->port, msgb_length(msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sup_accept_cb(struct ipa_server_link *link, int fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_sup_server *sup_server = link->data;
 | 
				
			||||||
 | 
						struct ipa_server_conn *server_conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						server_conn = talloc_zero(tall_reg_ctx, struct ipa_server_conn);
 | 
				
			||||||
 | 
						if (server_conn == NULL) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "cannot allocate memory for "
 | 
				
			||||||
 | 
									       "origin IPA\n");
 | 
				
			||||||
 | 
							close(fd);
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						server_conn = ipa_server_conn_create(tall_reg_ctx, link, fd,
 | 
				
			||||||
 | 
										   ipa_sock_server_cb, NULL, sup_server);
 | 
				
			||||||
 | 
						if (server_conn == NULL) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "could not create server peer: %s\n",
 | 
				
			||||||
 | 
								strerror(errno));
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sup_server->server_conn = server_conn;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct gsm_sup_server *sup_server_create(const char *ip_addr,
 | 
				
			||||||
 | 
											 unsigned int tcp_port,
 | 
				
			||||||
 | 
											 sup_read_cb_t read_cb,
 | 
				
			||||||
 | 
											 void *app)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gsm_sup_server *sup_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sup_server = talloc_zero(tall_reg_ctx, struct gsm_sup_server);
 | 
				
			||||||
 | 
						OSMO_ASSERT(sup_server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sup_server->app = app;
 | 
				
			||||||
 | 
						sup_server->read_cb = read_cb;
 | 
				
			||||||
 | 
						sup_server->link = ipa_server_link_create(tall_reg_ctx, NULL,
 | 
				
			||||||
 | 
										          ip_addr, tcp_port,
 | 
				
			||||||
 | 
											  sup_accept_cb, sup_server);
 | 
				
			||||||
 | 
						if (sup_server->link == NULL) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "cannot create OML "
 | 
				
			||||||
 | 
								"BSC link: %s\n", strerror(errno));
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ipa_server_link_open(sup_server->link) < 0) {
 | 
				
			||||||
 | 
							LOGP(DSUP, LOGL_ERROR, "cannot open OML BSC link: %s\n",
 | 
				
			||||||
 | 
								strerror(errno));
 | 
				
			||||||
 | 
							ipa_server_link_destroy(sup_server->link);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sup_server;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int sup_server_send(struct gsm_sup_server *sup_server, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!sup_server) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -ENOTCONN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sup_server->link) {
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							return -EAGAIN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_GSUP);
 | 
				
			||||||
 | 
						ipa_msg_push_header(msg, IPAC_PROTO_OSMO);
 | 
				
			||||||
 | 
						ipa_server_conn_send(sup_server->server_conn, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct msgb *sup_msgb_alloc(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return msgb_alloc_headroom(4000, 64, __func__);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										303
									
								
								openbsc/src/reg-proxy/tcp_client.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								openbsc/src/reg-proxy/tcp_client.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,303 @@
 | 
				
			|||||||
 | 
					//#include "internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <sys/fcntl.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					#include <ifaddrs.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <netdb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					#include <osmocom/gsm/tlv.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/logging.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
 | 
					//#include <osmocom/abis/e1_input.h>
 | 
				
			||||||
 | 
					//#include <osmocom/abis/ipaccess.h>
 | 
				
			||||||
 | 
					//#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/backtrace.h>
 | 
				
			||||||
 | 
					#include <openbsc/tcp_client.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tcp_client_conn_close(struct tcp_client_conn *link)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* be safe against multiple calls */
 | 
				
			||||||
 | 
						if (link->ofd->fd != -1) {
 | 
				
			||||||
 | 
							osmo_fd_unregister(link->ofd);
 | 
				
			||||||
 | 
							close(link->ofd->fd);
 | 
				
			||||||
 | 
							link->ofd->fd = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						msgb_free(link->pending_msg);
 | 
				
			||||||
 | 
						link->pending_msg = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_client_read(struct tcp_client_conn *link)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_fd *ofd = link->ofd;
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLINP, LOGL_DEBUG, "message received\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// FIX 1500
 | 
				
			||||||
 | 
						msg = msgb_alloc(1500, "TCP");
 | 
				
			||||||
 | 
						if (!msg)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("try to recv data msg->data = %d msg->data_len = %d \n", msg->data, msg->data_len);
 | 
				
			||||||
 | 
						ret = recv(ofd->fd, msg->data, msg->data_len, 0);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							if (ret == -EAGAIN)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							if (ret == -EPIPE || ret == -ECONNRESET)
 | 
				
			||||||
 | 
								LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
 | 
				
			||||||
 | 
							tcp_client_conn_close(link);
 | 
				
			||||||
 | 
							if (link->updown_cb)
 | 
				
			||||||
 | 
								link->updown_cb(link, 0);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						} else if (ret == 0) {
 | 
				
			||||||
 | 
							LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
 | 
				
			||||||
 | 
							tcp_client_conn_close(link);
 | 
				
			||||||
 | 
							if (link->updown_cb)
 | 
				
			||||||
 | 
								link->updown_cb(link, 0);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// TODO set len = ret
 | 
				
			||||||
 | 
						msg->data_len = ret;
 | 
				
			||||||
 | 
						printf("RECV SIP LEN = %d \n", ret);
 | 
				
			||||||
 | 
						if (link->read_cb)
 | 
				
			||||||
 | 
							link->read_cb(link, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_client_write(struct tcp_client_conn *link)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (link->write_cb)
 | 
				
			||||||
 | 
							link->write_cb(link);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcp_client_write_default_cb(struct tcp_client_conn *link)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct osmo_fd *ofd = link->ofd;
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
						struct llist_head *lh;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DLINP, LOGL_DEBUG, "sending data\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (llist_empty(&link->tx_queue)) {
 | 
				
			||||||
 | 
							ofd->when &= ~BSC_FD_WRITE;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lh = link->tx_queue.next;
 | 
				
			||||||
 | 
						llist_del(lh);
 | 
				
			||||||
 | 
						msg = llist_entry(lh, struct msgb, list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = send(link->ofd->fd, msg->data, msg->len, 0);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							if (errno == EPIPE || errno == ENOTCONN) {
 | 
				
			||||||
 | 
								tcp_client_conn_close(link);
 | 
				
			||||||
 | 
								if (link->updown_cb)
 | 
				
			||||||
 | 
									link->updown_cb(link, 0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							LOGP(DLINP, LOGL_ERROR, "error to send\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcp_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tcp_client_conn *link = ofd->data;
 | 
				
			||||||
 | 
						int error, ret;
 | 
				
			||||||
 | 
						socklen_t len = sizeof(error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch(link->state) {
 | 
				
			||||||
 | 
						case TCP_CLIENT_LINK_STATE_CONNECTING:
 | 
				
			||||||
 | 
							ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
 | 
				
			||||||
 | 
							if (ret >= 0 && error > 0) {
 | 
				
			||||||
 | 
								tcp_client_conn_close(link);
 | 
				
			||||||
 | 
								if (link->updown_cb)
 | 
				
			||||||
 | 
									link->updown_cb(link, 0);
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ofd->when &= ~BSC_FD_WRITE;
 | 
				
			||||||
 | 
							LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
 | 
				
			||||||
 | 
							link->state = TCP_CLIENT_LINK_STATE_CONNECTED;
 | 
				
			||||||
 | 
							if (link->updown_cb)
 | 
				
			||||||
 | 
								link->updown_cb(link, 1);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TCP_CLIENT_LINK_STATE_CONNECTED:
 | 
				
			||||||
 | 
							if (what & BSC_FD_READ) {
 | 
				
			||||||
 | 
								LOGP(DLINP, LOGL_DEBUG, "connected read\n");
 | 
				
			||||||
 | 
								tcp_client_read(link);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (what & BSC_FD_WRITE) {
 | 
				
			||||||
 | 
								LOGP(DLINP, LOGL_DEBUG, "connected write\n");
 | 
				
			||||||
 | 
								tcp_client_write(link);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tcp_client_conn * tcp_client_conn_create(void *ctx, int priv_nr,
 | 
				
			||||||
 | 
							       const char *dst_addr, uint16_t dst_port,
 | 
				
			||||||
 | 
							       const char *src_addr, uint16_t src_port,
 | 
				
			||||||
 | 
							       void (*updown_cb)(struct tcp_client_conn *link, int up),
 | 
				
			||||||
 | 
							       int (*read_cb)(struct tcp_client_conn *link,
 | 
				
			||||||
 | 
									      struct msgb *msgb),
 | 
				
			||||||
 | 
							       int (*write_cb)(struct tcp_client_conn *link),
 | 
				
			||||||
 | 
							       void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tcp_client_conn *tcp_link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcp_link = talloc_zero(ctx, struct tcp_client_conn);
 | 
				
			||||||
 | 
						if (!tcp_link)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcp_link->ofd = talloc_zero(ctx, struct osmo_fd);
 | 
				
			||||||
 | 
						if (tcp_link->ofd == NULL) {
 | 
				
			||||||
 | 
							talloc_free(tcp_link);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcp_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
 | 
				
			||||||
 | 
						tcp_link->ofd->priv_nr = priv_nr;
 | 
				
			||||||
 | 
						tcp_link->ofd->cb = tcp_client_fd_cb;
 | 
				
			||||||
 | 
						tcp_link->ofd->data = tcp_link;
 | 
				
			||||||
 | 
						tcp_link->ofd->fd = -1;
 | 
				
			||||||
 | 
						tcp_link->state = TCP_CLIENT_LINK_STATE_CONNECTING;
 | 
				
			||||||
 | 
						tcp_link->src_addr = talloc_strdup(tcp_link, src_addr);
 | 
				
			||||||
 | 
						tcp_link->src_port = src_port;
 | 
				
			||||||
 | 
						tcp_link->dst_addr = talloc_strdup(tcp_link, dst_addr);
 | 
				
			||||||
 | 
						tcp_link->dst_port = dst_port;
 | 
				
			||||||
 | 
						tcp_link->updown_cb = updown_cb;
 | 
				
			||||||
 | 
						tcp_link->read_cb = read_cb;
 | 
				
			||||||
 | 
						/* default to generic write callback if not set. */
 | 
				
			||||||
 | 
						if (write_cb == NULL)
 | 
				
			||||||
 | 
							tcp_link->write_cb = tcp_client_write_default_cb;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							tcp_link->write_cb = write_cb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcp_link->data = data;
 | 
				
			||||||
 | 
						INIT_LLIST_HEAD(&tcp_link->tx_queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return tcp_link;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tcp_client_conn_destroy(struct tcp_client_conn *link)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						talloc_free(link);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tcp_client_conn_open(struct tcp_client_conn *link)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						struct addrinfo hints, *bind_addr, *connect_addr;
 | 
				
			||||||
 | 
						int sfd, rc, on = 1;
 | 
				
			||||||
 | 
						char src_port_buf[16];
 | 
				
			||||||
 | 
						char dst_port_buf[16];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						link->state = TCP_CLIENT_LINK_STATE_CONNECTING;
 | 
				
			||||||
 | 
					//	ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
 | 
				
			||||||
 | 
					//			     link->addr, link->port,
 | 
				
			||||||
 | 
					//			     OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
 | 
				
			||||||
 | 
								     
 | 
				
			||||||
 | 
						sprintf(src_port_buf, "%u", link->src_port);		     
 | 
				
			||||||
 | 
						sprintf(dst_port_buf, "%u", link->dst_port);		     
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&hints, 0, sizeof(struct addrinfo));
 | 
				
			||||||
 | 
						hints.ai_family = AF_INET;
 | 
				
			||||||
 | 
						hints.ai_socktype = SOCK_STREAM;
 | 
				
			||||||
 | 
						hints.ai_protocol = IPPROTO_TCP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = getaddrinfo(link->dst_addr, dst_port_buf, &hints, &connect_addr);
 | 
				
			||||||
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							perror("getaddrinfo returned NULL");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hints.ai_flags |= AI_PASSIVE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = getaddrinfo(link->src_addr, src_port_buf, &hints, &bind_addr);
 | 
				
			||||||
 | 
						if (rc != 0) {
 | 
				
			||||||
 | 
							perror("getaddrinfo returned NULL");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sfd = socket(connect_addr->ai_family, connect_addr->ai_socktype, connect_addr->ai_protocol);
 | 
				
			||||||
 | 
						if (sfd < 0) {
 | 
				
			||||||
 | 
							perror("cannot create socket");
 | 
				
			||||||
 | 
					        return sfd;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) {
 | 
				
			||||||
 | 
							perror("cannot set this socket unblocking");
 | 
				
			||||||
 | 
							close(sfd);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							perror("cannot setsockopt socket");
 | 
				
			||||||
 | 
							close(sfd);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = bind(sfd, bind_addr->ai_addr, bind_addr->ai_addrlen);
 | 
				
			||||||
 | 
						if (rc < 0) {
 | 
				
			||||||
 | 
							perror("cannot bind socket");
 | 
				
			||||||
 | 
							close(sfd);
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = connect(sfd, connect_addr->ai_addr, connect_addr->ai_addrlen);
 | 
				
			||||||
 | 
						if (rc <0 && errno != EINPROGRESS) {
 | 
				
			||||||
 | 
							perror("cannot connect socket");
 | 
				
			||||||
 | 
							close(sfd);
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						freeaddrinfo(bind_addr);
 | 
				
			||||||
 | 
						freeaddrinfo(connect_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						listen(sfd, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						link->ofd->fd = sfd;
 | 
				
			||||||
 | 
						link->ofd->when |= BSC_FD_WRITE;
 | 
				
			||||||
 | 
						if (osmo_fd_register(link->ofd) < 0) {
 | 
				
			||||||
 | 
							close(sfd);
 | 
				
			||||||
 | 
							link->ofd->fd = -1;
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tcp_client_conn_send(struct tcp_client_conn *link, struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						msgb_enqueue(&link->tx_queue, msg);
 | 
				
			||||||
 | 
						link->ofd->when |= BSC_FD_WRITE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t tcp_client_conn_clear_queue(struct tcp_client_conn *link)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t deleted = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (!llist_empty(&link->tx_queue)) {
 | 
				
			||||||
 | 
							struct msgb *msg = msgb_dequeue(&link->tx_queue);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
							deleted += 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						link->ofd->when &= ~BSC_FD_WRITE;
 | 
				
			||||||
 | 
						return deleted;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										165
									
								
								openbsc/src/reg-proxy/test_sip.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										165
									
								
								openbsc/src/reg-proxy/test_sip.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,165 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					import binascii
 | 
				
			||||||
 | 
					import sip_parser
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					from twisted.internet import defer
 | 
				
			||||||
 | 
					from twisted.internet import protocol
 | 
				
			||||||
 | 
					from twisted.python import log
 | 
				
			||||||
 | 
					from twisted.protocols import sip
 | 
				
			||||||
 | 
					from time import sleep
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TCP_SRC_IP   = "127.0.0.1"
 | 
				
			||||||
 | 
					TCP_SRC_PORT = 5060
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RegistrationProxyServer(protocol.Protocol):
 | 
				
			||||||
 | 
					    src_ip = TCP_SRC_IP
 | 
				
			||||||
 | 
					    src_port = TCP_SRC_PORT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def connectionMade(self):
 | 
				
			||||||
 | 
					        self.ussd_queue = defer.DeferredQueue()
 | 
				
			||||||
 | 
					        self.ussd_queue.get().addCallback(self.sipClientDataReceived)
 | 
				
			||||||
 | 
					        from twisted.internet import reactor
 | 
				
			||||||
 | 
					        #reactor.listenTCP(UDP_TCP_PORT, self.sip_client_factory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def sipClientDataReceived(self, data):
 | 
				
			||||||
 | 
					        log.msg("\n[USSD:RX]\n%s" % data)
 | 
				
			||||||
 | 
					        if data:
 | 
				
			||||||
 | 
					          self.ussd_queue.get().addCallback(self.sipClientDataReceived)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          msgType, firstLine, headers, body = sip_parser.parseSipMessage(data)
 | 
				
			||||||
 | 
					          #print headers
 | 
				
			||||||
 | 
					          via = headers["via"][0].split(";")
 | 
				
			||||||
 | 
					          via_branch = via[1].split("=")
 | 
				
			||||||
 | 
					          from_hdr = headers["from"].split(";")
 | 
				
			||||||
 | 
					          from_tag = from_hdr[1]
 | 
				
			||||||
 | 
					          to_hdr = headers["to"].split(";")
 | 
				
			||||||
 | 
					          to_tag = "%s" % from_hdr[1]
 | 
				
			||||||
 | 
					          call_id = headers["call-id"]
 | 
				
			||||||
 | 
					          try:
 | 
				
			||||||
 | 
					              ctype = headers["content-type"]
 | 
				
			||||||
 | 
					          except:
 | 
				
			||||||
 | 
					              ctype = ""
 | 
				
			||||||
 | 
					          sip_url = re.split(r"[:@]", from_hdr[0])
 | 
				
			||||||
 | 
					          ussd_url = sip_url[1]
 | 
				
			||||||
 | 
					          try:
 | 
				
			||||||
 | 
					              contact = headers["contact"].split("@")
 | 
				
			||||||
 | 
					          except:
 | 
				
			||||||
 | 
					              pass
 | 
				
			||||||
 | 
					          cseq = headers["cseq"]
 | 
				
			||||||
 | 
					          via_dest_ip,via_dest_port=via[0].split(" ")[1].split(":")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if msgType=="INVITE":
 | 
				
			||||||
 | 
					              #sleep(5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              r = sip.Response(200, "OK")
 | 
				
			||||||
 | 
					              r.addHeader('Via',  headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
 | 
				
			||||||
 | 
					              r.addHeader('From', "%s;%s" % (from_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
 | 
				
			||||||
 | 
					              r.addHeader('To', "%s;%s" % (to_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
 | 
				
			||||||
 | 
					              r.addHeader('Call-Id', call_id)
 | 
				
			||||||
 | 
					              r.addHeader('Max-Forwards', 20)
 | 
				
			||||||
 | 
					              r.addHeader('Cseq',  cseq)
 | 
				
			||||||
 | 
					              r.addHeader('Contact',  '<sip:test@127.0.0.1:5060>')
 | 
				
			||||||
 | 
					              r.addHeader('Recv-Info', 'g.3gpp.ussd')
 | 
				
			||||||
 | 
					              r.addHeader('Content-Length', 0)
 | 
				
			||||||
 | 
					              #r.addHeader("Authentication-Info", auth_info)
 | 
				
			||||||
 | 
					              log.msg("\n[SIP:TX]\n%s" % r.toString())
 | 
				
			||||||
 | 
					              self.transport.write(r.toString())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              r = sip.Response(100, "Trying")
 | 
				
			||||||
 | 
					              r.addHeader('Via',  headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
 | 
				
			||||||
 | 
					              r.addHeader('From', "%s;%s" % (from_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
 | 
				
			||||||
 | 
					              r.addHeader('To', "%s;%s" % (to_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
 | 
				
			||||||
 | 
					              r.addHeader('Call-Id', call_id)
 | 
				
			||||||
 | 
					              r.addHeader('Max-Forwards', 20)
 | 
				
			||||||
 | 
					              r.addHeader('Cseq',  cseq)
 | 
				
			||||||
 | 
					              r.addHeader('Contact',  '<sip:test@127.0.0.1:5060>')
 | 
				
			||||||
 | 
					              r.addHeader('Content-Length', 0)
 | 
				
			||||||
 | 
					              log.msg("\n[SIP:TX]\n%s" % r.toString())
 | 
				
			||||||
 | 
					              self.transport.write(r.toString())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          elif msgType=="ACK" and to_hdr[0].startswith("<sip:*101"):
 | 
				
			||||||
 | 
					              msg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ussd-data><language>en</language><ussd-string>%s</ussd-string></ussd-data>" % (
 | 
				
			||||||
 | 
					                                "Select Item from menu:\n1) Option 1\n2) Option 2");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              r = sip.Request("INFO", to_hdr[0].replace('<', '').replace('>', ''))
 | 
				
			||||||
 | 
					              r.addHeader('Via', headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
 | 
				
			||||||
 | 
					              r.addHeader('From', "%s;%s" % (from_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
 | 
				
			||||||
 | 
					              r.addHeader('To', "%s;%s" % (to_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
 | 
				
			||||||
 | 
					              r.addHeader('Call-Id', call_id)
 | 
				
			||||||
 | 
					              r.addHeader('Max-Forwards', 20)
 | 
				
			||||||
 | 
					              r.addHeader('Cseq',  "%d INFO" % (int(cseq.split(' ')[0]) + 1))
 | 
				
			||||||
 | 
					              r.addHeader('Recv-Info', 'g.3gpp.ussd')
 | 
				
			||||||
 | 
					              r.addHeader('Content-Type', 'application/vnd.3gpp.ussd+xml')
 | 
				
			||||||
 | 
					              #r.addHeader('Content-Disposition', 'Info-Package')
 | 
				
			||||||
 | 
					              r.addHeader('Content-Length', len(msg))
 | 
				
			||||||
 | 
					              #r.addHeader("Authentication-Info", auth_info)
 | 
				
			||||||
 | 
					              log.msg("\n[SIP:TX]]\n%s" % r.toString())
 | 
				
			||||||
 | 
					              self.transport.write(r.toString() + msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          elif msgType=="ACK" or msgType=="INFO":
 | 
				
			||||||
 | 
					              msg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ussd-data><language>en</language><ussd-string>%s</ussd-string></ussd-data>" % (
 | 
				
			||||||
 | 
					                                "Test");
 | 
				
			||||||
 | 
					              if msgType=="INFO":
 | 
				
			||||||
 | 
					                  r = sip.Response(200, "OK")
 | 
				
			||||||
 | 
					                  r.addHeader('Via',  headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
 | 
				
			||||||
 | 
					                  r.addHeader('From', "%s;%s" % (from_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
 | 
				
			||||||
 | 
					                  r.addHeader('To', "%s;%s" % (to_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
 | 
				
			||||||
 | 
					                  r.addHeader('Call-Id', call_id)
 | 
				
			||||||
 | 
					                  r.addHeader('Max-Forwards', 20)
 | 
				
			||||||
 | 
					                  r.addHeader('Cseq',  cseq)
 | 
				
			||||||
 | 
					                  r.addHeader('Recv-Info', 'g.3gpp.ussd')
 | 
				
			||||||
 | 
					                  r.addHeader('Content-Length', 0)
 | 
				
			||||||
 | 
					                  #r.addHeader("Authentication-Info", auth_info)
 | 
				
			||||||
 | 
					                  log.msg("\n[SIP:TX]\n%s" % r.toString())
 | 
				
			||||||
 | 
					                  self.transport.write(r.toString())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              r = sip.Request("BYE", to_hdr[0].replace('<', '').replace('>', ''))
 | 
				
			||||||
 | 
					              r.addHeader('Via', headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
 | 
				
			||||||
 | 
					              r.addHeader('From', "%s;%s" % (from_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
 | 
				
			||||||
 | 
					              r.addHeader('To', "%s;%s" % (to_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
 | 
				
			||||||
 | 
					              r.addHeader('Call-Id', call_id)
 | 
				
			||||||
 | 
					              r.addHeader('Max-Forwards', 20)
 | 
				
			||||||
 | 
					              r.addHeader('Cseq',  "%d BYE" % (int(cseq.split(' ')[0]) + 1))
 | 
				
			||||||
 | 
					              if to_hdr[0].startswith('<sip:mapss'):
 | 
				
			||||||
 | 
					                      # Copy InvokeID
 | 
				
			||||||
 | 
					                      #      a10b02010602010e3003040121
 | 
				
			||||||
 | 
					                      #      --------__----------------  invoke_id
 | 
				
			||||||
 | 
					                      #msg = 'a20b0201%c%c300602010e80010c' % (body[8],body[9])
 | 
				
			||||||
 | 
					                      msg =  'a20b02010c300602010e80010c'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      r.addHeader('Content-Type', 'application/map-ss-binary')
 | 
				
			||||||
 | 
					                      r.addHeader('Content-Length', len(msg))
 | 
				
			||||||
 | 
					              else:
 | 
				
			||||||
 | 
					                      r.addHeader('Recv-Info', 'g.3gpp.ussd')
 | 
				
			||||||
 | 
					                      r.addHeader('Content-Type', 'application/vnd.3gpp.ussd+xml')
 | 
				
			||||||
 | 
					                      #r.addHeader('Content-Disposition', 'Info-Package')
 | 
				
			||||||
 | 
					                      r.addHeader('Content-Length', len(msg))
 | 
				
			||||||
 | 
					                      #r.addHeader("Authentication-Info", auth_info)
 | 
				
			||||||
 | 
					              log.msg("\n[SIP:TX]]\n%s" % r.toString())
 | 
				
			||||||
 | 
					              self.transport.write(r.toString() + msg)
 | 
				
			||||||
 | 
					          else:
 | 
				
			||||||
 | 
					              print msgType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          #self.ussd_queue.get().addCallback(self.sipClientDataReceived)
 | 
				
			||||||
 | 
					          #self.ussd_queue.get().addCallback(self.sipClientDataReceived)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dataReceived(self, data):
 | 
				
			||||||
 | 
					          #log.msg("\n[IMSI:RX] [Proxy <=============== BSC]\n%s" % data)
 | 
				
			||||||
 | 
					          self.ussd_queue.put(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RegistrationProxyServerFactory(protocol.ClientFactory):
 | 
				
			||||||
 | 
					    protocol = RegistrationProxyServer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    log.startLogging(sys.stdout)
 | 
				
			||||||
 | 
					    factory = RegistrationProxyServerFactory()
 | 
				
			||||||
 | 
					    from twisted.internet import reactor
 | 
				
			||||||
 | 
					    reactor.listenTCP(TCP_SRC_PORT, factory)
 | 
				
			||||||
 | 
					    reactor.run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								openbsc/src/ussd-proxy/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								openbsc/src/ussd-proxy/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					if BUILD_USSD_PROXY
 | 
				
			||||||
 | 
					AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
 | 
				
			||||||
 | 
					AM_CFLAGS=-Wall	$(COVERAGE_CFLAGS)			\
 | 
				
			||||||
 | 
					  	$(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) \
 | 
				
			||||||
 | 
						   -I/usr/include/sofia-sip-1.12 -DNO_GSM0480_SEND_FUNC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AM_LDFLAGS = $(COVERAGE_LDFLAGS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bin_PROGRAMS = ussd-proxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ussd_proxy_SOURCES = \
 | 
				
			||||||
 | 
							ussd_proxy.c ../libmsc/gsm_ussd_map_proto.c ../libmsc/gsm_04_80.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ussd_proxy_LDADD = \
 | 
				
			||||||
 | 
							-lsofia-sip-ua \
 | 
				
			||||||
 | 
							$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS)  \
 | 
				
			||||||
 | 
							$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
							
								
								
									
										1545
									
								
								openbsc/src/ussd-proxy/ussd_proxy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1545
									
								
								openbsc/src/ussd-proxy/ussd_proxy.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -25,6 +25,7 @@ noinst_HEADERS = \
 | 
				
			|||||||
bin_PROGRAMS = \
 | 
					bin_PROGRAMS = \
 | 
				
			||||||
	bs11_config \
 | 
						bs11_config \
 | 
				
			||||||
	isdnsync \
 | 
						isdnsync \
 | 
				
			||||||
 | 
						meas_json \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
if HAVE_SQLITE3
 | 
					if HAVE_SQLITE3
 | 
				
			||||||
bin_PROGRAMS += \
 | 
					bin_PROGRAMS += \
 | 
				
			||||||
@@ -121,3 +122,18 @@ osmo_meas_udp2db_CFLAGS = \
 | 
				
			|||||||
	$(LIBOSMOCORE_CFLAGS) \
 | 
						$(LIBOSMOCORE_CFLAGS) \
 | 
				
			||||||
	$(LIBOSMOGSM_CFLAGS) \
 | 
						$(LIBOSMOGSM_CFLAGS) \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					meas_json_SOURCES = \
 | 
				
			||||||
 | 
						meas_json.c \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					meas_json_LDADD = \
 | 
				
			||||||
 | 
						$(top_builddir)/src/libcommon/libcommon.a \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOGSM_LIBS) \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					meas_json_CFLAGS = \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_CFLAGS) \
 | 
				
			||||||
 | 
						$(LIBOSMOGSM_CFLAGS) \
 | 
				
			||||||
 | 
						$(NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										189
									
								
								openbsc/src/utils/meas_json.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								openbsc/src/utils/meas_json.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,189 @@
 | 
				
			|||||||
 | 
					/* Convert measurement report feed into JSON feed printed to stdout.
 | 
				
			||||||
 | 
					 * Each measurement report is printed as a separae JSON root entry.
 | 
				
			||||||
 | 
					 * All measurement reports are separated by a new line.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
 | 
				
			||||||
 | 
					 * With parts of code adopted from different places in OpenBSC.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/socket.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/select.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/gsm/gsm_utils.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/gsm_data.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_data_shared.h>
 | 
				
			||||||
 | 
					#include <openbsc/meas_feed.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_meas_rep_uni_json(struct gsm_meas_rep_unidir *mru)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("\"RXL-FULL\":%d, \"RXL-SUB\":%d, ",
 | 
				
			||||||
 | 
							rxlev2dbm(mru->full.rx_lev),
 | 
				
			||||||
 | 
							rxlev2dbm(mru->sub.rx_lev));
 | 
				
			||||||
 | 
						printf("\"RXQ-FULL\":%d, \"RXQ-SUB\":%d",
 | 
				
			||||||
 | 
							mru->full.rx_qual, mru->sub.rx_qual);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_meas_rep_json(struct gsm_meas_rep *mr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("\"NR\":%d", mr->nr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mr->flags & MEAS_REP_F_DL_DTX)
 | 
				
			||||||
 | 
							printf(", \"DTXd\":true");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf(", \"UL_MEAS\":{");
 | 
				
			||||||
 | 
						print_meas_rep_uni_json(&mr->ul);
 | 
				
			||||||
 | 
						printf("}");
 | 
				
			||||||
 | 
						printf(", \"BS_POWER\":%d", mr->bs_power);
 | 
				
			||||||
 | 
						if (mr->flags & MEAS_REP_F_MS_TO)
 | 
				
			||||||
 | 
							printf(", \"MS_TO\":%d", mr->ms_timing_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mr->flags & MEAS_REP_F_MS_L1) {
 | 
				
			||||||
 | 
							printf(", \"L1_MS_PWR\":%d", mr->ms_l1.pwr);
 | 
				
			||||||
 | 
							printf(", \"L1_FPC\":%s",
 | 
				
			||||||
 | 
								mr->flags & MEAS_REP_F_FPC ? "true" : "false");
 | 
				
			||||||
 | 
							printf(", \"L1_TA\":%u", mr->ms_l1.ta);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mr->flags & MEAS_REP_F_UL_DTX)
 | 
				
			||||||
 | 
							printf(", \"DTXu\":true");
 | 
				
			||||||
 | 
						if (mr->flags & MEAS_REP_F_BA1)
 | 
				
			||||||
 | 
							printf(", \"BA1\":true");
 | 
				
			||||||
 | 
						if (mr->flags & MEAS_REP_F_DL_VALID) {
 | 
				
			||||||
 | 
							printf(", \"DL_MEAS\":{");
 | 
				
			||||||
 | 
							print_meas_rep_uni_json(&mr->dl);
 | 
				
			||||||
 | 
							printf("}");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mr->num_cell == 7)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						printf(", \"NUM_NEIGH\":%u, \"NEIGH\":[", mr->num_cell);
 | 
				
			||||||
 | 
						for (i = 0; i < mr->num_cell; i++) {
 | 
				
			||||||
 | 
							struct gsm_meas_rep_cell *mrc = &mr->cell[i];
 | 
				
			||||||
 | 
							if (i!=0) printf(", ");
 | 
				
			||||||
 | 
							printf("\"IDX\":%u, \"ARFCN\":%u, \"BSIC\":%u, \"POWER\":%d",
 | 
				
			||||||
 | 
								mrc->neigh_idx, mrc->arfcn, mrc->bsic, rxlev2dbm(mrc->rxlev));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						printf("]");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_chan_info_json(struct meas_feed_meas *mfm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						printf("\"lchan_type\":\"%s\", \"pchan_type\":\"%s\", "
 | 
				
			||||||
 | 
							   "\"bts_nr\":%d, \"trx_nr\":%d, \"ts_nr\":%d, \"ss_nr\":%d",
 | 
				
			||||||
 | 
						gsm_lchant_name(mfm->lchan_type), gsm_pchan_name(mfm->pchan_type),
 | 
				
			||||||
 | 
						mfm->bts_nr, mfm->trx_nr, mfm->ts_nr, mfm->ss_nr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void print_meas_feed_json(struct meas_feed_meas *mfm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						time_t now = time(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("{");
 | 
				
			||||||
 | 
						printf("\"time\":%ld, \"imsi\":\"%s\", \"name\":\"%s\", \"scenario\":\"%s\", ",
 | 
				
			||||||
 | 
							now, mfm->imsi, mfm->name, mfm->scenario);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (mfm->hdr.version) {
 | 
				
			||||||
 | 
						case 1:
 | 
				
			||||||
 | 
							printf("\"chan_info\":{");
 | 
				
			||||||
 | 
							print_chan_info_json(mfm);
 | 
				
			||||||
 | 
							printf("}, ");
 | 
				
			||||||
 | 
							/* no break, fall to version 0 */
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
							printf("\"meas_rep\":{");
 | 
				
			||||||
 | 
							print_meas_rep_json(&mfm->mr);
 | 
				
			||||||
 | 
							printf("}");
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("}\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int handle_meas(struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct meas_feed_meas *mfm = (struct meas_feed_meas *) msgb_data(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						print_meas_feed_json(mfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int handle_msg(struct msgb *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct meas_feed_hdr *mfh = (struct meas_feed_hdr *) msgb_data(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (mfh->version != MEAS_FEED_VERSION)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (mfh->msg_type) {
 | 
				
			||||||
 | 
						case MEAS_FEED_MEAS:
 | 
				
			||||||
 | 
							handle_meas(msg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int udp_fd_cb(struct osmo_fd *ofd, unsigned int what)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (what & BSC_FD_READ) {
 | 
				
			||||||
 | 
							struct msgb *msg = msgb_alloc(1024, "UDP Rx");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc = read(ofd->fd, msgb_data(msg), msgb_tailroom(msg));
 | 
				
			||||||
 | 
							if (rc < 0)
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
							msgb_put(msg, rc);
 | 
				
			||||||
 | 
							handle_msg(msg);
 | 
				
			||||||
 | 
							msgb_free(msg);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						struct osmo_fd udp_ofd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						udp_ofd.cb = udp_fd_cb;
 | 
				
			||||||
 | 
						rc =  osmo_sock_init_ofd(&udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 8888, OSMO_SOCK_F_BIND);
 | 
				
			||||||
 | 
						if (rc < 0)
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							osmo_select_main(0);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						exit(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,6 +10,7 @@ SUBDIRS = \
 | 
				
			|||||||
	subscr \
 | 
						subscr \
 | 
				
			||||||
	mm_auth \
 | 
						mm_auth \
 | 
				
			||||||
	nanobts_omlattr \
 | 
						nanobts_omlattr \
 | 
				
			||||||
 | 
						ussd \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if BUILD_NAT
 | 
					if BUILD_NAT
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,6 +136,7 @@ void sms_alloc() {}
 | 
				
			|||||||
void sms_free() {}
 | 
					void sms_free() {}
 | 
				
			||||||
void gsm_net_update_ctype(struct gsm_network *network) {}
 | 
					void gsm_net_update_ctype(struct gsm_network *network) {}
 | 
				
			||||||
void gsm48_secure_channel() {}
 | 
					void gsm48_secure_channel() {}
 | 
				
			||||||
 | 
					void gsm0408_purge_ms() {}
 | 
				
			||||||
void paging_request_stop() {}
 | 
					void paging_request_stop() {}
 | 
				
			||||||
void vty_out() {}
 | 
					void vty_out() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,7 +114,7 @@ int auth_get_tuple_for_subscr_verbose(struct gsm_auth_tuple *atuple,
 | 
				
			|||||||
				      int key_seq)
 | 
									      int key_seq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int auth_action;
 | 
						int auth_action;
 | 
				
			||||||
	auth_action = auth_get_tuple_for_subscr(atuple, subscr, key_seq);
 | 
						auth_action = auth_get_tuple_for_subscr(GSM_AUTH_POLICY_ACCEPT_ALL, atuple, subscr, key_seq);
 | 
				
			||||||
	printf("auth_get_tuple_for_subscr(key_seq=%d) --> auth_action == %s\n",
 | 
						printf("auth_get_tuple_for_subscr(key_seq=%d) --> auth_action == %s\n",
 | 
				
			||||||
	       key_seq, auth_action_str(auth_action));
 | 
						       key_seq, auth_action_str(auth_action));
 | 
				
			||||||
	return auth_action;
 | 
						return auth_action;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,12 +85,6 @@ cat $abs_srcdir/bsc/bsc_test.ok > expout
 | 
				
			|||||||
AT_CHECK([$abs_top_builddir/tests/bsc/bsc_test], [], [expout], [ignore])
 | 
					AT_CHECK([$abs_top_builddir/tests/bsc/bsc_test], [], [expout], [ignore])
 | 
				
			||||||
AT_CLEANUP
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AT_SETUP([gbproxy])
 | 
					 | 
				
			||||||
AT_KEYWORDS([gbproxy])
 | 
					 | 
				
			||||||
cat $abs_srcdir/gbproxy/gbproxy_test.ok > expout
 | 
					 | 
				
			||||||
AT_CHECK([$abs_top_builddir/tests/gbproxy/gbproxy_test], [], [expout], [ignore])
 | 
					 | 
				
			||||||
AT_CLEANUP
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
AT_SETUP([trau])
 | 
					AT_SETUP([trau])
 | 
				
			||||||
AT_KEYWORDS([trau])
 | 
					AT_KEYWORDS([trau])
 | 
				
			||||||
cat $abs_srcdir/trau/trau_test.ok > expout
 | 
					cat $abs_srcdir/trau/trau_test.ok > expout
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								openbsc/tests/ussd/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								openbsc/tests/ussd/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
 | 
				
			||||||
 | 
					AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS)
 | 
				
			||||||
 | 
					noinst_PROGRAMS = ss_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# EXTRA_DIST = ss_test.ok
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ss_test_SOURCES = ss_test.c
 | 
				
			||||||
 | 
					ss_test_LDADD =	$(top_builddir)/src/libbsc/libbsc.a \
 | 
				
			||||||
 | 
								$(top_builddir)/src/libmsc/libmsc.a \
 | 
				
			||||||
 | 
								$(top_builddir)/src/libbsc/libbsc.a \
 | 
				
			||||||
 | 
								$(top_builddir)/src/libcommon/libcommon.a \
 | 
				
			||||||
 | 
								$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -ldbi
 | 
				
			||||||
							
								
								
									
										199
									
								
								openbsc/tests/ussd/ss_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								openbsc/tests/ussd/ss_test.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,199 @@
 | 
				
			|||||||
 | 
					/* simple test for the gsm0480  */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 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 Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <openbsc/gsm_ussd_map.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_ussd_map_proto.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_04_80.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_subscriber.h>
 | 
				
			||||||
 | 
					#include <openbsc/debug.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define COMPARE(result, op, value) \
 | 
				
			||||||
 | 
					    if (!((result) op (value))) {\
 | 
				
			||||||
 | 
						fprintf(stderr, "Compare failed. Was %x should be %x in %s:%d\n",result, value, __FILE__, __LINE__); \
 | 
				
			||||||
 | 
						exit(-1); \
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define COMPARE_STR(result, value) \
 | 
				
			||||||
 | 
						if (strcmp(result, value) != 0) { \
 | 
				
			||||||
 | 
							fprintf(stderr, "Compare failed. Was %s should be %s in %s:%d\n",result, value, __FILE__, __LINE__); \
 | 
				
			||||||
 | 
							exit(-1); \
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DBG(...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VERIFY(res, cmp, wanted)					\
 | 
				
			||||||
 | 
						if (!(res cmp wanted)) {					\
 | 
				
			||||||
 | 
							printf("ASSERT failed: %s:%d Wanted: %d %s %d\n",	\
 | 
				
			||||||
 | 
								__FILE__, __LINE__, res, # cmp, wanted);	\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t test_ss_int_01[] = {
 | 
				
			||||||
 | 
					0xa1, 0x0e, 0x02, 0x01, 0x00, 0x02, 0x01, 0x0e, 0x30, 0x06, 0x04, 0x01, 0x21, 0x83, 0x01, 0x10
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t test_ss_int_02[] = {
 | 
				
			||||||
 | 
					0xa1, 0x0b, 0x02, 0x01, 0x01, 0x02, 0x01, 0x0e, 0x30, 0x03, 0x04, 0x01, 0x21
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t test_ss_int_03[] = {
 | 
				
			||||||
 | 
					0xa1, 0x17, 0x02, 0x01, 0x01, 0x02, 0x01, 0x0a, 0x30, 0x0f, 0x04, 0x01, 0x21,
 | 
				
			||||||
 | 
					0x83, 0x01, 0x10, 0x84, 0x07, 0x91, 0x52, 0x75, 0x89, 0x46, 0x36, 0x25
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t test_ussd_01[] = {
 | 
				
			||||||
 | 
					0xa1, 0x81, 0x83, 0x02, 0x01, 0x01, 0x02, 0x01, 0x3c, 0x30, 0x7b, 0x04, 0x01,
 | 
				
			||||||
 | 
					0x0f, 0x04, 0x76, 0xd3, 0x66, 0x50, 0x4a, 0x55, 0xc4, 0x5c, 0x20, 0x6b, 0xda,
 | 
				
			||||||
 | 
					0x5c, 0x97, 0xd7, 0xe7, 0xe8, 0x34, 0xc8, 0x9e, 0x0f, 0x83, 0x68, 0x47, 0x50,
 | 
				
			||||||
 | 
					0xd2, 0x4d, 0x0f, 0xbb, 0xcb, 0xf4, 0xb4, 0x42, 0xe6, 0x02, 0x59, 0xd3, 0xe6,
 | 
				
			||||||
 | 
					0xba, 0xbc, 0x3e, 0x47, 0xa7, 0x41, 0xd6, 0x7c, 0x18, 0x34, 0x6d, 0x06, 0xa9,
 | 
				
			||||||
 | 
					0xc9, 0x65, 0x50, 0x31, 0x73, 0x81, 0xac, 0x69, 0x73, 0x5d, 0x5e, 0x9f, 0xa3,
 | 
				
			||||||
 | 
					0xd3, 0x20, 0x7b, 0x3e, 0x0c, 0x5a, 0xa7, 0xdb, 0x61, 0x7a, 0x38, 0x6d, 0x0e,
 | 
				
			||||||
 | 
					0xbb, 0x14, 0x34, 0x17, 0x68, 0xda, 0x0e, 0xcb, 0xe9, 0xa0, 0x6b, 0xb9, 0xbc,
 | 
				
			||||||
 | 
					0x2e, 0xbb, 0xc9, 0x8a, 0x9a, 0x0b, 0xd4, 0x4c, 0xb7, 0xd3, 0x20, 0x77, 0x18,
 | 
				
			||||||
 | 
					0x74, 0x2d, 0xdf, 0xcb, 0x20, 0x28, 0xbb, 0x3e, 0x57, 0xd8, 0x5c, 0x20, 0x7d,
 | 
				
			||||||
 | 
					0x38, 0x4d, 0x4e, 0x03
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t test_ussd_02[] = {
 | 
				
			||||||
 | 
					0xa2, 0x10, 0x02, 0x01, 0x01, 0x30, 0x0b, 0x02, 0x01, 0x3c, 0x30,
 | 
				
			||||||
 | 
					0x06, 0x04, 0x01, 0x0f, 0x04, 0x01, 0x34
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_uss_ser_deser(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const uint32_t ref = 1234567890;
 | 
				
			||||||
 | 
						const char* ext = "555333444";
 | 
				
			||||||
 | 
						struct msgb *data = msgb_alloc(4000, "test");
 | 
				
			||||||
 | 
						struct ss_header ssh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t r_ref;
 | 
				
			||||||
 | 
						struct ss_header r_ssh;
 | 
				
			||||||
 | 
						char r_ext_buf[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						printf("testing serializing-deserializing\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ssh.component_length = sizeof(test_ussd_01);
 | 
				
			||||||
 | 
						ssh.component_offset = 0;
 | 
				
			||||||
 | 
						ssh.message_type = GSM0480_MTYPE_REGISTER;
 | 
				
			||||||
 | 
						ssh.transaction_id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = subscr_uss_message(data, &ssh, ext, ref, test_ussd_01);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("uss len:%d\n", msgb_length(data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = rx_uss_message_parse(data->data, msgb_length(data), &r_ssh, &r_ref, r_ext_buf, sizeof(r_ext_buf));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ref == r_ref);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ssh.message_type == r_ssh.message_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = strcmp(ext, r_ext_buf);
 | 
				
			||||||
 | 
						printf("orig_ext:%s decoded_ext:%s\n", ext, r_ext_buf);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("orig_clen:%d decoded_clen:%d\n", ssh.component_length, r_ssh.component_length);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ssh.component_length == r_ssh.component_length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = memcmp(data->data + r_ssh.component_offset, test_ussd_01, sizeof(test_ussd_01));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_reset(data);
 | 
				
			||||||
 | 
						memset(&r_ssh, 0, sizeof(r_ssh));
 | 
				
			||||||
 | 
						printf("testing serializing-deserializing small\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = subscr_uss_message(data, &ssh, NULL, ref, NULL);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("uss len:%d\n", msgb_length(data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = rx_uss_message_parse(data->data, msgb_length(data), &r_ssh, &r_ref, NULL, 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ref == r_ref);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ssh.message_type == r_ssh.message_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_parse_ss(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ss_request ss;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						printf("testing parsing ss\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// mark as uninitialized
 | 
				
			||||||
 | 
						memset(&ss, 0xcc, sizeof(ss));
 | 
				
			||||||
 | 
						rc = gsm0480_parse_ss_facility(test_ussd_01, sizeof(test_ussd_01), &ss);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
						printf("Sample: test_ussd_01  ctype=%02x invoke_id=%02x opcode=%02x\n",
 | 
				
			||||||
 | 
						       ss.component_type, ss.invoke_id, ss.opcode);
 | 
				
			||||||
 | 
						printf("- USSD: len:%d lang:%d\n", ss.ussd_text_len, ss.ussd_text_language);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// mark as uninitialized
 | 
				
			||||||
 | 
						memset(&ss, 0xcc, sizeof(ss));
 | 
				
			||||||
 | 
						rc = gsm0480_parse_ss_facility(test_ussd_02, sizeof(test_ussd_02), &ss);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
						printf("Sample: test_ussd_02  ctype=%02x invoke_id=%02x opcode=%02x\n",
 | 
				
			||||||
 | 
						       ss.component_type, ss.invoke_id, ss.opcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// mark as uninitialized
 | 
				
			||||||
 | 
						memset(&ss, 0xcc, sizeof(ss));
 | 
				
			||||||
 | 
						rc = gsm0480_parse_ss_facility(test_ss_int_02, sizeof(test_ss_int_02), &ss);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
						printf("Sample: test_ss_int_02 ctype=%02x invoke_id=%02x opcode=%02x\n",
 | 
				
			||||||
 | 
						       ss.component_type, ss.invoke_id, ss.opcode);
 | 
				
			||||||
 | 
						printf("- SS: code:%d\n", ss.ss_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// mark as uninitialized
 | 
				
			||||||
 | 
						memset(&ss, 0xcc, sizeof(ss));
 | 
				
			||||||
 | 
						rc = gsm0480_parse_ss_facility(test_ss_int_01, sizeof(test_ss_int_01), &ss);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
						printf("Sample: test_ss_int_01 ctype=%02x invoke_id=%02x opcode=%02x\n",
 | 
				
			||||||
 | 
						       ss.component_type, ss.invoke_id, ss.opcode);
 | 
				
			||||||
 | 
						printf("- SS: code:%d\n", ss.ss_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// mark as uninitialized
 | 
				
			||||||
 | 
						memset(&ss, 0xcc, sizeof(ss));
 | 
				
			||||||
 | 
						rc = gsm0480_parse_ss_facility(test_ss_int_03, sizeof(test_ss_int_03), &ss);
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc == 1);
 | 
				
			||||||
 | 
						printf("Sample: test_ss_int_01 ctype=%02x invoke_id=%02x opcode=%02x\n",
 | 
				
			||||||
 | 
						       ss.component_type, ss.invoke_id, ss.opcode);
 | 
				
			||||||
 | 
						printf("- SS: code:%d\n", ss.ss_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						osmo_init_logging(&log_info);
 | 
				
			||||||
 | 
						log_set_log_level(osmo_stderr_target, LOGL_INFO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_uss_ser_deser();
 | 
				
			||||||
 | 
						test_parse_ss();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Done.\n");
 | 
				
			||||||
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user