This page gives a quick introduction into the setup of the Osmocom core network with an outgoing call uplink to the PSTN via sipgate.de It does not contain a detailed explanation of all the involved components, but only a compressed installation guide. For detailed information check the Osmocom website.

Nowaday Osmocom actually recommends installation via package apt-get install osmo-bsc osmo-stp osmo-mgw osmo-msc osmo-hlr, but as I always have something I need to fiddle with at some point, I prefer to build from source and thus have the source available for changes.

Hardware

nanoBTS

For information on connection and configuring the nanoBTS please check the nanoBTS page.

Host System

As host system I’m using Debian 10 with XFCE edition in a VirtualBox VM.

The overall setup will also perfectly run on a RaspberryPI 3.

VM

  • 4096MB RAM (less is sufficient)
  • 2 Network adapters
    • NAT adapter - for Uplink etc.
    • Bridged adapter - Ethernet interface for connection to BTS etc.
  • 50GB HDD, simply as I usually add various tools afterwards
  • Client extensions installed

Network Configuration

Settings for /etc/network/interfaces

auto lo
iface lo inet loopback

# Uplink Interface
auto enp0s3
iface enp0s3 inet dhcp
dns-nameservers 8.8.8.8

# Bridged Adapter to BTS
auto enp0s8
iface enp0s8 inet static
        address 192.168.1.20
        netmask 255.255.255.0

auto enp0s8:0
iface enp0s8:0 inet static
        address 192.168.1.21
        netmask 255.255.255.0

Software Installation

Osmocom

For the Osmocom parts, best head over to the official documentation here

SimpleHLR

You can fetch SimpleHLR from here. It just needs to be unpacked.

You will need the following packages

sudo apt install php php-sqlite3

asterisk

This also contains the creation of basic configuration.

sudo apt install libncurses5-dev libjansson-dev uuid-dev sqlite3 libsqlite3-dev libxml2-dev libncurses-dev libedit-dev
cd /usr/src
git clone http://gerrit.asterisk.org/asterisk asterisk
cd asterisk
./configure
make
sudo make install
sudo make basic-pbx

ntp

As we will need acurate time, we also need everything to synchronize our VM’s time.

sudo apt install ntpdate

Configuration Files

I’ve got my setup based in /root/ as such my config files are all in /root/cfg/

Osmocom Stuff

Osmocom provides a set of default configs which work like a charm right here

As stated there you might want to enable verbose logging by adding

log stderr
 logging filter all 1
 logging color 1
 logging print category 1
 logging timestamp 1
 logging print extended-timestamp 1
 logging level all debug

to the config files.

sip-connector.conf

app
mncc
  socket-path /tmp/bsc_mncc
sip
  local 0.0.0.0 5069
  remote 192.168.1.21 5060

dnsmasq.conf

We will need a DHCP server to give IPs to the basestations

listen-address=192.168.1.20
dhcp-range=192.168.1.50,192.168.1.100,12h

/etc/asterisk/asterisk.conf

Yes, my asterisk.conf is basically empty.

[options]
; If we want to start Asterisk with a default verbosity for the verbose
; or debug logger channel types, then we use these settings (by default
; they are disabled).
;verbose = 5
;debug = 2

; User and group to run asterisk as. NOTE: This will require changes to
; directory and device permissions.
;runuser = asterisk		; The user to run as. The default is root.
;rungroup = asterisk		; The group to run as. The default is root

;defaultlanguage = en

/etc/asterisk/extensions.conf

[globals]
; General internal dialing options used in context Dial-Users.
; Only the timeout is defined here. See the Dial app documentation for
; additional options.
INTERNAL_DIAL_OPT=,30

[Dialing-Errors]
; Handle any extensions dialed internally that don't otherwise exist.
; Comment out or remove this extension if you would rather have the calls
; ignored.
exten = _X.,1,Verbose(1, "User ${CALLERID(num)} dialed an invalid number.")
 same = n,Playback(pbx-invalid)
 same = n,Hangup()

[incoming]
exten => xxxSIPGATEUSERNAMExxx,1,Log(Notice, "Incoming call via sipgate from ${CALLERID(num)}. exten is currently ${EXTEN}")
exten => xxxSIPGATEUSERNAMExxx,2,Answer(),
exten => xxxSIGPATEUSERNAMExxx,n,Background(welcome)
exten => xxxSIPGATEUSERNAMExxx,n,Background(silence/9)
exten => xxxSIPGATEUSERNAMExxx,n,Hangup()
exten => _1337,1,Playback(tt-weasels)
exten => _1337,n,Hangup()
exten => _9090XXXXX,1,Log(Notice, "Incoming call for ${EXTEN} from ${CALLERID(num)}.")
exten => _9090XXXXX,2,DIAL(SIP/${EXTEN}@192.168.1.20:5069)
exten => _9090XXXXX,n,Hangup()

include = Dialing-Errors 

[internal]
exten => 1337,1,Answer
exten => 1337,2,Playback(tt-weasels)
exten => 1337,3,Hangup
exten => _9090XXXXX,1,DIAL(SIP/${EXTEN}@192.168.1.20:5069)
exten => 2222,1,DIAL(SIP/${EXTEN}@192.168.1.20:5069)
exten => _0!X.,1,Set(CALLERID(num)=SIPID)
exten => _0!X.,2,Dial(SIP/*31${EXTEN}@sipgate,30,trg)
exten => _0!X.,3,Hangup
include = Dialing-Errors

/etc/asterisk/sip.conf

[general]

context=internal
allowoverlap=no
domainsasrealm=yes
udpbindaddr=192.168.1.21
tcpbindaddr=192.168.1.21
transport=udp
srvlookup=yes

; login for sipgate uplink
register=xxxUSERxxx:xxxPASSxxx@sipgate.de/xxxUSERxxx

[sipgate]
type=peer
defaultuser=xxxUSERxxx
fromuser=xxxUSERxxx
secret=xxxPASSxxx
context=incoming
extension=xxxUSERxxx
host=sipgate.de
dtmfmode=rfc2833
qualify=yes
fromdomain=sipgate.de
nat=no
directmedia=no
canreinvite=no
insecure=port,invite
allow=!all,alaw,g722


[8888]
type=friend
host=dynamic
secret=123
context=internal

[7002]
type=friend
host=dynamic
secret=456
context=internal

[1111]
type=friend
host=dynamic
secret=123
conext=internal

[gsm]
type=peer
host=192.168.1.20
port=5069
context=gsm
insecure=port,invite
dtmfmode=rfc2833
disallow=all
allow=gsm

/etc/asterisk/cdr.conf

[general]
enable=yes

[custom]
; We log the unique ID as it can be useful for troubleshooting any issues
; that arise.
loguniqueid=yes

/etc/asterisk/cdr_custom.conf

[mappings]
; Our CDR log will be written to /var/log/asterisk/cdr-custom/Master.csv
; with the following schema.
Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})},${CDR(sequence)}

/etc/asterisk/logger.conf

[general]

[logfiles]

console = verbose,notice,warning,error

;messages = notice,warning,error
;full = verbose,notice,warning,error,debug
;security = security

/etc/asterisk/modules.conf

; Asterisk configuration file
;
; Module Loader configuration file
;

[modules]
autoload=yes
;
; Any modules that need to be loaded before the Asterisk core has been
; initialized (just after the logger has been initialized) can be loaded
; using 'preload'. This will frequently be needed if you wish to map all
; module configuration files into Realtime storage, since the Realtime
; driver will need to be loaded before the modules using those configuration
; files are initialized.
;
; An example of loading ODBC support would be:
;preload => res_odbc.so
;preload => res_config_odbc.so
;
; Uncomment the following if you wish to use the Speech Recognition API
;preload => res_speech.so
;
; If you want Asterisk to fail if a module does not load, then use
; the "require" keyword. Asterisk will exit with a status code of 2
; if a required module does not load.
;
; require = chan_sip.so
; If you want you can combine with preload
; preload-require = res_odbc.so
;
; If you want, load the GTK console right away.
;
noload => pbx_gtkconsole.so
;load => pbx_gtkconsole.so
;
load => res_musiconhold.so
;
; Load one of: chan_oss, alsa, or console (portaudio).
; By default, load chan_oss only (automatically).
;
noload => chan_alsa.so
;noload => chan_oss.so
noload => chan_console.so
load => chan_sip.so

Startup Scripts

bsc_start.sh

osmo-nitb -s -c ~/cfg/openbsc.conf -l ~/cfg/hlr.sqlite3 -P -C -d DLMUX:DRTP -m -T --debug=DSQL:DLSMS:DRLL:DCC:DMM:DRR:DMSC:DHO:DGPRS:DNS:DLLC:DCTRL 2>&1

ggsn_start.sh

osmo-ggsn -c ~/cfg/ggsn.conf

sgsn_start.sh

osmo-sgsn -c ~/cfg/sgsn.conf -d DRLL:DCC:DMM:DRR:DNM:DMSC:DHO:DGPRS:DNS:DLLC:DCTRL

sip-connector_start.sh

osmo-sip-connector -c ~/cfg/osmo-sip-connector.conf

simplehlr_start.sh

php -S 0.0.0.0:80 -t /root/webserver/SimpleHLR/.

routing.sh

echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -A POSTROUTING -s 192.168.254.0/24 -t nat -o enp0s3 -j MASQUERADE
iptables -A POSTROUTING -t nat -o enp0s8 -j MASQUERADE

HLR Adding Subscribers

Osmo-HLR should be listening on localhost:4258, thus you can connect to it using telnet 127.0.0.1 4258.

OsmoHLR> enable
OsmoHLR# subscriber imsi 123456789012345 create
% Created subscriber 123456789012345
    ID: 1
    IMSI: 123456789012345
    MSISDN: none
OsmoHLR# subscriber imsi 123456789012345 update msisdn 12345
% Updated subscriber IMSI='123456789012345' to MSISDN='12345'

On my old setup, the HLR used to add an entry for each user that tried to connect, then I’d allow access manually. The same can be achieved with Osmo-HLR. Frist you need to create the entries on demand.

OsmoHLR# configure terminal 
OsmoHLR(config)# hlr 
OsmoHLR(config-hlr)# subscriber-create-on-demand
  no-msisdn  Do not automatically assign MSISDN.
  <3-15>     Length of an automatically assigned MSISDN.
OsmoHLR(config-hlr)# subscriber-create-on-demand no-ms
OsmoHLR(config-hlr)# subscriber-create-on-demand no-msisdn 
  none   Do not allow any NAM (Network Access Mode) by default.
  cs     Allow access to circuit switched NAM by default.
  ps     Allow access to packet switched NAM by default.
  cs+ps  Allow access to circuit and packet switched NAM by default.
OsmoHLR(config-hlr)# subscriber-create-on-demand no-msisdn none

Obviously it makes sense to just add the setting to the static config file.

Then we can modify the subscriber and allow access to the cs, ps or cs+ps domains.

OsmoHLR# subscriber imsi 123456789012345 update network-access-mode 
none       cs         ps         cs+ps 

And the most import command

OsmoHLR# show subscribers all
ID     MSISDN        IMSI              IMEI              NAM
-----  ------------  ----------------  ----------------  -----
1      12345         123456789012345    -------------    CSPS 

Running

The easiest approach is using screen or multiple terminal sessions, as you will want to be able to view the log output. You will need a screen for the BSC, GGSN, SGSN and the sip-connector. Above this all the osmocom components offer access via VTY. As such you might need access to these terminals for configuration or trouble shooting. The same applies for the asterisk cli.

BSC VTY

The BSC VTY listens on port 4242 / TCP. The easiest way to connect is by using telnet.

telnet 127.0.0.1 4242

SGSN VTY

The SGSN VTY listens on port 4245 / TCP. The easist way to connect is by using telnet.

telnet 127.0.0.1 4245

The VTY is the easiest way of checking the active PDP contexts.

:~/cfg# telnet 127.0.0.1 4245
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Welcome to the OsmoSGSN control interface

Copyright (C) 2010 Harald Welte and On-Waves
License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
OsmoSGSN> show pdp-context all
PDP Context IMSI: 262230000000001, SAPI: 3, NSAPI: 5, TI: 0
  APN: internet
  PDP Address: IPv4 192.168.254.2
  GTP Local Control(4.0.0.0 / TEIC: 0x00000001) Data(4.0.0.0 / TEID: 0x00000001)
  GTP Remote Control(4.0.0.0 / TEIC: 0x00000001) Data(4.0.0.0 / TEID: 0x00000001)
 SGSN PDP Context Statistics:
  User Data  Messages ( In):        2 (1/s 2/m 0/h 0/d)
  User Data  Messages (Out):        0 (0/s 0/m 0/h 0/d)
  User Data  Bytes    ( In):      145 (73/s 145/m 0/h 0/d)
  User Data  Bytes    (Out):        0 (0/s 0/m 0/h 0/d)

asterisk CLI

The asterisk CLI is necessary for evaluating the state of the PSTN uplink.

:~/cfg# asterisk -r
Asterisk GIT-master-7c27e71, Copyright (C) 1999 - 2016, Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Connected to Asterisk GIT-master-7c27e71 currently running on TelCore2 (pid = 14391)
TelCore2*CLI> sip show registry
Host                                    dnsmgr Username       Refresh State                Reg.Time                 
sipgate.de:5060                         N      xxxxxxxxx          105 Registered           Sun, 26 Feb 2017 10:33:58
1 SIP registrations.
TelCore2*CLI>