drop files unrelated to osmo-sgsn

These either remain from openbsc.git or slipped in while applying recent
patches from openbsc.git and do not belong in osmo-sgsn.

Change-Id: Ie9dc7514c3850010d0e9b3ab716b4f4e8d83594f
This commit is contained in:
Neels Hofmeyr 2017-09-04 03:35:30 +02:00
parent f9ced184f5
commit 0c55de18a0
49 changed files with 0 additions and 2774 deletions

View File

@ -1,170 +0,0 @@
-- Split trace based on SCCP Source
-- There are still bugs to find... bugs bugs bugs... hmm
do
local function init_listener()
print("CREATED LISTENER")
local tap = Listener.new("ip", "sccp && (ip.src == 172.16.1.81 || ip.dst == 172.16.1.81)")
local sccp_type_field = Field.new("sccp.message_type")
local sccp_src_field = Field.new("sccp.slr")
local sccp_dst_field = Field.new("sccp.dlr")
local msg_type_field = Field.new("gsm_a.dtap_msg_mm_type")
local lu_rej_field = Field.new("gsm_a.dtap.rej_cause")
local ip_src_field = Field.new("ip.src")
local ip_dst_field = Field.new("ip.dst")
--
local bssmap_msgtype_field = Field.new("gsm_a.bssmap_msgtype")
-- assignment failure 0x03
--
--
local dtap_cause_field = Field.new("gsm_a_dtap.cause")
local dtap_cc_field = Field.new("gsm_a.dtap_msg_cc_type")
local connections = {}
function check_failure(con)
check_lu_reject(con)
check_disconnect(con)
check_failures(con)
end
-- cipher mode reject
function check_failures(con)
local msgtype = bssmap_msgtype_field()
if not msgtype then
return
end
msgtype = tonumber(msgtype)
if msgtype == 89 then
print("Cipher mode reject")
con[4] = true
elseif msgtype == 0x03 then
print("Assignment failure")
con[4] = true
elseif msgtype == 0x22 then
print("Clear Request... RF failure?")
con[4] = true
end
end
-- check if a DISCONNECT is normal
function check_disconnect(con)
local msg_type = dtap_cc_field()
if not msg_type then
return
end
if tonumber(msg_type) ~= 0x25 then
return
end
local cause = dtap_cause_field()
if not cause then
return
end
cause = tonumber(cause)
if cause ~= 0x10 then
print("DISCONNECT != Normal")
con[4] = true
end
end
-- check if we have a LU Reject
function check_lu_reject(con)
local msg_type = msg_type_field()
if not msg_type then
return
end
msg_type = tonumber(tostring(msg_type))
if msg_type == 0x04 then
print("LU REJECT with " .. tostring(lu_rej_field()))
con[4] = true
end
end
function tap.packet(pinfo,tvb,ip)
local ip_src = tostring(ip_src_field())
local ip_dst = tostring(ip_dst_field())
local sccp_type = tonumber(tostring(sccp_type_field()))
local sccp_src = sccp_src_field()
local sccp_dst = sccp_dst_field()
local con
if sccp_type == 0x01 then
elseif sccp_type == 0x2 then
local src = string.format("%s-%s", ip_src, tostring(sccp_src))
local dst = string.format("%s-%s", ip_dst, tostring(sccp_dst))
local datestring = os.date("%Y%m%d%H%M%S")
local pcap_name = string.format("alink_trace_%s-%s_%s.pcap", src, dst, datestring)
local dumper = Dumper.new_for_current(pcap_name)
local con = { ip_src, tostring(sccp_src), tostring(sccp_dst), false, dumper, pcap_name }
dumper:dump_current()
connections[src] = con
connections[dst] = con
elseif sccp_type == 0x4 then
-- close a connection... remove it from the list
local src = string.format("%s-%s", ip_src, tostring(sccp_src))
local dst = string.format("%s-%s", ip_dst, tostring(sccp_dst))
local con = connections[src]
if not con then
return
end
con[5]:dump_current()
con[5]:flush()
-- this causes a crash on unpacted wireshark
con[5]:close()
-- the connection had a failure
if con[4] == true then
local datestring = os.date("%Y%m%d%H%M%S")
local new_name = string.format("alink_failure_%s_%s-%s.pcap", datestring, con[2], con[3])
os.rename(con[6], new_name)
else
os.remove(con[6])
end
-- clear the old connection
connections[src] = nil
connections[dst] = nil
elseif sccp_type == 0x5 then
-- not handled yet... we should verify stuff here...
local dst = string.format("%s-%s", ip_dst, tostring(sccp_dst))
local con = connections[dst]
if not con then
return
end
con[5]:dump_current()
elseif sccp_type == 0x6 then
local dst = string.format("%s-%s", ip_dst, tostring(sccp_dst))
local con = connections[dst]
if not con then
print("DON'T KNOW THIS CONNECTION for " .. ip_dst)
return
end
con[5]:dump_current()
check_failure(con)
end
end
function tap.draw()
print("DRAW")
end
function tap.reset()
print("RESET")
end
end
init_listener()
end

View File

@ -1 +0,0 @@
Some crazy scripts call testing... and MSC link failure simulation

View File

@ -1,8 +0,0 @@
ABORT BUSY
ABORT 'NO CARRIER'
ABORT 'OK'
'' AT
SAY "Dialing a number\n"
'OK' ATD05660066;

View File

@ -1,11 +0,0 @@
#!/bin/sh
# Evil dial script..
while true;
do
chat -v -f all_dial < /dev/ttyACM0 > /dev/ttyACM0
sleep 5s
chat -v -f hangup < /dev/ttyACM0 > /dev/ttyACM0
sleep 2s
done

View File

@ -1,6 +0,0 @@
#!/bin/sh
sleep 3
echo "enable"
sleep 1
echo "drop bts connection 0 oml"
sleep 1

View File

@ -1,8 +0,0 @@
#!/bin/sh
while true;
do
echo "Going to drop the OML connection"
./drop-oml.sh | telnet 127.0.0.1 4242
sleep 58m
done

View File

@ -1,4 +0,0 @@
TIMEOUT 10
'' ^Z
SAY "Waiting for hangup confirm\n"
'' ATH;

View File

@ -1,8 +0,0 @@
#!/bin/sh
while true;
do
echo "Kill the osmo-bsc"
/usr/bin/kill -s SIGUSR2 `pidof osmo-bsc`
sleep 58s
done

View File

@ -1,120 +0,0 @@
#!/usr/bin/python
# -*- mode: python-mode; py-indent-tabs-mode: nil -*-
"""
/*
* Copyright (C) 2016 sysmocom s.f.m.c. GmbH
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 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 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.
*/
"""
from optparse import OptionParser
from ipa import Ctrl
import socket
verbose = False
def connect(host, port):
if verbose:
print "Connecting to host %s:%i" % (host, port)
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.setblocking(1)
sck.connect((host, port))
return sck
def do_set_get(sck, var, value = None):
(r, c) = Ctrl().cmd(var, value)
sck.send(c)
answer = Ctrl().rem_header(sck.recv(4096))
return (answer,) + Ctrl().verify(answer, r, var, value)
def set_var(sck, var, val):
(a, _, _) = do_set_get(sck, var, val)
return a
def get_var(sck, var):
(_, _, v) = do_set_get(sck, var)
return v
def _leftovers(sck, fl):
"""
Read outstanding data if any according to flags
"""
try:
data = sck.recv(1024, fl)
except socket.error as (s_errno, strerror):
return False
if len(data) != 0:
tail = data
while True:
(head, tail) = Ctrl().split_combined(tail)
print "Got message:", Ctrl().rem_header(head)
if len(tail) == 0:
break
return True
return False
if __name__ == '__main__':
parser = OptionParser("Usage: %prog [options] var [value]")
parser.add_option("-d", "--host", dest="host",
help="connect to HOST", metavar="HOST")
parser.add_option("-p", "--port", dest="port", type="int",
help="use PORT", metavar="PORT", default=4249)
parser.add_option("-g", "--get", action="store_true",
dest="cmd_get", help="perform GET operation")
parser.add_option("-s", "--set", action="store_true",
dest="cmd_set", help="perform SET operation")
parser.add_option("-v", "--verbose", action="store_true",
dest="verbose", help="be verbose", default=False)
parser.add_option("-m", "--monitor", action="store_true",
dest="monitor", help="monitor the connection for traps", default=False)
(options, args) = parser.parse_args()
verbose = options.verbose
if options.cmd_set and options.cmd_get:
parser.error("Get and set options are mutually exclusive!")
if not (options.cmd_get or options.cmd_set or options.monitor):
parser.error("One of -m, -g, or -s must be set")
if not (options.host):
parser.error("Destination host and port required!")
sock = connect(options.host, options.port)
if options.cmd_set:
if len(args) < 2:
parser.error("Set requires var and value arguments")
_leftovers(sock, socket.MSG_DONTWAIT)
print "Got message:", set_var(sock, args[0], ' '.join(args[1:]))
if options.cmd_get:
if len(args) != 1:
parser.error("Get requires the var argument")
_leftovers(sock, socket.MSG_DONTWAIT)
(a, _, _) = do_set_get(sock, args[0])
print "Got message:", a
if options.monitor:
while True:
if not _leftovers(sock, 0):
print "Connection is gone."
break
sock.close()

View File

@ -1,33 +0,0 @@
#!/usr/bin/env python
import os
f = open("unbalanced")
lines = []
for line in f:
lines.append(line)
filenames = {}
output = []
for line in lines:
if "[0x" in line:
start = line.find("[")
end = line.find("]")
addr = line[start+1:end]
try:
file = filenames[addr]
except KeyError:
r = os.popen("addr2line -fs -e ./bsc_hack %s" % addr)
all = r.read().replace("\n", ",")
file = all
filenames[addr] = file
line = line.replace(addr, file)
output.append(line)
g = open("unbalanced.2", "w")
g.write("".join(output))

View File

@ -1,37 +0,0 @@
#!/usr/bin/env python
#
# Convert ETSI documents to an enum
#
import re, sys
def convert(string):
string = string.strip().replace(" ", "").rjust(8, "0")
var = 0
offset = 7
for char in string:
assert offset >= 0
var = var | (int(char) << offset)
offset = offset - 1
return var
def string(name):
name = name.replace(" ", "_")
name = name.replace('"', "")
name = name.replace('/', '_')
name = name.replace('(', '_')
name = name.replace(')', '_')
return "%s_%s" % (sys.argv[2], name.upper())
file = open(sys.argv[1])
for line in file:
m = re.match(r"[ \t]*(?P<value>[01 ]+)[ ]+(?P<name>[a-zA-Z /0-9()]+)", line[:-1])
if m:
print "\t%s\t\t= %d," % (string(m.groupdict()["name"]), convert(m.groupdict()["value"]))
else:
print line[:-1]

View File

@ -1,147 +0,0 @@
#!/usr/bin/python2
mod_license = '''
/*
* Copyright (C) 2016 sysmocom s.f.m.c. GmbH
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 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 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, argparse, random, logging, tornado.ioloop, tornado.web, tornado.tcpclient, tornado.httpclient, eventsource, bsc_control
from eventsource import listener, request
'''
N. B: this is not an example of building proper REST API or building secure web application.
It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API.
Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem
from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that.
'''
token = None
stream = None
url = None
'''
Returns json according to following schema - see http://json-schema.org/documentation.html for details:
{
"title": "Ctrl Schema",
"type": "object",
"properties": {
"variable": {
"type": "string"
},
"varlue": {
"type": "string"
}
},
"required": ["interface", "variable", "value"]
}
Example validation from command-line:
json validate --schema-file=schema.json --document-file=data.json
The interface is represented as string because it might look different for IPv4 vs v6.
'''
def read_header(data):
t_length = bsc_control.ipa_ctrl_header(data)
if (t_length):
stream.read_bytes(t_length - 1, callback = read_trap)
else:
print >> sys.stderr, "protocol error: length missing in %s!" % data
@tornado.gen.coroutine
def read_trap(data):
(t, z, v, p) = data.split()
if (t != 'TRAP' or int(z) != 0):
print >> sys.stderr, "protocol error: TRAP != %s or 0! = %d" % (t, int(z))
else:
yield tornado.httpclient.AsyncHTTPClient().fetch(tornado.httpclient.HTTPRequest(url = "%s/%s/%s" % (url, "ping", token),
method = 'POST',
headers = {'Content-Type': 'application/json'},
body = tornado.escape.json_encode({ 'variable' : v, 'value' : p })))
stream.read_bytes(4, callback = read_header)
@tornado.gen.coroutine
def trap_setup(host, port, target_host, target_port, tk):
global stream
global url
global token
token = tk
url = "http://%s:%s/sse" % (host, port)
stream = yield tornado.tcpclient.TCPClient().connect(target_host, target_port)
stream.read_bytes(4, callback = read_header)
def get_v(s, v):
return { 'variable' : v, 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) }
class CtrlHandler(tornado.web.RequestHandler):
def initialize(self):
self.skt = bsc_control.connect(self.settings['ctrl_host'], self.settings['ctrl_port'])
def get(self, v):
self.write(get_v(self.skt, v))
def post(self):
self.write(get_v(self.skt, self.get_argument("variable")))
class SetCtrl(CtrlHandler):
def get(self, var, val):
bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val))
super(SetCtrl, self).get(tornado.escape.native_str(var))
def post(self):
bsc_control.set_var(self.skt, tornado.escape.native_str(self.get_argument("variable")), tornado.escape.native_str(self.get_argument("value")))
super(SetCtrl, self).post()
class Slash(tornado.web.RequestHandler):
def get(self):
self.write('<html><head><title>%s</title></head><body>Using Tornado framework v%s'
'<form action="/get" method="POST">'
'<input type="text" name="variable">'
'<input type="submit" value="GET">'
'</form>'
'<form action="/set" method="POST">'
'<input type="text" name="variable">'
'<input type="text" name="value">'
'<input type="submit" value="SET">'
'</form>'
'</body></html>' % ("Osmocom Control Interface Proxy", tornado.version))
if __name__ == '__main__':
p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.')
p.add_argument('-c', '--control-port', type = int, default = 4252, help = "Target Control Interface port")
p.add_argument('-a', '--control-host', default = 'localhost', help = "Target Control Interface adress")
p.add_argument('-b', '--host', default = 'localhost', help = "Adress to bind proxy's web interface")
p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface")
p.add_argument('-d', '--debug', action='store_true', help = "Activate debugging (default off)")
p.add_argument('-t', '--token', default = 'osmocom', help = "Token to be used by SSE client in URL e. g. http://127.0.0.1:8888/poll/osmocom where 'osmocom' is default token value")
p.add_argument('-k', '--keepalive', type = int, default = 5000, help = "Timeout betwwen keepalive messages, in milliseconds, defaults to 5000")
args = p.parse_args()
random.seed()
tornado.netutil.Resolver.configure('tornado.netutil.ThreadedResolver') # Use non-blocking resolver
logging.basicConfig()
application = tornado.web.Application([
(r"/", Slash),
(r"/get", CtrlHandler),
(r"/get/(.*)", CtrlHandler),
(r"/set", SetCtrl),
(r"/set/(.*)/(.*)", SetCtrl),
(r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.JSONIdEvent, keepalive = args.keepalive)),
], debug = args.debug, ctrl_host = args.control_host, ctrl_port = args.control_port)
application.listen(address = args.host, port = args.port)
trap_setup(args.host, args.port, application.settings['ctrl_host'], application.settings['ctrl_port'], args.token)
tornado.ioloop.IOLoop.instance().start()

View File

@ -1,18 +0,0 @@
-- Remove old data from the database
DELETE FROM Subscriber
WHERE id != 1 AND datetime('now', '-10 days') > updated AND authorized != 1;
DELETE FROM Equipment
WHERE datetime('now', '-10 days') > updated;
DELETE FROM EquipmentWatch
WHERE datetime('now', '-10 days') > updated;
DELETE FROM SMS
WHERE datetime('now', '-10 days') > created;
DELETE FROM VLR
WHERE datetime('now', '-10 days') > updated;
DELETE FROM ApduBlobs
WHERE datetime('now', '-10 days') > created;
DELETE FROM Counters
WHERE datetime('now', '-10 days') > timestamp;
DELETE FROM RateCounters
WHERE datetime('now', '-10 days') > timestamp;
VACUUM;

View File

@ -1,125 +0,0 @@
#!/usr/bin/python2.5
from __future__ import with_statement
from pysqlite2 import dbapi2 as sqlite3
import sys
hlr = sqlite3.connect(sys.argv[1])
web = sqlite3.connect(sys.argv[2])
# switch to autocommit
hlr.isolation_level = None
web.isolation_level = None
hlr.row_factory = sqlite3.Row
web.row_factory = sqlite3.Row
with hlr:
hlr_subscrs = hlr.execute("""
SELECT * FROM Subscriber
""").fetchall()
hlr_tokens = hlr.execute("""
SELECT * FROM AuthToken
""").fetchall()
with web:
web_tokens = web.execute("""
SELECT * FROM reg_tokens
""").fetchall()
web_sms = web.execute("""
SELECT * FROM sms_queue
""").fetchall()
# index by subscr id
hlr_subscrs_by_id = {}
hlr_subscrs_by_ext = {}
hlr_tokens_by_subscr_id = {}
for x in hlr_subscrs:
hlr_subscrs_by_id[x['id']] = x
hlr_subscrs_by_ext[x['extension']] = x
del hlr_subscrs
for x in hlr_tokens:
hlr_tokens_by_subscr_id[x['subscriber_id']] = x
del hlr_tokens
web_tokens_by_subscr_id = {}
for x in web_tokens:
web_tokens_by_subscr_id[x['subscriber_id']] = x
del web_tokens
# remove leftover web_tokens and correct inconsistent fields
with web:
for x in web_tokens_by_subscr_id.values():
subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None)
if subscr is None:
web.execute("""
DELETE FROM reg_tokens WHERE subscriber_id = ?
""", (x['subscriber_id'],))
del web_tokens_by_subscr_id[x['subscriber_id']]
continue
if str(x['imsi']) != str(subscr['imsi']) or \
x['extension'] != subscr['extension'] or \
x['tmsi'] != subscr['tmsi'] or \
x['lac'] != subscr['lac']:
web.execute("""
UPDATE reg_tokens
SET imsi = ?, extension = ?, tmsi = ?, lac = ?
WHERE subscriber_id = ?
""", (str(subscr['imsi']), subscr['extension'],
subscr['tmsi'], subscr['lac'], x['subscriber_id']))
# add missing web_tokens
with web:
for x in hlr_tokens_by_subscr_id.values():
subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None)
if subscr is None:
hlr.execute("""
DELETE FROM AuthToken WHERE subscriber_id = ?
""", (x['subscriber_id'],))
del hlr_tokens_by_subscr_id[x['subscriber_id']]
continue
webtoken = web_tokens_by_subscr_id.get(x['subscriber_id'], None)
if webtoken is None:
web.execute("""
INSERT INTO reg_tokens
(subscriber_id, extension, reg_completed, name, email, lac, imsi, token, tmsi)
VALUES
(?, ?, 0, ?, '', ?, ?, ?, ?)
""", (x['subscriber_id'], subscr['extension'], subscr['name'],
subscr['lac'], str(subscr['imsi']), x['token'], subscr['tmsi']))
# authorize subscribers
with hlr:
for x in web_tokens_by_subscr_id.values():
subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None)
if x['reg_completed'] and not subscr['authorized']:
hlr.execute("""
UPDATE Subscriber
SET authorized = 1
WHERE id = ?
""", (x['subscriber_id'],))
# Sync SMS from web to hlr
with hlr:
for sms in web_sms:
subscr = hlr_subscrs_by_ext.get(sms['receiver_ext'])
if subscr is None:
print '%s not found' % sms['receiver_ext']
continue
hlr.execute("""
INSERT INTO SMS
(created, sender_id, receiver_id, reply_path_req, status_rep_req, protocol_id, data_coding_scheme, ud_hdr_ind, text)
VALUES
(?, 1, ?, 0, 0, 0, 0, 0, ?)
""", (sms['created'], subscr['id'], sms['text']))
with web:
for sms in web_sms:
web.execute("""
DELETE FROM sms_queue WHERE id = ?
""", (sms['id'],))
hlr.close()
web.close()

View File

@ -1,60 +0,0 @@
#!/usr/bin/env python
# Simple server for mgcp... send audit, receive response..
import socket, time
MGCP_GATEWAY_PORT = 2427
MGCP_CALLAGENT_PORT = 2727
rsip_resp = """200 321321332\r\n"""
audit_packet = """AUEP %d 13@mgw MGCP 1.0\r\n"""
crcx_packet = """CRCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n"""
dlcx_packet = """DLCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\n"""
mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 6666 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"""
def hexdump(src, length=8):
"""Recipe is from http://code.activestate.com/recipes/142812/"""
result = []
digits = 4 if isinstance(src, unicode) else 2
for i in xrange(0, len(src), length):
s = src[i:i+length]
hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
result.append( b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text) )
return b'\n'.join(result)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("127.0.0.1", MGCP_CALLAGENT_PORT))
server_socket.setblocking(1)
last_ci = 1
def send_and_receive(packet):
global last_ci
server_socket.sendto(packet, ("127.0.0.1", MGCP_GATEWAY_PORT))
try:
data, addr = server_socket.recvfrom(4096)
# attempt to store the CI of the response
list = data.split("\n")
for item in list:
if item.startswith("I: "):
last_ci = int(item[3:])
print hexdump(data), addr
except socket.error, e:
print e
pass
def generate_tid():
import random
return random.randint(0, 65123)
while True:
send_and_receive(audit_packet % generate_tid())
send_and_receive(crcx_packet % generate_tid() )
send_and_receive(mdcx_packet % (generate_tid(), last_ci))
send_and_receive(dlcx_packet % (generate_tid(), last_ci))
time.sleep(3)

View File

@ -1,30 +0,0 @@
/* make test_regexp */
#include <sys/types.h>
#include <regex.h>
#include <stdio.h>
int main(int argc, char **argv)
{
regex_t reg;
regmatch_t matches[2];
if (argc != 4) {
printf("Invoke with: test_regexp REGEXP REPLACE NR\n");
return -1;
}
if (regcomp(&reg, argv[1], REG_EXTENDED) != 0) {
fprintf(stderr, "Regexp '%s' is not valid.\n", argv[1]);
return -1;
}
if (regexec(&reg, argv[3], 2, matches, 0) == 0 && matches[1].rm_eo != -1)
printf("New Number: %s%s\n", argv[2], &argv[3][matches[1].rm_so]);
else
printf("No match.\n");
regfree(&reg);
return 0;
}

View File

@ -1,65 +0,0 @@
#!/usr/bin/env python2.7
"""
AGPLv3+ 2016 Copyright Holger Hans Peter Freyther
Example of how to connect to the USSD side-channel and how to respond
with a fixed message.
"""
import socket
import struct
ussdSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ussdSocket.connect(('127.0.0.1', 5001))
def send_dt1(dstref, data):
dlen = struct.pack('B', len(data)).encode('hex')
hex = '06' + dstref.encode('hex') + '00' + '01' + dlen + data.encode('hex')
pdata = hex.decode('hex')
out = struct.pack('>HB', len(pdata), 0xfd) + pdata
ussdSocket.send(out)
def send_rel(srcref, dstref):
hex = '04' + dstref.encode('hex') + srcref.encode('hex') + '000100'
pdata = hex.decode('hex')
out = struct.pack('>HB', len(pdata), 0xfd) + pdata
ussdSocket.send(out)
def recv_one():
plen = ussdSocket.recv(3)
(plen,ptype) = struct.unpack(">HB", plen)
data = ussdSocket.recv(plen)
return ptype, data
# Assume this is the ID request
data = ussdSocket.recv(4)
ussdSocket.send("\x00\x08\xfe\x05\x00" + "\x05\x01" + "ussd")
# ^len ^len of tag ... and ignore
# Expect a fake message. see struct ipac_msgt_sccp_state
ptype, data = recv_one()
print("%d %s" % (ptype, data.encode('hex')))
(srcref, dstref, transid, invokeid) = struct.unpack("<3s3sBB", data[1:9])
print("New transID %d invoke %d" % (transid, invokeid))
# Expect a the invocation.. todo.. extract invoke id
ptype, data = recv_one()
print("%d %s" % (ptype, data.encode('hex')))
# Reply with BSSAP + GSM 04.08 + MAP portion
# 00 == invoke id 0f == DCS
res = "01002a9b2a0802e1901c22a220020100301b02013b301604010f041155e7d2f9bc3a41412894991c06a9c9a713"
send_dt1(dstref, res.decode('hex'))
clear = "000420040109"
send_dt1(dstref, clear.decode('hex'))
# should be the clear complete
send_rel(srcref, dstref)
# Give it some time to handle connection shutdown properly
print("Gracefully sleeping")
import time
time.sleep(3)

View File

@ -1,420 +0,0 @@
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp disable
-module(gen_rtp_header).
% -mode(compile).
-define(VERSION, "0.1").
-export([main/1]).
-record(rtp_packet,
{
version = 2,
padding = 0,
marker = 0,
payload_type = 0,
seqno = 0,
timestamp = 0,
ssrc = 0,
csrcs = [],
extension = <<>>,
payload = <<>>,
realtime
}).
main(Args) ->
DefaultOpts = [{format, state},
{ssrc, 16#11223344},
{rate, 8000},
{pt, 98}],
{PosArgs, Opts} = getopts_checked(Args, DefaultOpts),
log(debug, fun (Dev) ->
io:format(Dev, "Initial options:~n", []),
dump_opts(Dev, Opts),
io:format(Dev, "~s: ~p~n", ["Args", PosArgs])
end, [], Opts),
main(PosArgs, Opts).
main([First | RemArgs], Opts) ->
try
F = list_to_integer(First),
Format = proplists:get_value(format, Opts, state),
PayloadData = proplists:get_value(payload, Opts, undef),
InFile = proplists:get_value(file, Opts, undef),
Payload = case {PayloadData, InFile} of
{undef, undef} ->
% use default value
#rtp_packet{}#rtp_packet.payload;
{P, undef} -> P;
{_, File} ->
log(info, "Loading file '~s'~n", [File], Opts),
{ok, InDev} = file:open(File, [read]),
DS = [ Pl#rtp_packet.payload || {_T, Pl} <- read_packets(InDev, Opts)],
file:close(InDev),
log(debug, "File '~s' closed, ~w packets read.~n", [File, length(DS)], Opts),
DS
end,
Dev = standard_io,
write_packet_pre(Dev, Format),
do_groups(Dev, Payload, F, RemArgs, Opts),
write_packet_post(Dev, Format),
0
catch
_:_ ->
log(debug, "~p~n", [hd(erlang:get_stacktrace())], Opts),
usage(),
halt(1)
end
;
main(_, _Opts) ->
usage(),
halt(1).
%%% group (count + offset) handling %%%
do_groups(_Dev, _Pl, _F, [], _Opts) ->
ok;
do_groups(Dev, Pl, F, [L], Opts) ->
do_groups(Dev, Pl, F, [L, 0], Opts);
do_groups(Dev, Pl, First, [L, O | Args], Opts) ->
Ssrc = proplists:get_value(ssrc, Opts, #rtp_packet.ssrc),
PT = proplists:get_value(pt, Opts, #rtp_packet.payload_type),
Len = list_to_num(L),
Offs = list_to_num(O),
log(info, "Starting group: Ssrc=~.16B, PT=~B, First=~B, Len=~B, Offs=~B~n",
[Ssrc, PT, First, Len, Offs], Opts),
Pkg = #rtp_packet{ssrc = Ssrc, payload_type = PT},
Pl2 = write_packets(Dev, Pl, Pkg, First, Len, Offs, Opts),
{Args2, Opts2} = getopts_checked(Args, Opts),
log(debug, fun (Io) ->
io:format(Io, "Changed options:~n", []),
dump_opts(Io, Opts2 -- Opts)
end, [], Opts),
do_groups(Dev, Pl2, First+Len, Args2, Opts2).
%%% error handling helpers %%%
getopts_checked(Args, Opts) ->
try
getopts(Args, Opts)
catch
C:R ->
log(error, "~s~n",
[explain_error(C, R, erlang:get_stacktrace(), Opts)], Opts),
usage(),
halt(1)
end.
explain_error(error, badarg, [{erlang,list_to_integer,[S,B]} | _ ], _Opts) ->
io_lib:format("Invalid number '~s' (base ~B)", [S, B]);
explain_error(error, badarg, [{erlang,list_to_integer,[S]} | _ ], _Opts) ->
io_lib:format("Invalid decimal number '~s'", [S]);
explain_error(C, R, [Hd | _ ], _Opts) ->
io_lib:format("~p, ~p:~p", [Hd, C, R]);
explain_error(_, _, [], _Opts) ->
"".
%%% usage and options %%%
myname() ->
filename:basename(escript:script_name()).
usage(Text) ->
io:format(standard_error, "~s: ~s~n", [myname(), Text]),
usage().
usage() ->
io:format(standard_error,
"Usage: ~s [Options] Start Count1 Offs1 [[Options] Count2 Offs2 ...]~n",
[myname()]).
show_version() ->
io:format(standard_io,
"~s ~s~n", [myname(), ?VERSION]).
show_help() ->
io:format(standard_io,
"Usage: ~s [Options] Start Count1 Offs1 [[Options] Count2 Offs2 ...]~n~n" ++
"Options:~n" ++
" -h, --help this text~n" ++
" --version show version info~n" ++
" -i, --file=FILE reads payload from file (state format by default)~n" ++
" -f, --frame-size=N read payload as binary frames of size N instead~n" ++
" -p, --payload=HEX set constant payload~n" ++
" --verbose=N set verbosity~n" ++
" -v increase verbosity~n" ++
" --format=state use state format for output (default)~n" ++
" -C, --format=c use simple C lines for output~n" ++
" --format=carray use a C array for output~n" ++
" -s, --ssrc=SSRC set the SSRC~n" ++
" -t, --type=N set the payload type~n" ++
" -r, --rate=N set the RTP rate [8000]~n" ++
" -D, --duration=N set the packet duration in RTP time units [160]~n" ++
" -d, --delay=FLOAT add offset to playout timestamp~n" ++
"~n" ++
"Arguments:~n" ++
" Start initial packet (sequence) number~n" ++
" Count number of packets~n" ++
" Offs timestamp offset (in RTP units)~n" ++
"", [myname()]).
getopts([ "--file=" ++ File | R], Opts) ->
getopts(R, [{file, File} | Opts]);
getopts([ "-i" ++ T | R], Opts) ->
getopts_alias_arg("--file", T, R, Opts);
getopts([ "--frame-size=" ++ N | R], Opts) ->
Size = list_to_integer(N),
getopts(R, [{frame_size, Size}, {in_format, bin} | Opts]);
getopts([ "-f" ++ T | R], Opts) ->
getopts_alias_arg("--frame-size", T, R, Opts);
getopts([ "--duration=" ++ N | R], Opts) ->
Duration = list_to_integer(N),
getopts(R, [{duration, Duration} | Opts]);
getopts([ "-D" ++ T | R], Opts) ->
getopts_alias_arg("--duration", T, R, Opts);
getopts([ "--rate=" ++ N | R], Opts) ->
Rate = list_to_integer(N),
getopts(R, [{rate, Rate} | Opts]);
getopts([ "-r" ++ T | R], Opts) ->
getopts_alias_arg("--rate", T, R, Opts);
getopts([ "--version" | _], _Opts) ->
show_version(),
halt(0);
getopts([ "--help" | _], _Opts) ->
show_help(),
halt(0);
getopts([ "-h" ++ T | R], Opts) ->
getopts_alias_no_arg("--help", T, R, Opts);
getopts([ "--verbose=" ++ V | R], Opts) ->
Verbose = list_to_integer(V),
getopts(R, [{verbose, Verbose} | Opts]);
getopts([ "-v" ++ T | R], Opts) ->
Verbose = proplists:get_value(verbose, Opts, 0),
getopts_short_no_arg(T, R, [ {verbose, Verbose+1} | Opts]);
getopts([ "--format=state" | R], Opts) ->
getopts(R, [{format, state} | Opts]);
getopts([ "--format=c" | R], Opts) ->
getopts(R, [{format, c} | Opts]);
getopts([ "-C" ++ T | R], Opts) ->
getopts_alias_no_arg("--format=c", T, R, Opts);
getopts([ "--format=carray" | R], Opts) ->
getopts(R, [{format, carray} | Opts]);
getopts([ "--payload=" ++ Hex | R], Opts) ->
getopts(R, [{payload, hex_to_bin(Hex)} | Opts]);
getopts([ "--ssrc=" ++ Num | R], Opts) ->
getopts(R, [{ssrc, list_to_num(Num)} | Opts]);
getopts([ "-s" ++ T | R], Opts) ->
getopts_alias_arg("--ssrc", T, R, Opts);
getopts([ "--type=" ++ Num | R], Opts) ->
getopts(R, [{pt, list_to_num(Num)} | Opts]);
getopts([ "-t" ++ T | R], Opts) ->
getopts_alias_arg("--type", T, R, Opts);
getopts([ "--delay=" ++ Num | R], Opts) ->
getopts(R, [{delay, list_to_float(Num)} | Opts]);
getopts([ "-d" ++ T | R], Opts) ->
getopts_alias_arg("--delay", T, R, Opts);
% parsing helpers
getopts([ "--" | R], Opts) ->
{R, normalize_opts(Opts)};
getopts([ O = "--" ++ _ | _], _Opts) ->
usage("Invalid option: " ++ O),
halt(1);
getopts([ [ $-, C | _] | _], _Opts) when C < $0; C > $9 ->
usage("Invalid option: -" ++ [C]),
halt(1);
getopts(R, Opts) ->
{R, normalize_opts(Opts)}.
getopts_short_no_arg([], R, Opts) -> getopts(R, Opts);
getopts_short_no_arg(T, R, Opts) -> getopts([ "-" ++ T | R], Opts).
getopts_alias_no_arg(A, [], R, Opts) -> getopts([A | R], Opts);
getopts_alias_no_arg(A, T, R, Opts) -> getopts([A, "-" ++ T | R], Opts).
getopts_alias_arg(A, [], [T | R], Opts) -> getopts([A ++ "=" ++ T | R], Opts);
getopts_alias_arg(A, T, R, Opts) -> getopts([A ++ "=" ++ T | R], Opts).
normalize_opts(Opts) ->
[ proplists:lookup(E, Opts) || E <- proplists:get_keys(Opts) ].
%%% conversions %%%
bin_to_hex(Bin) -> [hd(integer_to_list(N,16)) || <<N:4>> <= Bin].
hex_to_bin(Hex) -> << <<(list_to_integer([Nib],16)):4>> || Nib <- Hex>>.
list_to_num("-" ++ Str) -> -list_to_num(Str);
list_to_num("0x" ++ Str) -> list_to_integer(Str, 16);
list_to_num("0b" ++ Str) -> list_to_integer(Str, 2);
list_to_num(Str = [ $0 | _ ]) -> list_to_integer(Str, 8);
list_to_num(Str) -> list_to_integer(Str, 10).
%%% dumping data %%%
dump_opts(Dev, Opts) ->
dump_opts2(Dev, Opts, proplists:get_keys(Opts)).
dump_opts2(Dev, Opts, [OptName | R]) ->
io:format(Dev, " ~-10s: ~p~n",
[OptName, proplists:get_value(OptName, Opts)]),
dump_opts2(Dev, Opts, R);
dump_opts2(_Dev, _Opts, []) -> ok.
%%% logging %%%
log(L, Fmt, Args, Opts) when is_list(Opts) ->
log(L, Fmt, Args, proplists:get_value(verbose, Opts, 0), Opts).
log(debug, Fmt, Args, V, Opts) when V > 2 -> log2("DEBUG", Fmt, Args, Opts);
log(info, Fmt, Args, V, Opts) when V > 1 -> log2("INFO", Fmt, Args, Opts);
log(notice, Fmt, Args, V, Opts) when V > 0 -> log2("NOTICE", Fmt, Args, Opts);
log(warn, Fmt, Args, _V, Opts) -> log2("WARNING", Fmt, Args, Opts);
log(error, Fmt, Args, _V, Opts) -> log2("ERROR", Fmt, Args, Opts);
log(Lvl, Fmt, Args, V, Opts) when V >= Lvl -> log2("", Fmt, Args, Opts);
log(_, _, _, _i, _) -> ok.
log2(Type, Fmt, Args, _Opts) when is_list(Fmt) ->
io:format(standard_error, "~s: " ++ Fmt, [Type | Args]);
log2("", Fmt, Args, _Opts) when is_list(Fmt) ->
io:format(standard_error, Fmt, Args);
log2(_Type, Fun, _Args, _Opts) when is_function(Fun, 1) ->
Fun(standard_error).
%%% RTP packets %%%
make_rtp_packet(P = #rtp_packet{version = 2}) ->
<< (P#rtp_packet.version):2,
0:1, % P
0:1, % X
0:4, % CC
(P#rtp_packet.marker):1,
(P#rtp_packet.payload_type):7,
(P#rtp_packet.seqno):16,
(P#rtp_packet.timestamp):32,
(P#rtp_packet.ssrc):32,
(P#rtp_packet.payload)/bytes
>>.
parse_rtp_packet(
<< 2:2, % Version 2
0:1, % P (not supported yet)
0:1, % X (not supported yet)
0:4, % CC (not supported yet)
M:1,
PT:7,
SeqNo: 16,
TS:32,
Ssrc:32,
Payload/bytes >>) ->
#rtp_packet{
version = 0,
marker = M,
payload_type = PT,
seqno = SeqNo,
timestamp = TS,
ssrc = Ssrc,
payload = Payload}.
%%% payload generation %%%
next_payload(F) when is_function(F) ->
{F(), F};
next_payload({F, D}) when is_function(F) ->
{P, D2} = F(D),
{P, {F, D2}};
next_payload([P | R]) ->
{P, R};
next_payload([]) ->
undef;
next_payload(Bin = <<_/bytes>>) ->
{Bin, Bin}.
%%% real writing work %%%
write_packets(_Dev, DS, _P, _F, 0, _O, _Opts) ->
DS;
write_packets(Dev, DataSource, P = #rtp_packet{}, F, L, O, Opts) ->
Format = proplists:get_value(format, Opts, state),
Ptime = proplists:get_value(duration, Opts, 160),
Delay = proplists:get_value(delay, Opts, 0),
Rate = proplists:get_value(rate, Opts, 8000),
case next_payload(DataSource) of
{Payload, DataSource2} ->
write_packet(Dev, Ptime * F / Rate + Delay,
P#rtp_packet{seqno = F, timestamp = F*Ptime+O,
payload = Payload},
Format),
write_packets(Dev, DataSource2, P, F+1, L-1, O, Opts);
Other -> Other
end.
write_packet(Dev, Time, P = #rtp_packet{}, Format) ->
Bin = make_rtp_packet(P),
write_packet_line(Dev, Time, P, Bin, Format).
write_packet_pre(Dev, carray) ->
io:format(Dev,
"struct {float t; int len; char *data;} packets[] = {~n", []);
write_packet_pre(_Dev, _) -> ok.
write_packet_post(Dev, carray) ->
io:format(Dev, "};~n", []);
write_packet_post(_Dev, _) -> ok.
write_packet_line(Dev, Time, _P, Bin, state) ->
io:format(Dev, "~f ~s~n", [Time, bin_to_hex(Bin)]);
write_packet_line(Dev, Time, #rtp_packet{seqno = N, timestamp = TS}, Bin, c) ->
ByteList = [ [ $0, $x | integer_to_list(Byte, 16) ] || <<Byte:8>> <= Bin ],
ByteStr = string:join(ByteList, ", "),
io:format(Dev, "/* time=~f, SeqNo=~B, TS=~B */ {~s}~n", [Time, N, TS, ByteStr]);
write_packet_line(Dev, Time, #rtp_packet{seqno = N, timestamp = TS}, Bin, carray) ->
io:format(Dev, " /* RTP: SeqNo=~B, TS=~B */~n", [N, TS]),
io:format(Dev, " {~f, ~B, \"", [Time, size(Bin)]),
[ io:format(Dev, "\\x~2.16.0B", [Byte]) || <<Byte:8>> <= Bin ],
io:format(Dev, "\"},~n", []).
%%% real reading work %%%
read_packets(Dev, Opts) ->
Format = proplists:get_value(in_format, Opts, state),
read_packets(Dev, Opts, Format).
read_packets(Dev, Opts, Format) ->
case read_packet(Dev, Opts, Format) of
eof -> [];
Tuple -> [Tuple | read_packets(Dev, Opts, Format)]
end.
read_packet(Dev, Opts, bin) ->
Size = proplists:get_value(frame_size, Opts),
case file:read(Dev, Size) of
{ok, Data} -> {0, #rtp_packet{payload = iolist_to_binary(Data)}};
eof -> eof
end;
read_packet(Dev, _Opts, Format) ->
case read_packet_line(Dev, Format) of
{Time, Bin} -> {Time, parse_rtp_packet(Bin)};
eof -> eof
end.
read_packet_line(Dev, state) ->
case io:fread(Dev, "", "~f ~s") of
{ok, [Time, Hex]} -> {Time, hex_to_bin(Hex)};
eof -> eof
end.

View File

@ -1,21 +0,0 @@
"
Simple UDP replay from the state files
"
PackageLoader fileInPackage: #Sockets.
FileStream fileIn: 'rtp_replay_shared.st'.
Eval [
| replay file host dport |
file := Smalltalk arguments at: 1 ifAbsent: [ 'rtpstream.state' ].
host := Smalltalk arguments at: 2 ifAbsent: [ '127.0.0.1' ].
dport := (Smalltalk arguments at: 3 ifAbsent: [ '4000' ]) asInteger.
sport := (Smalltalk arguments at: 4 ifAbsent: [ '0' ]) asInteger.
replay := RTPReplay on: file fromPort: sport.
Transcript nextPutAll: 'Going to stream now'; nl.
replay streamAudio: host port: dport.
]

View File

@ -1,118 +0,0 @@
"
Simple UDP replay from the state files
"
PackageLoader fileInPackage: #Sockets.
Object subclass: SDPUtils [
"Look into using PetitParser."
SDPUtils class >> findPort: aSDP [
aSDP linesDo: [:line |
(line startsWith: 'm=audio ') ifTrue: [
| stream |
stream := line readStream
skip: 'm=audio ' size;
yourself.
^ Number readFrom: stream.
]
].
^ self error: 'Not found'.
]
SDPUtils class >> findHost: aSDP [
aSDP linesDo: [:line |
(line startsWith: 'c=IN IP4 ') ifTrue: [
| stream |
^ stream := line readStream
skip: 'c=IN IP4 ' size;
upToEnd.
]
].
^ self error: 'Not found'.
]
]
Object subclass: RTPReplay [
| filename socket |
RTPReplay class >> on: aFile [
^ self new
initialize;
file: aFile; yourself
]
RTPReplay class >> on: aFile fromPort: aPort [
^ self new
initialize: aPort;
file: aFile; yourself
]
initialize [
self initialize: 0.
]
initialize: aPort [
socket := Sockets.DatagramSocket local: '0.0.0.0' port: aPort.
]
file: aFile [
filename := aFile
]
localPort [
^ socket port
]
streamAudio: aHost port: aPort [
| file last_time last_image udp_send dest |
last_time := nil.
last_image := nil.
file := FileStream open: filename mode: #read.
"Send the payload"
dest := Sockets.SocketAddress byName: aHost.
udp_send := [:payload | | datagram |
datagram := Sockets.Datagram data: payload contents address: dest port: aPort.
socket nextPut: datagram
].
[file atEnd] whileFalse: [
| lineStream time data now_image |
lineStream := file nextLine readStream.
"Read the time, skip the blank, parse the data"
time := Number readFrom: lineStream.
lineStream skip: 1.
data := WriteStream on: (ByteArray new: 30).
[lineStream atEnd] whileFalse: [
| hex |
hex := lineStream next: 2.
data nextPut: (Number readFrom: hex readStream radix: 16).
].
last_time isNil
ifTrue: [
"First time, send it right now"
last_time := time.
last_image := Time millisecondClockValue.
udp_send value: data.
]
ifFalse: [
| wait_image new_image_time |
"How long to wait?"
wait_image := last_image + ((time - last_time) * 1000).
[ wait_image > Time millisecondClockValue ]
whileTrue: [Processor yield].
udp_send value: data.
last_time := time.
last_image := wait_image.
]
]
]
]

View File

@ -1,87 +0,0 @@
"""
Create a SIP connection and then stream...
"""
PackageLoader
fileInPackage: #OsmoSIP.
"Load for the replay code"
FileStream fileIn: 'rtp_replay_shared.st'.
Osmo.SIPCall subclass: StreamCall [
| sem stream |
createCall: aSDP [
| sdp |
stream := RTPReplay on: 'rtp_ssrc6976010.240.240.1_to_10.240.240.50.state'.
sdp := aSDP % {stream localPort}.
^ super createCall: sdp.
]
sem: aSemaphore [
sem := aSemaphore
]
sessionNew [
| host port |
Transcript nextPutAll: 'The call has started'; nl.
Transcript nextPutAll: sdp_result; nl.
host := SDPUtils findHost: sdp_result.
port := SDPUtils findPort: sdp_result.
[
stream streamAudio: host port: port.
Transcript nextPutAll: 'Streaming has finished.'; nl.
] fork.
]
sessionFailed [
sem signal
]
sessionEnd [
sem signal
]
]
Eval [
| transport agent call sem sdp_fr sdp_amr |
sdp_fr := (WriteStream on: String new)
nextPutAll: 'v=0'; cr; nl;
nextPutAll: 'o=twinkle 1739517580 1043400482 IN IP4 127.0.0.1'; cr; nl;
nextPutAll: 's=-'; cr; nl;
nextPutAll: 'c=IN IP4 127.0.0.1'; cr; nl;
nextPutAll: 't=0 0'; cr; nl;
nextPutAll: 'm=audio %1 RTP/AVP 0 101'; cr; nl;
nextPutAll: 'a=rtpmap:0 PCMU/8000'; cr; nl;
nextPutAll: 'a=rtpmap:101 telephone-event/8000'; cr; nl;
nextPutAll: 'a=fmtp:101 0-15'; cr; nl;
nextPutAll: 'a=ptime:20'; cr; nl;
contents.
sem := Semaphore new.
transport := Osmo.SIPUdpTransport
startOn: '0.0.0.0' port: 5066.
agent := Osmo.SIPUserAgent createOn: transport.
transport start.
call := (StreamCall
fromUser: 'sip:1000@sip.zecke.osmocom.org'
host: '127.0.0.1'
port: 5060
to: 'sip:123456@127.0.0.1'
on: agent)
sem: sem; yourself.
call createCall: sdp_fr.
"Wait for the stream to have ended"
sem wait.
(Delay forSeconds: 4) wait.
]

View File

@ -1,28 +0,0 @@
print("Ni hao")
do
local tap = Listener.new("ip", "rtp")
local rtp_ssrc = Field.new("rtp.ssrc")
local frame_time = Field.new("frame.time_relative")
local rtp = Field.new("rtp")
function tap.packet(pinfo, tvb, ip)
local ip_src, ip_dst = tostring(ip.ip_src), tostring(ip.ip_dst)
local rtp_data = rtp()
local filename = "rtp_ssrc" .. rtp_ssrc() "_src_" .. ip_src .. "_to_" .. ip_dst .. ".state"
local f = io.open(filename, "a")
f:write(tostring(frame_time()) .. " ")
f:write(tostring(rtp_data.value))
f:write("\n")
f:close()
end
function tap.draw()
print("DRAW")
end
function tap.reset()
print("RESET")
end
end

View File

@ -1,66 +0,0 @@
"I create output for some simple SQL statements for the HLR db"
Eval [
"Create tables if they don't exist"
Transcript show: 'CREATE TABLE SMS (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created TIMESTAMP NOT NULL,
sent TIMESTAMP,
sender_id INTEGER NOT NULL,
receiver_id INTEGER NOT NULL,
deliver_attempts INTEGER NOT NULL DEFAULT 0,
valid_until TIMESTAMP,
reply_path_req INTEGER NOT NULL,
status_rep_req INTEGER NOT NULL,
protocol_id INTEGER NOT NULL,
data_coding_scheme INTEGER NOT NULL,
ud_hdr_ind INTEGER NOT NULL,
dest_addr TEXT,
user_data BLOB,
header BLOB,
text TEXT);'; nl;
show: 'CREATE TABLE Subscriber (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created TIMESTAMP NOT NULL,
updated TIMESTAMP NOT NULL,
imsi NUMERIC UNIQUE NOT NULL,
name TEXT,
extension TEXT UNIQUE,
authorized INTEGER NOT NULL DEFAULT 0,
tmsi TEXT UNIQUE,
lac INTEGER NOT NULL DEFAULT 0);'; nl.
"Create some dummy subscribers"
num_sub := 1000.
num_sms := 30.
lac := 1.
Transcript show: 'BEGIN;'; nl.
1 to: num_sub do: [:each |
Transcript show: 'INSERT INTO Subscriber
(imsi, created, updated, authorized, lac, extension)
VALUES
(%1, datetime(''now''), datetime(''now''), 1, %2, %3);' %
{(274090000000000 + each). lac. each}; nl.
].
1 to: num_sms do: [:sms |
1 to: num_sub do: [:sub |
Transcript show: 'INSERT INTO SMS
(created, sender_id, receiver_id, valid_until,
reply_path_req, status_rep_req, protocol_id,
data_coding_scheme, ud_hdr_ind, dest_addr,
text) VALUES
(datetime(''now''), 1, %1, ''2222-2-2'',
0, 0, 0,
0, 0, ''123456'',
''abc'');' % {sub}; nl.
]
].
Transcript show: 'COMMIT;'; nl.
]

View File

@ -1,10 +0,0 @@
"Query for one SMS"
Eval [
1 to: 100 do: [:each |
Transcript show: 'SELECT SMS.* FROM SMS
JOIN Subscriber ON SMS.receiver_id = Subscriber.id
WHERE SMS.id >= 1 AND SMS.sent IS NULL AND Subscriber.lac > 0
ORDER BY SMS.id LIMIT 1;'; nl.
].
]

View File

@ -1,5 +0,0 @@
probe process("/usr/lib/libsqlite3.so.0.8.6").function("sqlite3_get_table")
{
a = user_string($zSql);
printf("sqlite3_get_table called '%s'\n", a);
}

View File

@ -1,11 +0,0 @@
[Unit]
Description=OpenBSC MGCP
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-bsc_mgcp -s -c /etc/osmocom/osmo-bsc-mgcp.cfg
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@ -1,12 +0,0 @@
[Unit]
Description=OpenBSC BSC
Wants=osmo-bsc-mgcp.service
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-bsc -c /etc/osmocom/osmo-bsc.cfg -s
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@ -1,14 +0,0 @@
[Unit]
Description=Osmocom Mobile Switching Center (MSC)
Wants=osmo-hlr.service
After=osmo-hlr.service
After=osmo-hnbgw.service
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-msc -c /etc/osmocom/osmo-msc.cfg
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@ -1,11 +0,0 @@
[Unit]
Description=OpenBSC Network In the Box (NITB)
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-nitb -s -C -c /etc/osmocom/osmo-nitb.cfg -l /var/lib/osmocom/hlr.sqlite3
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@ -1,16 +0,0 @@
OBJS = testconv_main.o
CC = gcc
CFLAGS = -O0 -ggdb -Wall
LDFLAGS =
CPPFLAGS = -I../.. -I../../include $(shell pkg-config --cflags libosmocore) $(shell pkg-config --cflags libbcg729)
LIBS = ../../src/libmgcp/libmgcp.a ../../src/libcommon/libcommon.a $(shell pkg-config --libs libosmocore) $(shell pkg-config --libs libbcg729) -lgsm -lrt
testconv: $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
testconv_main.o: testconv_main.c
$(OBJS):
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<

View File

@ -1,133 +0,0 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/application.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/mgcp.h>
#include <openbsc/mgcp_internal.h>
#include "bscconfig.h"
#ifndef BUILD_MGCP_TRANSCODING
#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)"
#endif
#include "openbsc/mgcp_transcode.h"
static int audio_name_to_type(const char *name)
{
if (!strcasecmp(name, "gsm"))
return 3;
#ifdef HAVE_BCG729
else if (!strcasecmp(name, "g729"))
return 18;
#endif
else if (!strcasecmp(name, "pcma"))
return 8;
else if (!strcasecmp(name, "l16"))
return 11;
return -1;
}
int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst);
int main(int argc, char **argv)
{
char buf[4096] = {0x80, 0};
int cc, rc;
struct mgcp_rtp_end *dst_end;
struct mgcp_rtp_end *src_end;
struct mgcp_trunk_config tcfg = {{0}};
struct mgcp_endpoint endp = {0};
struct mgcp_process_rtp_state *state;
int in_size;
int in_samples = 160;
int out_samples = 0;
uint32_t ts = 0;
uint16_t seq = 0;
osmo_init_logging(&log_info);
tcfg.endpoints = &endp;
tcfg.number_endpoints = 1;
endp.tcfg = &tcfg;
mgcp_initialize_endp(&endp);
dst_end = &endp.bts_end;
src_end = &endp.net_end;
if (argc <= 2)
errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16} [SPP]");
if ((src_end->codec.payload_type = audio_name_to_type(argv[1])) == -1)
errx(1, "invalid input format '%s'", argv[1]);
if ((dst_end->codec.payload_type = audio_name_to_type(argv[2])) == -1)
errx(1, "invalid output format '%s'", argv[2]);
if (argc > 3)
out_samples = atoi(argv[3]);
if (out_samples) {
dst_end->codec.frame_duration_den = dst_end->codec.rate;
dst_end->codec.frame_duration_num = out_samples;
dst_end->frames_per_packet = 1;
}
rc = mgcp_transcoding_setup(&endp, dst_end, src_end);
if (rc < 0)
errx(1, "setup failed: %s", strerror(-rc));
state = dst_end->rtp_process_data;
OSMO_ASSERT(state != NULL);
in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0);
OSMO_ASSERT(sizeof(buf) >= in_size + 12);
buf[1] = src_end->codec.payload_type;
*(uint16_t*)(buf+2) = htons(1);
*(uint32_t*)(buf+4) = htonl(0);
*(uint32_t*)(buf+8) = htonl(0xaabbccdd);
while ((cc = read(0, buf + 12, in_size))) {
int cont;
int len;
if (cc != in_size)
err(1, "read");
*(uint16_t*)(buf+2) = htonl(seq);
*(uint32_t*)(buf+4) = htonl(ts);
seq += 1;
ts += in_samples;
cc += 12; /* include RTP header */
len = cc;
do {
cont = mgcp_transcoding_process_rtp(&endp, dst_end,
buf, &len, sizeof(buf));
if (cont == -EAGAIN) {
fprintf(stderr, "Got EAGAIN\n");
break;
}
if (cont < 0)
errx(1, "processing failed: %s", strerror(-cont));
len -= 12; /* ignore RTP header */
if (write(1, buf + 12, len) != len)
err(1, "write");
len = cont;
} while (len > 0);
}
return 0;
}

16
debian/copyright vendored
View File

@ -78,7 +78,6 @@ Files: .gitignore
doc/osmo-nitb-data_structures.dot
doc/paging.txt
include/Makefile.am
include/compat_af_isdn.h
include/openbsc/Makefile.am
include/openbsc/common.h
include/openbsc/crc24.h
@ -341,21 +340,6 @@ License: GPL-3.0+
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
Files: include/mISDNif.h
Copyright: 2008 Karsten Keil <kkeil@novell.com>
License: LGPL-2.1
This code is free software; you can redistribute it and/or modify
it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
version 2.1 as published by the Free Software Foundation.
.
This code 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 LESSER GENERAL PUBLIC LICENSE for more details.
.
On Debian systems, the complete text of the GNU Lesser General Public License
Version 2.1 can be found in `/usr/share/common-licenses/LGPL-2.1'.
Files: src/gprs/v42bis.c
Copyright: 2005-2011 Steve Underwood
License: LGPL-2.1

View File

@ -1,31 +0,0 @@
The Siemens BS-11 supports the following additional GSM 12.21 OML operations:
CREATE OBJECT
abis_om_fom_hdr.obj_class can be
A3:
A5: ALCO, BBSIG, CCLK, GPSU, LI, PA
A8: EnvaBTSE
A9: BPORT
the abis_om_obj_inst.trx_nr field indicates the index of object, whereas the
abis_om_fom_hdr.bts_nr indicates the type of the object.
enum abis_bs11_objtype {
BS11_OBJ_ALCO = 0x01,
BS11_OBJ_BBSIG = 0x02, /* obj_class: 0,1 */
BS11_OBJ_TRX1 = 0x03, /* only DEACTIVATE TRX1 */
BS11_OBJ_CCLK = 0x04,
BS11_OBJ_GPSU = 0x06,
BS11_OBJ_LI = 0x07,
BS11_OBJ_PA = 0x09, /* obj_class: 0, 1*/
};
In case of CREATE ENVABTSE, the abis_om_obj_inst.trx_nr indicates the EnvaBTSEx
number.
In case of A9 (CREAETE BPORT), the abis_om_obj_inst.bts_nr indicates which BPORT
shall be used.

View File

@ -1,25 +0,0 @@
Call routing in OpenBSC
Flow of events:
# MO call initiated by MS, CHANNEL RQD, IMMEDIATE ASSIGN
# MS sends CC SETUP message, we assume already on TCH/H FACCH
# OpenBSC does a subscriber lookup based on the target extension
* If a subscriber is found:
# send CALL PROCEEDING message to MO
# page the MT subscriber and ask itI to ask for TCH/H
# once paging completes, we have the TCH/H for the MT end
# send SETUP to MT
# receive CALL CONFIRMED from MT
# set-up the TRAU mux mapping between the E1 subslots for both TCH/H
# receive ALERTING from MT, route ALERTING to MO
# receive CONNECT from MT, confirm to MT with CONNECT_ACK
# send a CONNECT message to MO, receive CONNECT_ACK from MO
* If subscriber is not found:
# send RELEASE COMPLETE with apropriate cause to MO (1: unalloacated 3: no route)
Thoughts about RR/MM:
* we allocate RR/MM entities on demand, when we need them

View File

@ -1,95 +0,0 @@
GSM 04.08 7.1.7 / 9.1.7 RR CHANNEL RELESE
RSL 08.58 3.4 / ? RLL Link Release Request
RSL 08.58 4.6 / 8.4.5 DEACTivate SACCH
* Deactivate SACCH according to Channel Release Proc 04.08
* to be sent after RR CHANNEL RELEASE is sent to MS
RSL 08.58 4.7 / 8.4.14 RF CHANnel RELease
* tells the BTS to release a radio channel
* "when an activated radio channel is no longer needed"
* BTS responds with RF CHANnel RELease ACKnowledge
GSM 04.08 3.4.13: RR connection release procedure
* network sends RR CHANNEL RELEASE to MS on the DCCH
* start T3109
* deactivate SACCH
* MS disconnects main signalling link (by sending DISC)
* all other data links are disconnected by local end link release
* network receives DISC (BTS sends RLL REL IND to BSC)
* stop T3109
* start T3111
* when T3111 times out, the network can reuse the channls
* if T3109 times out, the network deactivates the channels
and can reuse them
* this probably means simply RF CHANnel RELease
== Implementation in OpenBSC ==
There are two possible reasons a gsm_subscriber_connection
will be released. One is a network failure, the other is
the completion of an operation/transaction.
=== Failure ===
The BSC API will call the gsm_04_08.c:gsm0408_clear_request callback
and the MSC part will release all transactions, operations and such
and the channels will be released as error case.
=== Success ===
Every time an 'operation' or 'transaction' is finished msc_release_connection
will be called and it will determine if the gsm_subscriber_connection can
be released.
In case it can be released bsc_api.c:gsm0808_clear will be called
which will release all lchan's associated with the connection. For the
primary channel a SACH Deactivate will be send with the release
reason NORMAL RELEASE.
bsc_api.c:gsm0808_clear
* Release a channel used for handover
* Release the primary lchan with normal release, SACH deactivate
chan_alloc.c:lchan_release(chan, sacch_deactivate, reason)
* Start the release procedure. It is working in steps with callbacks
coming from the abis_rsl.c code.
* Release all SAPI's > 0 as local end (The BTS should send a
REL_CONF a message)
* Send SACH Deactivate on SAPI=0 if required.
* Start T3109 (stop it when the main signalling link is disconnected)
or when the channel released. On timeout start the error handling.
* abis_rsl.c schedules the RSL_MT_RF_CHAN_REL once all SAPI's are
released and after T3111 has timed out or there is an error.
RX of RELease INDication:
* Calls internal rsl_handle_release which might release the RF.
RX of RELease CONFirmation:
* Calls internal rsl_handle_release which might release the RF.
* RX of RF_CHAN_REL_ACK
* call lchan_free()
=== Integration with SMS ===
* RX of CP_ERROR or unimplemented MT
* trigger trans_free() which will msc_release_connection()
* CP TC1* expired while waiting for CP-ACK
* trigger trans_free() which will msc_release_connection()
* RX of RP_ERROR
* trigger trans_free() which will msc_release_connection()
* TX of CP-ACK in MT DELIVER
* trigger trans_free() which will msc_release_connection()
* RX of CP-ACK in MO SUBMIT
* trigger trans_free() which will msc_release_connection()

View File

@ -1,172 +0,0 @@
E1 related data model
This data model describes the physical relationship of the individual
parts in the network, it is not the logical/protocol side of the GSM
network.
A BTS is connected to the BSC by some physical link. It could be an actual
E1 link, but it could also be abis-over-IP with a mixture of TCP and RTP/UDP.
To further complicate the fact, multiple BTS can share one such pysical
link. On a single E1 line, we can easily accomodate up to three BTS with
two TRX each.
Thus, it is best for OpenBSC to have some kind of abstraction layer. The BSC's
view of a BTS connected to it. We call this 'bts_link'. A bts_link can be
* all the TCP and UDP streams of a Abis-over-IP BTS
* a set of E1 timeslots for OML, RSL and TRAU connections on a E1 link
* a serial line exclusively used for OML messages (T-Link)
A bts_link can be registered with the OpenBSC core at runtime.
struct trx_link {
struct gsm_bts_trx *trx;
};
struct bts_link {
struct gsm_bts *bts;
struct trx_link trx_links[NUM_TRX];
};
Interface from stack to input core:
======================================================================
int abis_rsl_sendmsg(struct msgb *msg);
send a message through a RSL link to the TRX specified by the caller in
msg->trx.
int abis_rsl_rcvmsg(struct msgb *msg);
receive a message from a RSL link from the TRX specified by the
caller in msg->trx.
int abis_nm_sendmsg(struct msgb *msg);
send a message through a OML link to the BTS specified by the caller in
msg->trx->bts. The caller can just use bts->c0 to get the first TRX
in a BTS. (OML messages are not really sent to a TRX but to the BTS)
int abis_nm_rcvmsg(struct msgb *msg);
receive a message from a OML link from the BTS specified by the caller
in msg->trx->bts. The caller can just use bts->c0 to get the first
TRX in a BTS.
int abis_link_event(int event, void *data);
signal some event (such as layer 1 connect/disconnect) from the
input core to the stack.
int subch_demux_in(mx, const uint8_t *data, int len);
receive 'len' bytes from a given E1 timeslot (TRAU frames)
int subchan_mux_out(mx, uint8_t *data, int len);
obtain 'len' bytes of output data to be sent on E1 timeslot
Intrface by Input Core for Input Plugins
======================================================================
int btslink_register_plugin();
Configuration for the E1 input module
======================================================================
BTS
BTS number
number of TRX
OML link
E1 line number
timeslot number
[subslot number]
SAPI
TEI
for each TRX
RSL link
E1 line number
timeslot number
[subslot number]
SAPI
TEI
for each TS
E1 line number
timeslot number
subslot number
E1 input module data model
======================================================================
enum e1inp_sign_type {
E1INP_SIGN_NONE,
E1INP_SIGN_OML,
E1INP_SIGN_RSL,
};
struct e1inp_sign_link {
/* list of signalling links */
struct llist_head list;
enum e1inp_sign_type type;
/* trx for msg->trx of received msgs */
struct gsm_bts_trx *trx;
/* msgb queue of to-be-transmitted msgs */
struct llist_head tx_list;
/* SAPI and TEI on the E1 TS */
uint8_t sapi;
uint8_t tei;
}
enum e1inp_ts_type {
E1INP_TS_TYPE_NONE,
E1INP_TS_TYPE_SIGN,
E1INP_TS_TYPE_TRAU,
};
/* A timeslot in the E1 interface */
struct e1inp_ts {
enum e1inp_ts_type type;
struct e1inp_line *line;
union {
struct {
struct llist_head sign_links;
} sign;
struct {
/* subchannel demuxer for frames from E1 */
struct subch_demux demux;
/* subchannel muxer for frames to E1 */
struct subch_mux mux;
} trau;
};
union {
struct {
/* mISDN driver has one fd for each ts */
struct osmo_fd;
} misdn;
} driver;
};
struct e1inp_line {
unsigned int num;
char *name;
struct e1inp_ts ts[NR_E1_TS];
char *e1inp_driver;
void *driver_data;
};
/* Call from the Stack: configuration of this TS has changed */
int e1inp_update_ts(struct e1inp_ts *ts);
/* Receive a packet from the E1 driver */
int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
uint8_t tei, uint8_t sapi);
/* Send a packet, callback function in the driver */
int e1driver_tx_ts(struct e1inp_ts *ts, struct msgb *msg)
struct e1inp_driver {
const char *name;
int (*want_write)(struct e1inp_ts *ts);
};

View File

@ -1,101 +0,0 @@
!
! OsmoBSC (0.9.14+gitr1+3d331c0062bb0c9694dbd4d1eab7adc58138c3ae) configuration saved from vty
!!
password foo
!
!
line vty
no login
!
e1_input
e1_line 0 driver ipa
network
network country code 1
mobile network code 1
short name OsmoBSC
long name OsmoBSC
auth policy closed
location updating reject cause 13
encryption a5 0
neci 1
paging any use tch 0
rrlp mode none
mm info 1
handover 0
handover window rxlev averaging 10
handover window rxqual averaging 1
handover window rxlev neighbor averaging 10
handover power budget interval 6
handover power budget hysteresis 3
handover maximum distance 9999
bts 0
type nanobts
band DCS1800
cell_identity 0
location_area_code 1
training_sequence_code 7
base_station_id_code 63
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator ascending
rach tx integer 9
rach max transmission 7
dtx uplink force
dtx downlink
ip.access unit_id 0 0
oml ip.access stream_id 255 line 0
neighbor-list mode manual-si5
neighbor-list add arfcn 100
neighbor-list add arfcn 200
si5 neighbor-list add arfcn 10
si5 neighbor-list add arfcn 20
gprs mode none
trx 0
rf_locked 0
arfcn 871
nominal power 23
max_power_red 20
rsl e1 tei 0
timeslot 0
phys_chan_config CCCH+SDCCH4
hopping enabled 0
timeslot 1
phys_chan_config TCH/F
hopping enabled 0
timeslot 2
phys_chan_config TCH/F
hopping enabled 0
timeslot 3
phys_chan_config TCH/F
hopping enabled 0
timeslot 4
phys_chan_config TCH/F
hopping enabled 0
timeslot 5
phys_chan_config TCH/F
hopping enabled 0
timeslot 6
phys_chan_config TCH/F
hopping enabled 0
timeslot 7
phys_chan_config TCH/F
hopping enabled 0
cs7 instance 1
point-code 3.0.0
sccp-address bsc_local
point-code 3.0.0
sccp-address msc_remote
point-code 1.0.0
msc
bsc-addr bsc_local
msc-addr msc_remote
ip.access rtp-base 4000
timeout-ping 20
timeout-pong 5
dest 192.168.100.11 6666 0
access-list-name msc-list
no access-list-name
bsc
no access-list-name
access-list-name bsc-list

View File

@ -1,19 +0,0 @@
!
! MGCP configuration hand edited
! !
password foo
!
line vty
no login
!
mgcp
!local ip 10.23.24.2
!bts ip 10.24.24.1
!bind ip 10.23.24.1
bind port 2427
rtp base 4000
rtp force-ptime 20
sdp audio payload number 98
sdp audio payload name AMR/8000
number endpoints 31
no rtcp-omit

View File

@ -1 +0,0 @@
678012512671923:6:6:

View File

@ -1,13 +0,0 @@
nat
bsc 0
token lol
location_area_code 1234
description bsc
max-endpoints 32
paging forbidden 0
bsc 1
token wat
location_area_code 5678
description bsc
max-endpoints 32
paging forbidden 0

View File

@ -1,66 +0,0 @@
!
! OsmoBSCNAT (0.12.0.266-2daa9) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging timestamp 0
logging level all debug
logging level rll notice
logging level cc notice
logging level mm notice
logging level rr notice
logging level rsl notice
logging level nm info
logging level mncc notice
logging level pag notice
logging level meas notice
logging level sccp notice
logging level msc notice
logging level mgcp notice
logging level ho notice
logging level db notice
logging level ref notice
logging level gprs debug
logging level ns info
logging level bssgp debug
logging level llc debug
logging level sndcp debug
logging level nat notice
logging level ctrl notice
logging level smpp debug
logging level lglobal notice
logging level llapd notice
logging level linp notice
logging level lmux notice
logging level lmi notice
logging level lmib notice
logging level lsms notice
!
line vty
no login
!
mgcp
bind ip 0.0.0.0
bind port 2427
rtp bts-base 4000
rtp net-base 16000
rtp ip-dscp 0
no rtcp-omit
sdp audio-payload number 126
sdp audio-payload name AMR/8000
loop 0
number endpoints 1
call-agent ip 127.0.0.1
rtp transcoder-base 0
transcoder-remote-base 4000
nat
msc ip 127.0.0.1
msc port 5000
timeout auth 2
timeout ping 20
timeout pong 5
ip-dscp 0
bscs-config-file bscs.cfg
access-list bla imsi-allow ^11$

View File

@ -1,19 +0,0 @@
!
! OsmoMSC configuration saved from vty
!
line vty
no login
!
network
network country code 1
mobile network code 1
short name OsmoMSC
long name OsmoMSC
auth policy closed
location updating reject cause 13
encryption a5 0
rrlp mode none
mm info 1
msc
mgcpgw remote-ip 10.23.24.1
assign-tmsi

View File

@ -1,54 +0,0 @@
according to GSM 05.02:
general parameters from CCCH:
* CA cell allocation of ARFCN's (System Information / BCCH)
* FN: TDMA frame number (t1,t2,t3') in SCH
specific parameters from channel assignment:
* MA: mobile allocation, defines set of ARFCN's, up to 64
* MAIO: index
* HSN: hopping sequence generator number (0..64)
hopping sequence generation (6.2.3):
uint8_t rntable[114] = {
48, 98, 63, 1, 36, 95, 78, 102, 94, 73,
0, 64, 25, 81, 76, 59, 124, 23, 104, 100,
101, 47, 118, 85, 18, 56, 96, 86, 54, 2,
80, 34, 127, 13, 6, 89, 57, 103, 12, 74,
55, 111, 75, 38, 109, 71, 112, 29, 11, 88,
87, 19, 3, 68, 110, 26, 33, 31, 8, 45,
82, 58, 40, 107, 32, 5, 106, 92, 62, 67,
77, 108, 122, 37, 60, 66, 121, 42, 51, 126,
117, 114, 4, 90, 43, 52, 53, 113, 120, 72,
16, 49, 7, 79, 119, 61, 22, 84, 9, 97,
125, 99, 17, 123
};
/* mai=0 represents lowest ARFCN in the MA */
uint8_t hopping_mai(uint8_t hsn, uint32_t fn, uint8_t maio,
uint8_t t1, uint8_t t2, uint8_t t3_)
{
uint8_t mai;
if (hsn == 0) /* cyclic hopping */
mai = (fn + maio) % n;
else {
uint32_t m, m_, t_, s;
m = t2 + rntable[(hsn xor (t1 % 64)) + t3];
m_ = m % (2^NBIN);
t_ = t3 % (2^NBIN);
if (m_ < n then)
s = m_;
else
s = (m_ + t_) % n;
mai = (s + maio) % n;
}
return mai;
}

View File

@ -1,89 +0,0 @@
Ideas about a handover algorithm
======================================================================
This is mostly based on the results presented in Chapter 8 of "Performance
Enhancements in a Frequency Hopping GSM Network" by Thomas Toftegaard Nielsen
and Joeroen Wigard.
=== Reasons for performing handover ===
Section 2.1.1: Handover used in their CAPACITY simulation:
1) Interference Handover
Average RXLEV is satisfactory high, but average RXQUAL too low indicates
interference to the channel. Handover should be made.
2) Bad Quality
Averaged RXQUAL is lower than a threshold
3) Low Level / Signal Strength
Average RXLEV is lower than a threshold
4) Distance Handover
MS is too far away from a cell (measured by TA)
5) Power budget / Better Cell
RX Level of neighbor cell is at least "HO Margin dB" dB better than the
current serving cell.
=== Ideal parameters for HO algorithm ===
Chapter 8, Section 2.2, Table 24:
Window RXLEV averaging: 10 SACCH frames (no weighting)
Window RXQUAL averaging: 1 SACCH frame (no averaging)
Level Threashold: 1 of the last 1 AV-RXLEV values < -110dBm
Quality Threshold: 3 of the last 4 AV-RXQUAL values >= 5
Interference Threshold: 1 of the last AV-RXLEV > -85 dBm &
3 of the last 4 AV-RXQUAL values >= 5
Power Budget: Level of neighbor cell > 3 dB better
Power Budget Interval: Every 6 SACCH frames (6 seconds ?!?)
Distance Handover: Disabled
Evaluation rule 1: RXLEV of the candidate cell a tleast -104 dBm
Evaluation rule 2: Level of candidate cell > 3dB better own cell
Timer Successful HO: 5 SACCH frames
Timer Unsuccessful HO: 1 SACCH frame
In a non-frequency hopping case, RXQUAL threshold can be decreased to
RXLEV >= 4
When frequency hopping is enabled, the following additional parameters
should be introduced:
* No intra-cell handover
* Use a HO Margin of 2dB
=== Handover Channel Reservation ===
In loaded network, each cell should reserve some channels for handovers,
rather than using all of them for new call establishment. This reduces the
need to drop calls due to failing handovers, at the expense of failing new call
attempts.
=== Dynamic HO Margin ===
The handover margin (hysteresis) should depend on the RXQUAL. Optimal results
were achieved with the following settings:
* RXQUAL <= 4: 9 dB
* RXQUAL == 5: 6 dB
* RXQUAL >= 6: 1 dB
== Actual Handover on a protocol level ==
After the BSC has decided a handover shall be done, it has to
# allocate a channel at the new BTS
# allocate a handover reference
# activate the channel on the BTS side using RSL CHANNEL ACTIVATION,
indicating the HO reference
# BTS responds with CHAN ACT ACK, including GSM frame number
# BSC sends 04.08 HO CMD to MS using old BTS

View File

@ -1,94 +0,0 @@
IPA SCCP message flow in the BSC
February, 2013 Holger Hans Peter Freyther
CONTENTS
1. SCCP inside the IPA header
2. Supported SCCP message types
3. Receiving SCCP messages
4. Sending SCCP messages
1. SCCP inside the IPA header
Many Soft-MSCs implement something that is called SCCP/lite. This means
that SCCP messages are transported inside a small multiplexing protocol
over TCP/IP. This is an alternative to a full SIGTRAN implementation.
The multiplexing protocol is the same as used with the sysmoBTS and the
ip.access nanoBTS. It is a three byte header with two bytes for the length
in network byte order and one byte for the type. The type to be used for
SCCP is 0xFD.
struct ipa_header {
uint16_t length_in_network_order;
uint8_t type;
} __attribute__((packed));
2. Supported SCCP message types
To implement GSM 08.08 only a subset of SCCP messages need to be implemented.
For transporting paging and reset messages SCCP UDT messages are used. For
the connections with a Mobile Station (MS) a SCCP connection is opened. This
means that the SCCP CR, SCCP CC, SCCP CREF, SCCP RLC, SCCP RLSD, SCCP DT1
and SCCP IT messages are supported.
3. Receiving SCCP UDT messages
This is an illustration of the flow of messages. The IPA multiplexing protocol
is used for various protocols. This means there is a central place where the
multiplexing stream terminates. The stream is terminated in the osmo_bsc_msc.c
file and the ipaccess_a_fd_cb method. For SCCP messages the SCCP dispatching
sccp_system_incoming method is called. This function is implemented in the
libosmo-sccp library.
To receive UDT messages osmo_bsc_sccp.c:osmo_bsc_sccp_init is using the
sccp_set_read function to register a callback for UDT messages. The callback
is msc_sccp_read and it is calling bsc_handle_udt that is implemented in the
osmo_bsc_bssap.c. This function will handle the GSM 08.08 BSSAP messages.
Currently only the reset acknowledge and the paging messages are handled.
The BSC currently does not accept incoming SCCP messages and is only opening
SCCP connections to the MSC. When opening a connection the callbacks for state
changes (connection confirmed, released, release complete) are set and a routine
for handling incoming data. This registration is done in the osmo_bsc_sccp.c
file and the bsc_create_new_connection method. The name of the callback is
msc_outgoing_sccp_data and this will call bsc_handle_dt1 that is implemented
in the osmo_bsc_bssap.c file. This will forward the messages to the right
Mobile Station (MS).
4. Sending SCCP messages
There are three parts to sending that will be explained below. The first part
is to send an entire SCCP frame (which includes the GSM 08.08 data) to the
MSC. This is done by first registering the low level sending. sccp_system_init
is called with the function that is responsible for sending a message. The
msc_sccp_write_ipa will call the msc_queue_write function with the data and
the right MSC connection. Below the msc_queue_write the IPA header will be
prepended to the msg and then send to the MSC.
The BSC supports multiple different A-link connections, the decision to pick
the right MSC is done in this method. It is either done via the SCCP connection
or the ctx pointer.
When the BSC is starting a BSS RESET message will be sent to the MSC. The reset
is created in osmo_bsc_msc.c:initialize_if_needed and sccp_write is called with
the GSM 08.08 data and the connection to use. The libosmo-sccp library will
embed it into a SCCP UDT message and call the msc_sccp_write_ipa method.
When a new SCCP connection is to be created the bsc_create_new_connection
in the osmo_bsc_sccp.c file. The sccp_connection_socket method will create
the context for a SCCP connection. The state and data callback will be used
to be notified about data and changes. Once the connection is configured the
bsc_open_connection will be called that will ask the libosmo-sccp library to
create a SCCP CR message using the sccp_connection_connect method. For active
connections the sccp_connection_write method will be called.

View File

@ -1,22 +0,0 @@
oml interface design notes
problems:
* there is no way how to tag a command sent to the BTS, with the response
having the same tag to identify the originator of the command
* therefore, we can have e.g. both the BSC and the OML interface send a
SET ATTRIBUTE message, where the responses would end up at the wrong
query.
* The BTS has 10s to ACK/NACK a command. We do not run any timers.
the only possible solutions i can imagine:
* have some kind of exclusive locking, where the OML interface gets blocked
from the BSC and is exclusively assigned to the OML console until all commands
of the OML console have terminated. This can either be done explicitly
dynamically or on demand
* use the OML interface synchronously, i.e. always wait for the response from
the BTS before
* unilateral / unsolicited messages need to be broadcasted to both the BSC and
the OML console

View File

@ -1,33 +0,0 @@
digraph G {
net [label="gsm_network"]
bts [label="gsm_bts"]
trx [label="gsm_bts_trx"]
ts [label="gsm_bts_trx_ts"]
lchan [label="gsm_lchan"]
sub [label="gsm_subscriber"]
subcon [label="gsm_subscriber_conn"]
sccpcon [label="osmo_bsc_sccp_con"]
subgrp [label="gsm_subscriber_group"]
net -> bts
bts -> trx
trx -> ts
ts -> lchan
lchan -> ts
ts -> trx
trx -> bts
bts -> net
lchan -> subcon
subcon -> sub
subcon -> sccpcon
subcon -> lchan
subcon -> lchan [label="ho_lchan"]
subcon -> bts
subcon -> lchan [label="secondary_lchan"]
sub -> subgrp
subgrp -> net
}

View File

@ -1,48 +0,0 @@
GSM Paging implementation in OpenBSC
== Code structure ==
The code is implemented in the libbsc/paging.c file. The external
interface is documented/specified in the include/openbsc/paging.h
header file. The code is used by the NITB and BSC application.
== Implementation ==
Paging can be initiated in two ways. The standard way is to page by
LAC. Each BTS has its own list/queue of outstanding paging operation.
When a subscriber is paged one "struct paging_request" per BTS will
be allocated and added to the tail of the list. The BTS is supposed
to be configured to not repeat the paging.
A paging_request will remain in the queue until a paging response or at
the expiry of the T3113. Every 500 milliseconds a RSL paging command is
send to the BTS. The 500 milliseconds is a throttling to not crash the
ip.access nanoBTS. Once one paging_request has been handled it will be
put at the end of the queue/list and the available slots for the BTS
will be decreased.
The available slots will be updated based on the paging load information
element of the CCCH Load indication. If no paging slots are considered
to be available and no load indication is sent a timer is started. The
current timeout is 500 milliseconds and at the expiry of the timer the
available slots will be set to 20.
OpenBSC has the " paging free <-1-1024>" configuration option. In case
there are less free channels than required no paging request will be
sent to the BTS. Instead it will be attempted to send the paging request
at the next timeout (500 milliseconds).
== Limitation ==
The paging throughput could be higher but this has lead to crashes on the
ip.access nanoBTS in the past.
== Configuration ==
=== ip.access nanoBTS ===
The current CCCH Load indication threshold is 10% and the period is 1 second.
The code can be found inside the src/libbsc/bts_ipaccess_nanobts.c inside the
nanobts_attr_bts array.

View File

@ -1,73 +0,0 @@
#!/usr/bin/perl
use strict;
use DBI;
my $dbh = DBI->connect("dbi:SQLite:dbname=hlr.sqlite3","","");
my %mcc_names;
my %mcc_mnc_names;
sub get_mcc_mnc_name($)
{
my $mcc_mnc = shift;
my $ret = $mcc_mnc;
if ($mcc_mnc_names{$mcc_mnc} ne '') {
$ret = $mcc_mnc_names{$mcc_mnc};
}
return $ret;
}
sub read_networks($)
{
my $filename = shift;
my $cur_name;
open(INFILE, $filename);
while (my $l = <INFILE>) {
chomp($l);
if ($l =~ /^#/) {
next;
}
if ($l =~ /^\t/) {
my ($mcc, $mnc, $brand, $r) = split(' ', $l, 4);
#printf("%s|%s|%s\n", $mcc, $mnc, $brand);
$mcc_mnc_names{"$mcc-$mnc"} = $brand;
$mcc_names{$mcc} = $cur_name;
} elsif ($l =~ /^(\w\w)\t(.*)/) {
#printf("%s|%s\n", $1, $2);
$cur_name = $2;
}
}
close(INFILE);
}
read_networks("networks.tab");
my %oper_count;
my %country_count;
#my $sth = $dbh->prepare("SELECT imsi FROM subscriber where authorized=1");
my $sth = $dbh->prepare("SELECT imsi FROM subscriber");
$sth->execute();
while (my $href = $sth->fetchrow_hashref) {
my ($mcc, $mnc) = $$href{imsi} =~ /(\d{3})(\d{2}).*/;
#printf("%s %s-%s \n", $$href{imsi}, $mcc, $mnc);
$oper_count{"$mcc-$mnc"}++;
$country_count{$mcc}++;
}
foreach my $c (sort{$country_count{$b} <=> $country_count{$a}} keys %country_count) {
printf("%s: %d\n", $mcc_names{$c}, $country_count{$c});
foreach my $k (sort{$oper_count{$b} <=> $oper_count{$a}} keys %oper_count) {
if ($k =~ /^$c-/) {
printf("\t%s: %d\n", get_mcc_mnc_name($k), $oper_count{$k});
}
}
}