26 Commits
0.1.0 ... 0.2.0

Author SHA1 Message Date
Harald Welte
fa4826bfa6 Bump version: 0.1.0.25-287a → 0.2.0
Change-Id: I01298571913ea29cb98b58cdc0b1f92352622585
2021-01-24 16:15:50 +01:00
Harald Welte
287a6aaeb0 osmo-cbc.spec: License is AGPLv3-or-later + MIT
Change-Id: Id193997a2883189a2f3451203523a901f9f64fd4
2021-01-24 16:06:54 +01:00
Harald Welte
557fcbc110 contrib/osmo-cbc.spec: Add sub-package osmo-cbc-utils
This sub-package contains cbc-apitool.py

Change-Id: Id1ba3a26f3b40a42c69c61e844f00f2ddc70941b
2021-01-24 16:05:02 +01:00
Harald Welte
bc80894f0e debian: Package cbc-apitool.py as a sub-package
We don't want osmo-cbc to depend on python3 at runtime, so let's use
a sub-package for osmo-cbc-apitool.py

Change-Id: Id16613811993a2baa06ebc2da6c6591ace70a3f9
2021-01-24 15:54:43 +01:00
Harald Welte
2b158c3b2d manual: Document cbc-apitool.py
Change-Id: I2a65e7a582c8bb72d80731fb6e77a796ae4f9b4c
2021-01-24 15:54:43 +01:00
Harald Welte
071a60e465 manual: Add dotty graph on position of CBC in network
Change-Id: I0216ebb34b2efc218628341495d026bf4ec0f026
2021-01-24 15:54:43 +01:00
Harald Welte
24507ffd0d manual: Document ECBE; include JSON schema; cross-references
Change-Id: I358f72331aa9832cc56c67396eb41b62307a3258
2021-01-24 15:54:43 +01:00
Harald Welte
6467dfdb9c Makefile.am: add *.json to EXTRA_DIST
Otherwise the source tarballs would not contain the json schema

Change-Id: I1a3685bcff0e50a644e904c221d7d285f6215da1
2021-01-24 15:54:40 +01:00
Harald Welte
f80d53068a Makefile.am: cosmetic changes
Change-Id: Ib667fcf37413d15cd9b1cf53931e3360214b049e
2021-01-24 15:02:29 +01:00
Harald Welte
367cdb3697 cbc-apitool: Fix parsing if no argument is goven
Change-Id: I3abd7a22dc5df2bf7c926fb0e1ba09e60628f55d
2021-01-24 14:05:47 +01:00
Harald Welte
8e1093e244 terminate if CBSP or ECBE ports cannot be bound
Change-Id: I748648a0bd5a06da26cddc34ff0d9b6000e71370
2021-01-24 14:05:47 +01:00
Harald Welte
78fd4efa81 Make ECBE (REST interface) local bind IP + port VTY-configurable
Change-Id: I656d0d1c7b21db90b62e71109d9844476a2e3215
2021-01-24 14:05:47 +01:00
Harald Welte
5180d5ffae Make CBSP local bind IP+port VTY-configurable
Change-Id: I9ba3f4cf129d6df4468defc92697f1df62348719
2021-01-24 12:11:22 +01:00
Harald Welte
51977c72f3 vty: Allow IPv6 address for peer remote-ip
Change-Id: Iafb2da2357b09c6e2c9a5199c947358650cced18
2021-01-24 11:21:16 +01:00
Harald Welte
b8b77e77e4 manual: Chapters on configuration + vty introspection
Change-Id: I9af54ffc6f967702e8f66265dc15b35bbc173c4b
2021-01-24 11:16:43 +01:00
Harald Welte
51657edefd osmo-cbc.spec: No AUTHORS file; correct name of README.md
Change-Id: Ia53e6d1fe785e6bfc92f305963cf06b760f30edd
2021-01-24 00:10:15 +01:00
Harald Welte
7e00b941b8 osmo-cbc.spec: Don't depend on libosmo-mgcp-client
The CBC has nothing to do with MGCP

Change-Id: Ie2f1f67d8141b2437e723fb27e1d1c3225156a91
2021-01-24 00:09:20 +01:00
Harald Welte
8b596fecb1 cbc-apitool.py: Generalize, make parameters configurable
Do away with most of the hard-coded defaults and allow user to specify
a variety of parameters via the command line.  Also, start to use
argparse subparsers for better usability

Change-Id: Ib7b8121676bef9310f219affc6f3cc76b6986b2a
2021-01-23 23:48:04 +01:00
Harald Welte
f1afe95754 spec file: Add missing libulfius dependency
Change-Id: I2ebef5f5e2d749af094d31cac493dcb5ac2d7866
2021-01-23 21:54:18 +01:00
Harald Welte
f97cd9672d charset: Fix padding of USSD messages in 7bit GSM alphabet
USSD messages are sent in pages of 82 bytes, and there is no way to
indicate a shorter payload length inside the page.  Hence, we always
must pad up to the end of the page, using <CR> characters.

Change-Id: I9950431e920579e6c3a0d12348573f51d21739ec
2021-01-23 21:54:17 +01:00
Harald Welte
1d78b2e73d debian/osmo-cbc.install: Fix typo (extra apostrophe at EOL)
Change-Id: Iebd5e3ca1e3c1f998c112f9c5f5fdcf5e0d24f35
2021-01-23 14:56:53 +01:00
Harald Welte
e88eceb790 Add README.md file
Change-Id: Ib2a019290a80d67e26875d972f6a8ee700f73bb6
2021-01-22 20:15:30 +01:00
Harald Welte
d1c50f54cd Add RPM spec file
Change-Id: I79e04228e8034e0d50a44f54c36363074fc01995
2021-01-22 20:15:30 +01:00
Harald Welte
5bf735efc9 Add simplistic cbc-apitool.py as example on how to use the REST API
Change-Id: I6cbc30a3f8bf833fea785437488aed8b8af2fcbc
2021-01-22 20:15:30 +01:00
Harald Welte
eaee3e30b1 add link to upstream bug related to custom malloc/free
Change-Id: If58d307bbdade5d4d7c5e39ada8c14c052d215a9
2021-01-14 18:11:00 +00:00
Oliver Smith
55956f4512 contrib/jenkins: don't build osmo-gsm-manuals
Related: OS#4912
Change-Id: Ide27f522e0979f9f7b41cd073d5451fa60ab125f
2021-01-13 13:12:58 +01:00
27 changed files with 913 additions and 44 deletions

2
.gitignore vendored
View File

@@ -58,3 +58,5 @@ doc/manuals/osmobsc-usermanual.xml
doc/manuals/common
doc/manuals/build
doc/manuals/vty/cbc_vty_reference.xml
contrib/osmo-cbc.spec

View File

@@ -3,7 +3,13 @@ AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
SUBDIRS = src doc contrib tests
EXTRA_DIST = .version git-version-gen
EXTRA_DIST = .version \
README.md \
git-version-gen \
contrib/osmo-cbc.spec.in \
cbc.schema.json \
smscb.schema.json \
$(NULL)
AM_DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)

69
README.md Normal file
View File

@@ -0,0 +1,69 @@
osmo-cbc - Osmocom Cell Broadcast Centre
========================================
This repository contains a C-language implementation of a minimal
3GPP Cell Broadcast Centre (CBC). It is part of the
[Osmocom](https://osmocom.org/) Open Source Mobile Communications
project.
A Cell Broadcast Centre is the central network element of a cellular network
for distribution of Cell Broadcast and Emergency messages.
This code implements
* the CBSP protocol on the CBC-BSC interface
* a custom HTTP/REST based interface for external users to create/delete CBS messages
We plan to add support for the following features in the future:
* the SABP protocol on the CBC-RNC (or CBC-HNBGW) interface for UMTS support
* the SBcAP protocol on the CBC-MME interface for LTE support
Homepage
--------
The official homepage of the project is
https://osmocom.org/projects/osmo-cbc/wiki
GIT Repository
--------------
You can clone from the official osmo-cbc.git repository using
git clone https://git.osmocom.org/osmo-cbc.git
There is a cgit interface at https://git.osmocom.org/osmo-cbc/
Documentation
-------------
User Manuals and VTY reference manuals are [optionally] built in PDF form
as part of the build process.
Pre-rendered PDF version of the current "master" can be found at
[User Manual](https://ftp.osmocom.org/docs/latest/osmocbc-usermanual.pdf)
as well as the [VTY Reference Manual for osmo-cbc](https://ftp.osmocom.org/docs/latest/osmocbc-vty-reference.pdf)
Mailing List
------------
Discussions related to osmo-cbc are happening on the
openbsc@lists.osmocom.org mailing list, please see
https://lists.osmocom.org/mailman/listinfo/openbsc for subscription
options and the list archive.
Please observe the [Osmocom Mailing List
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
when posting.
Contributing
------------
Our coding standards are described at
https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards
We us a gerrit based patch submission/review process for managing
contributions. Please see
https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit for
more details
The current patch queue for osmo-cbc can be seen at
https://gerrit.osmocom.org/#/q/project:osmo-cbc+status:open

View File

@@ -168,6 +168,7 @@ AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
AC_OUTPUT(
src/Makefile
contrib/Makefile
contrib/osmo-cbc.spec
tests/Makefile
doc/Makefile
doc/examples/Makefile

View File

@@ -1 +1,4 @@
SUBDIRS = systemd
EXTRA_DIST = cbc-apitool.py \
$(NULL)

157
contrib/cbc-apitool.py Executable file
View File

@@ -0,0 +1,157 @@
#!/usr/bin/env python3
#
# (C) 2020-2021 by Harald Welte <laforge@osmocom.org>
#
# SPDX-License-Identifier: MIT
#
# This is a simplistic program to show how the REST API of osmo-cbc can be used to
# create and delete Cell Broadcast Messages
#
# A lot of the parameters are currently hard-coded, see the 'js' variable definitions
# below.
import sys
import argparse
import requests
def build_url(suffix):
BASE_PATH= "/api/ecbe/v1"
return "http://%s:%u%s%s" % (server_host, server_port, BASE_PATH, suffix)
def rest_post(suffix, js = None):
url = build_url(suffix)
if verbose:
print("POST %s (%s)" % (url, str(js)))
resp = requests.post(url, json=js)
if verbose:
print("-> %s" % (resp))
if not resp.ok:
print("POST failed")
return resp
def rest_delete(suffix, js = None):
url = build_url(suffix)
if verbose:
print("DELETE %s (%s)" % (url, str(js)))
resp = requests.delete(url, json=js)
if verbose:
print("-> %s" % (resp))
if not resp.ok:
print("DELETE failed " + str(resp))
return resp
def do_create_cbs(args):
js = {
'cbe_name': "cbc_apitool",
'category': "normal",
'repetition_period': args.repetition_period,
'num_of_bcast': args.num_of_bcast,
'scope': {
'scope_plmn': { }
},
'smscb_message': {
'message_id': args.msg_id,
'serial_nr': {
'serial_nr_decoded': {
'geo_scope': "plmn_wide",
'msg_code': args.msg_code,
'update_nr': args.update_nr
}
},
'payload': {
'payload_decoded': {
'character_set': "gsm",
#'language': 'en',
'data_utf8': args.payload_data_utf8,
#'data_utf8': "Mahlzeit1 Mahlzeit2 Mahlzeit3 Mahlzeit4 Mahlzeit5 Mahlzeit6 Mahlzeit7 Mahlzeit8"
#'data_utf8': "Mahlzeit1 Mahlzeit2 Mahlzeit3 Mahlzeit4 Mahlzeit5 Mahlzeit6 Mahlzeit7 Mahlzeit8 Mahlzeit9 Mahlzeit10 Mahlzeti11 Mahlzeit12 Mahlzeit13 Mahlzeit14 Mahlzeit15 Mahlzeit16 Mahlzeit17 Mahlzeit18 Mahlzeit19 Mahlzeit20 Mahlzeit21 Mahlzeit22 Mahlzeit23 Mahlzeit24 Mahlzeit25 Mahlzeit26 Mahlzeit27 Mahlzeit28"
}
}
}
}
rest_post("/message", js);
def do_create_etws(args):
js = {
'cbe_name': "cbc_apitool",
'category': "normal",
'repetition_period': args.repetition_period,
'num_of_bcast': args.num_of_bcast,
'scope': {
'scope_plmn': { }
},
'smscb_message': {
'message_id': args.msg_id,
'serial_nr': {
'serial_nr_decoded': {
'geo_scope': "plmn_wide",
'msg_code': args.msg_code,
'update_nr': args.update_nr
}
},
'payload': {
'payload_etws': {
'warning_type': {
'warning_type_decoded': 'earthquake'
},
'emergency_user_alert': True,
'popup_on_display': True
}
}
}
}
rest_post("/message", js);
def do_delete(args):
rest_delete("/message/%u" % (args.msg_id))
def main(argv):
global server_port, server_host, verbose
parser = argparse.ArgumentParser()
parser.add_argument("-H", "--host", help="Host to connect to", default="localhost")
parser.add_argument("-p", "--port", help="TCP port to connect to", default=12345)
parser.add_argument("-v", "--verbose", help="increase output verbosity", action='count', default=0)
subparsers = parser.add_subparsers(required=True)
parser_c_cbs = subparsers.add_parser('create-cbs', help='Create a new CBS message')
parser_c_cbs.add_argument("--msg-id", type=int, help='Message Identifier', required=True)
parser_c_cbs.add_argument("--msg-code", type=int, help='Message Code', default=768)
parser_c_cbs.add_argument("--update-nr", type=int, help='Update Number', default=0)
parser_c_cbs.add_argument("--repetition-period", type=int, help='Repetition Period', default=5)
parser_c_cbs.add_argument("--num-of-bcast", type=int, help='Number of Broadcasts', default=999)
parser_c_cbs.add_argument("--payload-data-utf8", type=str, help='Payload Data in UTF8', required=True)
parser_c_cbs.set_defaults(func=do_create_cbs)
parser_c_etws = subparsers.add_parser('create-etws', help='Create a new ETWS message')
parser_c_etws.add_argument("--msg-id", type=int, help='Message Identifier', required=True)
parser_c_etws.add_argument("--msg-code", type=int, help='Message Code', default=768)
parser_c_etws.add_argument("--update-nr", type=int, help='Update Number', default=0)
parser_c_etws.add_argument("--repetition-period", type=int, help='Repetition Period', default=5)
parser_c_etws.add_argument("--num-of-bcast", type=int, help='Number of Broadcasts', default=999)
parser_c_etws.set_defaults(func=do_create_etws)
parser_delete = subparsers.add_parser('delete', help='Delete a message')
parser_delete.add_argument("--msg-id", type=int, help='Message Identifier', required=True)
parser_delete.set_defaults(func=do_delete)
argv = sys.argv
if len(sys.argv) == 1:
args = parser.parse_args(['-h'])
else:
args = parser.parse_args()
server_host = args.host
server_port = args.port
verbose = args.verbose
args.func(args)
if __name__ == "__main__":
main(sys.argv)

View File

@@ -36,7 +36,6 @@ osmo-build-dep.sh libosmo-netif "" --disable-doxygen
# Additional configure options and depends
CONFIG=""
if [ "$WITH_MANUALS" = "1" ]; then
osmo-build-dep.sh osmo-gsm-manuals
CONFIG="--enable-manuals"
fi

104
contrib/osmo-cbc.spec.in Normal file
View File

@@ -0,0 +1,104 @@
#
# spec file for package osmo-cbc
#
# Copyright (c) 2021, Harald Welte <laforge@gnumonks.org>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
## Disable LTO for now since it breaks compilation of the tests
## https://osmocom.org/issues/4113
%define _lto_cflags %{nil}
Name: osmo-cbc
Version: @VERSION@
Release: 0
Summary: OsmoCBC: Osmocom's Cell Broadcast Centre for 3GPP mobile networks
License: AGPL-3.0-or-later
Group: Hardware/Mobile
URL: https://osmocom.org/projects/osmo-cbc
Source: %{name}-%{version}.tar.xz
BuildRequires: automake >= 1.9
BuildRequires: libtool >= 2
BuildRequires: pkgconfig >= 0.20
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libcrypto) >= 0.9.5
BuildRequires: pkgconfig(libosmo-netif) >= 0.6.0
BuildRequires: pkgconfig(libosmo-sccp) >= 0.10.0
BuildRequires: pkgconfig(libosmo-sigtran) >= 0.10.0
BuildRequires: pkgconfig(libosmoabis) >= 0.6.0
BuildRequires: pkgconfig(libosmocore) >= 1.2.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.2.0
BuildRequires: pkgconfig(libosmogb)
BuildRequires: pkgconfig(libosmogsm) >= 1.2.0
BuildRequires: pkgconfig(libosmovty) >= 1.2.0
BuildRequires: pkgconfig(talloc)
BuildRequires: pkgconfig(libulfius)
%{?systemd_requires}
%description
OsmoCBC: Osmocom's Cell Broadcast Centre for 3GPP mobile networks.
%package utils
Summary: CLI utility to interface osmo-cbc REST interface
License: MIT
Group: Productivity/Telephony/Utilities
%description utils
CLI utility to interface with the osmo-cbc REST interface (ECBE).
%prep
%setup -q
%build
echo "%{version}" >.tarball-version
autoreconf -fi
%configure \
--docdir=%{_docdir}/%{name} \
--with-systemdsystemunitdir=%{_unitdir}
make %{?_smp_mflags}
%install
%make_install
install -m 755 contrib/cbc-apitool.py %{buildroot}/usr/bin/cbc-apitool.py
%if 0%{?suse_version}
%preun
%service_del_preun %{name}.service
%postun
%service_del_postun %{name}.service
%pre
%service_add_pre %{name}.service
%post
%service_add_post %{name}.service
%endif
%check
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%files
%license COPYING
%doc README.md
%{_bindir}/osmo-cbc
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-cbc
%{_docdir}/%{name}/examples/osmo-cbc/osmo-cbc*.cfg
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-cbc.cfg
%{_unitdir}/%{name}.service
%files utils
%{_bindir}/cbc-apitool.py
%changelog

32
debian/changelog vendored
View File

@@ -1,5 +1,33 @@
osmo-cbc (0.1) UNRELEASED; urgency=medium
osmo-cbc (0.2.0) unstable; urgency=medium
[ Harald Welte ]
* Initial release.
* add link to upstream bug related to custom malloc/free
* Add simplistic cbc-apitool.py as example on how to use the REST API
* Add RPM spec file
* Add README.md file
* debian/osmo-cbc.install: Fix typo (extra apostrophe at EOL)
* charset: Fix padding of USSD messages in 7bit GSM alphabet
* spec file: Add missing libulfius dependency
* cbc-apitool.py: Generalize, make parameters configurable
* osmo-cbc.spec: Don't depend on libosmo-mgcp-client
* osmo-cbc.spec: No AUTHORS file; correct name of README.md
* manual: Chapters on configuration + vty introspection
* vty: Allow IPv6 address for peer remote-ip
* Make CBSP local bind IP+port VTY-configurable
* Make ECBE (REST interface) local bind IP + port VTY-configurable
* terminate if CBSP or ECBE ports cannot be bound
* cbc-apitool: Fix parsing if no argument is goven
* Makefile.am: cosmetic changes
* Makefile.am: add *.json to EXTRA_DIST
* manual: Document ECBE; include JSON schema; cross-references
* manual: Add dotty graph on position of CBC in network
* manual: Document cbc-apitool.py
* debian: Package cbc-apitool.py as a sub-package
* contrib/osmo-cbc.spec: Add sub-package osmo-cbc-utils
* osmo-cbc.spec: License is AGPLv3-or-later + MIT
-- Harald Welte <lafore@gnumonks.org> Wed, 06 Jan 2021 12:13:12 +0100
[ Oliver Smith ]
* contrib/jenkins: don't build osmo-gsm-manuals
-- Harald Welte <laforge@osmocom.org> Sun, 24 Jan 2021 16:15:49 +0100

6
debian/control vendored
View File

@@ -27,6 +27,12 @@ Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: OsmoCBC: Osmocom's Cell Broadcast Center
Package: osmo-cbc-utils
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}, python3
Description: Utilities for OsmoCBC: Osmocom's Cell Broadcast Center
Package: osmo-cbc-dbg
Section: debug
Architecture: any

1
debian/osmo-cbc-utils.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/bin/cbc-apitool.py

View File

@@ -1,4 +1,4 @@
/etc/osmocom/osmo-cbc.cfg
lib/systemd/system/osmo-cbc.service
usr/bin/osmo-cbc
usr/share/doc/osmo-cbc/examples/osmo-cbc/*.cfg usr/share/doc/osmo-bsc/examples`
usr/share/doc/osmo-cbc/examples/osmo-cbc/*.cfg usr/share/doc/osmo-bsc/examples

5
debian/rules vendored
View File

@@ -50,8 +50,9 @@ override_dh_auto_configure:
dh_auto_configure -- $(CONFIGURE_FLAGS)
#
# Do not install libtool archive, python .pyc .pyo
#override_dh_install:
# dh_install --list-missing -X.la -X.pyc -X.pyo
override_dh_install:
install -m 755 contrib/cbc-apitool.py debian/tmp/usr/bin/cbc-apitool.py
dh_install
# See https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#bpp-dbg
override_dh_strip:

View File

@@ -3,6 +3,7 @@ EXTRA_DIST = osmocbc-usermanual.adoc \
osmocbc-vty-reference.xml \
regen_doc.sh \
chapters \
images \
vty
if BUILD_MANUALS

View File

@@ -0,0 +1,79 @@
[[apitool]]
== `cbc-apitool.py`
`cbc-apitool.py` is a very simple/basic python3 script that can be used
to demonstrate the use of the ECBE REST interface (<<ecbe>>) from the
command line.
It uses the python3 standard librariy `requests` in order to issue ECBE
API request over HTTP towards osmo-cbc.
`cbc-apitool.py` has a couple of sub-commands, each of which offer
=== Common options
*-h, --help*::
Print a short help message about the supported common options.
*-H, --host HOST*::
Remote host name/IP to which to connect (typically your ECBE
bind address of osmo-cbc). Default: 127.0.0.1.
*-p, --port PORT*::
Remote TCP port number to which to connect (typically your ECBE
bind address of osmo-cbc). Default: 12345
*-v, --verbose*::
Print some more verbose information like the HTTP requests
and responses during execution.
=== `create-cbs`: Creating a new CBS message
You can create a new CBS message using `cbc-apitool create-cbs`.
==== `create-cbs` Options
*-h, --help*::
Print a short help message about the supported create-cbs options.
*--msg-id MSG_ID*::
Specify the message ID of the to-be-created CBS
message. Range: 0..65535
*--msg-code MSG_CODE*::
Specify the message code (part of the serial number). Range:
0..1023. Default: 768
*--update-nr UPDATE_NR*::
Specify the update number (part of the serial number). Range:
0..15. Default: 0
*--repetition-period REPETITION_PERIOD*::
How frequently this message shall be repeated (in number of CBCH
slots). Default: 5
*--num-of-bcast NUM_OF_BCAST*::
Number of times this message shall be broadcast (Default: 999).
*--payload-data-utf8 PAYLOAD_DATA_UTF8*::
Payload data (typically text message) in UTF8 encoding. Will be
transcoded to 7bit GSM alphabet internally.
==== `create-etws` Options
*-h, --help*::
Print a short help message about the supported create-cbs options.
*--msg-id MSG_ID*::
Specify the message ID of the to-be-created CBS
message. Range: 0..65535
*--msg-code MSG_CODE*::
Specify the message code (part of the serial number). Range:
0..1023. Default: 768
*--update-nr UPDATE_NR*::
Specify the update number (part of the serial number). Range:
0..15. Default: 0
*--repetition-period REPETITION_PERIOD*::
How frequently this message shall be repeated (in number of CBCH
slots). Default: 5
*--num-of-bcast NUM_OF_BCAST*::
Number of times this message shall be broadcast (Default: 999).
==== `delete` Options
*--msg-id MSG_ID*::
Specify the message ID of the to-be-created CBS
message. Range: 0..65535

View File

@@ -0,0 +1,83 @@
[[configuration]]
== Configuration
=== CBSP / Peer Configuration
CBSP is the BSC-CBC interface within the 3GPP architecture. It serves
to communicate CSB and ETWS messages from the CBC to the BSC, who then
subsequently distributes it among the (matching) cells within the BSC
coverage area.
[[config-cbsp]]
==== Configuring the CBSP connections
According to 3GPP TS 48.049, a BSC typically operates as a TCP server,
and the CBC connects as TCP client. This would require the CBC to have
out-of-band knowledge of all the BSCs in the network (and their IP
addresses).
In order to comply with the specifications, OsmoCBC supports this mode
of operation as CBSP TCP client. However, to make network operation and
configuration more simple, it also can operate in TCP server mode,
accepting incoming connections from the BSCs. This way the BSCs need to
know the CBC IP address, but not vice-versa.
The CBC related configuration of OsmoBSC can be found in the `cbc` configuration
node of the VTY interface.
The default port number for the CBSP server is 48049, according to the CBSP
specification.
.Example: Configure TCP server mode and allow arbitrary BSCs to connect
----
cbc
unknown-peers accept
----
.Example: Configure TCP client mode and define each BSC
----
cbc
peer my-bsc-1
protocol cbsp
remote-port 46133
remote-ip 1.2.3.4
peer my-bsc-2
remote-port 46133
remote-ip 1.2.3.4
----
For more details on the available configuration commands, please check the OsmoCBC VTY Reference.
==== Configuring the IP/Port for CBSP to bind to
It can be configure to which IP and TCP port the CBSP protocol binds to.
The default is to bind to the 3GPP standard port number 48049 for CBSP at the
loopback IP address 127.0.0.1.
.Example: Configure CBSP to bind to 127.0.0.1:48049
----
cbc
cbsp
local-ip 127.0.0.1
local-port 48049
----
[[config-ecbe]]
=== ECBE (REST Interface) Configuration
==== Configuring the IP/Port for ECBE to bind to
It can be configure to which IP and TCP port the ECBE REST Interface binds to.
The default is to bind to is the non-standard port number 12349 at the
loopback IP address 127.0.0.1.
.Example: Configure ECBE REST interface to bind to 127.0.0.1:8080
----
cbc
ecbe
local-ip 127.0.0.1
local-port 8080
----

View File

@@ -0,0 +1,49 @@
[[ecbe]]
== ECBE REST interface
The ECBE (External Cell Broadcast Entity) REST interface is specified in
the JSON schema files `cbc.schema.json` and `smscb.schema.json`, which
are part of the OsmoCBC distribution.
The REST interface binds to the IP and TCP port as configured and
can be reached at `http://IP:PORT/api/ecbe/v1`
NOTE:: It is your responsibility to properly secure access to the REST
interface endpoint to ensure only legitimate users can access it. This
may be achieved via packet filtering and a reverse HTTP proxy.
=== API endpoints
==== `POST /api/ecbe/v1/message`
This command is used to create a new SMSCB or ETWS message inside the CBC.
The `cbc_messsage` type as specified in the JSON schema (<<ecbe-json>>).
==== `DELETE /api/ecbe/v1/message/:message_id`
This command is used to delete an existing SMSCB or ETWS message from the CBC.
The `:message_id` parameter is the decimal integer representation of the
cbc_message.smscb.message_id that was specified when creating the
message via the POST command stated above.
[[ecbe-json]]
=== JSON Schema
==== `cbc.schema.json`
This is the main JSOM schema for osmo-cbc. In many places, it
references `smscb.schema.json` described further below.
----
include::{srcdir}/../../cbc.schema.json[]
----
==== `smscb.schema.json`
This JSON schema describes a lot of the basic data types relevant for
SMSCB. It is used heavily by `cbc.schema.json` described above.
----
include::{srcdir}/../../smscb.schema.json[]
----

View File

@@ -0,0 +1,91 @@
== Introspection using the VTY
OsmoCBC offers a VTY interface on TCP port 4264. Like all Osmocom VTY interfaces,
it is normally bound only to the loopback address 127.0.0.1. You can change this
via the configuration.
The actual IP/Port is printed to the log at startup time:
----
20210124110559489 DLGLOBAL NOTICE Available via telnet 127.0.0.1 4264 (telnet_interface.c:104)
----
=== Peer State
Using the `show peers` command, you can check on the state of all configured and/or connected
peers:
.Example: Showing a list of all peers
----
OsmoCBC> show peers
|Name | IP | Port | Proto | State |
|--------------------|----------------|------|-------|---------------------|
|ttcn3 | 127.0.0.1 | 9999 | CBSP | <disconnected> |
|local-bsc | 127.0.0.1 | 46133| CBSP | IDLE |
----
=== CBS Messages
Using `show messages cbs`, a list of all current CBS messages can be obtained.
.Example: Showing a list of all CBS messages
----
OsmoCBC> show messages cbs
|MsgId|SerNo| CBE Name | Category |Period|E|DCS|
|-----|-----|--------------------|-------------|------|-|---|
| 04D2| 7000|cbc_apitool |Normal | 5 |N| 0f|
----
Using `show message 1234`, details about a specific CBS message can be obtained:
.Example: Showing details about a single CBS message
----
OsmoCBC> show message id 1234
Message ID 04D2, Serial Number 7000, State: ACTIVE
Created by CBE 'cbc_apitool' at Sun Jan 24 11:10:31 2021
Repetition Period: 5 ( 9.41s), Number of broadcasts: 999
Warning Period: 4294967295s
DCS: 0x0f, Number of pages: 1, User Data Bytes: 7
Page 0: cd309aad2fa7e98d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168
Peer: 'ttcn3', State: ACTIVE
Cells Installed:
Cells Failed:
Number of Broadcasts Completed:
Peer: 'local-bsc', State: ACTIVE
Cells Installed:
CGI 901-70-1-1234
Cells Failed:
Number of Broadcasts Completed:
----
=== ETWS Messages
Using `show messages etws` a list of all current ETWS messages can be obtained.
.Example: Showing a list of all ETWS messages
----
OsmoCBC> show messages etws
|MsgId|SerNo| CBE Name | Category |Period|E|Warning Type|
|-----|-----|--------------------|-------------|------|-|------------|
| 03E8| 7000|cbc_apitool |Normal | 5 |N| 0000|
----
.Example: Showing details of one single ETWS message
----
OsmoCBC> show message id 1000
Message ID 03E8, Serial Number 7000, State: ACTIVE
Created by CBE 'cbc_apitool' at Sun Jan 24 11:14:42 2021
Repetition Period: 5 ( 9.41s), Number of broadcasts: 999
ETWS Warning Type Value: 0x00, User Alert: On, Popup: On
Security: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Peer: 'ttcn3', State: ACTIVE
Cells Installed:
Cells Failed:
Number of Broadcasts Completed:
Peer: 'local-bsc', State: ACTIVE
Cells Installed:
CGI 901-70-1-1234
Cells Failed:
Number of Broadcasts Completed:
----

View File

@@ -10,6 +10,12 @@ It acts as a gateway between external applications / users, such as government
authorities for civil protection, and the various components within the 3GPP
network to actually deliver those broadcast and/or emergency messages.
.Role of the CBC inside the 3GPP network architecture
[graphviz]
----
include::../images/cbc-in-network.dot[]
----
[[about]]
=== About OsmoCBC
@@ -49,29 +55,16 @@ that all BSCs need to know the IP address of the CBC. In this situation,
the CBC doesn't need to know each and every BSC in the network. It
simply only accepts incoming CBSP connections.
For more information, see <<config-cbsp>> on how CBSP is configured.
=== REST interface
=== ECBE REST interface
The REST interface is specified in the JSON schema files
`cbc.schema.json` and `smscb.schema.json`, which are part of the OsmoCBC
distribution.
3GPP does not specify the external interface by which competent
authorities can submit SMSCB and/or ETWS messages to a CBC.
The REST interface currently binds to TCP port 12345 (on INADRR_ANY) and
can be reached at http://localhost:1234/api/ecbe/v1"
Hence, a non-standard, Osmocom specific HTTP/REST/JSON based interface
is offered for external entities to create and delete SMSCB and ETWS
messages within the CBC. This interface is called ECBE.
NOTE:: It is your responsibility to properly secure access to the REST
interface endpoint to ensure only legitimate users can access it. This
may be achieved via packet filtering and a reverse HTTP proxy.
==== POST /api/ecbe/v1/message
This command is used to create a new SMSCB or ETWS message inside the CBC.
The `cbc_messsage` type as specified in the JSON schema.
==== DELETE /api/ecbe/v1/message/:message_id
This command is used to delete an existing SMSCB or ETWS message from the CBC.
The `:message_id` parameter is the decimal integer representation of the
cbc_message.smscb.message_id that was specified when creating the
message via the POST command stated above.
For more information, see <<ecbe>> on the ECBE API definition and <<config-ecbe>>
on how it is configured.

View File

@@ -0,0 +1,17 @@
digraph G {
rankdir = RL;
CBC [color=red];
CBE -> CBC [label="REST/JSON"];
CBC -> BSC [label="CBSP"];
CBC -> RNC [label="SABP"];
CBC -> MME [label="SBc-AP"];
BSC -> BTS [label="A-bis RSL"];
RNC -> NodeB [label="Iub"];
MME -> eNodeB [label="S1-AP"];
BTS -> UE [label="CBCH"];
NodeB -> UE [label="BMC/CTCH"];
eNodeB -> UE [label="SIB10/11/12"];
}

View File

@@ -12,6 +12,14 @@ include::{srcdir}/chapters/overview.adoc[]
include::{srcdir}/chapters/running.adoc[]
include::{srcdir}/chapters/configuration.adoc[]
include::{srcdir}/chapters/introspection.adoc[]
include::{srcdir}/chapters/ecbe-rest-interface.adoc[]
include::{srcdir}/chapters/cbc-apitool.adoc[]
include::./common/chapters/counters-overview.adoc[]
include::{srcdir}/chapters/counters.adoc[]

View File

@@ -165,6 +165,14 @@ struct cbc_message {
struct cbc {
struct {
bool permit_unknown_peers;
struct {
char *local_host;
int local_port;
} cbsp;
struct {
char *local_host;
int local_port;
} ecbe;
} config;
struct llist_head messages; /* cbc_message.list */

View File

@@ -1,6 +1,6 @@
/* Osmocom CBC (Cell Broacast Centre) */
/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
/* (C) 2019-2021 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
@@ -219,6 +219,10 @@ int main(int argc, char **argv)
INIT_LLIST_HEAD(&g_cbc->peers);
INIT_LLIST_HEAD(&g_cbc->messages);
INIT_LLIST_HEAD(&g_cbc->expired_messages);
g_cbc->config.cbsp.local_host = talloc_strdup(g_cbc, "127.0.0.1");
g_cbc->config.cbsp.local_port = CBSP_TCP_PORT;
g_cbc->config.ecbe.local_host = talloc_strdup(g_cbc, "127.0.0.1");
g_cbc->config.ecbe.local_port = 12345;
cbc_vty_init();
@@ -240,9 +244,17 @@ int main(int argc, char **argv)
exit(1);
}
cbsp_cbc_create(tall_cbc_ctx, NULL, -1, &cbc_client_rx_cb);
if (cbsp_cbc_create(tall_cbc_ctx, g_cbc->config.cbsp.local_host, g_cbc->config.cbsp.local_port,
&cbc_client_rx_cb) == NULL) {
perror("Error binidng CBSP port\n");
exit(1);
}
rest_api_init(tall_rest_ctx, 12345);
rc = rest_api_init(tall_rest_ctx, g_cbc->config.ecbe.local_host, g_cbc->config.ecbe.local_port);
if (rc < 0) {
perror("Error binidng ECBE port\n");
exit(1);
}
LOGP(DREST, LOGL_INFO, "Main thread tid: %lu\n", pthread_self());
g_cbc->it_q.rest2main = osmo_it_q_alloc(g_cbc, "rest2main", 10, rest2main_read_cb, NULL);

View File

@@ -1,6 +1,6 @@
/* Osmocom CBC (Cell Broacast Centre) */
/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
/* (C) 2019-2021 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
@@ -267,6 +267,8 @@ DEFUN(show_messages_etws, show_messages_etws_cmd,
enum cbc_vty_node {
CBC_NODE = _LAST_OSMOVTY_NODE + 1,
PEER_NODE,
CBSP_NODE,
ECBE_NODE,
};
static struct cmd_node cbc_node = {
@@ -310,6 +312,96 @@ static int config_write_cbc(struct vty *vty)
return CMD_SUCCESS;
}
DEFUN(cfg_cbsp, cfg_cbsp_cmd,
"cbsp",
"Cell Broadcast Service Protocol\n")
{
vty->node = CBSP_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_ecbe, cfg_ecbe_cmd,
"ecbe",
"External CBS Entity (REST Interface)\n")
{
vty->node = ECBE_NODE;
return CMD_SUCCESS;
}
/* CBSP */
static struct cmd_node cbsp_node = {
CBSP_NODE,
"%s(config-cbsp)# ",
1,
};
static int config_write_cbsp(struct vty *vty)
{
vty_out(vty, " cbsp%s", VTY_NEWLINE);
vty_out(vty, " local-ip %s%s", g_cbc->config.cbsp.local_host, VTY_NEWLINE);
vty_out(vty, " local-port %u%s", g_cbc->config.cbsp.local_port, VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(cfg_cbsp_local_ip, cfg_cbsp_local_ip_cmd,
"local-ip (A.B.C.D|X:X::X:X)",
"Local IP address for CBSP\n"
"Local IPv4 address for CBSP\n" "Local IPv6 address for CBSP\n")
{
osmo_talloc_replace_string(g_cbc, &g_cbc->config.cbsp.local_host, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_cbsp_local_port, cfg_cbsp_local_port_cmd,
"local-port <0-65535>",
"Local TCP port for CBSP\n"
"Local TCP port for CBSP\n")
{
g_cbc->config.cbsp.local_port = atoi(argv[0]);
return CMD_SUCCESS;
}
/* ECBE */
static struct cmd_node ecbe_node = {
ECBE_NODE,
"%s(config-ecbe)# ",
1,
};
static int config_write_ecbe(struct vty *vty)
{
vty_out(vty, " ecbe%s", VTY_NEWLINE);
vty_out(vty, " local-ip %s%s", g_cbc->config.ecbe.local_host, VTY_NEWLINE);
vty_out(vty, " local-port %u%s", g_cbc->config.ecbe.local_port, VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(cfg_ecbe_local_ip, cfg_ecbe_local_ip_cmd,
"local-ip (A.B.C.D|X:X::X:X)",
"Local IP address for CBSP\n"
"Local IPv4 address for ECBE REST Interface\n"
"Local IPv6 address for ECBE REST Interface\n")
{
osmo_talloc_replace_string(g_cbc, &g_cbc->config.ecbe.local_host, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_ecbe_local_port, cfg_ecbe_local_port_cmd,
"local-port <0-65535>",
"Local TCP port for ECBE RESET Interface\n"
"Local TCP port for ECBE RESET Interface\n")
{
g_cbc->config.ecbe.local_port = atoi(argv[0]);
return CMD_SUCCESS;
}
/* PEER */
DEFUN(cfg_cbc_peer, cfg_cbc_peer_cmd,
@@ -377,7 +469,7 @@ DEFUN(cfg_peer_no_remote_port, cfg_peer_no_remote_port_cmd,
DEFUN(cfg_peer_remote_ip, cfg_peer_remote_ip_cmd,
"remote-ip A.B.C.D",
"remote-ip (A.B.C.D|X:X::X:X)",
"Configure remote IP of peer\n"
"Remote IP address of peer\n")
{
@@ -418,6 +510,16 @@ void cbc_vty_init(void)
install_node(&cbc_node, config_write_cbc);
install_lib_element(CBC_NODE, &cfg_permit_unknown_peers_cmd);
install_lib_element(CBC_NODE, &cfg_cbsp_cmd);
install_node(&cbsp_node, config_write_cbsp);
install_lib_element(CBSP_NODE, &cfg_cbsp_local_ip_cmd);
install_lib_element(CBSP_NODE, &cfg_cbsp_local_port_cmd);
install_lib_element(CBC_NODE, &cfg_ecbe_cmd);
install_node(&ecbe_node, config_write_ecbe);
install_lib_element(ECBE_NODE, &cfg_ecbe_local_ip_cmd);
install_lib_element(ECBE_NODE, &cfg_ecbe_local_port_cmd);
install_lib_element(CBC_NODE, &cfg_cbc_peer_cmd);
install_lib_element(CBC_NODE, &cfg_cbc_no_peer_cmd);
install_node(&peer_node, config_write_peer);

View File

@@ -26,13 +26,40 @@
#include "charset.h"
/* pad the entire "remainder" of a buffer with repeated instances of the given pad character */
static void pad_with_septets(uint8_t *buf, size_t buf_len, int num_septets, char pad_char)
{
unsigned int bit_offset;
for (bit_offset = num_septets * 7; bit_offset + 7 <= buf_len * 8; bit_offset += 7) {
unsigned int byte_offset = bit_offset / 8;
unsigned int bits = bit_offset % 8;
/* put one more septet */
buf[byte_offset] |= ((pad_char << bits) & 0xff);
if (bits > 1)
buf[byte_offset+1] = (pad_char) >> (8-bits);
}
}
/* return number of output bytes written */
int charset_utf8_to_gsm7(uint8_t *out, size_t out_len, const char *in, size_t in_len)
{
int octets;
int octets, num_septets, num_bits, num_bytes_used;
/* FIXME: implement this for 'escape' characters outside 7bit alphabet */
gsm_7bit_encode_n_ussd(out, out_len, in, &octets);
return octets;
num_septets = gsm_7bit_encode_n(out, out_len, in, &octets);
num_bits = num_septets * 7;
/* we need to pad the entire remainder of the message with <CR> */
pad_with_septets(out, out_len, num_septets, '\r');
/* return actual number of output octets used, excluding any padding */
num_bytes_used = num_bits/8;
if (num_bits % 8)
num_bytes_used++;
return num_bytes_used;
}
/* return number of output bytes written */

View File

@@ -25,7 +25,7 @@ enum cbsp_server_event {
/* rest_api.c */
int rest_api_init(void *ctx, uint16_t port);
int rest_api_init(void *ctx, const char *bind_addr, uint16_t port);
void rest_api_fin(void);
/* cbc_vty.c */

View File

@@ -1,6 +1,6 @@
/* Osmocom CBC (Cell Broacast Centre) */
/* (C) 2019-2020 by Harald Welte <laforge@gnumonks.org>
/* (C) 2019-2021 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
@@ -31,6 +31,7 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/gsm/protocol/gsm_48_049.h>
@@ -677,27 +678,48 @@ static void my_o_free(void *obj)
}
#endif
int rest_api_init(void *ctx, uint16_t port)
int rest_api_init(void *ctx, const char *bind_addr, uint16_t port)
{
struct osmo_sockaddr_str sastr;
int i;
#ifdef ULFIUS_MALLOC_NOT_BROKEN
/* See https://github.com/babelouest/ulfius/issues/63 */
g_tall_rest = ctx;
o_set_alloc_funcs(my_o_malloc, my_o_realloc, my_o_free);
#endif
if (ulfius_init_instance(&g_instance, port, NULL, NULL) != U_OK)
return -1;
OSMO_STRLCPY_ARRAY(sastr.ip, bind_addr);
sastr.port = port;
if (strchr(bind_addr, ':')) {
#if (ULFIUS_VERSION_MAJOR > 2) || (ULFIUS_VERSION_MAJOR == 2) && (ULFIUS_VERSION_MINOR >= 6)
struct sockaddr_in6 sin6;
sastr.af = AF_INET6;
osmo_sockaddr_str_to_sockaddr_in6(&sastr, &sin6);
if (ulfius_init_instance_ipv6(&g_instance, port, &sin6, U_USE_IPV6, NULL) != U_OK)
return -1;
#else
LOGP(DREST, LOGL_FATAL, "IPv6 requires ulfius version >= 2.6\n");
return -2;
#endif
} else {
struct sockaddr_in sin;
sastr.af = AF_INET;
osmo_sockaddr_str_to_sockaddr_in(&sastr, &sin);
if (ulfius_init_instance(&g_instance, port, &sin, NULL) != U_OK)
return -1;
}
g_instance.mhd_response_copy_data = 1;
for (i = 0; i < ARRAY_SIZE(api_endpoints); i++)
ulfius_add_endpoint(&g_instance, &api_endpoints[i]);
if (ulfius_start_framework(&g_instance) != U_OK) {
LOGP(DREST, LOGL_FATAL, "Cannot start REST API on port %u\n", port);
LOGP(DREST, LOGL_FATAL, "Cannot start ECBE REST API at %s:%u\n", bind_addr, port);
return -1;
}
LOGP(DREST, LOGL_NOTICE, "Started REST API on port %u\n", port);
LOGP(DREST, LOGL_NOTICE, "Started ECBE REST API at %s:%u\n", bind_addr, port);
return 0;
}