mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-10-23 08:12:01 +00:00
Compare commits
88 Commits
osmith/kil
...
fairwaves/
Author | SHA1 | Date | |
---|---|---|---|
|
bd6784dbe8 | ||
|
5788904242 | ||
|
362a757f56 | ||
|
444a9b9304 | ||
|
8d8bedff4c | ||
|
084a35588f | ||
|
03bf40f6a5 | ||
|
842e599c5c | ||
|
16e9c4a70f | ||
|
fdee81b35f | ||
|
582242d2f5 | ||
|
fb5a18db4b | ||
|
8a8703e06c | ||
|
d68abba3d0 | ||
|
bbd3c7cd46 | ||
|
0a2a92a4f5 | ||
|
a52726dae8 | ||
|
8af593e4e4 | ||
|
fb11fc1a7a | ||
|
0904c1de19 | ||
|
c301ef4ea7 | ||
|
59dc70462b | ||
|
e7dc282b51 | ||
|
45fdb6a728 | ||
|
32906636f1 | ||
|
b314380065 | ||
|
8bb11c90fc | ||
|
933de8cb48 | ||
|
1bcfaa7119 | ||
|
6c079bb981 | ||
|
c572ac8733 | ||
|
53d1a9186c | ||
|
2f749ef103 | ||
|
17276417ef | ||
|
234f6714a7 | ||
|
3e7a48c475 | ||
|
9d53708f58 | ||
|
da8c96e097 | ||
|
d4839fe14a | ||
|
db0e216845 | ||
|
2d9f39ec43 | ||
|
e5e251c396 | ||
|
991691f8df | ||
|
955d8800e5 | ||
|
9a4936a234 | ||
|
012c9203e4 | ||
|
5087f994fd | ||
|
420e4d445c | ||
|
a8f56961be | ||
|
b2679b822e | ||
|
0ce3516a47 | ||
|
2b5eb8ddb0 | ||
|
fd245fcfa8 | ||
|
9f24671589 | ||
|
acddb2a632 | ||
|
800369d258 | ||
|
236d81fa0c | ||
|
8e58f575e7 | ||
|
da0864dfde | ||
|
fc969503e1 | ||
|
1e4a954c73 | ||
|
2f4878a90f | ||
|
70e6f2ec74 | ||
|
be9419881c | ||
|
a363aa3fc0 | ||
|
9cddaeafd5 | ||
|
9fe68b0fbc | ||
|
1c30463e76 | ||
|
bcc2567579 | ||
|
924292977f | ||
|
a317e334c2 | ||
|
76c7cec298 | ||
|
c70110945a | ||
|
f5fe345dbb | ||
|
07a5b120e9 | ||
|
dfeabbbff6 | ||
|
1371303689 | ||
|
f7cb56572a | ||
|
014316f514 | ||
|
b96f1912da | ||
|
adc681331e | ||
|
8516d533db | ||
|
c6e735fd00 | ||
|
cc75a7f014 | ||
|
1c33b89886 | ||
|
077e62cded | ||
|
a78396dcb3 | ||
|
e9c81d2581 |
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -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
151
debian/control
vendored
@@ -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
4
debian/osmocom-meas-utils.install
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/usr/bin/osmo-meas-udp2db
|
||||
/usr/bin/osmo-meas-pcap2db
|
||||
/usr/bin/meas_vis
|
||||
/usr/bin/meas_json
|
9
debian/osmocom-proxy.install
vendored
Normal file
9
debian/osmocom-proxy.install
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
usr/bin/reg-proxy
|
||||
etc/sv/reg-proxy
|
||||
etc/service/reg-proxy
|
||||
etc/reg-proxy.config
|
||||
|
||||
usr/bin/ussd-proxy
|
||||
etc/sv/ussd-proxy
|
||||
etc/service/ussd-proxy
|
||||
etc/ussd-proxy.config
|
12
debian/rules
vendored
12
debian/rules
vendored
@@ -17,16 +17,10 @@ override_dh_autoreconf:
|
||||
cd openbsc && autoreconf --install --force
|
||||
|
||||
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
3
etc/reg-proxy.config
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
COMMAND_LINE="-S 172.31.0.16 -s 5040 -D 172.31.0.10 -d 5040"
|
1
etc/service/reg-proxy
Symbolic link
1
etc/service/reg-proxy
Symbolic link
@@ -0,0 +1 @@
|
||||
../sv/reg-proxy
|
1
etc/service/ussd-proxy
Symbolic link
1
etc/service/ussd-proxy
Symbolic link
@@ -0,0 +1 @@
|
||||
../sv/ussd-proxy/
|
4
etc/sv/reg-proxy/log/run
Executable file
4
etc/sv/reg-proxy/log/run
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
LOG_FOLDER=/var/log/reg-proxy
|
||||
mkdir -p $LOG_FOLDER
|
||||
exec svlogd -tt $LOG_FOLDER
|
6
etc/sv/reg-proxy/run
Executable file
6
etc/sv/reg-proxy/run
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
. /etc/reg-proxy.config
|
||||
exec 2>&1
|
||||
echo "reg-proxy restart" | /usr/bin/ts >> /var/log/runsv.log
|
||||
exec reg-proxy $COMMAND_LINE
|
4
etc/sv/ussd-proxy/log/run
Executable file
4
etc/sv/ussd-proxy/log/run
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
LOG_FOLDER=/var/log/ussd-proxy
|
||||
mkdir -p $LOG_FOLDER
|
||||
exec svlogd -tt $LOG_FOLDER
|
6
etc/sv/ussd-proxy/run
Executable file
6
etc/sv/ussd-proxy/run
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
. /etc/ussd-proxy.config
|
||||
exec 2>&1
|
||||
echo "ussd-proxy restart" | /usr/bin/ts >> /var/log/runsv.log
|
||||
exec ussd-proxy $COMMAND_LINE
|
3
etc/ussd-proxy.config
Normal file
3
etc/ussd-proxy.config
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
COMMAND_LINE="-t sip:172.31.0.6:5060 -u sip:172.31.0.29:5090 -l8"
|
@@ -211,6 +211,18 @@ AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
|
||||
AC_MSG_RESULT([$enable_ext_tests])
|
||||
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)
|
||||
|
@@ -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 */
|
||||
|
@@ -38,6 +38,8 @@ enum {
|
||||
DRANAP,
|
||||
DSUA,
|
||||
DV42BIS,
|
||||
DSUP,
|
||||
DSS,
|
||||
Debug_LastEntry,
|
||||
};
|
||||
|
||||
|
@@ -94,4 +94,8 @@ void allocate_security_operation(struct gsm_subscriber_connection *conn);
|
||||
|
||||
int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, struct amr_mode *modes);
|
||||
|
||||
int 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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
26
openbsc/include/openbsc/gsm_sup.h
Normal file
26
openbsc/include/openbsc/gsm_sup.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef _GSM_SUP_H
|
||||
#define _GSM_SUP_H
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <osmocom/gsm/gsm0480.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_11.h>
|
||||
|
||||
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
|
||||
LOGP(DSUP, level, "SUBSCR(%s) " fmt, \
|
||||
(subscr) ? (subscr)->imsi : "---", \
|
||||
## args)
|
||||
|
||||
/* Callback for both HLR/auth and USSD SUP sockets */
|
||||
int sup_read_cb(struct gsup_client *sup_client, struct msgb *msg);
|
||||
|
||||
/*
|
||||
int subscr_query_auth_info(struct gsm_subscriber *subscr);
|
||||
*/
|
||||
int subscr_location_update(struct gsm_subscriber *subscr);
|
||||
int subscr_purge_ms(struct gsm_subscriber *subscr);
|
||||
|
||||
int subscr_tx_sms_message(struct gsm_subscriber *subscr,
|
||||
struct gsm411_rp_hdr *rph);
|
||||
|
||||
#endif /* _GSM_SUP_H */
|
14
openbsc/include/openbsc/gsm_ussd_map.h
Normal file
14
openbsc/include/openbsc/gsm_ussd_map.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _GSM_USSD_MAP_H
|
||||
#define _GSM_USSD_MAP_H
|
||||
|
||||
#include <openbsc/gsup_client.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/gsm_ussd_map_proto.h>
|
||||
|
||||
int ussd_map_read_cb(struct gsup_client *sup_client,
|
||||
struct msgb *msg);
|
||||
|
||||
int ussd_map_tx_message(struct gsm_network *net, struct ss_header *req,
|
||||
const char *extension, uint32_t ref, const uint8_t *component_data);
|
||||
|
||||
#endif /* _GSM_USSD_MAP_H */
|
25
openbsc/include/openbsc/gsm_ussd_map_proto.h
Normal file
25
openbsc/include/openbsc/gsm_ussd_map_proto.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef _GSM_USSD_MAP_PROTO_H
|
||||
#define _GSM_USSD_MAP_PROTO_H
|
||||
|
||||
#include <osmocom/gsm/gsm0480.h>
|
||||
|
||||
|
||||
enum {
|
||||
FMAP_MSISDN = 0x80
|
||||
};
|
||||
|
||||
int subscr_uss_message(struct msgb *msg,
|
||||
struct ss_header *req,
|
||||
const char* extension,
|
||||
uint32_t ref,
|
||||
const uint8_t *component_data);
|
||||
|
||||
int rx_uss_message_parse(const uint8_t* data,
|
||||
size_t len,
|
||||
struct ss_header *ss,
|
||||
uint32_t *ref,
|
||||
char* extention,
|
||||
size_t extention_len);
|
||||
|
||||
|
||||
#endif /* _GSM_USSD_MAP_PROTO_H */
|
@@ -47,6 +47,7 @@ struct gsup_client {
|
||||
struct osmo_timer_list connect_timer;
|
||||
int is_connected;
|
||||
int got_ipa_pong;
|
||||
struct gsm_network *net;
|
||||
};
|
||||
|
||||
struct gsup_client *gsup_client_create(const char *ip_addr,
|
||||
|
15
openbsc/include/openbsc/reg_proxy.h
Normal file
15
openbsc/include/openbsc/reg_proxy.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _REG_PROXY_H
|
||||
#define _REG_PROXY_H
|
||||
|
||||
#include <openbsc/sup_server.h>
|
||||
#include <openbsc/sip_client.h>
|
||||
#include <osip2/osip.h>
|
||||
void *tall_reg_ctx;
|
||||
|
||||
struct reg_proxy {
|
||||
struct gsm_sup_server *sup_server;
|
||||
struct sip_client *sip_client;
|
||||
osip_t *osip;
|
||||
};
|
||||
|
||||
#endif /* _REG_PROXY_H */
|
16
openbsc/include/openbsc/sip.h
Normal file
16
openbsc/include/openbsc/sip.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef _SIP_H
|
||||
#define _SIP_H
|
||||
|
||||
#include <openbsc/sip_client.h>
|
||||
#include <openbsc/reg_proxy.h>
|
||||
#include <osip2/osip.h>
|
||||
#include <osmocom/gsm/gsm0480.h>
|
||||
|
||||
int tx_ss_handle(struct sip_client *sip_client, osip_t *osip, struct ss_request *ss,
|
||||
const char *extention);
|
||||
|
||||
int tx_sip_register(struct sip_client *sip_client, osip_t *osip, char *imsi, int expires_time);
|
||||
|
||||
int sip_client_init(struct reg_proxy *reg, const char *src_ip, u_int16_t src_port,
|
||||
const char *dst_ip, u_int16_t dst_port, int expires_time);
|
||||
#endif /* _SIP_H */
|
36
openbsc/include/openbsc/sip_client.h
Normal file
36
openbsc/include/openbsc/sip_client.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/timer.h>
|
||||
|
||||
#define SIP_RECONNECT_INTERVAL 10
|
||||
|
||||
struct msgb;
|
||||
struct ipa_client_conn;
|
||||
struct sip_client;
|
||||
|
||||
/* Expects message in msg->l2h */
|
||||
typedef int (*sip_read_cb_t)(struct sip_client *sip_client, struct msgb *msg);
|
||||
|
||||
struct sip_client {
|
||||
struct tcp_client_conn *link;
|
||||
sip_read_cb_t read_cb;
|
||||
void *data;
|
||||
|
||||
struct osmo_timer_list connect_timer;
|
||||
int is_connected;
|
||||
|
||||
char *src_ip;
|
||||
char *dst_ip;
|
||||
u_int16_t src_port;
|
||||
u_int16_t dst_port;
|
||||
int expires_time;
|
||||
};
|
||||
|
||||
struct sip_client *sip_client_create(const char *src_ip, u_int16_t src_port,
|
||||
const char *dst_ip, u_int16_t dst_port,
|
||||
int expires_time, sip_read_cb_t read_cb,
|
||||
void *data);
|
||||
|
||||
void sip_client_destroy(struct sip_client *sip_client);
|
||||
int sip_client_send(struct sip_client *sip_client, struct msgb *msg);
|
||||
struct msgb *sip_msgb_alloc(void);
|
19
openbsc/include/openbsc/sup.h
Normal file
19
openbsc/include/openbsc/sup.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _SUP_H
|
||||
#define _SUP_H
|
||||
|
||||
#include <openbsc/reg_proxy.h>
|
||||
|
||||
#define LOGGSUPP(level, sup, fmt, args...) \
|
||||
LOGP(DGPRS, level, "SUP(%s) " fmt, \
|
||||
(sup)->imsi, \
|
||||
## args)
|
||||
|
||||
int sup_server_init(struct reg_proxy *reg);
|
||||
|
||||
int handle_location_update_result(struct gsm_sup_server *sup_server,
|
||||
char *imsi, char *msisdn);
|
||||
|
||||
int handle_purge_ms_result(struct gsm_sup_server *sup_server,
|
||||
char *imsi);
|
||||
|
||||
#endif /* _SUP_H */
|
29
openbsc/include/openbsc/sup_server.h
Normal file
29
openbsc/include/openbsc/sup_server.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef _SUP_SERVER_H
|
||||
#define _SUP_SERVER_H
|
||||
|
||||
#include <osmocom/abis/ipa.h>
|
||||
|
||||
//struct msgb;
|
||||
struct ipa_server_conn;
|
||||
struct gsm_sup_server;
|
||||
|
||||
/* Expects message in msg->l2h */
|
||||
typedef int (*sup_read_cb_t)(struct gsm_sup_server *sup_server, struct msgb *msg);
|
||||
|
||||
struct gsm_sup_server {
|
||||
struct ipa_server_link *link;
|
||||
sup_read_cb_t read_cb;
|
||||
void *data;
|
||||
struct osmo_fd fd;
|
||||
struct ipa_server_conn *server_conn;
|
||||
void *app;
|
||||
};
|
||||
|
||||
struct gsm_sup_server *sup_server_create(const char *ip_addr,
|
||||
unsigned int tcp_port,
|
||||
sup_read_cb_t read_cb,
|
||||
void *app);
|
||||
|
||||
int sup_server_send(struct gsm_sup_server *sup_server, struct msgb *msg);
|
||||
|
||||
#endif /* _SUP_SERVER_H */
|
51
openbsc/include/openbsc/tcp_client.h
Normal file
51
openbsc/include/openbsc/tcp_client.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef _TCP_CLIENT_H_
|
||||
#define _TCP_CLIENT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/core/select.h>
|
||||
|
||||
|
||||
struct msgb;
|
||||
|
||||
enum tcp_client_conn_state {
|
||||
TCP_CLIENT_LINK_STATE_NONE = 0,
|
||||
TCP_CLIENT_LINK_STATE_CONNECTING = 1,
|
||||
TCP_CLIENT_LINK_STATE_CONNECTED = 2,
|
||||
TCP_CLIENT_LINK_STATE_MAX
|
||||
};
|
||||
|
||||
struct tcp_client_conn {
|
||||
struct osmo_fd *ofd;
|
||||
struct llist_head tx_queue;
|
||||
struct osmo_timer_list timer;
|
||||
enum tcp_client_conn_state state;
|
||||
const char *src_addr;
|
||||
uint16_t src_port;
|
||||
const char *dst_addr;
|
||||
uint16_t dst_port;
|
||||
void (*updown_cb)(struct tcp_client_conn *link, int up);
|
||||
int (*read_cb)(struct tcp_client_conn *link, struct msgb *msg);
|
||||
int (*write_cb)(struct tcp_client_conn *link);
|
||||
void *data;
|
||||
struct msgb *pending_msg;
|
||||
};
|
||||
|
||||
struct tcp_client_conn *
|
||||
tcp_client_conn_create(void *ctx, int priv_nr,
|
||||
const char *dst_addr, uint16_t dst_port,
|
||||
const char *src_addr, uint16_t src_port,
|
||||
void (*updown)(struct tcp_client_conn *link, int),
|
||||
int (*read_cb)(struct tcp_client_conn *link, struct msgb *msgb),
|
||||
int (*write_cb)(struct tcp_client_conn *link),
|
||||
void *data);
|
||||
void tcp_client_conn_destroy(struct tcp_client_conn *link);
|
||||
|
||||
int tcp_client_conn_open(struct tcp_client_conn *link);
|
||||
void tcp_client_conn_close(struct tcp_client_conn *link);
|
||||
|
||||
void tcp_client_conn_send(struct tcp_client_conn *link, struct msgb *msg);
|
||||
size_t tcp_client_conn_clear_queue(struct tcp_client_conn *link);
|
||||
|
||||
#endif
|
@@ -32,6 +32,11 @@ struct gsm_trans {
|
||||
/* reference from MNCC or other application */
|
||||
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,
|
||||
|
@@ -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
|
||||
|
@@ -44,6 +44,8 @@ SUBDIRS += \
|
||||
utils \
|
||||
ipaccess \
|
||||
gprs \
|
||||
reg-proxy \
|
||||
ussd-proxy \
|
||||
$(NULL)
|
||||
|
||||
# Conditional Programs
|
||||
|
@@ -2115,9 +2115,17 @@ DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
|
||||
"Maximum transmit power of the MS in dBm")
|
||||
{
|
||||
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,
|
||||
|
@@ -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);
|
||||
|
@@ -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",
|
||||
|
@@ -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 }
|
||||
};
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
628
openbsc/src/libmsc/gsm_sup.c
Normal file
628
openbsc/src/libmsc/gsm_sup.c
Normal file
@@ -0,0 +1,628 @@
|
||||
/* GSM Subscriber Update Protocol */
|
||||
|
||||
/* (C) 2015 by Ivan Klyuchnikov <kluchnikovi@gmail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/gsm_sup.h>
|
||||
#include <osmocom/gsm/tlv.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <openbsc/gsup_client.h>
|
||||
#include <openbsc/osmo_msc.h>
|
||||
#include <openbsc/gprs_utils.h>
|
||||
#include <openbsc/ussd.h>
|
||||
#include <openbsc/gsm_04_11.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_11.h>
|
||||
#include <osmocom/gsm/gsm0411_utils.h>
|
||||
|
||||
#if 0
|
||||
enum {
|
||||
FMAP_MSISDN = 0x80
|
||||
};
|
||||
|
||||
static int subscr_uss_message(struct msgb *msg,
|
||||
struct ss_request *req,
|
||||
const char* extention)
|
||||
{
|
||||
size_t bcd_len = 0;
|
||||
uint8_t *gsup_indicator;
|
||||
|
||||
gsup_indicator = msgb_put(msg, 4);
|
||||
|
||||
/* First byte should always be OSMO_GSUP_MSGT_MAP */
|
||||
gsup_indicator[0] = OSMO_GSUP_MSGT_MAP;
|
||||
gsup_indicator[1] = req->message_type;
|
||||
/* TODO ADD tid */
|
||||
gsup_indicator[2] = req->component_type;
|
||||
|
||||
/* invokeId */
|
||||
msgb_tlv_put(msg, GSM0480_COMPIDTAG_INVOKE_ID, 1, &req->invoke_id);
|
||||
|
||||
/* opCode */
|
||||
msgb_tlv_put(msg, GSM0480_OPERATION_CODE, 1, &req->opcode);
|
||||
|
||||
if (req->ussd_text_len > 0) {
|
||||
msgb_tlv_put(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_len + 1, &req->ussd_text_language);
|
||||
}
|
||||
|
||||
if (extention) {
|
||||
uint8_t bcd_buf[32];
|
||||
bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0,
|
||||
extention);
|
||||
msgb_tlv_put(msg, FMAP_MSISDN, bcd_len - 1, &bcd_buf[1]);
|
||||
}
|
||||
|
||||
/* fill actual length */
|
||||
gsup_indicator[3] = 3 + 3 + (req->ussd_text_len + 1 + 2) + (bcd_len + 2);;
|
||||
|
||||
/* wrap with GSM0480_CTYPE_INVOKE */
|
||||
// gsm0480_wrap_invoke(msg, req->opcode, invoke_id);
|
||||
// gsup_indicator = msgb_push(msgb, 1);
|
||||
// gsup_indicator[0] = OSMO_GSUP_MSGT_MAP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int subscr_tx_uss_message(struct ss_request *req,
|
||||
struct gsm_subscriber *subscr)
|
||||
{
|
||||
struct msgb *msg = gsup_client_msgb_alloc();
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
//GSM0480_OP_CODE_PROCESS_USS_REQ
|
||||
subscr_uss_message(msg, req, subscr->extension);
|
||||
|
||||
return gsup_client_send(subscr->group->net->ussd_sup_client, msg);
|
||||
}
|
||||
|
||||
|
||||
static int rx_uss_message_parse(struct ss_request *ss,
|
||||
const uint8_t* data,
|
||||
size_t len,
|
||||
char* extention,
|
||||
size_t extention_len)
|
||||
{
|
||||
const uint8_t* const_data = data;
|
||||
|
||||
if (len < 1 + 2 + 3 + 3)
|
||||
return -1;
|
||||
|
||||
/* skip OSMO_GSUP_MSGT_MAP */
|
||||
ss->message_type = *(++const_data);
|
||||
ss->component_type = *(++const_data);
|
||||
const_data += 2;
|
||||
|
||||
//
|
||||
if (*const_data != GSM0480_COMPIDTAG_INVOKE_ID) {
|
||||
return -1;
|
||||
}
|
||||
const_data += 2;
|
||||
ss->invoke_id = *const_data;
|
||||
const_data++;
|
||||
|
||||
//
|
||||
if (*const_data != GSM0480_OPERATION_CODE) {
|
||||
return -1;
|
||||
}
|
||||
const_data += 2;
|
||||
ss->opcode = *const_data;
|
||||
const_data++;
|
||||
|
||||
|
||||
while (const_data - data < len) {
|
||||
uint8_t len;
|
||||
switch (*const_data) {
|
||||
case ASN1_OCTET_STRING_TAG:
|
||||
ss->ussd_text_len = len = (*(++const_data) - 1);
|
||||
ss->ussd_text_language = *(++const_data);
|
||||
memcpy(ss->ussd_text,
|
||||
++const_data,
|
||||
(len > MAX_LEN_USSD_STRING) ? MAX_LEN_USSD_STRING : len);
|
||||
const_data += len;
|
||||
break;
|
||||
|
||||
case FMAP_MSISDN:
|
||||
len = *(++const_data);
|
||||
gsm48_decode_bcd_number(extention,
|
||||
extention_len,
|
||||
const_data,
|
||||
0);
|
||||
const_data += len + 1;
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DMM, "Unknown code: %d\n", *const_data);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx_uss_message(const uint8_t* data, size_t len)
|
||||
{
|
||||
char extention[32] = {0};
|
||||
struct ss_request ss;
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
|
||||
if (rx_uss_message_parse(&ss, data, len, extention, sizeof(extention))) {
|
||||
LOGP(DSUP, LOGL_ERROR, "Can't parse uss message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGP(DSUP, LOGL_ERROR, "Got invoke_id=0x%02x opcode=0x%02x facility=0x%02x text=%s\n",
|
||||
ss.invoke_id, ss.opcode, ss.component_type, ss.ussd_text);
|
||||
|
||||
return on_ussd_response(&ss, extention);
|
||||
}
|
||||
#endif
|
||||
|
||||
int subscr_tx_sms_message(struct gsm_subscriber *subscr,
|
||||
struct gsm411_rp_hdr *rph)
|
||||
{
|
||||
uint8_t *data;
|
||||
struct msgb *msg = gsup_client_msgb_alloc();
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msgb_put_u8(msg, OSMO_GSUP_MSGT_SMS);
|
||||
|
||||
if (subscr->extension) {
|
||||
uint8_t bcd_buf[32];
|
||||
int bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf),
|
||||
0, subscr->extension);
|
||||
msgb_tlv_put(msg, 0x82, bcd_len - 1, &bcd_buf[1]);
|
||||
}
|
||||
msgb_put_u8(msg, rph->msg_type);
|
||||
msgb_put_u8(msg, rph->msg_ref);
|
||||
|
||||
data = msgb_put(msg, rph->len - 2);
|
||||
memcpy(data, rph->data, rph->len - 2);
|
||||
|
||||
return gsup_client_send(subscr->group->net->sms_client, msg);
|
||||
}
|
||||
|
||||
static int rx_sms_message(struct gsup_client *sup_client,
|
||||
const uint8_t* data, size_t data_len)
|
||||
{
|
||||
|
||||
int rc;
|
||||
char extension[15];
|
||||
uint8_t *value;
|
||||
size_t value_len;
|
||||
int offset = 1;
|
||||
uint8_t *rp_hdr = (uint8_t*)data + offset;
|
||||
data_len -= 1;
|
||||
|
||||
rc = osmo_match_shift_tlv(&rp_hdr, &data_len, 0x82, &value, &value_len);
|
||||
|
||||
if (rc <= 0)
|
||||
return -GMM_CAUSE_INV_MAND_INFO;
|
||||
|
||||
if (value_len * 2 + 1 > ARRAY_SIZE(extension))
|
||||
return -GMM_CAUSE_INV_MAND_INFO;
|
||||
|
||||
/* Note that gsm48_decode_bcd_number expects the number of encoded MSISDN
|
||||
* octets in the first octet. By coincidence (the TLV encoding) the byte
|
||||
* before the value part already contains this length so we can use it
|
||||
* here.
|
||||
*/
|
||||
OSMO_ASSERT(value[-1] == value_len);
|
||||
gsm48_decode_bcd_number(extension, ARRAY_SIZE(extension), value - 1, 0);
|
||||
offset += 2 + value_len;
|
||||
|
||||
struct msgb *msg = gsm411_msgb_alloc();
|
||||
uint8_t *rp_msg;
|
||||
rp_msg = (uint8_t *)msgb_put(msg, data_len);
|
||||
memcpy(rp_msg, data + offset, data_len);
|
||||
|
||||
struct gsm_subscriber *subscr;
|
||||
struct gsm_network *net = sup_client->net;
|
||||
subscr = subscr_get_by_extension(net->subscr_group, extension);
|
||||
if (!subscr) {
|
||||
msgb_free(msg);
|
||||
return -GMM_CAUSE_IMSI_UNKNOWN;
|
||||
}
|
||||
return gsm411_send_rp_msg_subscr(subscr, msg);
|
||||
}
|
||||
|
||||
static int subscr_tx_sup_message(struct gsup_client *sup_client,
|
||||
struct gsm_subscriber *subscr,
|
||||
struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
struct msgb *msg = gsup_client_msgb_alloc();
|
||||
|
||||
if (strlen(gsup_msg->imsi) == 0 && subscr)
|
||||
strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
|
||||
|
||||
osmo_gsup_encode(msg, gsup_msg);
|
||||
|
||||
LOGGSUBSCRP(LOGL_INFO, subscr,
|
||||
"Sending SUP, will send: %s\n", msgb_hexdump(msg));
|
||||
|
||||
if (!sup_client) {
|
||||
msgb_free(msg);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return gsup_client_send(sup_client, msg);
|
||||
}
|
||||
|
||||
/*
|
||||
int subscr_query_auth_info(struct gsm_subscriber *subscr)
|
||||
{
|
||||
struct osmo_gsup_message gsup_msg = {0};
|
||||
|
||||
LOGGSUBSCRP(LOGL_INFO, subscr,
|
||||
"subscriber auth info is not available\n");
|
||||
|
||||
gsup_msg.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
|
||||
return subscr_tx_sup_message(subscr->group->net->hlr_sup_client, subscr, &gsup_msg);
|
||||
}
|
||||
*/
|
||||
int subscr_location_update(struct gsm_subscriber *subscr)
|
||||
{
|
||||
struct osmo_gsup_message gsup_msg = {0};
|
||||
|
||||
LOGGSUBSCRP(LOGL_INFO, subscr,
|
||||
"subscriber data is not available\n");
|
||||
|
||||
gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
|
||||
return subscr_tx_sup_message(subscr->group->net->hlr_sup_client, subscr, &gsup_msg);
|
||||
}
|
||||
|
||||
int subscr_purge_ms(struct gsm_subscriber *subscr)
|
||||
{
|
||||
struct osmo_gsup_message gsup_msg = {0};
|
||||
gsup_msg.message_type = OSMO_GSUP_MSGT_PURGE_MS_REQUEST;
|
||||
return subscr_tx_sup_message(subscr->group->net->hlr_sup_client, subscr, &gsup_msg);
|
||||
}
|
||||
|
||||
static int subscr_tx_sup_error_reply(struct gsup_client *sup_client,
|
||||
struct gsm_subscriber *subscr,
|
||||
struct osmo_gsup_message *gsup_orig,
|
||||
enum gsm48_gmm_cause cause)
|
||||
{
|
||||
struct osmo_gsup_message gsup_reply = {0};
|
||||
|
||||
strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
|
||||
gsup_reply.cause = cause;
|
||||
gsup_reply.message_type =
|
||||
OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
|
||||
|
||||
return subscr_tx_sup_message(sup_client, subscr, &gsup_reply);
|
||||
}
|
||||
|
||||
/*
|
||||
static int subscr_handle_sup_auth_res(struct gsup_client *sup_client,
|
||||
struct gsm_subscriber *subscr,
|
||||
struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
|
||||
struct gsm_security_operation *op;
|
||||
|
||||
|
||||
LOGGSUBSCRP(LOGL_INFO, subscr,
|
||||
"Got SendAuthenticationInfoResult, num_auth_vectors = %zu\n",
|
||||
gsup_msg->num_auth_vectors);
|
||||
|
||||
if (gsup_msg->num_auth_vectors > 0) {
|
||||
op = conn->sec_operation;
|
||||
memcpy(&op->atuple, gsup_msg->auth_vectors, sizeof(struct gsm_auth_vectors));
|
||||
db_sync_lastauthtuple_for_subscr(&op->atuple, subscr);
|
||||
gsm48_tx_mm_auth_req(conn, op->atuple.rand, op->atuple.key_seq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
static int subscr_handle_sup_upd_loc_res(struct gsm_subscriber *subscr,
|
||||
struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
uint8_t msisdn_lv[10];
|
||||
|
||||
if (!subscr->group) {
|
||||
LOGGSUBSCRP(LOGL_ERROR, subscr,
|
||||
"Update location result was received, but LUR procedure timedout.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gsup_msg->msisdn_enc) {
|
||||
if (gsup_msg->msisdn_enc_len > sizeof(msisdn_lv) - 1) {
|
||||
LOGP(DSUP, LOGL_ERROR, "MSISDN too long (%zu)\n",
|
||||
gsup_msg->msisdn_enc_len);
|
||||
return -1;
|
||||
} else {
|
||||
msisdn_lv[0] = gsup_msg->msisdn_enc_len;
|
||||
memcpy(msisdn_lv+1, gsup_msg->msisdn_enc,
|
||||
gsup_msg->msisdn_enc_len);
|
||||
gsm48_decode_bcd_number(subscr->extension, sizeof(subscr->extension),
|
||||
msisdn_lv,0);
|
||||
db_sync_subscriber(subscr);
|
||||
}
|
||||
}
|
||||
|
||||
struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
|
||||
|
||||
if (conn) {
|
||||
if (conn->loc_operation)
|
||||
conn->loc_operation->waiting_for_remote_accept = 0;
|
||||
gsm0408_authorize(conn,NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int subscr_handle_sup_purge_ms_res(struct gsm_subscriber *subscr,
|
||||
struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
LOGP(DSUP, LOGL_INFO, "SUP PURGE MS result OK for IMSI:%s\n", subscr->imsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_cause(int cause)
|
||||
{
|
||||
switch (cause) {
|
||||
case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
|
||||
case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
|
||||
return EACCES;
|
||||
|
||||
case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
|
||||
return EHOSTUNREACH;
|
||||
|
||||
case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int subscr_handle_sup_upd_loc_err(struct gsm_subscriber *subscr,
|
||||
struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
int cause_err;
|
||||
struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
|
||||
|
||||
cause_err = check_cause(gsup_msg->cause);
|
||||
|
||||
LOGGSUBSCRP(LOGL_DEBUG, subscr,
|
||||
"Update location has failed with cause %d, handled as: %s\n",
|
||||
gsup_msg->cause, strerror(cause_err));
|
||||
|
||||
switch (cause_err) {
|
||||
case EACCES:
|
||||
LOGGSUBSCRP(LOGL_NOTICE, subscr,
|
||||
"GSM update location failed, access denied, "
|
||||
"MM cause = '%s' (%d)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
|
||||
gsup_msg->cause);
|
||||
gsm0408_loc_upd_rej(conn, gsup_msg->cause);
|
||||
release_loc_updating_req(conn, 0);
|
||||
break;
|
||||
|
||||
case EHOSTUNREACH:
|
||||
LOGGSUBSCRP(LOGL_NOTICE, subscr,
|
||||
"GSM update location failed, MM cause = '%s' (%d)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
|
||||
gsup_msg->cause);
|
||||
// TODO: Try to find subscriber in local HLR?
|
||||
gsm0408_loc_upd_rej(conn, gsup_msg->cause);
|
||||
release_loc_updating_req(conn, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
case EINVAL:
|
||||
LOGGSUBSCRP(LOGL_ERROR, subscr,
|
||||
"SUP protocol remote error, MM cause = '%s' (%d)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
|
||||
gsup_msg->cause);
|
||||
break;
|
||||
}
|
||||
|
||||
return -gsup_msg->cause;
|
||||
}
|
||||
|
||||
/*
|
||||
static int subscr_handle_sup_auth_err(struct gsm_subscriber *subscr,
|
||||
struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
int cause_err;
|
||||
struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
|
||||
gsm_cbfn *cb = conn->sec_operation->cb;
|
||||
|
||||
cause_err = check_cause(gsup_msg->cause);
|
||||
|
||||
LOGGSUBSCRP(LOGL_DEBUG, subscr,
|
||||
"Send authentication info has failed with cause %d, "
|
||||
"handled as: %s\n",
|
||||
gsup_msg->cause, strerror(cause_err));
|
||||
|
||||
switch (cause_err) {
|
||||
case EACCES:
|
||||
LOGGSUBSCRP(LOGL_NOTICE, subscr,
|
||||
"GSM send auth info req failed, access denied, "
|
||||
"MM cause = '%s' (%d)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
|
||||
gsup_msg->cause);
|
||||
if (cb)
|
||||
cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED,
|
||||
NULL, conn, conn->sec_operation->cb_data);
|
||||
release_security_operation(conn);
|
||||
break;
|
||||
|
||||
case EHOSTUNREACH:
|
||||
LOGGSUBSCRP(LOGL_NOTICE, subscr,
|
||||
"GSM send auth info req failed, MM cause = '%s' (%d)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
|
||||
gsup_msg->cause);
|
||||
// TODO: Try to resend auth request?
|
||||
if (cb)
|
||||
cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED,
|
||||
NULL, conn, conn->sec_operation->cb_data);
|
||||
release_security_operation(conn);
|
||||
break;
|
||||
|
||||
default:
|
||||
case EINVAL:
|
||||
LOGGSUBSCRP(LOGL_ERROR, subscr,
|
||||
"SUP protocol remote error, MM cause = '%s' (%d)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
|
||||
gsup_msg->cause);
|
||||
break;
|
||||
}
|
||||
|
||||
return -gsup_msg->cause;
|
||||
}
|
||||
*/
|
||||
static int subscr_handle_unknown_imsi(struct gsup_client *sup_client,
|
||||
struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
|
||||
subscr_tx_sup_error_reply(sup_client, NULL, gsup_msg,
|
||||
GMM_CAUSE_IMSI_UNKNOWN);
|
||||
LOGP(DSUP, LOGL_NOTICE,
|
||||
"Unknown IMSI %s, discarding SUP request "
|
||||
"of type 0x%02x\n",
|
||||
gsup_msg->imsi, gsup_msg->message_type);
|
||||
} else if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
|
||||
LOGP(DSUP, LOGL_NOTICE,
|
||||
"Unknown IMSI %s, discarding SUP error "
|
||||
"of type 0x%02x, cause '%s' (%d)\n",
|
||||
gsup_msg->imsi, gsup_msg->message_type,
|
||||
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
|
||||
gsup_msg->cause);
|
||||
} else {
|
||||
LOGP(DSUP, LOGL_NOTICE,
|
||||
"Unknown IMSI %s, discarding SUP response "
|
||||
"of type 0x%02x\n",
|
||||
gsup_msg->imsi, gsup_msg->message_type);
|
||||
}
|
||||
|
||||
return -GMM_CAUSE_IMSI_UNKNOWN;
|
||||
}
|
||||
|
||||
static int subscr_rx_sup_message(struct gsup_client *sup_client, struct msgb *msg)
|
||||
{
|
||||
uint8_t *data = msgb_l2(msg);
|
||||
size_t data_len = msgb_l2len(msg);
|
||||
int rc = 0;
|
||||
|
||||
struct osmo_gsup_message gsup_msg = {0};
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
if (*data == OSMO_GSUP_MSGT_SMS) {
|
||||
return rx_sms_message(sup_client, data, data_len);
|
||||
}
|
||||
rc = osmo_gsup_decode(data, data_len, &gsup_msg);
|
||||
if (rc < 0) {
|
||||
LOGP(DSUP, LOGL_ERROR,
|
||||
"decoding SUP message fails with error '%s' (%d)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, -rc), -rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!gsup_msg.imsi[0]) {
|
||||
LOGP(DSUP, LOGL_ERROR, "Missing IMSI in SUP message\n");
|
||||
|
||||
if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
|
||||
subscr_tx_sup_error_reply(sup_client, NULL, &gsup_msg,
|
||||
GMM_CAUSE_INV_MAND_INFO);
|
||||
return -GMM_CAUSE_INV_MAND_INFO;
|
||||
}
|
||||
|
||||
if (!gsup_msg.cause && OSMO_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
|
||||
gsup_msg.cause = GMM_CAUSE_NET_FAIL;
|
||||
|
||||
subscr = subscr_get_by_imsi(NULL, gsup_msg.imsi);
|
||||
|
||||
if (!subscr) {
|
||||
return subscr_handle_unknown_imsi(sup_client, &gsup_msg);
|
||||
}
|
||||
|
||||
LOGGSUBSCRP(LOGL_INFO, subscr,
|
||||
"Received SUP message of type 0x%02x\n", gsup_msg.message_type);
|
||||
|
||||
switch (gsup_msg.message_type) {
|
||||
/*
|
||||
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
|
||||
rc = subscr_handle_sup_auth_res(sup_client, subscr, &gsup_msg);
|
||||
break;
|
||||
|
||||
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
|
||||
rc = subscr_handle_sup_auth_err(subscr, &gsup_msg);
|
||||
break;
|
||||
*/
|
||||
case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT:
|
||||
rc = subscr_handle_sup_upd_loc_res(subscr, &gsup_msg);
|
||||
break;
|
||||
|
||||
case OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR:
|
||||
rc = subscr_handle_sup_upd_loc_err(subscr, &gsup_msg);
|
||||
break;
|
||||
|
||||
case OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
|
||||
case OSMO_GSUP_MSGT_PURGE_MS_ERROR:
|
||||
case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
|
||||
rc = subscr_handle_sup_purge_ms_res(subscr, &gsup_msg);
|
||||
break;
|
||||
|
||||
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
|
||||
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
|
||||
case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST:
|
||||
case OSMO_GSUP_MSGT_DELETE_DATA_REQUEST:
|
||||
LOGGSUBSCRP(LOGL_ERROR, subscr,
|
||||
"Rx SUP message type %d not yet implemented\n",
|
||||
gsup_msg.message_type);
|
||||
subscr_tx_sup_error_reply(sup_client, subscr, &gsup_msg,
|
||||
GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
|
||||
rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGGSUBSCRP(LOGL_ERROR, subscr,
|
||||
"Rx SUP message type %d not valid at SGSN\n",
|
||||
gsup_msg.message_type);
|
||||
if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
|
||||
subscr_tx_sup_error_reply(sup_client, subscr, &gsup_msg,
|
||||
GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
|
||||
rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
|
||||
break;
|
||||
};
|
||||
|
||||
subscr_put(subscr);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sup_read_cb(struct gsup_client *sup_client, struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = subscr_rx_sup_message(sup_client, msg);
|
||||
msgb_free(msg);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
return rc;
|
||||
}
|
93
openbsc/src/libmsc/gsm_ussd_map.c
Normal file
93
openbsc/src/libmsc/gsm_ussd_map.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/* GSM USSD external MAP interface */
|
||||
|
||||
/* (C) 2015 by Sergey Kostanbaev <sergey.kostanbaev@gmail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/gsm_ussd_map.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <openbsc/gsup_client.h>
|
||||
#include <openbsc/osmo_msc.h>
|
||||
#include <openbsc/gprs_utils.h>
|
||||
#include <openbsc/ussd.h>
|
||||
|
||||
|
||||
int ussd_map_tx_message(struct gsm_network* net,
|
||||
struct ss_header *req,
|
||||
const char* extension,
|
||||
uint32_t ref,
|
||||
const uint8_t* component_data)
|
||||
{
|
||||
struct msgb *msg = gsup_client_msgb_alloc();
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
subscr_uss_message(msg, req, extension, ref, component_data);
|
||||
|
||||
return gsup_client_send(net->ussd_sup_client, msg);
|
||||
}
|
||||
|
||||
|
||||
static int ussd_map_rx_message_int(struct gsm_network *net, const uint8_t* data, size_t len)
|
||||
{
|
||||
char extension[32] = {0};
|
||||
uint32_t ref;
|
||||
struct ss_header ss;
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
|
||||
if (rx_uss_message_parse(data, len, &ss, &ref, extension, sizeof(extension))) {
|
||||
LOGP(DSS, LOGL_ERROR, "Can't parse SUP MAP SS message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGP(DSS, LOGL_ERROR, "Got type=0x%02x len=%d\n",
|
||||
ss.message_type, ss.component_length);
|
||||
|
||||
return on_ussd_response(net, ref, &ss, data + ss.component_offset, extension);
|
||||
}
|
||||
|
||||
static int ussd_map_rx_message(struct gsup_client *sup_client, struct msgb *msg)
|
||||
{
|
||||
uint8_t *data = msgb_l2(msg);
|
||||
size_t data_len = msgb_l2len(msg);
|
||||
struct gsm_network *gsmnet = (struct gsm_network *)sup_client->data;
|
||||
|
||||
if (*data != OSMO_GSUP_MSGT_USSD_MAP) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ussd_map_rx_message_int(gsmnet, data, data_len);
|
||||
}
|
||||
|
||||
int ussd_map_read_cb(struct gsup_client *sup_client, struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ussd_map_rx_message(sup_client, msg);
|
||||
msgb_free(msg);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
return rc;
|
||||
}
|
211
openbsc/src/libmsc/gsm_ussd_map_proto.c
Normal file
211
openbsc/src/libmsc/gsm_ussd_map_proto.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/* GSM USSD external MAP protocol on pseudo TCAP */
|
||||
|
||||
/* (C) 2015 by Sergey Kostanbaev <sergey.kostanbaev@gmail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/gsm_ussd_map.h>
|
||||
#include <openbsc/gsm_ussd_map_proto.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <openbsc/osmo_msc.h>
|
||||
#include <openbsc/gprs_utils.h>
|
||||
#include <openbsc/ussd.h>
|
||||
|
||||
/*
|
||||
* 0 - OSMO_GSUP_MSGT_USSD_MAP constant
|
||||
* 1 - LEN
|
||||
* 2 - message_type [ REGISTER / FACILITY / RELEASE COMPLETE ]
|
||||
* 3,4,5,6 - tid ID associated with the session
|
||||
* 7 - FMAP_MSISDN constant
|
||||
* 8 - extention_len
|
||||
* 9..x - extention
|
||||
* x+1 .. original MAP message
|
||||
*/
|
||||
|
||||
int subscr_uss_message(struct msgb *msg,
|
||||
struct ss_header *req,
|
||||
const char* extension,
|
||||
uint32_t ref,
|
||||
const uint8_t* component_data)
|
||||
{
|
||||
uint8_t bcd_lvlen;
|
||||
uint8_t offset = 0;
|
||||
uint8_t *gsup_indicator;
|
||||
|
||||
gsup_indicator = msgb_put(msg, 7);
|
||||
|
||||
/* First byte should always be OSMO_GSUP_MSGT_USSD_MAP */
|
||||
gsup_indicator[offset++] = OSMO_GSUP_MSGT_USSD_MAP;
|
||||
gsup_indicator[offset++] = 0; // Total length
|
||||
gsup_indicator[offset++] = req->message_type;
|
||||
|
||||
gsup_indicator[offset++] = ref >> 24;
|
||||
gsup_indicator[offset++] = ref >> 16;
|
||||
gsup_indicator[offset++] = ref >> 8;
|
||||
gsup_indicator[offset++] = ref;
|
||||
|
||||
if (extension) {
|
||||
gsup_indicator[offset++] = FMAP_MSISDN;
|
||||
bcd_lvlen = gsm48_encode_bcd_number(gsup_indicator + offset,
|
||||
32, 0, extension);
|
||||
|
||||
offset += bcd_lvlen;
|
||||
msgb_put(msg, bcd_lvlen + 1);
|
||||
}
|
||||
|
||||
if (component_data) {
|
||||
msgb_put(msg, req->component_length);
|
||||
memcpy(gsup_indicator + offset, component_data, req->component_length);
|
||||
}
|
||||
|
||||
gsup_indicator[1] = offset + req->component_length - 2; //except OSMO_GSUP_MSGT_USSD_MAP and length field
|
||||
return 0;
|
||||
#if 0
|
||||
gsup_indicator[6] = req->component_type;
|
||||
|
||||
/* invokeId */
|
||||
msgb_tlv_put(msg, GSM0480_COMPIDTAG_INVOKE_ID, 1, &req->invoke_id);
|
||||
|
||||
/* opCode */
|
||||
msgb_tlv_put(msg, GSM0480_OPERATION_CODE, 1, &req->opcode);
|
||||
|
||||
if (req->ussd_text_len > 0) {
|
||||
msgb_tlv_put(msg, ASN1_OCTET_STRING_TAG, req->ussd_text_len + 1, &req->ussd_text_language);
|
||||
}
|
||||
|
||||
if (extension) {
|
||||
uint8_t bcd_buf[32];
|
||||
bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0,
|
||||
extension);
|
||||
msgb_tlv_put(msg, FMAP_MSISDN, bcd_len - 1, &bcd_buf[1]);
|
||||
}
|
||||
|
||||
/* fill actual length */
|
||||
gsup_indicator[7] = 3 + 3 + (req->ussd_text_len + 1 + 2) + (bcd_len + 2);;
|
||||
|
||||
/* wrap with GSM0480_CTYPE_INVOKE */
|
||||
// gsm0480_wrap_invoke(msg, req->opcode, invoke_id);
|
||||
// gsup_indicator = msgb_push(msgb, 1);
|
||||
// gsup_indicator[0] = OSMO_GSUP_MSGT_MAP;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
int rx_uss_message_parse(const uint8_t* data,
|
||||
size_t len,
|
||||
struct ss_header *ss,
|
||||
uint32_t *pref,
|
||||
char* extention,
|
||||
size_t extention_len)
|
||||
{
|
||||
uint8_t ext_len;
|
||||
const uint8_t* const_data = data + 1; // Skip constant
|
||||
uint32_t ref;
|
||||
int total_len;
|
||||
|
||||
if (len < 7)
|
||||
return -1;
|
||||
|
||||
/* skip OSMO_GSUP_MSGT_MAP */
|
||||
total_len = *(const_data++);
|
||||
ss->message_type = *(const_data++);
|
||||
|
||||
ref = ((uint32_t)(*(const_data++))) << 24;
|
||||
ref |= ((uint32_t)(*(const_data++))) << 16;
|
||||
ref |= ((uint32_t)(*(const_data++))) << 8;
|
||||
ref |= ((uint32_t)(*(const_data++)));
|
||||
if (pref)
|
||||
*pref = ref;
|
||||
|
||||
total_len -= 4 + 1; // ref + sizeof(len)
|
||||
|
||||
if (*const_data == FMAP_MSISDN) {
|
||||
ext_len = *(++const_data);
|
||||
if (extention) {
|
||||
gsm48_decode_bcd_number(extention,
|
||||
extention_len,
|
||||
const_data,
|
||||
0);
|
||||
}
|
||||
const_data += ext_len + 1;
|
||||
total_len -= ext_len + 2; // tag FMAP_MSISDN + sizeof(len)
|
||||
}
|
||||
|
||||
ss->component_offset = const_data - data;
|
||||
ss->component_length = total_len; //data[ss->component_offset + 1];
|
||||
|
||||
return 0;
|
||||
#if 0
|
||||
ss->component_type = *(++const_data);
|
||||
|
||||
/* skip full len and move to component id */
|
||||
const_data += 2;
|
||||
|
||||
if (*const_data != GSM0480_COMPIDTAG_INVOKE_ID) {
|
||||
return -1;
|
||||
}
|
||||
const_data += 2;
|
||||
ss->invoke_id = *const_data;
|
||||
const_data++;
|
||||
|
||||
//
|
||||
if (*const_data != GSM0480_OPERATION_CODE) {
|
||||
return -1;
|
||||
}
|
||||
const_data += 2;
|
||||
ss->opcode = *const_data;
|
||||
const_data++;
|
||||
|
||||
|
||||
while (const_data - data < len) {
|
||||
uint8_t len;
|
||||
switch (*const_data) {
|
||||
case ASN1_OCTET_STRING_TAG:
|
||||
ss->ussd_text_len = len = (*(++const_data) - 1);
|
||||
ss->ussd_text_language = *(++const_data);
|
||||
memcpy(ss->ussd_text,
|
||||
++const_data,
|
||||
(len > MAX_LEN_USSD_STRING) ? MAX_LEN_USSD_STRING : len);
|
||||
const_data += len;
|
||||
break;
|
||||
|
||||
case FMAP_MSISDN:
|
||||
len = *(++const_data);
|
||||
gsm48_decode_bcd_number(extention,
|
||||
extention_len,
|
||||
const_data,
|
||||
0);
|
||||
const_data += len + 1;
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DSS, "Unknown code: %d\n", *const_data);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
@@ -61,6 +61,22 @@ struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
20
openbsc/src/reg-proxy/Makefile.am
Normal file
20
openbsc/src/reg-proxy/Makefile.am
Normal file
@@ -0,0 +1,20 @@
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall $(COVERAGE_CFLAGS) \
|
||||
$(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS)
|
||||
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
|
||||
|
||||
bin_PROGRAMS = reg-proxy
|
||||
|
||||
reg_proxy_SOURCES = \
|
||||
../gprs/gprs_utils.c \
|
||||
tcp_client.c sup_server.c sup.c sip.c sip_client.c reg_proxy.c
|
||||
|
||||
reg_proxy_LDADD = \
|
||||
-losipparser2 -losip2 \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
-ldbi $(LIBCRYPT) \
|
||||
$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS)
|
||||
|
||||
|
330
openbsc/src/reg-proxy/reg_proxy.c
Normal file
330
openbsc/src/reg-proxy/reg_proxy.c
Normal file
@@ -0,0 +1,330 @@
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define ENABLE_TRACE
|
||||
#include <osip2/osip.h>
|
||||
|
||||
//#define _GNU_SOURCE
|
||||
//#include <getopt.h>
|
||||
|
||||
//#include <openbsc/db.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <openbsc/debug.h>
|
||||
//#include <osmocom/abis/abis.h>
|
||||
//#include <osmocom/abis/e1_input.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <openbsc/signal.h>
|
||||
//#include <openbsc/osmo_msc.h>
|
||||
//#include <openbsc/osmo_msc_data.h>
|
||||
//#include <openbsc/sms_queue.h>
|
||||
//#include <openbsc/vty.h>
|
||||
//#include <openbsc/bss.h>
|
||||
//#include <openbsc/mncc.h>
|
||||
//#include <openbsc/token_auth.h>
|
||||
//#include <openbsc/handover_decision.h>
|
||||
//#include <openbsc/rrlp.h>
|
||||
//#include <osmocom/ctrl/control_if.h>
|
||||
//#include <osmocom/ctrl/ports.h>
|
||||
//#include <openbsc/ctrl.h>
|
||||
//#include <openbsc/osmo_bsc_rf.h>
|
||||
//#include <openbsc/smpp.h>
|
||||
#include <openbsc/reg_proxy.h>
|
||||
#include <openbsc/sup.h>
|
||||
#include <openbsc/sip.h>
|
||||
|
||||
#define DIPA_PROXY_TEST 0
|
||||
|
||||
static const char *sip_src_ip = "127.0.0.1";
|
||||
static const char *sip_dst_ip = "127.0.0.1";
|
||||
static u_int16_t src_port = 5150;
|
||||
static u_int16_t dst_port = 5060;
|
||||
static int expires_time = 3600;
|
||||
|
||||
struct log_info_cat ipa_proxy_test_cat[] = {
|
||||
[DIPA_PROXY_TEST] = {
|
||||
.name = "DLINP_IPA_PROXY_TEST",
|
||||
.description = "IPA proxy test",
|
||||
.color = "\033[1;35m",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
};
|
||||
|
||||
const struct log_info ipa_proxy_test_log_info = {
|
||||
.filter_fn = NULL,
|
||||
.cat = ipa_proxy_test_cat,
|
||||
.num_cat = ARRAY_SIZE(ipa_proxy_test_cat),
|
||||
};
|
||||
|
||||
|
||||
static void print_usage()
|
||||
{
|
||||
printf("Usage: reg-proxy\n");
|
||||
}
|
||||
|
||||
static void print_help()
|
||||
{
|
||||
printf(" Some useful help...\n");
|
||||
printf(" -h --help this text\n");
|
||||
printf(" -S --sip-src-ip ip-addr Sip client IP address (source).\n");
|
||||
printf(" -s --src-port port Sip client port (source).\n");
|
||||
printf(" -D --sip-dst-ip ip-addr Sip server IP address (destination).\n");
|
||||
printf(" -d --dst-port port Sip server port (destination).\n");
|
||||
printf(" -t --expires-time Registration expiry time in seconds.\n");
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char **argv)
|
||||
{
|
||||
while (1) {
|
||||
int option_index = 0, c;
|
||||
static struct option long_options[] = {
|
||||
{"help", 0, 0, 'h'},
|
||||
{"sip-src-ip", 1, 0, 'S'},
|
||||
{"src-port", 1, 0, 's'},
|
||||
{"sip-dst-ip", 1, 0, 'D'},
|
||||
{"dst-port", 1, 0, 'd'},
|
||||
{"expires-time", 1, 0, 't'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "hS:s:D:d:t:",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_usage();
|
||||
print_help();
|
||||
exit(0);
|
||||
case 'S':
|
||||
sip_src_ip = optarg;
|
||||
break;
|
||||
case 's':
|
||||
src_port = atoi(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
sip_dst_ip = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dst_port = atoi(optarg);
|
||||
break;
|
||||
case 't':
|
||||
expires_time = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct reg_proxy *reg_proxy_init()
|
||||
{
|
||||
struct reg_proxy *reg;
|
||||
|
||||
reg = talloc_zero(tall_reg_ctx, struct reg_proxy);
|
||||
if (!reg)
|
||||
return NULL;
|
||||
return reg;
|
||||
}
|
||||
|
||||
static void signal_handler(int signal)
|
||||
{
|
||||
fprintf(stdout, "signal %u received\n", signal);
|
||||
|
||||
switch (signal) {
|
||||
case SIGINT:
|
||||
//bsc_shutdown_net(bsc_gsmnet);
|
||||
//osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
|
||||
sleep(3);
|
||||
exit(0);
|
||||
break;
|
||||
case SIGABRT:
|
||||
/* in case of abort, we want to obtain a talloc report
|
||||
* and then return to the caller, who will abort the process */
|
||||
case SIGUSR1:
|
||||
talloc_report(tall_reg_ctx, stderr);
|
||||
talloc_report_full(tall_reg_ctx, stderr);
|
||||
break;
|
||||
case SIGUSR2:
|
||||
talloc_report_full(tall_reg_ctx, stderr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void printf_trace_func (char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap)
|
||||
{
|
||||
const char* desc = " ";
|
||||
switch(level)
|
||||
{
|
||||
case OSIP_FATAL:
|
||||
desc = " FATAL ";
|
||||
break;
|
||||
case OSIP_BUG:
|
||||
desc = " BUG ";
|
||||
break;
|
||||
case OSIP_ERROR:
|
||||
desc = " ERROR ";
|
||||
break;
|
||||
case OSIP_WARNING:
|
||||
desc = "WARNING";
|
||||
break;
|
||||
case OSIP_INFO1:
|
||||
desc = " INFO1 ";
|
||||
break;
|
||||
case OSIP_INFO2:
|
||||
desc = " INFO2 ";
|
||||
break;
|
||||
case OSIP_INFO3:
|
||||
desc = " INFO3 ";
|
||||
break;
|
||||
case OSIP_INFO4:
|
||||
desc = " INFO4 ";
|
||||
break;
|
||||
default:
|
||||
desc = " ";
|
||||
}
|
||||
|
||||
printf ("|%s| <%s: %i> | ", desc, fi, li);
|
||||
vprintf(chfr, ap);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void nict_trans_free(osip_t * osip)
|
||||
{
|
||||
int pos = 0;
|
||||
while (!osip_list_eol(&osip->osip_nict_transactions, pos)) {
|
||||
osip_transaction_t *tr = (osip_transaction_t*) osip_list_get(&osip->osip_nict_transactions, pos);
|
||||
if (tr->state== NICT_TERMINATED)
|
||||
osip_transaction_free(tr);
|
||||
else
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
struct reg_proxy *reg;
|
||||
|
||||
tall_reg_ctx = talloc_named_const(NULL, 1, "reg_proxy");
|
||||
//talloc_ctx_init();
|
||||
|
||||
//libosmo_abis_init(tall_reg_ctx);
|
||||
osmo_init_logging(&log_info);
|
||||
printf("Initializing OSIP\n");
|
||||
|
||||
// use custom function
|
||||
osip_trace_initialize_func(END_TRACE_LEVEL, &printf_trace_func);
|
||||
|
||||
|
||||
//osmo_init_logging(&ipa_proxy_test_log_info);
|
||||
|
||||
/* seed the PRNG */
|
||||
//srand(time(NULL));
|
||||
|
||||
/*
|
||||
if (db_init(database_name)) {
|
||||
printf("DB: Failed to init database. Please check the option settings.\n");
|
||||
return -1;
|
||||
}
|
||||
printf("DB: Database initialized.\n");
|
||||
|
||||
if (db_prepare()) {
|
||||
printf("DB: Failed to prepare database.\n");
|
||||
return -1;
|
||||
}
|
||||
printf("DB: Database prepared.\n");
|
||||
*/
|
||||
/* parse options */
|
||||
handle_options(argc, argv);
|
||||
|
||||
reg = reg_proxy_init();
|
||||
if (!reg) {
|
||||
LOGP(DSUP, LOGL_FATAL, "Cannot create reg_proxy struck\n");
|
||||
exit(2);
|
||||
}
|
||||
rc = sup_server_init(reg);
|
||||
if (rc < 0) {
|
||||
LOGP(DSUP, LOGL_FATAL, "Cannot set up subscriber management\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
rc = sip_client_init(reg, sip_src_ip, src_port, sip_dst_ip, dst_port, expires_time);
|
||||
if (rc < 0) {
|
||||
LOGP(DSUP, LOGL_FATAL, "Cannot set up SIP\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* setup the timer */
|
||||
/*
|
||||
db_sync_timer.cb = db_sync_timer_cb;
|
||||
db_sync_timer.data = NULL;
|
||||
if (use_db_counter)
|
||||
osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL);
|
||||
|
||||
bsc_gsmnet->subscr_expire_timer.cb = subscr_expire_cb;
|
||||
bsc_gsmnet->subscr_expire_timer.data = NULL;
|
||||
osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
|
||||
*/
|
||||
signal(SIGINT, &signal_handler);
|
||||
signal(SIGABRT, &signal_handler);
|
||||
signal(SIGUSR1, &signal_handler);
|
||||
signal(SIGUSR2, &signal_handler);
|
||||
osmo_init_ignore_signals();
|
||||
|
||||
/*
|
||||
if (daemonize) {
|
||||
rc = osmo_daemonize();
|
||||
if (rc < 0) {
|
||||
perror("Error during daemonize");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
*/
|
||||
printf("Entering Main loop 1\n");
|
||||
OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Check OSIP_TRACE init\n"));
|
||||
|
||||
while (1) {
|
||||
log_reset_context();
|
||||
osmo_select_main(0); //<-- TIMER handling
|
||||
osip_nict_execute(reg->osip);
|
||||
osip_timers_nict_execute(reg->osip);
|
||||
|
||||
osip_ict_execute(reg->osip);
|
||||
osip_timers_ict_execute(reg->osip);
|
||||
|
||||
osip_nist_execute(reg->osip);
|
||||
osip_timers_nist_execute(reg->osip);
|
||||
|
||||
osip_ist_execute(reg->osip);
|
||||
osip_timers_ist_execute(reg->osip);
|
||||
|
||||
osip_retransmissions_execute(reg->osip);
|
||||
nict_trans_free(reg->osip);
|
||||
}
|
||||
}
|
623
openbsc/src/reg-proxy/sip.c
Normal file
623
openbsc/src/reg-proxy/sip.c
Normal file
@@ -0,0 +1,623 @@
|
||||
#include <openbsc/sip_client.h>
|
||||
#include <openbsc/reg_proxy.h>
|
||||
#include <openbsc/sup.h>
|
||||
#include <osmocom/gsm/gsm0480.h>
|
||||
#include <osip2/osip.h>
|
||||
#include <osip2/osip_dialog.h>
|
||||
#include <osip2/osip_fifo.h>
|
||||
#include <osip2/osip_time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define MESSAGE_MAX_LENGTH 4000
|
||||
#define MAX_ADDR_STR 128
|
||||
#define MESSAGE_ENTRY_MAX_LENGTH 256
|
||||
#define SIP_URI_SCHEME "sip"
|
||||
#define SIP_VERSION "SIP/2.0"
|
||||
#define EXPIRES_TIME_INSECS 3600
|
||||
#define SIP_ALLOW "REGISTER, INVITE, INFO, ACK, CANCEL, BYE"
|
||||
|
||||
|
||||
|
||||
int get_seqnum(void)
|
||||
{
|
||||
static int seq_num = 1;
|
||||
if (seq_num < (1<<30)) {
|
||||
seq_num++;
|
||||
}
|
||||
else {
|
||||
seq_num = 1;
|
||||
}
|
||||
return seq_num;
|
||||
}
|
||||
|
||||
int sip_send(struct sip_client *sip_client, osip_t *osip,
|
||||
osip_message_t *msg, osip_fsm_type_t transaction_type)
|
||||
{
|
||||
int status;
|
||||
osip_transaction_t *transaction;
|
||||
osip_event_t *sip_event;
|
||||
|
||||
status = osip_transaction_init(&transaction, transaction_type, osip, msg);
|
||||
if (status) {
|
||||
printf("Failed to init transaction %d",status);
|
||||
osip_message_free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
osip_transaction_set_your_instance(transaction, sip_client);
|
||||
osip_transaction_set_reserved6(transaction, osip);
|
||||
|
||||
sip_event = osip_new_outgoing_sipmessage(msg);
|
||||
if (!sip_event) {
|
||||
printf("Can't allocate message");
|
||||
osip_message_free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sip_event->transactionid = transaction->transactionid;
|
||||
|
||||
status = osip_message_force_update(msg);
|
||||
|
||||
if (status) {
|
||||
printf("Failed force update %d",status);
|
||||
osip_message_free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = osip_transaction_add_event(transaction, sip_event);
|
||||
|
||||
if (status) {
|
||||
printf("Can't add event %d",status);
|
||||
osip_message_free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Event added, waiting message to send ..... %d\n",status);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int tx_sip_register(struct sip_client *sip_client, osip_t *osip, char *imsi,
|
||||
int expires_time)
|
||||
{
|
||||
osip_message_t *reg_msg;
|
||||
|
||||
char *call_id_num = NULL;
|
||||
char *seq_num_str = NULL;
|
||||
osip_call_id_t *call_id;
|
||||
char tmp[MESSAGE_ENTRY_MAX_LENGTH];
|
||||
osip_cseq_t *cseq;
|
||||
char src_port[6];
|
||||
|
||||
if (osip_message_init(®_msg)) {
|
||||
OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Can't init message!\n"));
|
||||
return -1;
|
||||
}
|
||||
osip_message_set_method(reg_msg, osip_strdup("REGISTER"));
|
||||
|
||||
/////
|
||||
osip_uri_init(&(reg_msg->req_uri));
|
||||
osip_uri_set_scheme(reg_msg->req_uri, osip_strdup(SIP_URI_SCHEME));
|
||||
osip_uri_set_host(reg_msg->req_uri, osip_strdup(sip_client->dst_ip));
|
||||
//if (osip_uri_parse(reg_msg->req_uri, SIP_SERVER)) {
|
||||
// OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"uri parse failed!\n"));
|
||||
// osip_message_free(reg_msg);
|
||||
// return -1;
|
||||
//}
|
||||
////////
|
||||
osip_message_set_version(reg_msg, osip_strdup(SIP_VERSION));
|
||||
//osip_message_set_status_code(reg_msg, 0);
|
||||
//osip_message_set_reason_phrase(reg_msg, NULL);
|
||||
|
||||
sprintf(tmp, "<sip:%s@%s>", imsi, sip_client->dst_ip);
|
||||
osip_message_set_to(reg_msg, tmp);
|
||||
sprintf(tmp, "<sip:%s@%s>;tag=%u", imsi, sip_client->dst_ip, osip_build_random_number());
|
||||
osip_message_set_from(reg_msg, tmp);
|
||||
|
||||
if (osip_call_id_init(&call_id)) {
|
||||
OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"call id failed!\n"));
|
||||
osip_message_free(reg_msg);
|
||||
return -1;
|
||||
}
|
||||
call_id_num = (char *)osip_malloc(MAX_ADDR_STR);
|
||||
sprintf(call_id_num, "%u", osip_build_random_number());
|
||||
osip_call_id_set_number(call_id, call_id_num);
|
||||
reg_msg->call_id = call_id;
|
||||
|
||||
if (osip_cseq_init(&cseq)) {
|
||||
OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"seq init failed!\n"));
|
||||
osip_message_free(reg_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
seq_num_str = (char *)osip_malloc(11);
|
||||
sprintf(seq_num_str,"%i", get_seqnum());
|
||||
osip_cseq_set_number(cseq, seq_num_str);
|
||||
osip_cseq_set_method(cseq, osip_strdup("REGISTER"));
|
||||
reg_msg->cseq = cseq;
|
||||
|
||||
osip_message_set_max_forwards(reg_msg, "70");
|
||||
|
||||
sprintf(src_port, "%u", sip_client->src_port);
|
||||
sprintf(tmp, "SIP/2.0/%s %s:%s;branch=z9hG4bK%u", "TCP", sip_client->src_ip,
|
||||
src_port, osip_build_random_number());
|
||||
osip_message_set_via(reg_msg, tmp);
|
||||
|
||||
sprintf(tmp, "<sip:%s@%s:%s>", imsi, sip_client->src_ip, src_port);
|
||||
osip_message_set_contact(reg_msg, tmp);
|
||||
|
||||
sprintf(tmp, "%i", expires_time);
|
||||
osip_message_set_expires(reg_msg, tmp);
|
||||
|
||||
osip_message_set_content_length(reg_msg, "0");
|
||||
|
||||
osip_message_set_allow(reg_msg, SIP_ALLOW);
|
||||
|
||||
printf("REG message ready, try to send\n");
|
||||
|
||||
if (sip_send(sip_client, osip, reg_msg, NICT)) {
|
||||
printf("Error sending message!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rx_sip_message(struct sip_client *sip_client, struct msgb *msg)
|
||||
{
|
||||
char sip_msg[MESSAGE_MAX_LENGTH];
|
||||
osip_event_t *sipevent;
|
||||
struct reg_proxy *reg = sip_client->data;
|
||||
|
||||
printf("processSipMsg: RECEIVED MSG\n");
|
||||
strncpy(sip_msg, (char*)msg->data,msg->data_len);
|
||||
printf("processSipMsg: sip_msg = %s\n", sip_msg);
|
||||
|
||||
sipevent= osip_parse(sip_msg,msg->data_len);
|
||||
if((sipevent==NULL)||(sipevent->sip==NULL)) {
|
||||
printf("Could not parse SIP message\n");
|
||||
osip_event_free(sipevent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (osip_find_transaction_and_add_event(reg->osip,sipevent)) {
|
||||
printf("New transaction!\n");
|
||||
if (MSG_IS_REQUEST(sipevent->sip)) {
|
||||
printf("Got New Request:%s\n",sip_msg);
|
||||
} else if (MSG_IS_RESPONSE(sipevent->sip)) {
|
||||
printf("Got New Response:%s\n",sip_msg);
|
||||
} else {
|
||||
printf("Unsupported message:%s\n",sip_msg);
|
||||
osip_event_free(sipevent);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sip_read_cb(struct sip_client *sip_client, struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
rc = rx_sip_message(sip_client, msg);
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int sip_cb_send(osip_transaction_t *tr, osip_message_t *sip_msg, char *host, int port, int out_socket)
|
||||
{
|
||||
|
||||
size_t msg_len;
|
||||
char *msg_p;
|
||||
struct msgb *msg = sip_msgb_alloc();
|
||||
int err;
|
||||
struct sip_client *sip_client = osip_transaction_get_your_instance(tr);
|
||||
printf("SIP Send Msg\n");
|
||||
|
||||
if ((err = osip_message_to_str(sip_msg, &msg_p, &msg_len)) != 0){
|
||||
osip_message_free(sip_msg);
|
||||
msgb_free(msg);
|
||||
printf("SIP failed to convert message: %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
printf("SIP convert message ok\n");
|
||||
|
||||
if (!msg_p) {
|
||||
msgb_free(msg);
|
||||
osip_message_free(sip_msg);
|
||||
printf("SIP msg_p = NULL fail!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sip_client == NULL) {
|
||||
osip_dialog_t* diag = (osip_dialog_t* )sip_msg->application_data;
|
||||
if (diag == NULL) {
|
||||
msgb_free(msg);
|
||||
osip_free(msg_p);
|
||||
osip_message_free(sip_msg);
|
||||
printf("Unable to send:\n%s\n", msg_p);
|
||||
return -1;
|
||||
}
|
||||
sip_client = (struct sip_client *)diag->your_instance;
|
||||
}
|
||||
|
||||
printf("SIP msg_p != NULL OK!, msg_len = %d\n", msg_len);
|
||||
memcpy(msg->data, (uint8_t*)msg_p, msg_len);
|
||||
msg->data_len = msg_len;
|
||||
msg->len += msg_len;
|
||||
printf("SIP ready to send msg via IPA\n");
|
||||
osip_free(msg_p);
|
||||
return sip_client_send(sip_client, msg);
|
||||
}
|
||||
|
||||
|
||||
void sip_cb_rcv1xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_NICT_STATUS_1XX_RECEIVED\n");
|
||||
}
|
||||
|
||||
void sip_cb_rcv2xx(int type, osip_transaction_t *tr, osip_message_t *sip_msg)
|
||||
{
|
||||
printf("OSIP_NICT_STATUS_2XX_RECEIVED\n");
|
||||
osip_contact_t *contact;
|
||||
osip_to_t* to;
|
||||
struct sip_client *sip_client = osip_transaction_get_your_instance(tr);
|
||||
struct reg_proxy *reg = sip_client->data;
|
||||
char imsi[16];
|
||||
char msisdn[16];
|
||||
|
||||
to = osip_message_get_to(sip_msg);
|
||||
memcpy(imsi, to->url->username, 16);
|
||||
printf("OSIP_NICT_STATUS_2XX_RECEIVED imsi = %s \n", imsi);
|
||||
|
||||
if (osip_message_get_contact(sip_msg, 0, &contact) < 0) {
|
||||
handle_purge_ms_result(reg->sup_server, imsi);
|
||||
} else {
|
||||
memcpy(msisdn, contact->url->username, 16);
|
||||
printf("OSIP_NICT_STATUS_2XX_RECEIVED msisdn = %s \n", msisdn);
|
||||
handle_location_update_result(reg->sup_server, imsi, msisdn);
|
||||
}
|
||||
}
|
||||
|
||||
void sip_cb_rcv2xx_again(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN\n");
|
||||
}
|
||||
|
||||
void sip_cb_rcv3xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_NICT_STATUS_3XX_RECEIVED\n");
|
||||
}
|
||||
|
||||
void sip_cb_rcv4xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_NICT_STATUS_4XX_RECEIVED\n");
|
||||
}
|
||||
void sip_cb_rcv5xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_NICT_STATUS_5XX_RECEIVED\n");
|
||||
}
|
||||
void sip_cb_rcv6xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_NICT_STATUS_6XX_RECEIVED\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sip_cb_ict_rcv2xx(int type, osip_transaction_t *tr, osip_message_t *sip_msg)
|
||||
{
|
||||
printf("OSIP_ICT_STATUS_2XX_RECEIVED\n");
|
||||
//osip_contact_t *contact;
|
||||
osip_to_t* to;
|
||||
osip_from_t* from;
|
||||
struct sip_client *sip_client = osip_transaction_get_your_instance(tr);
|
||||
osip_t* osip = osip_transaction_get_reserved6(tr);
|
||||
|
||||
//struct reg_proxy *reg = sip_client->data;
|
||||
|
||||
//char request[32];
|
||||
char from_str[32];
|
||||
char to_str[32];
|
||||
int rc;
|
||||
|
||||
//osip_message_get_contact(sip_msg, 0, &contact);
|
||||
//strncpy(request, contact->url->username, sizeof(request));
|
||||
|
||||
from = osip_message_get_from(sip_msg);
|
||||
strncpy(from_str, from->url->username, sizeof(from_str));
|
||||
|
||||
to = osip_message_get_to(sip_msg);
|
||||
strncpy(to_str, to->url->username, sizeof(to_str));
|
||||
|
||||
printf("FROM: %s TO: %s\n", from_str, to_str);
|
||||
osip_dialog_t *dialog;
|
||||
if (MSG_IS_RESPONSE_FOR(sip_msg, "INVITE")) {
|
||||
//dialog = my_application_search_existing_dialog(sip_msg);
|
||||
//if (dialog == NULL) //NO EXISTING DIALOG
|
||||
{
|
||||
int err = osip_dialog_init_as_uac(&dialog, sip_msg);
|
||||
if (err) {
|
||||
printf("Can't osip_dialog_init_as_uac %d\n", err);
|
||||
}
|
||||
//my_application_add_existing_dialog(dialog);
|
||||
}
|
||||
}
|
||||
dialog->your_instance = sip_client;
|
||||
|
||||
osip_message_t *ack_msg;
|
||||
if (osip_message_init(&ack_msg)) {
|
||||
OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Can't init message!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
osip_message_set_method(ack_msg, osip_strdup("ACK"));
|
||||
|
||||
osip_uri_init(&(ack_msg->req_uri));
|
||||
osip_uri_set_scheme(ack_msg->req_uri, osip_strdup(SIP_URI_SCHEME));
|
||||
osip_uri_set_username(ack_msg->req_uri, osip_strdup(to_str));
|
||||
osip_uri_set_host(ack_msg->req_uri, osip_strdup(sip_client->dst_ip));
|
||||
|
||||
osip_message_set_version(ack_msg, osip_strdup(SIP_VERSION));
|
||||
|
||||
//osip_message_set_to(ack_msg, to->displayname);
|
||||
//osip_message_set_from(ack_msg, from->displayname);
|
||||
osip_from_clone(from, &ack_msg->from);
|
||||
osip_to_clone(to, &ack_msg->to);
|
||||
|
||||
rc = osip_call_id_clone(sip_msg->call_id, &(ack_msg->call_id));
|
||||
assert (rc == 0);
|
||||
|
||||
osip_cseq_t* cseq;
|
||||
rc = osip_cseq_init(&cseq);
|
||||
assert (rc == 0);
|
||||
|
||||
//char* seq_num_str = (char *)osip_malloc(11);
|
||||
//sprintf(seq_num_str,"%i", atoi(sip_msg->cseq->number) + 1); // Hardcoded
|
||||
osip_cseq_set_number(cseq, osip_strdup(sip_msg->cseq->number));
|
||||
osip_cseq_set_method(cseq, osip_strdup("ACK"));
|
||||
ack_msg->cseq = cseq;
|
||||
|
||||
osip_message_set_max_forwards(ack_msg, "70");
|
||||
|
||||
char tmp[MESSAGE_ENTRY_MAX_LENGTH];
|
||||
snprintf(tmp, sizeof(tmp), "SIP/2.0/%s %s:%s;branch=z9hG4bK-%u",
|
||||
"TCP",
|
||||
//from->url->host,
|
||||
//from->url->port,
|
||||
"127.0.0.1",
|
||||
"5150",
|
||||
osip_build_random_number());
|
||||
|
||||
osip_message_set_via(ack_msg, tmp);
|
||||
|
||||
char src_port[7];
|
||||
snprintf(src_port, sizeof(src_port), "%u", sip_client->src_port);
|
||||
snprintf(tmp, sizeof(tmp), "<sip:ussd_sip@%s:%s>", sip_client->src_ip, src_port);
|
||||
osip_message_set_contact(ack_msg, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%i", EXPIRES_TIME_INSECS);
|
||||
osip_message_set_expires(ack_msg, tmp);
|
||||
|
||||
osip_message_set_content_length(ack_msg, "0");
|
||||
ack_msg->application_data = dialog;
|
||||
|
||||
|
||||
int status;
|
||||
osip_transaction_t *transaction;
|
||||
status = osip_transaction_init(&transaction, ICT, osip, ack_msg);
|
||||
if (status) {
|
||||
printf("Failed to init transaction %d\n", status);
|
||||
return ;
|
||||
}
|
||||
|
||||
osip_transaction_set_your_instance(transaction, sip_client);
|
||||
osip_transaction_set_reserved5(transaction, dialog);
|
||||
osip_transaction_set_reserved6(transaction, osip);
|
||||
|
||||
osip_event_t *sip_event = osip_new_outgoing_sipmessage(ack_msg);
|
||||
if (!sip_event) {
|
||||
printf("Can't allocate message\n");
|
||||
osip_message_free(ack_msg);
|
||||
return ;
|
||||
}
|
||||
|
||||
sip_event->transactionid = transaction->transactionid;
|
||||
status = osip_message_force_update(ack_msg);
|
||||
if (status) {
|
||||
printf("Failed force update %d\n",status);
|
||||
osip_message_free(ack_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
status = osip_transaction_add_event(transaction, sip_event);
|
||||
if (status) {
|
||||
printf("Can't add event %d\n",status);
|
||||
osip_message_free(ack_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
osip_ict_execute(osip);
|
||||
// osip_start_ack_retransmissions(transaction,
|
||||
// dialog, ack_msg, to->url->host,
|
||||
// (to->url->port) ? atoi(to->url->port) : 5060, -1);
|
||||
|
||||
}
|
||||
|
||||
void sip_cb_ict_rcv1xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_ICT_STATUS_1XX_RECEIVED\n");
|
||||
}
|
||||
void sip_cb_ict_rcv2xx_again(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_ICT_STATUS_2XX_RECEIVED_AGAIN\n");
|
||||
}
|
||||
void sip_cb_ict_rcv3456xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
|
||||
{
|
||||
printf("OSIP_ICT_STATUS_3456XX_RECEIVED\n");
|
||||
}
|
||||
|
||||
void sip_cb_ict_kill_transaction(int type, osip_transaction_t *tr)
|
||||
{
|
||||
printf("OSIP_ICT_KILL_TRANSACTION\n");
|
||||
//int i = osip_remove_transaction (osip_transaction_get_reserved6(tr), tr);
|
||||
//i = osip_transaction_free2(tr);
|
||||
//if (i != 0) fprintf(stderr, "cannot remove transaction\n");
|
||||
printf("KILLED TRANSACTION\n");
|
||||
}
|
||||
|
||||
void cb_transport_error(int type, osip_transaction_t *a, int error)
|
||||
{
|
||||
printf("OSIP_ICT_TRANSPORT_ERROR trnasaction: %p error: %d\n",
|
||||
a, error);
|
||||
}
|
||||
|
||||
void sip_set_cbs(osip_t *osip)
|
||||
{
|
||||
osip_set_cb_send_message(osip, sip_cb_send);
|
||||
osip_set_message_callback (osip, OSIP_NICT_STATUS_1XX_RECEIVED, sip_cb_rcv1xx);
|
||||
osip_set_message_callback (osip, OSIP_NICT_STATUS_2XX_RECEIVED, sip_cb_rcv2xx);
|
||||
osip_set_message_callback (osip, OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN, sip_cb_rcv2xx_again);
|
||||
osip_set_message_callback (osip, OSIP_NICT_STATUS_3XX_RECEIVED, sip_cb_rcv3xx);
|
||||
osip_set_message_callback (osip, OSIP_NICT_STATUS_4XX_RECEIVED, sip_cb_rcv4xx);
|
||||
osip_set_message_callback (osip, OSIP_NICT_STATUS_5XX_RECEIVED, sip_cb_rcv5xx);
|
||||
osip_set_message_callback (osip, OSIP_NICT_STATUS_6XX_RECEIVED, sip_cb_rcv6xx);
|
||||
|
||||
osip_set_message_callback (osip, OSIP_ICT_STATUS_1XX_RECEIVED, sip_cb_ict_rcv1xx);
|
||||
osip_set_message_callback (osip, OSIP_ICT_STATUS_2XX_RECEIVED, sip_cb_ict_rcv2xx);
|
||||
osip_set_message_callback (osip, OSIP_ICT_STATUS_2XX_RECEIVED_AGAIN, sip_cb_ict_rcv2xx_again);
|
||||
osip_set_message_callback (osip, OSIP_ICT_STATUS_3XX_RECEIVED, sip_cb_ict_rcv3456xx);
|
||||
osip_set_message_callback (osip, OSIP_ICT_STATUS_4XX_RECEIVED, sip_cb_ict_rcv3456xx);
|
||||
osip_set_message_callback (osip, OSIP_ICT_STATUS_5XX_RECEIVED, sip_cb_ict_rcv3456xx);
|
||||
osip_set_message_callback (osip, OSIP_ICT_STATUS_6XX_RECEIVED, sip_cb_ict_rcv3456xx);
|
||||
|
||||
osip_set_kill_transaction_callback(osip, OSIP_ICT_KILL_TRANSACTION, sip_cb_ict_kill_transaction);
|
||||
|
||||
osip_set_transport_error_callback(osip, OSIP_ICT_TRANSPORT_ERROR, cb_transport_error);
|
||||
|
||||
//osip_set_kill_transaction_callback(osip ,OSIP_NIST_KILL_TRANSACTION, &cb_ist_kill_transaction);
|
||||
//osip_set_kill_transaction_callback(osip ,OSIP_NICT_KILL_TRANSACTION, &cb_nict_kill_transaction);
|
||||
//osip_set_kill_transaction_callback(osip ,OSIP_NIST_KILL_TRANSACTION, &cb_nist_kill_transaction);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int sip_client_init(struct reg_proxy *reg, const char *src_ip, u_int16_t src_port,
|
||||
const char *dst_ip, u_int16_t dst_port, int expires_time)
|
||||
{
|
||||
|
||||
reg->sip_client = sip_client_create(src_ip, src_port, dst_ip, dst_port, expires_time,
|
||||
&sip_read_cb, reg);
|
||||
if (!reg->sip_client)
|
||||
return -1;
|
||||
|
||||
if (osip_init(®->osip)!=0)
|
||||
return -1;
|
||||
|
||||
sip_set_cbs(reg->osip);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// USSD part
|
||||
#define MAX_USSD_CONTENT 1000
|
||||
|
||||
int tx_ss_handle(struct sip_client *sip_client, osip_t *osip, struct ss_request *ss,
|
||||
const char *extention)
|
||||
{
|
||||
osip_message_t *reg_msg;
|
||||
|
||||
//static int seq_num = 1;
|
||||
char *call_id_num = NULL;
|
||||
char *seq_num_str = NULL;
|
||||
osip_call_id_t *call_id;
|
||||
char tmp[MESSAGE_ENTRY_MAX_LENGTH];
|
||||
osip_cseq_t *cseq;
|
||||
char src_port[6];
|
||||
|
||||
if (osip_message_init(®_msg)) {
|
||||
OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Can't init message!\n"));
|
||||
return -1;
|
||||
}
|
||||
osip_message_set_method(reg_msg, osip_strdup("INVITE"));
|
||||
|
||||
/////
|
||||
osip_uri_init(&(reg_msg->req_uri));
|
||||
osip_uri_set_scheme(reg_msg->req_uri, osip_strdup(SIP_URI_SCHEME));
|
||||
osip_uri_set_username(reg_msg->req_uri, osip_strdup(ss->ussd_text));
|
||||
osip_uri_set_host(reg_msg->req_uri, osip_strdup(sip_client->dst_ip));
|
||||
osip_message_set_version(reg_msg, osip_strdup(SIP_VERSION));
|
||||
|
||||
|
||||
sprintf(tmp, "<sip:%s@%s>", ss->ussd_text, sip_client->dst_ip);
|
||||
osip_message_set_to(reg_msg, tmp);
|
||||
|
||||
sprintf(tmp, "<sip:%s@%s>;tag=%u", extention, sip_client->dst_ip, osip_build_random_number());
|
||||
osip_message_set_from(reg_msg, tmp);
|
||||
|
||||
if (osip_call_id_init(&call_id)) {
|
||||
OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"call id failed!\n"));
|
||||
osip_message_free(reg_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
call_id_num = (char *)osip_malloc(MAX_ADDR_STR);
|
||||
sprintf(call_id_num, "%u", osip_build_random_number());
|
||||
osip_call_id_set_number(call_id, call_id_num);
|
||||
reg_msg->call_id = call_id;
|
||||
|
||||
if (osip_cseq_init(&cseq)) {
|
||||
OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"seq init failed!\n"));
|
||||
osip_message_free(reg_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
seq_num_str = (char *)osip_malloc(11);
|
||||
sprintf(seq_num_str,"%i", 1); // Hardcoded
|
||||
osip_cseq_set_number(cseq, seq_num_str);
|
||||
osip_cseq_set_method(cseq, osip_strdup("INVITE"));
|
||||
reg_msg->cseq = cseq;
|
||||
|
||||
osip_message_set_max_forwards(reg_msg, "70");
|
||||
|
||||
snprintf(src_port, sizeof(src_port), "%u", sip_client->src_port);
|
||||
snprintf(tmp, sizeof(tmp), "SIP/2.0/%s %s:%s;branch=z9hG4bK-%u", "TCP", sip_client->src_ip,
|
||||
src_port, osip_build_random_number());
|
||||
osip_message_set_via(reg_msg, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "<sip:ussd_sip@%s:%s>", sip_client->src_ip, src_port);
|
||||
osip_message_set_contact(reg_msg, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%i", EXPIRES_TIME_INSECS);
|
||||
osip_message_set_expires(reg_msg, tmp);
|
||||
|
||||
// Content
|
||||
char content[MAX_USSD_CONTENT];
|
||||
int content_len = snprintf(content, sizeof(content),
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<ussd-data>\n"
|
||||
" <language>%s</language>\n"
|
||||
" <ussd-string>%s</ussd-string>\n"
|
||||
"</ussd-data>",
|
||||
"en",
|
||||
ss->ussd_text);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%i", content_len);
|
||||
osip_message_set_content_length(reg_msg, tmp);
|
||||
osip_message_set_content_type(reg_msg, "application/vnd.3gpp.ussd+xml");
|
||||
|
||||
osip_message_set_body(reg_msg, content, content_len);
|
||||
|
||||
//osip_message_set_allow(reg_msg, SIP_ALLOW);
|
||||
|
||||
printf("REG message ready, try to send\n");
|
||||
|
||||
if (sip_send(sip_client, osip, reg_msg, ICT)) {
|
||||
printf("Error sending message!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
277
openbsc/src/reg-proxy/sip_client.c
Normal file
277
openbsc/src/reg-proxy/sip_client.c
Normal file
@@ -0,0 +1,277 @@
|
||||
#include <openbsc/reg_proxy.h>
|
||||
#include <openbsc/sip_client.h>
|
||||
|
||||
//#include <osmocom/abis/ipa.h>
|
||||
//#include <osmocom/gsm/protocol/ipaccess.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <openbsc/tcp_client.h>
|
||||
|
||||
//extern void *tall_reg_ctx;
|
||||
|
||||
//static void start_test_procedure(struct gsup_client *gsupc);
|
||||
|
||||
/*
|
||||
static void gsup_client_send_ping(struct gsup_client *gsupc)
|
||||
{
|
||||
struct msgb *msg = gsup_client_msgb_alloc();
|
||||
|
||||
msg->l2h = msgb_put(msg, 1);
|
||||
msg->l2h[0] = IPAC_MSGT_PING;
|
||||
ipa_msg_push_header(msg, IPAC_PROTO_IPACCESS);
|
||||
ipa_client_conn_send(gsupc->link, msg);
|
||||
}
|
||||
*/
|
||||
|
||||
static int sip_client_connect(struct sip_client *sip_client)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (sip_client->is_connected)
|
||||
return 0;
|
||||
|
||||
if (osmo_timer_pending(&sip_client->connect_timer)) {
|
||||
LOGP(DSUP, LOGL_DEBUG,
|
||||
"SIP connect: connect timer already running\n");
|
||||
osmo_timer_del(&sip_client->connect_timer);
|
||||
}
|
||||
|
||||
if (tcp_client_conn_clear_queue(sip_client->link) > 0)
|
||||
LOGP(DSUP, LOGL_DEBUG, "SIP connect: discarded stored messages\n");
|
||||
|
||||
rc = tcp_client_conn_open(sip_client->link);
|
||||
|
||||
if (rc >= 0) {
|
||||
LOGP(DSUP, LOGL_INFO, "SIP connecting to %s:%d\n",
|
||||
sip_client->link->dst_addr, sip_client->link->dst_port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOGP(DSUP, LOGL_INFO, "SIP failed to connect to %s:%d: %s\n",
|
||||
sip_client->link->dst_addr, sip_client->link->dst_port, strerror(-rc));
|
||||
|
||||
if (rc == -EBADF || rc == -ENOTSOCK || rc == -EAFNOSUPPORT ||
|
||||
rc == -EINVAL)
|
||||
return rc;
|
||||
|
||||
osmo_timer_schedule(&sip_client->connect_timer, SIP_RECONNECT_INTERVAL, 0);
|
||||
|
||||
LOGP(DSUP, LOGL_INFO, "Scheduled timer to retry SIP connect to %s:%d\n",
|
||||
sip_client->link->dst_addr, sip_client->link->dst_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connect_timer_cb(void *sip_client_)
|
||||
{
|
||||
struct sip_client *sip_client = sip_client_;
|
||||
|
||||
if (sip_client->is_connected)
|
||||
return;
|
||||
|
||||
sip_client_connect(sip_client);
|
||||
}
|
||||
|
||||
static void sip_client_updown_cb(struct tcp_client_conn *link, int up)
|
||||
{
|
||||
struct sip_client *sip_client = link->data;
|
||||
|
||||
LOGP(DSUP, LOGL_INFO, "SIP link to %s:%d %s\n",
|
||||
link->dst_addr, link->dst_port, up ? "UP" : "DOWN");
|
||||
|
||||
sip_client->is_connected = up;
|
||||
|
||||
if (up) {
|
||||
osmo_timer_del(&sip_client->connect_timer);
|
||||
} else {
|
||||
osmo_timer_schedule(&sip_client->connect_timer,
|
||||
SIP_RECONNECT_INTERVAL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int sip_client_read_cb(struct tcp_client_conn *link, struct msgb *msg)
|
||||
{
|
||||
//struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
|
||||
//struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
|
||||
printf("Recv sip message! len = %d\n", msg->data_len);
|
||||
struct sip_client *sip_client = (struct sip_client *)link->data;
|
||||
//int rc;
|
||||
|
||||
//msg->l2h = &hh->data[0];
|
||||
|
||||
OSMO_ASSERT(sip_client->read_cb != NULL);
|
||||
sip_client->read_cb(sip_client, msg);
|
||||
|
||||
/* Not freeing msg here, because that must be done by the read_cb. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
static void ping_timer_cb(void *gsupc_)
|
||||
{
|
||||
struct gsup_client *gsupc = gsupc_;
|
||||
|
||||
LOGP(DGPRS, LOGL_INFO, "GSUP ping callback (%s, %s PONG)\n",
|
||||
gsupc->is_connected ? "connected" : "not connected",
|
||||
gsupc->got_ipa_pong ? "got" : "didn't get");
|
||||
|
||||
if (gsupc->got_ipa_pong) {
|
||||
start_test_procedure(gsupc);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGP(DGPRS, LOGL_NOTICE, "GSUP ping timed out, reconnecting\n");
|
||||
ipa_client_conn_close(gsupc->link);
|
||||
gsupc->is_connected = 0;
|
||||
|
||||
gsup_client_connect(gsupc);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
static void start_test_procedure(struct gsup_client *gsupc)
|
||||
{
|
||||
gsupc->ping_timer.data = gsupc;
|
||||
gsupc->ping_timer.cb = &ping_timer_cb;
|
||||
|
||||
gsupc->got_ipa_pong = 0;
|
||||
osmo_timer_schedule(&gsupc->ping_timer, OSMO_GSUP_PING_INTERVAL, 0);
|
||||
LOGP(DGPRS, LOGL_DEBUG, "GSUP sending PING\n");
|
||||
gsup_client_send_ping(gsupc);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
int ipa_client_write_cb(struct ipa_client_conn *link)
|
||||
{
|
||||
struct osmo_fd *ofd = link->ofd;
|
||||
struct msgb *msg;
|
||||
struct llist_head *lh;
|
||||
int ret;
|
||||
|
||||
LOGP(DLINP, LOGL_DEBUG, "sending data\n");
|
||||
|
||||
|
||||
if (llist_empty(&link->tx_queue)) {
|
||||
ofd->when &= ~BSC_FD_WRITE;
|
||||
return 0;
|
||||
}
|
||||
lh = link->tx_queue.next;
|
||||
llist_del(lh);
|
||||
msg = llist_entry(lh, struct msgb, list);
|
||||
|
||||
printf("ipa_client_write_cb sending data... msg->len= %d\n", msg->len);
|
||||
|
||||
ret = send(link->ofd->fd, msg->data, msg->len, 0);
|
||||
if (ret < 0) {
|
||||
if (errno == EPIPE || errno == ENOTCONN) {
|
||||
ipa_client_conn_close(link);
|
||||
if (link->updown_cb)
|
||||
link->updown_cb(link, 0);
|
||||
}
|
||||
LOGP(DLINP, LOGL_ERROR, "error to send\n");
|
||||
printf("ipa_client_write_cb error to send!!!! ret = %d errno = %d\n", ret, errno);
|
||||
}
|
||||
msgb_free(msg);
|
||||
printf("ipa_client_write_cb send OK ret = %d\n", ret);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
struct sip_client *sip_client_create(const char *src_ip, u_int16_t src_port,
|
||||
const char *dst_ip, u_int16_t dst_port,
|
||||
int expires_time, sip_read_cb_t read_cb,
|
||||
void *data)
|
||||
{
|
||||
struct sip_client *sip_client;
|
||||
int rc;
|
||||
|
||||
sip_client = talloc_zero(tall_reg_ctx, struct sip_client);
|
||||
OSMO_ASSERT(sip_client);
|
||||
|
||||
sip_client->link = tcp_client_conn_create(sip_client,
|
||||
0,
|
||||
dst_ip, dst_port,
|
||||
src_ip, src_port,
|
||||
sip_client_updown_cb,
|
||||
sip_client_read_cb,
|
||||
NULL,
|
||||
sip_client);
|
||||
if (!sip_client->link)
|
||||
goto failed;
|
||||
|
||||
sip_client->connect_timer.data = sip_client;
|
||||
sip_client->connect_timer.cb = &connect_timer_cb;
|
||||
sip_client->dst_ip = dst_ip;
|
||||
sip_client->src_ip = src_ip;
|
||||
sip_client->dst_port = dst_port;
|
||||
sip_client->src_port = src_port;
|
||||
sip_client->expires_time = expires_time;
|
||||
|
||||
rc = sip_client_connect(sip_client);
|
||||
|
||||
if (rc < 0)
|
||||
goto failed;
|
||||
|
||||
sip_client->read_cb = read_cb;
|
||||
sip_client->data = data;
|
||||
|
||||
return sip_client;
|
||||
|
||||
failed:
|
||||
sip_client_destroy(sip_client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sip_client_destroy(struct sip_client *sip_client)
|
||||
{
|
||||
osmo_timer_del(&sip_client->connect_timer);
|
||||
|
||||
if (sip_client->link) {
|
||||
tcp_client_conn_close(sip_client->link);
|
||||
tcp_client_conn_destroy(sip_client->link);
|
||||
sip_client->link = NULL;
|
||||
}
|
||||
talloc_free(sip_client);
|
||||
}
|
||||
|
||||
int sip_client_send(struct sip_client *sip_client, struct msgb *msg)
|
||||
{
|
||||
if (!sip_client) {
|
||||
printf(" sip_client == NULL ");
|
||||
msgb_free(msg);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
if (!sip_client->is_connected) {
|
||||
printf(" !sip_client->is_connected ");
|
||||
msgb_free(msg);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
//ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_GSUP);
|
||||
//ipa_msg_push_header(msg, IPAC_PROTO_OSMO);
|
||||
printf(" TRY tcp_client_conn_send\n");
|
||||
|
||||
tcp_client_conn_send(sip_client->link, msg);
|
||||
|
||||
printf(" DONE tcp_client_conn_send\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct msgb *sip_msgb_alloc(void)
|
||||
{
|
||||
return msgb_alloc_headroom(400000, 64, __func__);
|
||||
}
|
137
openbsc/src/reg-proxy/sip_parser.py
Normal file
137
openbsc/src/reg-proxy/sip_parser.py
Normal file
@@ -0,0 +1,137 @@
|
||||
################################################################################
|
||||
#
|
||||
# Stand-alone VoIP honeypot client (preparation for Dionaea integration)
|
||||
# Copyright (c) 2010 Tobias Wulff (twu200 at gmail)
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
||||
# Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
|
||||
import sys
|
||||
import string
|
||||
|
||||
# SIP headers have short forms
|
||||
shortHeaders = {"call-id": "i",
|
||||
"contact": "m",
|
||||
"content-encoding": "e",
|
||||
"content-length": "l",
|
||||
"content-type": "c",
|
||||
"from": "f",
|
||||
"subject": "s",
|
||||
"to": "t",
|
||||
"via": "v",
|
||||
"cseq": "cseq",
|
||||
"accept": "accept",
|
||||
"user-agent": "user-agent",
|
||||
"max-forwards": "max-forwards",
|
||||
"www-authentication": "www-authentication",
|
||||
"authorization": "authorization",
|
||||
"allow": "allow",
|
||||
"recv-info": "recv-info",
|
||||
"supported": "supported"
|
||||
}
|
||||
|
||||
longHeaders = {}
|
||||
for k, v in shortHeaders.items():
|
||||
longHeaders[v] = k
|
||||
del k, v
|
||||
|
||||
class SipParsingError(Exception):
|
||||
"""Exception class for errors occuring during SIP message parsing"""
|
||||
|
||||
def parseSipMessage(msg):
|
||||
"""Parses a SIP message (string), returns a tupel (type, firstLine, header,
|
||||
body)"""
|
||||
# Sanitize input: remove superfluous leading and trailing newlines and
|
||||
# spaces
|
||||
msg = msg.strip("\n\r\t ")
|
||||
|
||||
# Split request/status line plus headers and body: we don't care about the
|
||||
# body in the SIP parser
|
||||
parts = msg.split("\n\r\n", 1)
|
||||
if len(parts) < 1:
|
||||
raise SipParsingError("Message too short")
|
||||
|
||||
msg = parts[0]
|
||||
|
||||
# Python way of doing a ? b : c
|
||||
body = len(parts) == 2 and parts[1] or parts[len(parts)-1]
|
||||
|
||||
# Normalize line feed and carriage return to \n
|
||||
msg = msg.replace("\n\r", "\n")
|
||||
|
||||
# Split lines into a list, each item containing one line
|
||||
lines = msg.split('\n')
|
||||
|
||||
# Get message type (first word, smallest possible one is "ACK" or "BYE")
|
||||
sep = lines[0].find(' ')
|
||||
if sep < 3:
|
||||
raise SipParsingError("Malformed request or status line")
|
||||
|
||||
msgType = lines[0][:sep]
|
||||
firstLine = lines[0][sep+1:]
|
||||
|
||||
# Done with first line: delete from list of lines
|
||||
del lines[0]
|
||||
|
||||
# Parse header
|
||||
headers = {}
|
||||
for i in range(len(lines)):
|
||||
# Take first line and remove from list of lines
|
||||
line = lines.pop(0)
|
||||
|
||||
# Strip each line of leading and trailing whitespaces
|
||||
line = line.strip("\n\r\t ")
|
||||
|
||||
# Break on empty line (end of headers)
|
||||
if len(line.strip(' ')) == 0:
|
||||
break
|
||||
|
||||
# Parse header lines
|
||||
sep = line.find(':')
|
||||
if sep < 1:
|
||||
raise SipParsingError("Malformed header line (no ':')")
|
||||
|
||||
# Get header identifier (word before the ':')
|
||||
identifier = line[:sep]
|
||||
identifier = identifier.lower()
|
||||
|
||||
# Check for valid header
|
||||
if identifier not in shortHeaders.keys() and \
|
||||
identifier not in longHeaders.keys():
|
||||
raise SipParsingError("Unknown header type: {}".format(identifier))
|
||||
|
||||
# Get long header identifier if necessary
|
||||
if identifier in longHeaders.keys():
|
||||
identifier = longHeaders[identifier]
|
||||
|
||||
# Get header value (line after ':')
|
||||
value = line[sep+1:].strip(' ')
|
||||
|
||||
# The Via header can occur multiple times
|
||||
if identifier == "via":
|
||||
if identifier not in headers:
|
||||
headers["via"] = [value]
|
||||
else:
|
||||
headers["via"].append(value)
|
||||
|
||||
# Assign any other header value directly to the header key
|
||||
else:
|
||||
headers[identifier] = value
|
||||
|
||||
# Return message type, header dictionary, and body string
|
||||
return (msgType, firstLine, headers, body)
|
407
openbsc/src/reg-proxy/sup.c
Normal file
407
openbsc/src/reg-proxy/sup.c
Normal 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;
|
||||
}
|
164
openbsc/src/reg-proxy/sup_server.c
Normal file
164
openbsc/src/reg-proxy/sup_server.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/* GSM Subscriber Update Protocol server */
|
||||
|
||||
/* (C) 2015 by Ivan Klyuchnikov <kluchnikovi@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmocom/abis/ipa.h>
|
||||
#include <osmocom/gsm/protocol/ipaccess.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openbsc/sup_server.h>
|
||||
#include <openbsc/reg_proxy.h>
|
||||
|
||||
static int ipa_sock_server_cb(struct ipa_server_conn *conn, struct msgb *msg)
|
||||
{
|
||||
struct gsm_sup_server *sup_server = conn->data;
|
||||
struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
|
||||
struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
|
||||
int ret;
|
||||
|
||||
msg->l2h = &hh->data[0]; /* Handle IPA PING, PONG and ID_ACK messages. */
|
||||
ret = ipa_ccm_rcvmsg_base(msg, &conn->ofd);
|
||||
switch(ret) {
|
||||
case -1:
|
||||
/* error in IPA control message handling */
|
||||
goto invalid;
|
||||
case 1:
|
||||
/* this is an IPA control message, skip further processing */
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
case 0:
|
||||
/* this is not an IPA control message, continue */
|
||||
break;
|
||||
default:
|
||||
LOGP(DSUP, LOGL_ERROR, "Unexpected return from "
|
||||
"ipa_ccm_rcvmsg_base "
|
||||
"(ret=%d)\n", ret);
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (hh->proto != IPAC_PROTO_OSMO)
|
||||
goto invalid;
|
||||
|
||||
if (!he || msgb_l2len(msg) < sizeof(*he) ||
|
||||
he->proto != IPAC_PROTO_EXT_GSUP)
|
||||
goto invalid;
|
||||
|
||||
msg->l2h = &he->data[0];
|
||||
|
||||
OSMO_ASSERT(sup_server->read_cb != NULL);
|
||||
sup_server->read_cb(sup_server, msg);
|
||||
|
||||
/* Not freeing msg here, because that must be done by the read_cb. */
|
||||
return 0;
|
||||
|
||||
invalid:
|
||||
LOGP(DSUP, LOGL_NOTICE,
|
||||
"SUP received an invalid IPA message from %s:%d, size = %d\n",
|
||||
sup_server->link->addr, sup_server->link->port, msgb_length(msg));
|
||||
|
||||
msgb_free(msg);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
static int sup_accept_cb(struct ipa_server_link *link, int fd)
|
||||
{
|
||||
struct gsm_sup_server *sup_server = link->data;
|
||||
struct ipa_server_conn *server_conn;
|
||||
|
||||
|
||||
server_conn = talloc_zero(tall_reg_ctx, struct ipa_server_conn);
|
||||
if (server_conn == NULL) {
|
||||
LOGP(DSUP, LOGL_ERROR, "cannot allocate memory for "
|
||||
"origin IPA\n");
|
||||
close(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
server_conn = ipa_server_conn_create(tall_reg_ctx, link, fd,
|
||||
ipa_sock_server_cb, NULL, sup_server);
|
||||
if (server_conn == NULL) {
|
||||
LOGP(DSUP, LOGL_ERROR, "could not create server peer: %s\n",
|
||||
strerror(errno));
|
||||
return -ENOMEM;
|
||||
}
|
||||
sup_server->server_conn = server_conn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct gsm_sup_server *sup_server_create(const char *ip_addr,
|
||||
unsigned int tcp_port,
|
||||
sup_read_cb_t read_cb,
|
||||
void *app)
|
||||
{
|
||||
struct gsm_sup_server *sup_server;
|
||||
|
||||
sup_server = talloc_zero(tall_reg_ctx, struct gsm_sup_server);
|
||||
OSMO_ASSERT(sup_server);
|
||||
|
||||
sup_server->app = app;
|
||||
sup_server->read_cb = read_cb;
|
||||
sup_server->link = ipa_server_link_create(tall_reg_ctx, NULL,
|
||||
ip_addr, tcp_port,
|
||||
sup_accept_cb, sup_server);
|
||||
if (sup_server->link == NULL) {
|
||||
LOGP(DSUP, LOGL_ERROR, "cannot create OML "
|
||||
"BSC link: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
if (ipa_server_link_open(sup_server->link) < 0) {
|
||||
LOGP(DSUP, LOGL_ERROR, "cannot open OML BSC link: %s\n",
|
||||
strerror(errno));
|
||||
ipa_server_link_destroy(sup_server->link);
|
||||
return NULL;
|
||||
}
|
||||
return sup_server;
|
||||
}
|
||||
|
||||
int sup_server_send(struct gsm_sup_server *sup_server, struct msgb *msg)
|
||||
{
|
||||
if (!sup_server) {
|
||||
msgb_free(msg);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
if (!sup_server->link) {
|
||||
msgb_free(msg);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_GSUP);
|
||||
ipa_msg_push_header(msg, IPAC_PROTO_OSMO);
|
||||
ipa_server_conn_send(sup_server->server_conn, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct msgb *sup_msgb_alloc(void)
|
||||
{
|
||||
return msgb_alloc_headroom(4000, 64, __func__);
|
||||
}
|
||||
|
303
openbsc/src/reg-proxy/tcp_client.c
Normal file
303
openbsc/src/reg-proxy/tcp_client.c
Normal file
@@ -0,0 +1,303 @@
|
||||
//#include "internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/gsm/tlv.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
//#include <osmocom/abis/e1_input.h>
|
||||
//#include <osmocom/abis/ipaccess.h>
|
||||
//#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/backtrace.h>
|
||||
#include <openbsc/tcp_client.h>
|
||||
|
||||
void tcp_client_conn_close(struct tcp_client_conn *link)
|
||||
{
|
||||
/* be safe against multiple calls */
|
||||
if (link->ofd->fd != -1) {
|
||||
osmo_fd_unregister(link->ofd);
|
||||
close(link->ofd->fd);
|
||||
link->ofd->fd = -1;
|
||||
}
|
||||
msgb_free(link->pending_msg);
|
||||
link->pending_msg = NULL;
|
||||
}
|
||||
|
||||
static void tcp_client_read(struct tcp_client_conn *link)
|
||||
{
|
||||
struct osmo_fd *ofd = link->ofd;
|
||||
struct msgb *msg;
|
||||
int ret;
|
||||
|
||||
LOGP(DLINP, LOGL_DEBUG, "message received\n");
|
||||
|
||||
// FIX 1500
|
||||
msg = msgb_alloc(1500, "TCP");
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
printf("try to recv data msg->data = %d msg->data_len = %d \n", msg->data, msg->data_len);
|
||||
ret = recv(ofd->fd, msg->data, msg->data_len, 0);
|
||||
if (ret < 0) {
|
||||
if (ret == -EAGAIN)
|
||||
return;
|
||||
if (ret == -EPIPE || ret == -ECONNRESET)
|
||||
LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
|
||||
tcp_client_conn_close(link);
|
||||
if (link->updown_cb)
|
||||
link->updown_cb(link, 0);
|
||||
return;
|
||||
} else if (ret == 0) {
|
||||
LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
|
||||
tcp_client_conn_close(link);
|
||||
if (link->updown_cb)
|
||||
link->updown_cb(link, 0);
|
||||
return;
|
||||
}
|
||||
// TODO set len = ret
|
||||
msg->data_len = ret;
|
||||
printf("RECV SIP LEN = %d \n", ret);
|
||||
if (link->read_cb)
|
||||
link->read_cb(link, msg);
|
||||
}
|
||||
|
||||
static void tcp_client_write(struct tcp_client_conn *link)
|
||||
{
|
||||
if (link->write_cb)
|
||||
link->write_cb(link);
|
||||
}
|
||||
|
||||
static int tcp_client_write_default_cb(struct tcp_client_conn *link)
|
||||
{
|
||||
struct osmo_fd *ofd = link->ofd;
|
||||
struct msgb *msg;
|
||||
struct llist_head *lh;
|
||||
int ret;
|
||||
|
||||
LOGP(DLINP, LOGL_DEBUG, "sending data\n");
|
||||
|
||||
if (llist_empty(&link->tx_queue)) {
|
||||
ofd->when &= ~BSC_FD_WRITE;
|
||||
return 0;
|
||||
}
|
||||
lh = link->tx_queue.next;
|
||||
llist_del(lh);
|
||||
msg = llist_entry(lh, struct msgb, list);
|
||||
|
||||
ret = send(link->ofd->fd, msg->data, msg->len, 0);
|
||||
if (ret < 0) {
|
||||
if (errno == EPIPE || errno == ENOTCONN) {
|
||||
tcp_client_conn_close(link);
|
||||
if (link->updown_cb)
|
||||
link->updown_cb(link, 0);
|
||||
}
|
||||
LOGP(DLINP, LOGL_ERROR, "error to send\n");
|
||||
}
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcp_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
struct tcp_client_conn *link = ofd->data;
|
||||
int error, ret;
|
||||
socklen_t len = sizeof(error);
|
||||
|
||||
switch(link->state) {
|
||||
case TCP_CLIENT_LINK_STATE_CONNECTING:
|
||||
ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
|
||||
if (ret >= 0 && error > 0) {
|
||||
tcp_client_conn_close(link);
|
||||
if (link->updown_cb)
|
||||
link->updown_cb(link, 0);
|
||||
return 0;
|
||||
}
|
||||
ofd->when &= ~BSC_FD_WRITE;
|
||||
LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
|
||||
link->state = TCP_CLIENT_LINK_STATE_CONNECTED;
|
||||
if (link->updown_cb)
|
||||
link->updown_cb(link, 1);
|
||||
break;
|
||||
case TCP_CLIENT_LINK_STATE_CONNECTED:
|
||||
if (what & BSC_FD_READ) {
|
||||
LOGP(DLINP, LOGL_DEBUG, "connected read\n");
|
||||
tcp_client_read(link);
|
||||
}
|
||||
if (what & BSC_FD_WRITE) {
|
||||
LOGP(DLINP, LOGL_DEBUG, "connected write\n");
|
||||
tcp_client_write(link);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tcp_client_conn * tcp_client_conn_create(void *ctx, int priv_nr,
|
||||
const char *dst_addr, uint16_t dst_port,
|
||||
const char *src_addr, uint16_t src_port,
|
||||
void (*updown_cb)(struct tcp_client_conn *link, int up),
|
||||
int (*read_cb)(struct tcp_client_conn *link,
|
||||
struct msgb *msgb),
|
||||
int (*write_cb)(struct tcp_client_conn *link),
|
||||
void *data)
|
||||
{
|
||||
struct tcp_client_conn *tcp_link;
|
||||
|
||||
tcp_link = talloc_zero(ctx, struct tcp_client_conn);
|
||||
if (!tcp_link)
|
||||
return NULL;
|
||||
|
||||
tcp_link->ofd = talloc_zero(ctx, struct osmo_fd);
|
||||
if (tcp_link->ofd == NULL) {
|
||||
talloc_free(tcp_link);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tcp_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
|
||||
tcp_link->ofd->priv_nr = priv_nr;
|
||||
tcp_link->ofd->cb = tcp_client_fd_cb;
|
||||
tcp_link->ofd->data = tcp_link;
|
||||
tcp_link->ofd->fd = -1;
|
||||
tcp_link->state = TCP_CLIENT_LINK_STATE_CONNECTING;
|
||||
tcp_link->src_addr = talloc_strdup(tcp_link, src_addr);
|
||||
tcp_link->src_port = src_port;
|
||||
tcp_link->dst_addr = talloc_strdup(tcp_link, dst_addr);
|
||||
tcp_link->dst_port = dst_port;
|
||||
tcp_link->updown_cb = updown_cb;
|
||||
tcp_link->read_cb = read_cb;
|
||||
/* default to generic write callback if not set. */
|
||||
if (write_cb == NULL)
|
||||
tcp_link->write_cb = tcp_client_write_default_cb;
|
||||
else
|
||||
tcp_link->write_cb = write_cb;
|
||||
|
||||
tcp_link->data = data;
|
||||
INIT_LLIST_HEAD(&tcp_link->tx_queue);
|
||||
|
||||
return tcp_link;
|
||||
}
|
||||
|
||||
void tcp_client_conn_destroy(struct tcp_client_conn *link)
|
||||
{
|
||||
talloc_free(link);
|
||||
}
|
||||
|
||||
int tcp_client_conn_open(struct tcp_client_conn *link)
|
||||
{
|
||||
int ret;
|
||||
struct addrinfo hints, *bind_addr, *connect_addr;
|
||||
int sfd, rc, on = 1;
|
||||
char src_port_buf[16];
|
||||
char dst_port_buf[16];
|
||||
|
||||
|
||||
link->state = TCP_CLIENT_LINK_STATE_CONNECTING;
|
||||
// ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
|
||||
// link->addr, link->port,
|
||||
// OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
|
||||
|
||||
sprintf(src_port_buf, "%u", link->src_port);
|
||||
sprintf(dst_port_buf, "%u", link->dst_port);
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
rc = getaddrinfo(link->dst_addr, dst_port_buf, &hints, &connect_addr);
|
||||
if (rc != 0) {
|
||||
perror("getaddrinfo returned NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hints.ai_flags |= AI_PASSIVE;
|
||||
|
||||
rc = getaddrinfo(link->src_addr, src_port_buf, &hints, &bind_addr);
|
||||
if (rc != 0) {
|
||||
perror("getaddrinfo returned NULL");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sfd = socket(connect_addr->ai_family, connect_addr->ai_socktype, connect_addr->ai_protocol);
|
||||
if (sfd < 0) {
|
||||
perror("cannot create socket");
|
||||
return sfd;
|
||||
}
|
||||
if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) {
|
||||
perror("cannot set this socket unblocking");
|
||||
close(sfd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
if (rc < 0) {
|
||||
perror("cannot setsockopt socket");
|
||||
close(sfd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = bind(sfd, bind_addr->ai_addr, bind_addr->ai_addrlen);
|
||||
if (rc < 0) {
|
||||
perror("cannot bind socket");
|
||||
close(sfd);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = connect(sfd, connect_addr->ai_addr, connect_addr->ai_addrlen);
|
||||
if (rc <0 && errno != EINPROGRESS) {
|
||||
perror("cannot connect socket");
|
||||
close(sfd);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
freeaddrinfo(bind_addr);
|
||||
freeaddrinfo(connect_addr);
|
||||
|
||||
listen(sfd, 10);
|
||||
|
||||
link->ofd->fd = sfd;
|
||||
link->ofd->when |= BSC_FD_WRITE;
|
||||
if (osmo_fd_register(link->ofd) < 0) {
|
||||
close(sfd);
|
||||
link->ofd->fd = -1;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tcp_client_conn_send(struct tcp_client_conn *link, struct msgb *msg)
|
||||
{
|
||||
msgb_enqueue(&link->tx_queue, msg);
|
||||
link->ofd->when |= BSC_FD_WRITE;
|
||||
}
|
||||
|
||||
size_t tcp_client_conn_clear_queue(struct tcp_client_conn *link)
|
||||
{
|
||||
size_t deleted = 0;
|
||||
|
||||
while (!llist_empty(&link->tx_queue)) {
|
||||
struct msgb *msg = msgb_dequeue(&link->tx_queue);
|
||||
msgb_free(msg);
|
||||
deleted += 1;
|
||||
}
|
||||
|
||||
link->ofd->when &= ~BSC_FD_WRITE;
|
||||
return deleted;
|
||||
}
|
165
openbsc/src/reg-proxy/test_sip.py
Executable file
165
openbsc/src/reg-proxy/test_sip.py
Executable file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
import string
|
||||
import random
|
||||
import binascii
|
||||
import sip_parser
|
||||
import re
|
||||
from twisted.internet import defer
|
||||
from twisted.internet import protocol
|
||||
from twisted.python import log
|
||||
from twisted.protocols import sip
|
||||
from time import sleep
|
||||
|
||||
TCP_SRC_IP = "127.0.0.1"
|
||||
TCP_SRC_PORT = 5060
|
||||
|
||||
class RegistrationProxyServer(protocol.Protocol):
|
||||
src_ip = TCP_SRC_IP
|
||||
src_port = TCP_SRC_PORT
|
||||
|
||||
def connectionMade(self):
|
||||
self.ussd_queue = defer.DeferredQueue()
|
||||
self.ussd_queue.get().addCallback(self.sipClientDataReceived)
|
||||
from twisted.internet import reactor
|
||||
#reactor.listenTCP(UDP_TCP_PORT, self.sip_client_factory)
|
||||
|
||||
def sipClientDataReceived(self, data):
|
||||
log.msg("\n[USSD:RX]\n%s" % data)
|
||||
if data:
|
||||
self.ussd_queue.get().addCallback(self.sipClientDataReceived)
|
||||
|
||||
msgType, firstLine, headers, body = sip_parser.parseSipMessage(data)
|
||||
#print headers
|
||||
via = headers["via"][0].split(";")
|
||||
via_branch = via[1].split("=")
|
||||
from_hdr = headers["from"].split(";")
|
||||
from_tag = from_hdr[1]
|
||||
to_hdr = headers["to"].split(";")
|
||||
to_tag = "%s" % from_hdr[1]
|
||||
call_id = headers["call-id"]
|
||||
try:
|
||||
ctype = headers["content-type"]
|
||||
except:
|
||||
ctype = ""
|
||||
sip_url = re.split(r"[:@]", from_hdr[0])
|
||||
ussd_url = sip_url[1]
|
||||
try:
|
||||
contact = headers["contact"].split("@")
|
||||
except:
|
||||
pass
|
||||
cseq = headers["cseq"]
|
||||
via_dest_ip,via_dest_port=via[0].split(" ")[1].split(":")
|
||||
|
||||
if msgType=="INVITE":
|
||||
#sleep(5)
|
||||
|
||||
r = sip.Response(200, "OK")
|
||||
r.addHeader('Via', headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
|
||||
r.addHeader('From', "%s;%s" % (from_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
|
||||
r.addHeader('To', "%s;%s" % (to_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
|
||||
r.addHeader('Call-Id', call_id)
|
||||
r.addHeader('Max-Forwards', 20)
|
||||
r.addHeader('Cseq', cseq)
|
||||
r.addHeader('Contact', '<sip:test@127.0.0.1:5060>')
|
||||
r.addHeader('Recv-Info', 'g.3gpp.ussd')
|
||||
r.addHeader('Content-Length', 0)
|
||||
#r.addHeader("Authentication-Info", auth_info)
|
||||
log.msg("\n[SIP:TX]\n%s" % r.toString())
|
||||
self.transport.write(r.toString())
|
||||
|
||||
r = sip.Response(100, "Trying")
|
||||
r.addHeader('Via', headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
|
||||
r.addHeader('From', "%s;%s" % (from_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
|
||||
r.addHeader('To', "%s;%s" % (to_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
|
||||
r.addHeader('Call-Id', call_id)
|
||||
r.addHeader('Max-Forwards', 20)
|
||||
r.addHeader('Cseq', cseq)
|
||||
r.addHeader('Contact', '<sip:test@127.0.0.1:5060>')
|
||||
r.addHeader('Content-Length', 0)
|
||||
log.msg("\n[SIP:TX]\n%s" % r.toString())
|
||||
self.transport.write(r.toString())
|
||||
|
||||
|
||||
elif msgType=="ACK" and to_hdr[0].startswith("<sip:*101"):
|
||||
msg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ussd-data><language>en</language><ussd-string>%s</ussd-string></ussd-data>" % (
|
||||
"Select Item from menu:\n1) Option 1\n2) Option 2");
|
||||
|
||||
r = sip.Request("INFO", to_hdr[0].replace('<', '').replace('>', ''))
|
||||
r.addHeader('Via', headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
|
||||
r.addHeader('From', "%s;%s" % (from_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
|
||||
r.addHeader('To', "%s;%s" % (to_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
|
||||
r.addHeader('Call-Id', call_id)
|
||||
r.addHeader('Max-Forwards', 20)
|
||||
r.addHeader('Cseq', "%d INFO" % (int(cseq.split(' ')[0]) + 1))
|
||||
r.addHeader('Recv-Info', 'g.3gpp.ussd')
|
||||
r.addHeader('Content-Type', 'application/vnd.3gpp.ussd+xml')
|
||||
#r.addHeader('Content-Disposition', 'Info-Package')
|
||||
r.addHeader('Content-Length', len(msg))
|
||||
#r.addHeader("Authentication-Info", auth_info)
|
||||
log.msg("\n[SIP:TX]]\n%s" % r.toString())
|
||||
self.transport.write(r.toString() + msg)
|
||||
|
||||
elif msgType=="ACK" or msgType=="INFO":
|
||||
msg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ussd-data><language>en</language><ussd-string>%s</ussd-string></ussd-data>" % (
|
||||
"Test");
|
||||
if msgType=="INFO":
|
||||
r = sip.Response(200, "OK")
|
||||
r.addHeader('Via', headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
|
||||
r.addHeader('From', "%s;%s" % (from_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
|
||||
r.addHeader('To', "%s;%s" % (to_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
|
||||
r.addHeader('Call-Id', call_id)
|
||||
r.addHeader('Max-Forwards', 20)
|
||||
r.addHeader('Cseq', cseq)
|
||||
r.addHeader('Recv-Info', 'g.3gpp.ussd')
|
||||
r.addHeader('Content-Length', 0)
|
||||
#r.addHeader("Authentication-Info", auth_info)
|
||||
log.msg("\n[SIP:TX]\n%s" % r.toString())
|
||||
self.transport.write(r.toString())
|
||||
|
||||
r = sip.Request("BYE", to_hdr[0].replace('<', '').replace('>', ''))
|
||||
r.addHeader('Via', headers["via"][0]) #sip.Via(via_dest_ip, via_dest_port, transport='TCP', ttl=None, hidden=False, received=None, rport=None, branch=via_branch[1], maddr=None).toString())
|
||||
r.addHeader('From', "%s;%s" % (from_hdr[0], to_tag)) #"<sip:%s@%s>;%s" % (from_hdr[0], self.src_ip, from_tag))
|
||||
r.addHeader('To', "%s;%s" % (to_hdr[0], from_tag)) #"<sip:%s@%s>;%s" % (to_hdr[0], self.src_ip, to_tag))
|
||||
r.addHeader('Call-Id', call_id)
|
||||
r.addHeader('Max-Forwards', 20)
|
||||
r.addHeader('Cseq', "%d BYE" % (int(cseq.split(' ')[0]) + 1))
|
||||
if to_hdr[0].startswith('<sip:mapss'):
|
||||
# Copy InvokeID
|
||||
# a10b02010602010e3003040121
|
||||
# --------__---------------- invoke_id
|
||||
#msg = 'a20b0201%c%c300602010e80010c' % (body[8],body[9])
|
||||
msg = 'a20b02010c300602010e80010c'
|
||||
|
||||
r.addHeader('Content-Type', 'application/map-ss-binary')
|
||||
r.addHeader('Content-Length', len(msg))
|
||||
else:
|
||||
r.addHeader('Recv-Info', 'g.3gpp.ussd')
|
||||
r.addHeader('Content-Type', 'application/vnd.3gpp.ussd+xml')
|
||||
#r.addHeader('Content-Disposition', 'Info-Package')
|
||||
r.addHeader('Content-Length', len(msg))
|
||||
#r.addHeader("Authentication-Info", auth_info)
|
||||
log.msg("\n[SIP:TX]]\n%s" % r.toString())
|
||||
self.transport.write(r.toString() + msg)
|
||||
else:
|
||||
print msgType
|
||||
|
||||
#self.ussd_queue.get().addCallback(self.sipClientDataReceived)
|
||||
#self.ussd_queue.get().addCallback(self.sipClientDataReceived)
|
||||
|
||||
def dataReceived(self, data):
|
||||
#log.msg("\n[IMSI:RX] [Proxy <=============== BSC]\n%s" % data)
|
||||
self.ussd_queue.put(data)
|
||||
|
||||
class RegistrationProxyServerFactory(protocol.ClientFactory):
|
||||
protocol = RegistrationProxyServer
|
||||
|
||||
if __name__ == "__main__":
|
||||
log.startLogging(sys.stdout)
|
||||
factory = RegistrationProxyServerFactory()
|
||||
from twisted.internet import reactor
|
||||
reactor.listenTCP(TCP_SRC_PORT, factory)
|
||||
reactor.run()
|
||||
|
||||
|
19
openbsc/src/ussd-proxy/Makefile.am
Normal file
19
openbsc/src/ussd-proxy/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
if BUILD_USSD_PROXY
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall $(COVERAGE_CFLAGS) \
|
||||
$(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) \
|
||||
-I/usr/include/sofia-sip-1.12 -DNO_GSM0480_SEND_FUNC
|
||||
|
||||
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
|
||||
|
||||
bin_PROGRAMS = ussd-proxy
|
||||
|
||||
ussd_proxy_SOURCES = \
|
||||
ussd_proxy.c ../libmsc/gsm_ussd_map_proto.c ../libmsc/gsm_04_80.c
|
||||
|
||||
ussd_proxy_LDADD = \
|
||||
-lsofia-sip-ua \
|
||||
$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS)
|
||||
endif
|
1544
openbsc/src/ussd-proxy/ussd_proxy.c
Normal file
1544
openbsc/src/ussd-proxy/ussd_proxy.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ noinst_HEADERS = \
|
||||
bin_PROGRAMS = \
|
||||
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)
|
||||
|
188
openbsc/src/utils/meas_json.c
Normal file
188
openbsc/src/utils/meas_json.c
Normal 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);
|
||||
}
|
@@ -10,6 +10,7 @@ SUBDIRS = \
|
||||
subscr \
|
||||
mm_auth \
|
||||
nanobts_omlattr \
|
||||
ussd \
|
||||
$(NULL)
|
||||
|
||||
if BUILD_NAT
|
||||
|
@@ -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() {}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
12
openbsc/tests/ussd/Makefile.am
Normal file
12
openbsc/tests/ussd/Makefile.am
Normal file
@@ -0,0 +1,12 @@
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
|
||||
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS)
|
||||
noinst_PROGRAMS = ss_test
|
||||
|
||||
# EXTRA_DIST = ss_test.ok
|
||||
|
||||
ss_test_SOURCES = ss_test.c
|
||||
ss_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libmsc/libmsc.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -ldbi
|
199
openbsc/tests/ussd/ss_test.c
Normal file
199
openbsc/tests/ussd/ss_test.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/* simple test for the gsm0480 */
|
||||
/*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
||||
#include <openbsc/gsm_ussd_map.h>
|
||||
#include <openbsc/gsm_ussd_map_proto.h>
|
||||
#include <openbsc/gsm_04_80.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <osmocom/core/application.h>
|
||||
|
||||
#define COMPARE(result, op, value) \
|
||||
if (!((result) op (value))) {\
|
||||
fprintf(stderr, "Compare failed. Was %x should be %x in %s:%d\n",result, value, __FILE__, __LINE__); \
|
||||
exit(-1); \
|
||||
}
|
||||
|
||||
#define COMPARE_STR(result, value) \
|
||||
if (strcmp(result, value) != 0) { \
|
||||
fprintf(stderr, "Compare failed. Was %s should be %s in %s:%d\n",result, value, __FILE__, __LINE__); \
|
||||
exit(-1); \
|
||||
}
|
||||
|
||||
#define DBG(...)
|
||||
|
||||
#define VERIFY(res, cmp, wanted) \
|
||||
if (!(res cmp wanted)) { \
|
||||
printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \
|
||||
__FILE__, __LINE__, res, # cmp, wanted); \
|
||||
}
|
||||
|
||||
const uint8_t test_ss_int_01[] = {
|
||||
0xa1, 0x0e, 0x02, 0x01, 0x00, 0x02, 0x01, 0x0e, 0x30, 0x06, 0x04, 0x01, 0x21, 0x83, 0x01, 0x10
|
||||
};
|
||||
|
||||
const uint8_t test_ss_int_02[] = {
|
||||
0xa1, 0x0b, 0x02, 0x01, 0x01, 0x02, 0x01, 0x0e, 0x30, 0x03, 0x04, 0x01, 0x21
|
||||
};
|
||||
|
||||
const uint8_t test_ss_int_03[] = {
|
||||
0xa1, 0x17, 0x02, 0x01, 0x01, 0x02, 0x01, 0x0a, 0x30, 0x0f, 0x04, 0x01, 0x21,
|
||||
0x83, 0x01, 0x10, 0x84, 0x07, 0x91, 0x52, 0x75, 0x89, 0x46, 0x36, 0x25
|
||||
};
|
||||
|
||||
const uint8_t test_ussd_01[] = {
|
||||
0xa1, 0x81, 0x83, 0x02, 0x01, 0x01, 0x02, 0x01, 0x3c, 0x30, 0x7b, 0x04, 0x01,
|
||||
0x0f, 0x04, 0x76, 0xd3, 0x66, 0x50, 0x4a, 0x55, 0xc4, 0x5c, 0x20, 0x6b, 0xda,
|
||||
0x5c, 0x97, 0xd7, 0xe7, 0xe8, 0x34, 0xc8, 0x9e, 0x0f, 0x83, 0x68, 0x47, 0x50,
|
||||
0xd2, 0x4d, 0x0f, 0xbb, 0xcb, 0xf4, 0xb4, 0x42, 0xe6, 0x02, 0x59, 0xd3, 0xe6,
|
||||
0xba, 0xbc, 0x3e, 0x47, 0xa7, 0x41, 0xd6, 0x7c, 0x18, 0x34, 0x6d, 0x06, 0xa9,
|
||||
0xc9, 0x65, 0x50, 0x31, 0x73, 0x81, 0xac, 0x69, 0x73, 0x5d, 0x5e, 0x9f, 0xa3,
|
||||
0xd3, 0x20, 0x7b, 0x3e, 0x0c, 0x5a, 0xa7, 0xdb, 0x61, 0x7a, 0x38, 0x6d, 0x0e,
|
||||
0xbb, 0x14, 0x34, 0x17, 0x68, 0xda, 0x0e, 0xcb, 0xe9, 0xa0, 0x6b, 0xb9, 0xbc,
|
||||
0x2e, 0xbb, 0xc9, 0x8a, 0x9a, 0x0b, 0xd4, 0x4c, 0xb7, 0xd3, 0x20, 0x77, 0x18,
|
||||
0x74, 0x2d, 0xdf, 0xcb, 0x20, 0x28, 0xbb, 0x3e, 0x57, 0xd8, 0x5c, 0x20, 0x7d,
|
||||
0x38, 0x4d, 0x4e, 0x03
|
||||
};
|
||||
|
||||
const uint8_t test_ussd_02[] = {
|
||||
0xa2, 0x10, 0x02, 0x01, 0x01, 0x30, 0x0b, 0x02, 0x01, 0x3c, 0x30,
|
||||
0x06, 0x04, 0x01, 0x0f, 0x04, 0x01, 0x34
|
||||
};
|
||||
|
||||
static void test_uss_ser_deser(void)
|
||||
{
|
||||
const uint32_t ref = 1234567890;
|
||||
const char* ext = "555333444";
|
||||
struct msgb *data = msgb_alloc(4000, "test");
|
||||
struct ss_header ssh;
|
||||
|
||||
uint32_t r_ref;
|
||||
struct ss_header r_ssh;
|
||||
char r_ext_buf[32];
|
||||
|
||||
int rc;
|
||||
printf("testing serializing-deserializing\n");
|
||||
|
||||
ssh.component_length = sizeof(test_ussd_01);
|
||||
ssh.component_offset = 0;
|
||||
ssh.message_type = GSM0480_MTYPE_REGISTER;
|
||||
ssh.transaction_id = 0;
|
||||
|
||||
rc = subscr_uss_message(data, &ssh, ext, ref, test_ussd_01);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
printf("uss len:%d\n", msgb_length(data));
|
||||
|
||||
rc = rx_uss_message_parse(data->data, msgb_length(data), &r_ssh, &r_ref, r_ext_buf, sizeof(r_ext_buf));
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(ref == r_ref);
|
||||
OSMO_ASSERT(ssh.message_type == r_ssh.message_type);
|
||||
|
||||
rc = strcmp(ext, r_ext_buf);
|
||||
printf("orig_ext:%s decoded_ext:%s\n", ext, r_ext_buf);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
printf("orig_clen:%d decoded_clen:%d\n", ssh.component_length, r_ssh.component_length);
|
||||
OSMO_ASSERT(ssh.component_length == r_ssh.component_length);
|
||||
|
||||
rc = memcmp(data->data + r_ssh.component_offset, test_ussd_01, sizeof(test_ussd_01));
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
|
||||
msgb_reset(data);
|
||||
memset(&r_ssh, 0, sizeof(r_ssh));
|
||||
printf("testing serializing-deserializing small\n");
|
||||
|
||||
rc = subscr_uss_message(data, &ssh, NULL, ref, NULL);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
|
||||
printf("uss len:%d\n", msgb_length(data));
|
||||
|
||||
rc = rx_uss_message_parse(data->data, msgb_length(data), &r_ssh, &r_ref, NULL, 0);
|
||||
OSMO_ASSERT(rc == 0);
|
||||
OSMO_ASSERT(ref == r_ref);
|
||||
OSMO_ASSERT(ssh.message_type == r_ssh.message_type);
|
||||
|
||||
}
|
||||
|
||||
static void test_parse_ss(void)
|
||||
{
|
||||
struct ss_request ss;
|
||||
int rc;
|
||||
printf("testing parsing ss\n");
|
||||
|
||||
// mark as uninitialized
|
||||
memset(&ss, 0xcc, sizeof(ss));
|
||||
rc = gsm0480_parse_ss_facility(test_ussd_01, sizeof(test_ussd_01), &ss);
|
||||
OSMO_ASSERT(rc == 1);
|
||||
printf("Sample: test_ussd_01 ctype=%02x invoke_id=%02x opcode=%02x\n",
|
||||
ss.component_type, ss.invoke_id, ss.opcode);
|
||||
printf("- USSD: len:%d lang:%d\n", ss.ussd_text_len, ss.ussd_text_language);
|
||||
|
||||
// mark as uninitialized
|
||||
memset(&ss, 0xcc, sizeof(ss));
|
||||
rc = gsm0480_parse_ss_facility(test_ussd_02, sizeof(test_ussd_02), &ss);
|
||||
OSMO_ASSERT(rc == 1);
|
||||
printf("Sample: test_ussd_02 ctype=%02x invoke_id=%02x opcode=%02x\n",
|
||||
ss.component_type, ss.invoke_id, ss.opcode);
|
||||
|
||||
// mark as uninitialized
|
||||
memset(&ss, 0xcc, sizeof(ss));
|
||||
rc = gsm0480_parse_ss_facility(test_ss_int_02, sizeof(test_ss_int_02), &ss);
|
||||
OSMO_ASSERT(rc == 1);
|
||||
printf("Sample: test_ss_int_02 ctype=%02x invoke_id=%02x opcode=%02x\n",
|
||||
ss.component_type, ss.invoke_id, ss.opcode);
|
||||
printf("- SS: code:%d\n", ss.ss_code);
|
||||
|
||||
// mark as uninitialized
|
||||
memset(&ss, 0xcc, sizeof(ss));
|
||||
rc = gsm0480_parse_ss_facility(test_ss_int_01, sizeof(test_ss_int_01), &ss);
|
||||
OSMO_ASSERT(rc == 1);
|
||||
printf("Sample: test_ss_int_01 ctype=%02x invoke_id=%02x opcode=%02x\n",
|
||||
ss.component_type, ss.invoke_id, ss.opcode);
|
||||
printf("- SS: code:%d\n", ss.ss_code);
|
||||
|
||||
// mark as uninitialized
|
||||
memset(&ss, 0xcc, sizeof(ss));
|
||||
rc = gsm0480_parse_ss_facility(test_ss_int_03, sizeof(test_ss_int_03), &ss);
|
||||
OSMO_ASSERT(rc == 1);
|
||||
printf("Sample: test_ss_int_01 ctype=%02x invoke_id=%02x opcode=%02x\n",
|
||||
ss.component_type, ss.invoke_id, ss.opcode);
|
||||
printf("- SS: code:%d\n", ss.ss_code);
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
osmo_init_logging(&log_info);
|
||||
log_set_log_level(osmo_stderr_target, LOGL_INFO);
|
||||
|
||||
test_uss_ser_deser();
|
||||
test_parse_ss();
|
||||
|
||||
printf("Done.\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Reference in New Issue
Block a user