Compare commits

...

88 Commits

Author SHA1 Message Date
Ivan Kluchnikov
bd6784dbe8 debian: Update changelog to 0.15.1-fw.1 2017-02-15 19:54:56 +03:00
Ivan Klyuchnikov
5788904242 gsup: Update code after rebase to updated gsup implementation 2017-02-07 19:01:13 +03:00
Ivan Kluchnikov
362a757f56 osmo-nitb: Send purge ms to reg-proxy and handle response 2017-02-07 18:59:56 +03:00
Ivan Kluchnikov
444a9b9304 reg-proxy: Implement purge ms forwarding and handling 2017-02-07 18:59:56 +03:00
Ivan Kluchnikov
8d8bedff4c gsm_04_08: Change reject cause for not "attached" subscribers from "destination out of order" to "no user responding" 2017-02-07 18:59:56 +03:00
Ivan Kluchnikov
084a35588f reg-proxy: fix osip transactions releasing procedure
* implement nict_trans_free function for checking list of osip_nict_transactions and releasing transactions in terminated state
* call nict_trans_free function in main loop
* transactions should not be released in message callback functions, so remove osip_transaction_free and osip_message_free from sip_cb_rcv2xx function
2017-02-07 18:59:56 +03:00
Ivan Kluchnikov
03bf40f6a5 reg-proxy: use osip_strdup function, because we should allocate memory for scheme and host values to be used in osip_uri_set_ functions 2017-02-07 18:59:56 +03:00
Ivan Kluchnikov
842e599c5c reg-proxy: we shouldn't free call_id_num and seq_num_str, because they are used in osip_message and will be freed by osip_message_free function 2017-02-07 18:59:56 +03:00
Ivan Kluchnikov
16e9c4a70f reg-proxy: free allocated ipa control messages in ipa_sock_server_cb function 2017-02-07 18:59:56 +03:00
Ivan Kluchnikov
fdee81b35f reg-proxy: free all allocated osip elements, messages and transactions 2017-02-07 18:59:56 +03:00
Ivan Kluchnikov
582242d2f5 gsm_sup: check connection before use it, because it can be already closed 2017-02-07 18:59:56 +03:00
Sergey.Kostanbaev
fb5a18db4b ussd_proxy: fix decoding GSM7 to latin1 2017-02-07 18:59:56 +03:00
Sergey Kostanbaev
8a8703e06c fix incorrect autorebase 2017-02-07 18:59:56 +03:00
Sergey Kostanbaev
d68abba3d0 fixup after rebase 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
bbd3c7cd46 reg-proxy: Implement handling LU responses without msisdn
If we receive 200 ok response with imsi instead of msisdn in sip contact header, we should send LU response message to osmo-nitb without msisdn.
2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
0a2a92a4f5 gsm_sup: Update subscriber info in database only if msisdn is received in LU response 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
a52726dae8 msc: Increase value of location update timer to 10 sec
We should increase this timer, because LU procedure can take more than 5 sec, if 'remote' auth policy is used.
2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
8af593e4e4 sms: Route all sms from/to subscribers with extension length = 5 to local smsc 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
fb11fc1a7a sup: pass subscriber group parameter to subscr_get_by_extension function
Subscriber group parameter should be set for subscriber in subscr_get_by_extension function, because it is used in connection_for_subscr function.
2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
0904c1de19 sms: Use gsm411_rp_hdr structure instead of manual parsing of RP messages 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
c301ef4ea7 sms: MO RP ACK and RP ERROR should be also forwarded to the sms socket 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
59dc70462b sms: In case of receiving MO RP-DATA, we should assign RP message reference value to transaction variable 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
e7dc282b51 sup: Fix RP header offset and RP data length calculations 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
45fdb6a728 vty: Install sms_destination_cmd element as NITB_NODE 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
32906636f1 sms: Add functions for forwarding/handling SMS in RP format to/from external application 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
b314380065 sms: Add new socket for forwarding/receiving SMS in RP format to/from external application 2017-02-07 18:59:55 +03:00
Ivan Kluchnikov
8bb11c90fc trans: Add new parameter message reference for SMS and function for finding transaction by this reference 2017-02-07 18:59:55 +03:00
Sergey Kostanbaev
933de8cb48 send actual message in facility op (not initial) 2017-02-07 18:59:55 +03:00
Kirill Zakharenko
1bcfaa7119 debian: use --enable-ussd-proxy with ./configure 2017-02-07 18:59:55 +03:00
Kirill Zakharenko
6c079bb981 reg-proxy, ussd-proxy: don't use realtime priority 2017-02-07 18:59:55 +03:00
Sergey.Kostanbaev
c572ac8733 add test for registerSS 2017-02-07 18:59:55 +03:00
Sergey.Kostanbaev
53d1a9186c set transaction_id from transaction data 2017-02-07 18:59:55 +03:00
Sergey Kostanbaev
2f749ef103 emulation for SS 2017-02-07 18:59:55 +03:00
Sergey Kostanbaev
17276417ef various bugs in ss reply 2017-02-07 18:59:55 +03:00
Sergey.Kostanbaev
234f6714a7 add generation of src/ussd-proxy/Makefile 2017-02-07 18:59:54 +03:00
Sergey.Kostanbaev
3e7a48c475 add forgotten files 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
9d53708f58 add forgotten file 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
da8c96e097 recovery latin1 USSD message, probably bad rebase 2017-02-07 18:59:54 +03:00
Sergey.Kostanbaev
d4839fe14a manual merge SS from sup-ussd-on-master-ss-wip 2017-02-07 18:59:54 +03:00
Ivan Kluchnikov
db0e216845 msc: Implement 'remote-closed' authentication policy
This mode is modified version of 'remote' policy.
Osmo-nitb uses remote subscription data only if the MS is activated in local HLR, otherwise osmo-nitb rejects subscriber.
2017-02-07 18:59:54 +03:00
Ivan Kluchnikov
2d9f39ec43 reg-proxy: Added configuration parameter for setting registration expiry time 2017-02-07 18:59:54 +03:00
Ivan Kluchnikov
e5e251c396 sup: fix handling update location result message
If LUR procedure timed out, we should just skip update location result message.
2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
991691f8df ussd_proxy: add content-type sip tag in bye for 3rd party software workaround 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
955d8800e5 ussd_proxy: add -x proxy option 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
9a4936a234 ussd_proxy: add -7 option to force latin1 convertion to gsm 7-bit 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
012c9203e4 ussd: handle UCS-2 coding 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
5087f994fd libmsc: set proper length field in ASN.1 format for USSD internals 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
420e4d445c libmsc: fix no return and use after free 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
a8f56961be ussd_proxy: handle reject from sup and send BYE to sip 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
b2679b822e ussd: send reject to sup 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
0ce3516a47 ussd_proxy: add debug output when session is destroyed 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
2b5eb8ddb0 libmsc: use message type as an entry point and handle release complete message 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
fd245fcfa8 ussd_proxy: fix reject after resultLast 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
9f24671589 ussd_proxy: add -l parameter to set loglevel in sip sofia 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
acddb2a632 ussd_proxy: remove dead code 2017-02-07 18:59:54 +03:00
Kirill Zakharenko
800369d258 debian: new package for reg-proxy & ussd-proxy 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
236d81fa0c ussd_proxy: detailed help 2017-02-07 18:59:54 +03:00
Sergey Kostanbaev
8e58f575e7 ussd_proxy: handle multiple USSD sessions 2017-02-07 18:59:53 +03:00
Sergey Kostanbaev
da0864dfde ussd_proxy: handle session timeout 2017-02-07 18:59:53 +03:00
Sergey Kostanbaev
fc969503e1 ussd_proxy: handle error callback 2017-02-07 18:59:53 +03:00
Sergey Kostanbaev
1e4a954c73 ussd_proxy: handle USSD dialogs into sip INFO messages 2017-02-07 18:59:53 +03:00
Sergey Kostanbaev
2f4878a90f ussd_proxy: handle basic errors to release channel 2017-02-07 18:59:53 +03:00
Sergey Kostanbaev
70e6f2ec74 ussd_proxy: properly set To and From SIP headers 2017-02-07 18:59:53 +03:00
Sergey Kostanbaev
be9419881c Add forgotten Makefile 2017-02-07 18:59:53 +03:00
Sergey Kostanbaev
a363aa3fc0 add standalone ussd_proxy utility based on sip sofia 2017-02-07 18:59:53 +03:00
Kirill Zakharenko
9cddaeafd5 debian: added libosip2 to build dependencies 2017-02-07 18:59:53 +03:00
Alexander Chemeris
9fe68b0fbc libmsc: Add a comment to the HLR SUP socket creation. 2017-02-07 18:59:53 +03:00
Alexander Chemeris
1c30463e76 libmsc: Create a separate SUP socket for USSD. 2017-02-07 18:59:53 +03:00
Alexander Chemeris
bcc2567579 libmsc: Fix comment style. 2017-02-07 18:59:53 +03:00
Alexander Chemeris
924292977f libmsc: Remove sup_init() to make SUP socket initialiaton generic. 2017-02-07 18:59:53 +03:00
Alexander Chemeris
a317e334c2 libmsc: Make internal functions 'static' in gsm_sup. 2017-02-07 18:59:53 +03:00
Alexander Chemeris
76c7cec298 libmsc: Whitespace fix in gsm_sup.c, no code changes. 2017-02-07 18:59:53 +03:00
Alexander Chemeris
c70110945a libmsc: Rename sup_client to hlr_sup_client in preparation for multiple SUP clients. 2017-02-07 18:59:53 +03:00
Sergey Kostanbaev
f5fe345dbb USSD MAP external interface over SUP 2017-02-07 18:59:53 +03:00
Ivan Klyuchnikov
07a5b120e9 Revert "ussd: Add band-aid for interrogationSS"
This reverts commit 5085e0bf4c.
2017-02-07 18:59:53 +03:00
Ivan Kluchnikov
dfeabbbff6 reg-proxy: add application which allows translate SUP to SIP and SIP to SUP 2017-02-07 18:59:53 +03:00
Ivan Kluchnikov
1371303689 sup: Fix msisdn decoding 2017-02-07 18:59:53 +03:00
Ivan Kluchnikov
f7cb56572a sup: Change status of waiting_for_remote_accept before checking subscriber 2017-02-07 18:59:53 +03:00
Ivan Kluchnikov
014316f514 nitb: Integrate the SUP client into the osmo-nitb 2017-02-07 18:59:53 +03:00
Ivan Kluchnikov
b96f1912da msc: Implement 'remote' authentication policy
- All location update requests should be send to the remote HLR and accepted.
- Authentication info should be also received from remote HLR.
- SUP is used for sending/handling subscription data to/from remote HLR.
2017-02-07 18:59:52 +03:00
Ivan Kluchnikov
adc681331e sup: Add functions to create/handle SUP messages
- Add functions to send location update request and handle responses.
- Add functions to query auth info and handle responses.
2017-02-07 18:57:31 +03:00
Ivan Kluchnikov
8516d533db debug: Add DSUP debug category for subscriber update protocol 2017-02-07 18:57:31 +03:00
Ivan Kluchnikov
c6e735fd00 debian: Add osmocom-meas-utils package 2017-02-07 18:57:31 +03:00
Ivan Kluchnikov
cc75a7f014 debian: build only osmo-nitb package - enable smpp support - disable the gbproxy test (failing) 2017-02-07 18:57:30 +03:00
Alexander Chemeris
1c33b89886 utils: Support new fields in the v1 of meas_feed in meas_json. 2017-02-07 18:53:38 +03:00
Alexander Chemeris
077e62cded utils: 'meas_json' utility to convert measurement feed into a JSON feed. 2017-02-07 18:53:38 +03:00
Alexander Chemeris
a78396dcb3 libbsc: Update a BTS's SIs when ms_max_power is changed from VTY.
Otherwise you have to restart BTS or at least break the RSL connection
to apply the change.
2017-02-07 18:53:38 +03:00
Alexander Chemeris
e9c81d2581 libmsc: Update 'max_power_red' VTY command.
Changes:
 * Apply change even if the supplied value is odd, just warn that it is rounded.
 * Apply change even if the supplied value is higher than the 24dB maximum
   suggested by the standard, just warn about this.
 * Apply change to the BTS over OML immediately.
2017-02-07 18:53:38 +03:00
69 changed files with 6562 additions and 223 deletions

6
debian/changelog vendored
View File

@@ -1,3 +1,9 @@
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
* Move forward toward a new release.

151
debian/control vendored
View File

@@ -6,7 +6,6 @@ Build-Depends: debhelper (>= 9),
autotools-dev,
autoconf-archive,
pkg-config,
libgtp-dev,
libosmocore-dev,
libosmo-sccp-dev,
libdbi0-dev,
@@ -17,23 +16,14 @@ Build-Depends: debhelper (>= 9),
libpcap-dev,
libssl-dev,
libc-ares-dev,
libsmpp34-dev
libsmpp34-dev,
libosip2-dev,
libsofia-sip-ua-dev
Standards-Version: 3.9.8
Vcs-Git: git://bs11-abis.gnumonks.org/openbsc.git
Vcs-Browser: http://openbsc.osmocom.org/trac/browser
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
Architecture: any
Depends: ${shlibs:Depends},
@@ -44,138 +34,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
Mobile Switching Center (MSC) which is needed when using osmocom-bsc.
Package: osmocom-ipaccess-utils
Package: osmocom-meas-utils
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends}
Description: Command line utilities for ip.access nanoBTS
This package contains utilities that are specific for nanoBTS when being used
together with OpenBSC. It contains mainly three tools: ipaccess-find,
ipaccess-config and ipaccess-proxy.
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
${misc:Depends},
libcdk5,
sqlite3
Description: Measurement utilities for the OpenBSC
Measurement utilities for the OpenBSC.
Package: osmocom-nitb-dbg
Architecture: any
Section: debug
Priority: extra
Depends: osmocom-nitb (= ${binary:Version}), ${misc:Depends}
Depends: osmocom-nitb (= ${binary:Version}),
${misc:Depends}
Description: Debug symbols for the OpenBSC NITB
Make debugging possible
Package: osmocom-ipaccess-utils-dbg
Package: osmocom-meas-utils-dbg
Architecture: any
Section: debug
Priority: extra
Depends: osmocom-ipaccess-utils (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the OpenBSC ip.access utils
Depends: osmocom-meas-utils (= ${binary:Version}),
${misc:Depends}
Description: Debug symbols for the OpenBSC measurement utilities
Make debugging possible
Package: osmocom-bs11-utils-dbg
Package: osmocom-proxy
Architecture: any
Section: debug
Priority: extra
Depends: osmocom-bs11-utils (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the OpenBSC BS11 utils
Make debugging possible
Depends: ${shlibs:Depends},
${misc:Depends}
Description: GSM Network-in-a-Box, implements BSC, MSC, SMSC, HLR, VLR
reg and ussd proxies
Package: osmocom-sgsn-dbg
Package: osmocom-proxy-dbg
Architecture: any
Section: debug
Priority: extra
Depends: osmocom-sgsn (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the OpenBSC Serving GPRS Support Node
Make debugging possible
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
Depends: osmocom-nitb (= ${binary:Version}),
${misc:Depends}
Description: Debug symbols for the OpenBSC Proxies
Make debugging possible

4
debian/osmocom-meas-utils.install vendored Normal file
View 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
View 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
View File

@@ -17,16 +17,10 @@ override_dh_autoreconf:
cd openbsc && autoreconf --install --force
override_dh_strip:
dh_strip -posmocom-bsc --dbg-package=osmocom-bsc-dbg
dh_strip -posmocom-nitb --dbg-package=osmocom-nitb-dbg
dh_strip -posmocom-ipaccess-utils --dbg-package=osmocom-ipaccess-utils-dbg
dh_strip -posmocom-bs11-utils --dbg-package=osmocom-bs11-utils-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
dh_strip -posmocom-meas-utils --dbg-package=osmocom-meas-utils-dbg
dh_strip -posmocom-proxy --dbg-package=osmocom-proxy-dbg
override_dh_auto_configure:
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
View 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
View File

@@ -0,0 +1 @@
../sv/reg-proxy

1
etc/service/ussd-proxy Symbolic link
View File

@@ -0,0 +1 @@
../sv/ussd-proxy/

4
etc/sv/reg-proxy/log/run Executable file
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,3 @@
#!/bin/bash
COMMAND_LINE="-t sip:172.31.0.6:5060 -u sip:172.31.0.29:5090 -l8"

View File

@@ -211,6 +211,18 @@ AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
AC_MSG_RESULT([$enable_ext_tests])
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
AM_CONFIG_HEADER(bscconfig.h)
@@ -234,6 +246,8 @@ AC_OUTPUT(
src/ipaccess/Makefile
src/utils/Makefile
src/gprs/Makefile
src/reg-proxy/Makefile
src/ussd-proxy/Makefile
tests/Makefile
tests/atlocal
tests/gsm0408/Makefile
@@ -258,6 +272,7 @@ AC_OUTPUT(
tests/slhc/Makefile
tests/v42bis/Makefile
tests/nanobts_omlattr/Makefile
tests/ussd/Makefile
doc/Makefile
doc/examples/Makefile
Makefile)

View File

@@ -2,6 +2,7 @@
#define _AUTH_H
#include <osmocom/core/utils.h>
#include <openbsc/gsm_data.h>
struct gsm_auth_tuple;
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);
}
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);
#endif /* _AUTH_H */

View File

@@ -38,6 +38,8 @@ enum {
DRANAP,
DSUA,
DV42BIS,
DSUP,
DSS,
Debug_LastEntry,
};

View File

@@ -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 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

View File

@@ -38,5 +38,8 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn,
struct gsm_sms *sms);
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);
#endif

View File

@@ -7,12 +7,17 @@
struct gsm_subscriber_connection;
int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
const struct msgb *in_msg, const char* response_text,
const struct ss_request *req);
int gsm0480_send_component(struct gsm_subscriber_connection *conn,
struct msgb *msg,
struct ss_header* reqhdr);
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
const struct msgb *msg,
const struct ss_request *request);
uint8_t invoke_id,
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,
const char *text);

View File

@@ -15,6 +15,7 @@
#include <openbsc/rest_octets.h>
#include <openbsc/common_cs.h>
#include <openbsc/gsup_client.h>
/** annotations for msgb ownership */
#define __uses
@@ -70,6 +71,7 @@ struct gsm_loc_updating_operation {
struct osmo_timer_list updating_timer;
unsigned int waiting_for_imsi : 1;
unsigned int waiting_for_imei : 1;
unsigned int waiting_for_remote_accept : 1;
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_TOKEN, /* accept first, send token per sms, then revoke authorization */
GSM_AUTH_POLICY_REGEXP, /* accept IMSIs matching given regexp */
GSM_AUTH_POLICY_REMOTE,
GSM_AUTH_POLICY_REMOTE_CLOSED
};
#define GSM_T3101_DEFAULT 10
@@ -320,6 +324,9 @@ struct gsm_network {
struct llist_head upqueue;
struct llist_head trans_list;
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;
struct llist_head bts_list;

View 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 */

View 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 */

View 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 */

View File

@@ -47,6 +47,7 @@ struct gsup_client {
struct osmo_timer_list connect_timer;
int is_connected;
int got_ipa_pong;
struct gsm_network *net;
};
struct gsup_client *gsup_client_create(const char *ip_addr,

View 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 */

View 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 */

View 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);

View 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 */

View 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 */

View 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

View File

@@ -32,6 +32,11 @@ struct gsm_trans {
/* reference from MNCC or other application */
uint32_t callref;
/* SMS RP message reference */
uint8_t msg_ref;
/* handle SMS local */
uint8_t sms_local;
/* if traffic channel receive was requested */
int tch_recv;
@@ -56,6 +61,11 @@ struct gsm_trans {
struct gsm_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);
struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
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_subscriber *subscr,

View File

@@ -5,6 +5,19 @@
#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 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

View File

@@ -44,6 +44,8 @@ SUBDIRS += \
utils \
ipaccess \
gprs \
reg-proxy \
ussd-proxy \
$(NULL)
# Conditional Programs

View File

@@ -2115,9 +2115,17 @@ DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
"Maximum transmit power of the MS in dBm")
{
struct gsm_bts *bts = vty->index;
int rc;
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;
}
@@ -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 in dB\n")
{
int ret = CMD_SUCCESS;
int maxpwr_r = atoi(argv[0]);
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. */
/* FIXME: check if our BTS type supports more than 12 */
if (maxpwr_r < 0 || maxpwr_r > upper_limit) {
vty_out(vty, "%% Power %d dB is not in the valid range%s",
if (maxpwr_r < 0) {
vty_out(vty, "%% Power %d dB can not be negative%s",
maxpwr_r, VTY_NEWLINE);
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) {
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);
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;
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 CMD_SUCCESS;
return ret;
}
DEFUN(cfg_trx_rsl_e1,

View File

@@ -105,13 +105,15 @@ DEFUN(cfg_net_name_long,
DEFUN(cfg_net_auth_policy,
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"
"Set the GSM network authentication policy\n"
"Require the MS to be activated in HLR\n"
"Accept all MS, whether in HLR or not\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]);
struct gsm_network *gsmnet = gsmnet_from_vty(vty);

View File

@@ -160,6 +160,11 @@ static const struct log_info_cat default_categories[] = {
.description = "SMPP interface for external SMS apps",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DSUP] = {
.name = "DSUP",
.description = "SUP interface for external HLR",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DFILTER] = {
.name = "DFILTER",
.description = "BSC/NAT IMSI based filtering",

View File

@@ -163,6 +163,8 @@ static const struct value_string auth_policy_names[] = {
{ GSM_AUTH_POLICY_ACCEPT_ALL, "accept-all" },
{ GSM_AUTH_POLICY_TOKEN, "token" },
{ GSM_AUTH_POLICY_REGEXP, "regexp" },
{ GSM_AUTH_POLICY_REMOTE, "remote" },
{ GSM_AUTH_POLICY_REMOTE_CLOSED, "remote-closed" },
{ 0, NULL }
};

View File

@@ -28,6 +28,7 @@ libmsc_a_SOURCES = \
gsm_04_08.c \
gsm_04_11.c \
gsm_04_80.c \
gsm_sup.c \
gsm_subscriber.c \
mncc.c \
mncc_builtin.c \
@@ -42,6 +43,8 @@ libmsc_a_SOURCES = \
osmo_msc.c \
ctrl_commands.c \
meas_feed.c \
gsm_ussd_map_proto.c \
gsm_ussd_map.c \
$(NULL)
if BUILD_SMPP

View File

@@ -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
* 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_auth_info ainfo;
int rc;
if (auth_policy != GSM_AUTH_POLICY_REMOTE &&
auth_policy != GSM_AUTH_POLICY_REMOTE_CLOSED) {
/* Get subscriber info (if any) */
rc = db_get_authinfo_for_subscr(&ainfo, subscr);
if (rc < 0) {
LOGP(DMM, LOGL_NOTICE,
"No retrievable Ki for subscriber %s, skipping auth\n",
subscr_name(subscr));
"No retrievable Ki for subscriber %s, skipping auth\n");
return rc == -ENOENT ? AUTH_NOT_AVAIL : AUTH_ERROR;
}
}
/* If possible, re-use the last tuple and skip auth */
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;
}
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 */
if (rc != 0) {
/* If db_get_lastauthtuple_for_subscr() returned nothing, make

View File

@@ -56,6 +56,7 @@
#include <openbsc/osmo_msc.h>
#include <openbsc/handover.h>
#include <openbsc/mncc_int.h>
#include <openbsc/gsm_sup.h>
#include <osmocom/abis/e1_input.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 (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)
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);
case GSM_AUTH_POLICY_ACCEPT_ALL:
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:
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)
return;
@@ -384,7 +407,7 @@ static int _gsm0408_authorize_sec_cb(unsigned int hooknum, unsigned int event,
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)
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.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[] = {
@@ -703,6 +726,8 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb
/* schedule the reject timer */
schedule_reject(conn);
conn->loc_operation->waiting_for_remote_accept = 1;
if (!subscr) {
DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
/* 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);
}
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)
{
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) {
gsm0408_purge_ms(subscr);
subscr_update(subscr, conn->bts,
GSM_SUBSCRIBER_UPDATE_DETACHED);
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 */
return mncc_release_ind(net, NULL, data->callref,
GSM48_CAUSE_LOC_PRN_S_LU,
GSM48_CC_CAUSE_DEST_OOO);
GSM48_CC_CAUSE_USER_NOTRESPOND);
}
/* Create transaction */
trans = trans_alloc(net, subscr, GSM48_PDISC_CC, 0xff, data->callref);

View File

@@ -56,6 +56,7 @@
#include <openbsc/bsc_rll.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_api.h>
#include <openbsc/gsm_sup.h>
#ifdef BUILD_SMPP
#include "smpp_smsc.h"
@@ -361,6 +362,36 @@ try_local:
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)
* 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));
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);
if (rc == 0)
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;
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
* successfully received a SMS. We can now safely mark it as
* 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,
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) {
LOGP(DLSMS, LOGL_ERROR,
"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->conn = conn;
trans->sms_local = 1;
/* Hardcode SMSC Originating Address for now */
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;
}
}

View File

@@ -39,6 +39,22 @@
#include <osmocom/core/msgb.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)
{
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;
}
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 */
int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
const struct msgb *in_msg, const char *response_text,
const struct ss_request *req)
data[0] = msgb->len - 1;
return data;
}
/* 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 gsm48_hdr *gh;
uint8_t *ptr8;
int response_len;
/* First put the payload text into the message */
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 */
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 */
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 */
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 */
msgb_push_TLV1(msg, GSM0480_OPERATION_CODE,
GSM0480_OP_CODE_PROCESS_USS_REQ);
msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, req->opcode);
/* 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 */
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 */
msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT);
/* Pre-pend the invoke ID */
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);
} 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 */
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id
| (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);
}
#endif
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
const struct msgb *in_msg,
const struct ss_request *req)
uint8_t invoke_id,
uint8_t transaction_id)
{
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 */
msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL,
GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
/* 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 */
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 */
msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
/* And finally pre-pend the L3 header */
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
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;
return gsm0808_submit_dtap(conn, msg, 0, 0);
#endif
}
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 gsm0808_submit_dtap(conn, msg, 0, 0);
}
#endif

View File

@@ -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,
gsm_cbfn *cb, void *cb_data);
void gsm0408_purge_ms(struct gsm_subscriber *subscr);
/*
* 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",
subscr_name(s), id);
gsm0408_purge_ms(s);
s->lac = GSM_LAC_RESERVED_DETACHED;
db_sync_subscriber(s);

View 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;
}

View 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;
}

View 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
}

View File

@@ -61,6 +61,22 @@ struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
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_subscriber *subscr,
uint8_t protocol, uint8_t trans_id,
@@ -80,6 +96,7 @@ struct gsm_trans *trans_alloc(struct gsm_network *net,
trans->protocol = protocol;
trans->transaction_id = trans_id;
trans->callref = callref;
trans->sms_local = 0;
trans->net = net;
llist_add_tail(&trans->entry, &net->trans_list);

View File

@@ -33,49 +33,83 @@
#include <openbsc/gsm_subscriber.h>
#include <openbsc/debug.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 */
const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
/* 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 */
int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
int rc;
struct ss_header reqhdr;
struct ss_request req;
char request_string[MAX_LEN_USSD_STRING + 1];
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(&reqhdr, 0, sizeof(reqhdr));
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) {
DEBUGP(DMM, "Unhandled SS\n");
rc = gsm0480_send_ussd_reject(conn, msg, &req);
DEBUGP(DSS, "Incorrect SS header\n");
msc_release_connection(conn);
return rc;
}
/* Interrogation or releaseComplete? */
if (req.ussd_text[0] == '\0' || req.ussd_text[0] == 0xFF) {
if (req.ss_code > 0) {
/* Assume interrogateSS or modification of it and reject */
rc = gsm0480_send_ussd_reject(conn, msg, &req);
rc = gsm0480_parse_ss_facility(gh->data + reqhdr.component_offset,
reqhdr.component_length,
&req);
if (!rc) {
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);
return rc;
}
/* Still assuming a Release-Complete and returning */
if (reqhdr.message_type == GSM0480_MTYPE_RELEASE_COMPLETE)
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)) {
DEBUGP(DMM, "USSD: Own number requested\n");
rc = send_own_number(conn, msg, &req);
gsm_7bit_decode_n_ussd(request_string, MAX_LEN_USSD_STRING, req.ussd_text, req.ussd_text_len);
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 {
DEBUGP(DMM, "Unhandled USSD %s\n", req.ussd_text);
rc = gsm0480_send_ussd_reject(conn, msg, &req);
DEBUGP(DSS, "Unhandled USSD %s\n", request_string);
rc = gsm0480_send_ussd_reject(conn, req.invoke_id, reqhdr.transaction_id);
}
/* 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 */
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 response_string[GSM_EXTENSION_LENGTH + 20];
int response_len;
/* Need trailing CR as EOT character */
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);
}
}

View File

@@ -50,8 +50,11 @@
#include <openbsc/sms_queue.h>
#include <openbsc/mncc_int.h>
#include <openbsc/handover.h>
#include <openbsc/gsup_client.h>
#include <openbsc/gsm_ussd_map.h>
#include <osmocom/vty/logging.h>
#include <openbsc/gsm_sup.h>
#include "meas_feed.h"
@@ -1027,6 +1030,53 @@ DEFUN(meas_feed_scenario, meas_feed_scenario_cmd,
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,
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_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;
}

View File

@@ -53,6 +53,7 @@
#include <openbsc/ctrl.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/smpp.h>
#include <openbsc/gsm_sup.h>
#include "../../bscconfig.h"
@@ -367,6 +368,18 @@ int main(int argc, char **argv)
}
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 */
db_sync_timer.cb = db_sync_timer_cb;
db_sync_timer.data = NULL;

View 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)

View 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
View 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(&reg_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(&reg->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(&reg_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;
}

View 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__);
}

View 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)

407
openbsc/src/reg-proxy/sup.c Normal file
View File

@@ -0,0 +1,407 @@
#include <openbsc/sup_server.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;
}

View 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__);
}

View 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
View 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()

View 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

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,7 @@ noinst_HEADERS = \
bin_PROGRAMS = \
bs11_config \
isdnsync \
meas_json \
$(NULL)
if HAVE_SQLITE3
bin_PROGRAMS += \
@@ -121,3 +122,18 @@ osmo_meas_udp2db_CFLAGS = \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(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)

View File

@@ -0,0 +1,188 @@
/* 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 <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);
}

View File

@@ -10,6 +10,7 @@ SUBDIRS = \
subscr \
mm_auth \
nanobts_omlattr \
ussd \
$(NULL)
if BUILD_NAT

View File

@@ -136,6 +136,7 @@ void sms_alloc() {}
void sms_free() {}
void gsm_net_update_ctype(struct gsm_network *network) {}
void gsm48_secure_channel() {}
void gsm0408_purge_ms() {}
void paging_request_stop() {}
void vty_out() {}

View File

@@ -114,7 +114,7 @@ int auth_get_tuple_for_subscr_verbose(struct gsm_auth_tuple *atuple,
int key_seq)
{
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",
key_seq, auth_action_str(auth_action));
return auth_action;

View File

@@ -85,12 +85,6 @@ cat $abs_srcdir/bsc/bsc_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/bsc/bsc_test], [], [expout], [ignore])
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_KEYWORDS([trau])
cat $abs_srcdir/trau/trau_test.ok > expout

View 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

View 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;
}