mirror of
				https://github.com/Telecominfraproject/OpenCellular.git
				synced 2025-11-03 20:07:51 +00:00 
			
		
		
		
	Merge commit 'c263ce2f41e27c99bba611763279cf434b893ed9' as 'software/osmo/system-images/git/meta-sysmocom-bsp/recipes-sysmobts/osmo-bts/files/osmo-bts'
This commit is contained in:
		@@ -0,0 +1,82 @@
 | 
			
		||||
*.o
 | 
			
		||||
*.a
 | 
			
		||||
Makefile.in
 | 
			
		||||
Makefile
 | 
			
		||||
.deps
 | 
			
		||||
 | 
			
		||||
btsconfig.h
 | 
			
		||||
btsconfig.h.in
 | 
			
		||||
 | 
			
		||||
aclocal.m4
 | 
			
		||||
autom4te.cache
 | 
			
		||||
config.log
 | 
			
		||||
config.status
 | 
			
		||||
config.guess
 | 
			
		||||
config.sub
 | 
			
		||||
configure
 | 
			
		||||
compile
 | 
			
		||||
depcomp
 | 
			
		||||
install-sh
 | 
			
		||||
missing
 | 
			
		||||
stamp-h1
 | 
			
		||||
libtool
 | 
			
		||||
ltmain.sh
 | 
			
		||||
core
 | 
			
		||||
core.*
 | 
			
		||||
 | 
			
		||||
# git-version-gen magic
 | 
			
		||||
.tarball-version
 | 
			
		||||
.version
 | 
			
		||||
 | 
			
		||||
src/osmo-bts-sysmo/sysmobts-calib
 | 
			
		||||
src/osmo-bts-sysmo/l1fwd-proxy
 | 
			
		||||
src/osmo-bts-sysmo/osmo-bts-sysmo
 | 
			
		||||
src/osmo-bts-sysmo/osmo-bts-sysmo-remote
 | 
			
		||||
src/osmo-bts-sysmo/sysmobts-mgr
 | 
			
		||||
src/osmo-bts-sysmo/sysmobts-util
 | 
			
		||||
 | 
			
		||||
src/osmo-bts-litecell15/lc15bts-mgr
 | 
			
		||||
src/osmo-bts-litecell15/lc15bts-util
 | 
			
		||||
src/osmo-bts-litecell15/misc/.dirstamp
 | 
			
		||||
src/osmo-bts-litecell15/osmo-bts-lc15
 | 
			
		||||
 | 
			
		||||
src/osmo-bts-trx/osmo-bts-trx
 | 
			
		||||
 | 
			
		||||
src/osmo-bts-octphy/osmo-bts-octphy
 | 
			
		||||
 | 
			
		||||
src/osmo-bts-virtual/osmo-bts-virtual
 | 
			
		||||
src/osmo-bts-omldummy/osmo-bts-omldummy
 | 
			
		||||
 | 
			
		||||
tests/atconfig
 | 
			
		||||
tests/package.m4
 | 
			
		||||
tests/agch/agch_test
 | 
			
		||||
tests/paging/paging_test
 | 
			
		||||
tests/cipher/cipher_test
 | 
			
		||||
tests/sysmobts/sysmobts_test
 | 
			
		||||
tests/meas/meas_test
 | 
			
		||||
tests/misc/misc_test
 | 
			
		||||
tests/handover/handover_test
 | 
			
		||||
tests/tx_power/tx_power_test
 | 
			
		||||
tests/testsuite
 | 
			
		||||
tests/testsuite.log
 | 
			
		||||
 | 
			
		||||
# Possible generated file
 | 
			
		||||
doc/vty_reference.xml
 | 
			
		||||
 | 
			
		||||
# Backups, vi, merges
 | 
			
		||||
*~
 | 
			
		||||
*.sw?
 | 
			
		||||
*.orig
 | 
			
		||||
*.sav
 | 
			
		||||
 | 
			
		||||
# debian
 | 
			
		||||
.tarball-version
 | 
			
		||||
debian/autoreconf.after
 | 
			
		||||
debian/autoreconf.before
 | 
			
		||||
debian/files
 | 
			
		||||
debian/*.debhelper.log
 | 
			
		||||
debian/*.substvars
 | 
			
		||||
debian/osmo-bts-trx-dbg/
 | 
			
		||||
debian/osmo-bts-trx/
 | 
			
		||||
debian/tmp/
 | 
			
		||||
/tests/power/power_test
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
[gerrit]
 | 
			
		||||
host=gerrit.osmocom.org
 | 
			
		||||
project=osmo-bts
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
Harald Welte <laforge@gnumonks.org> <laflocal@hanuman.gnumonks.org>
 | 
			
		||||
Harald Welte <laforge@gnumonks.org> <laflocal@goeller.de.gnumonks.org>
 | 
			
		||||
Holger Hans Peter Freyther <holger@moiji-mobile.com> <zecke@selfish.org>
 | 
			
		||||
Holger Hans Peter Freyther <holger@moiji-mobile.com> <ich@tamarin.(none)>
 | 
			
		||||
Holger Hans Peter Freyther <holgre@moiji-mobile.com> <holger@freyther.de>
 | 
			
		||||
Andreas Eversberg <jolly@eversberg.eu>
 | 
			
		||||
Andreas Eversberg <jolly@eversberg.eu> <Andreas.Eversberg@versatel.de>
 | 
			
		||||
Andreas Eversberg <jolly@eversberg.eu> <root@nuedel.(none)>
 | 
			
		||||
Pablo Neira Ayuso <pablo@soleta.eu> <pablo@gnumonks.org>
 | 
			
		||||
Max Suraev <msuraev@sysmocom.de>
 | 
			
		||||
Tom Tsou <tom.tsou@ettus.com> <tom@tsou.cc>
 | 
			
		||||
@@ -0,0 +1,661 @@
 | 
			
		||||
                    GNU AFFERO GENERAL PUBLIC LICENSE
 | 
			
		||||
                       Version 3, 19 November 2007
 | 
			
		||||
 | 
			
		||||
 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 | 
			
		||||
 Everyone is permitted to copy and distribute verbatim copies
 | 
			
		||||
 of this license document, but changing it is not allowed.
 | 
			
		||||
 | 
			
		||||
                            Preamble
 | 
			
		||||
 | 
			
		||||
  The GNU Affero General Public License is a free, copyleft license for
 | 
			
		||||
software and other kinds of works, specifically designed to ensure
 | 
			
		||||
cooperation with the community in the case of network server software.
 | 
			
		||||
 | 
			
		||||
  The licenses for most software and other practical works are designed
 | 
			
		||||
to take away your freedom to share and change the works.  By contrast,
 | 
			
		||||
our General Public Licenses are intended to guarantee your freedom to
 | 
			
		||||
share and change all versions of a program--to make sure it remains free
 | 
			
		||||
software for all its users.
 | 
			
		||||
 | 
			
		||||
  When we speak of free software, we are referring to freedom, not
 | 
			
		||||
price.  Our General Public Licenses are designed to make sure that you
 | 
			
		||||
have the freedom to distribute copies of free software (and charge for
 | 
			
		||||
them if you wish), that you receive source code or can get it if you
 | 
			
		||||
want it, that you can change the software or use pieces of it in new
 | 
			
		||||
free programs, and that you know you can do these things.
 | 
			
		||||
 | 
			
		||||
  Developers that use our General Public Licenses protect your rights
 | 
			
		||||
with two steps: (1) assert copyright on the software, and (2) offer
 | 
			
		||||
you this License which gives you legal permission to copy, distribute
 | 
			
		||||
and/or modify the software.
 | 
			
		||||
 | 
			
		||||
  A secondary benefit of defending all users' freedom is that
 | 
			
		||||
improvements made in alternate versions of the program, if they
 | 
			
		||||
receive widespread use, become available for other developers to
 | 
			
		||||
incorporate.  Many developers of free software are heartened and
 | 
			
		||||
encouraged by the resulting cooperation.  However, in the case of
 | 
			
		||||
software used on network servers, this result may fail to come about.
 | 
			
		||||
The GNU General Public License permits making a modified version and
 | 
			
		||||
letting the public access it on a server without ever releasing its
 | 
			
		||||
source code to the public.
 | 
			
		||||
 | 
			
		||||
  The GNU Affero General Public License is designed specifically to
 | 
			
		||||
ensure that, in such cases, the modified source code becomes available
 | 
			
		||||
to the community.  It requires the operator of a network server to
 | 
			
		||||
provide the source code of the modified version running there to the
 | 
			
		||||
users of that server.  Therefore, public use of a modified version, on
 | 
			
		||||
a publicly accessible server, gives the public access to the source
 | 
			
		||||
code of the modified version.
 | 
			
		||||
 | 
			
		||||
  An older license, called the Affero General Public License and
 | 
			
		||||
published by Affero, was designed to accomplish similar goals.  This is
 | 
			
		||||
a different license, not a version of the Affero GPL, but Affero has
 | 
			
		||||
released a new version of the Affero GPL which permits relicensing under
 | 
			
		||||
this license.
 | 
			
		||||
 | 
			
		||||
  The precise terms and conditions for copying, distribution and
 | 
			
		||||
modification follow.
 | 
			
		||||
 | 
			
		||||
                       TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
  0. Definitions.
 | 
			
		||||
 | 
			
		||||
  "This License" refers to version 3 of the GNU Affero General Public License.
 | 
			
		||||
 | 
			
		||||
  "Copyright" also means copyright-like laws that apply to other kinds of
 | 
			
		||||
works, such as semiconductor masks.
 | 
			
		||||
 | 
			
		||||
  "The Program" refers to any copyrightable work licensed under this
 | 
			
		||||
License.  Each licensee is addressed as "you".  "Licensees" and
 | 
			
		||||
"recipients" may be individuals or organizations.
 | 
			
		||||
 | 
			
		||||
  To "modify" a work means to copy from or adapt all or part of the work
 | 
			
		||||
in a fashion requiring copyright permission, other than the making of an
 | 
			
		||||
exact copy.  The resulting work is called a "modified version" of the
 | 
			
		||||
earlier work or a work "based on" the earlier work.
 | 
			
		||||
 | 
			
		||||
  A "covered work" means either the unmodified Program or a work based
 | 
			
		||||
on the Program.
 | 
			
		||||
 | 
			
		||||
  To "propagate" a work means to do anything with it that, without
 | 
			
		||||
permission, would make you directly or secondarily liable for
 | 
			
		||||
infringement under applicable copyright law, except executing it on a
 | 
			
		||||
computer or modifying a private copy.  Propagation includes copying,
 | 
			
		||||
distribution (with or without modification), making available to the
 | 
			
		||||
public, and in some countries other activities as well.
 | 
			
		||||
 | 
			
		||||
  To "convey" a work means any kind of propagation that enables other
 | 
			
		||||
parties to make or receive copies.  Mere interaction with a user through
 | 
			
		||||
a computer network, with no transfer of a copy, is not conveying.
 | 
			
		||||
 | 
			
		||||
  An interactive user interface displays "Appropriate Legal Notices"
 | 
			
		||||
to the extent that it includes a convenient and prominently visible
 | 
			
		||||
feature that (1) displays an appropriate copyright notice, and (2)
 | 
			
		||||
tells the user that there is no warranty for the work (except to the
 | 
			
		||||
extent that warranties are provided), that licensees may convey the
 | 
			
		||||
work under this License, and how to view a copy of this License.  If
 | 
			
		||||
the interface presents a list of user commands or options, such as a
 | 
			
		||||
menu, a prominent item in the list meets this criterion.
 | 
			
		||||
 | 
			
		||||
  1. Source Code.
 | 
			
		||||
 | 
			
		||||
  The "source code" for a work means the preferred form of the work
 | 
			
		||||
for making modifications to it.  "Object code" means any non-source
 | 
			
		||||
form of a work.
 | 
			
		||||
 | 
			
		||||
  A "Standard Interface" means an interface that either is an official
 | 
			
		||||
standard defined by a recognized standards body, or, in the case of
 | 
			
		||||
interfaces specified for a particular programming language, one that
 | 
			
		||||
is widely used among developers working in that language.
 | 
			
		||||
 | 
			
		||||
  The "System Libraries" of an executable work include anything, other
 | 
			
		||||
than the work as a whole, that (a) is included in the normal form of
 | 
			
		||||
packaging a Major Component, but which is not part of that Major
 | 
			
		||||
Component, and (b) serves only to enable use of the work with that
 | 
			
		||||
Major Component, or to implement a Standard Interface for which an
 | 
			
		||||
implementation is available to the public in source code form.  A
 | 
			
		||||
"Major Component", in this context, means a major essential component
 | 
			
		||||
(kernel, window system, and so on) of the specific operating system
 | 
			
		||||
(if any) on which the executable work runs, or a compiler used to
 | 
			
		||||
produce the work, or an object code interpreter used to run it.
 | 
			
		||||
 | 
			
		||||
  The "Corresponding Source" for a work in object code form means all
 | 
			
		||||
the source code needed to generate, install, and (for an executable
 | 
			
		||||
work) run the object code and to modify the work, including scripts to
 | 
			
		||||
control those activities.  However, it does not include the work's
 | 
			
		||||
System Libraries, or general-purpose tools or generally available free
 | 
			
		||||
programs which are used unmodified in performing those activities but
 | 
			
		||||
which are not part of the work.  For example, Corresponding Source
 | 
			
		||||
includes interface definition files associated with source files for
 | 
			
		||||
the work, and the source code for shared libraries and dynamically
 | 
			
		||||
linked subprograms that the work is specifically designed to require,
 | 
			
		||||
such as by intimate data communication or control flow between those
 | 
			
		||||
subprograms and other parts of the work.
 | 
			
		||||
 | 
			
		||||
  The Corresponding Source need not include anything that users
 | 
			
		||||
can regenerate automatically from other parts of the Corresponding
 | 
			
		||||
Source.
 | 
			
		||||
 | 
			
		||||
  The Corresponding Source for a work in source code form is that
 | 
			
		||||
same work.
 | 
			
		||||
 | 
			
		||||
  2. Basic Permissions.
 | 
			
		||||
 | 
			
		||||
  All rights granted under this License are granted for the term of
 | 
			
		||||
copyright on the Program, and are irrevocable provided the stated
 | 
			
		||||
conditions are met.  This License explicitly affirms your unlimited
 | 
			
		||||
permission to run the unmodified Program.  The output from running a
 | 
			
		||||
covered work is covered by this License only if the output, given its
 | 
			
		||||
content, constitutes a covered work.  This License acknowledges your
 | 
			
		||||
rights of fair use or other equivalent, as provided by copyright law.
 | 
			
		||||
 | 
			
		||||
  You may make, run and propagate covered works that you do not
 | 
			
		||||
convey, without conditions so long as your license otherwise remains
 | 
			
		||||
in force.  You may convey covered works to others for the sole purpose
 | 
			
		||||
of having them make modifications exclusively for you, or provide you
 | 
			
		||||
with facilities for running those works, provided that you comply with
 | 
			
		||||
the terms of this License in conveying all material for which you do
 | 
			
		||||
not control copyright.  Those thus making or running the covered works
 | 
			
		||||
for you must do so exclusively on your behalf, under your direction
 | 
			
		||||
and control, on terms that prohibit them from making any copies of
 | 
			
		||||
your copyrighted material outside their relationship with you.
 | 
			
		||||
 | 
			
		||||
  Conveying under any other circumstances is permitted solely under
 | 
			
		||||
the conditions stated below.  Sublicensing is not allowed; section 10
 | 
			
		||||
makes it unnecessary.
 | 
			
		||||
 | 
			
		||||
  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
 | 
			
		||||
 | 
			
		||||
  No covered work shall be deemed part of an effective technological
 | 
			
		||||
measure under any applicable law fulfilling obligations under article
 | 
			
		||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
 | 
			
		||||
similar laws prohibiting or restricting circumvention of such
 | 
			
		||||
measures.
 | 
			
		||||
 | 
			
		||||
  When you convey a covered work, you waive any legal power to forbid
 | 
			
		||||
circumvention of technological measures to the extent such circumvention
 | 
			
		||||
is effected by exercising rights under this License with respect to
 | 
			
		||||
the covered work, and you disclaim any intention to limit operation or
 | 
			
		||||
modification of the work as a means of enforcing, against the work's
 | 
			
		||||
users, your or third parties' legal rights to forbid circumvention of
 | 
			
		||||
technological measures.
 | 
			
		||||
 | 
			
		||||
  4. Conveying Verbatim Copies.
 | 
			
		||||
 | 
			
		||||
  You may convey verbatim copies of the Program's source code as you
 | 
			
		||||
receive it, in any medium, provided that you conspicuously and
 | 
			
		||||
appropriately publish on each copy an appropriate copyright notice;
 | 
			
		||||
keep intact all notices stating that this License and any
 | 
			
		||||
non-permissive terms added in accord with section 7 apply to the code;
 | 
			
		||||
keep intact all notices of the absence of any warranty; and give all
 | 
			
		||||
recipients a copy of this License along with the Program.
 | 
			
		||||
 | 
			
		||||
  You may charge any price or no price for each copy that you convey,
 | 
			
		||||
and you may offer support or warranty protection for a fee.
 | 
			
		||||
 | 
			
		||||
  5. Conveying Modified Source Versions.
 | 
			
		||||
 | 
			
		||||
  You may convey a work based on the Program, or the modifications to
 | 
			
		||||
produce it from the Program, in the form of source code under the
 | 
			
		||||
terms of section 4, provided that you also meet all of these conditions:
 | 
			
		||||
 | 
			
		||||
    a) The work must carry prominent notices stating that you modified
 | 
			
		||||
    it, and giving a relevant date.
 | 
			
		||||
 | 
			
		||||
    b) The work must carry prominent notices stating that it is
 | 
			
		||||
    released under this License and any conditions added under section
 | 
			
		||||
    7.  This requirement modifies the requirement in section 4 to
 | 
			
		||||
    "keep intact all notices".
 | 
			
		||||
 | 
			
		||||
    c) You must license the entire work, as a whole, under this
 | 
			
		||||
    License to anyone who comes into possession of a copy.  This
 | 
			
		||||
    License will therefore apply, along with any applicable section 7
 | 
			
		||||
    additional terms, to the whole of the work, and all its parts,
 | 
			
		||||
    regardless of how they are packaged.  This License gives no
 | 
			
		||||
    permission to license the work in any other way, but it does not
 | 
			
		||||
    invalidate such permission if you have separately received it.
 | 
			
		||||
 | 
			
		||||
    d) If the work has interactive user interfaces, each must display
 | 
			
		||||
    Appropriate Legal Notices; however, if the Program has interactive
 | 
			
		||||
    interfaces that do not display Appropriate Legal Notices, your
 | 
			
		||||
    work need not make them do so.
 | 
			
		||||
 | 
			
		||||
  A compilation of a covered work with other separate and independent
 | 
			
		||||
works, which are not by their nature extensions of the covered work,
 | 
			
		||||
and which are not combined with it such as to form a larger program,
 | 
			
		||||
in or on a volume of a storage or distribution medium, is called an
 | 
			
		||||
"aggregate" if the compilation and its resulting copyright are not
 | 
			
		||||
used to limit the access or legal rights of the compilation's users
 | 
			
		||||
beyond what the individual works permit.  Inclusion of a covered work
 | 
			
		||||
in an aggregate does not cause this License to apply to the other
 | 
			
		||||
parts of the aggregate.
 | 
			
		||||
 | 
			
		||||
  6. Conveying Non-Source Forms.
 | 
			
		||||
 | 
			
		||||
  You may convey a covered work in object code form under the terms
 | 
			
		||||
of sections 4 and 5, provided that you also convey the
 | 
			
		||||
machine-readable Corresponding Source under the terms of this License,
 | 
			
		||||
in one of these ways:
 | 
			
		||||
 | 
			
		||||
    a) Convey the object code in, or embodied in, a physical product
 | 
			
		||||
    (including a physical distribution medium), accompanied by the
 | 
			
		||||
    Corresponding Source fixed on a durable physical medium
 | 
			
		||||
    customarily used for software interchange.
 | 
			
		||||
 | 
			
		||||
    b) Convey the object code in, or embodied in, a physical product
 | 
			
		||||
    (including a physical distribution medium), accompanied by a
 | 
			
		||||
    written offer, valid for at least three years and valid for as
 | 
			
		||||
    long as you offer spare parts or customer support for that product
 | 
			
		||||
    model, to give anyone who possesses the object code either (1) a
 | 
			
		||||
    copy of the Corresponding Source for all the software in the
 | 
			
		||||
    product that is covered by this License, on a durable physical
 | 
			
		||||
    medium customarily used for software interchange, for a price no
 | 
			
		||||
    more than your reasonable cost of physically performing this
 | 
			
		||||
    conveying of source, or (2) access to copy the
 | 
			
		||||
    Corresponding Source from a network server at no charge.
 | 
			
		||||
 | 
			
		||||
    c) Convey individual copies of the object code with a copy of the
 | 
			
		||||
    written offer to provide the Corresponding Source.  This
 | 
			
		||||
    alternative is allowed only occasionally and noncommercially, and
 | 
			
		||||
    only if you received the object code with such an offer, in accord
 | 
			
		||||
    with subsection 6b.
 | 
			
		||||
 | 
			
		||||
    d) Convey the object code by offering access from a designated
 | 
			
		||||
    place (gratis or for a charge), and offer equivalent access to the
 | 
			
		||||
    Corresponding Source in the same way through the same place at no
 | 
			
		||||
    further charge.  You need not require recipients to copy the
 | 
			
		||||
    Corresponding Source along with the object code.  If the place to
 | 
			
		||||
    copy the object code is a network server, the Corresponding Source
 | 
			
		||||
    may be on a different server (operated by you or a third party)
 | 
			
		||||
    that supports equivalent copying facilities, provided you maintain
 | 
			
		||||
    clear directions next to the object code saying where to find the
 | 
			
		||||
    Corresponding Source.  Regardless of what server hosts the
 | 
			
		||||
    Corresponding Source, you remain obligated to ensure that it is
 | 
			
		||||
    available for as long as needed to satisfy these requirements.
 | 
			
		||||
 | 
			
		||||
    e) Convey the object code using peer-to-peer transmission, provided
 | 
			
		||||
    you inform other peers where the object code and Corresponding
 | 
			
		||||
    Source of the work are being offered to the general public at no
 | 
			
		||||
    charge under subsection 6d.
 | 
			
		||||
 | 
			
		||||
  A separable portion of the object code, whose source code is excluded
 | 
			
		||||
from the Corresponding Source as a System Library, need not be
 | 
			
		||||
included in conveying the object code work.
 | 
			
		||||
 | 
			
		||||
  A "User Product" is either (1) a "consumer product", which means any
 | 
			
		||||
tangible personal property which is normally used for personal, family,
 | 
			
		||||
or household purposes, or (2) anything designed or sold for incorporation
 | 
			
		||||
into a dwelling.  In determining whether a product is a consumer product,
 | 
			
		||||
doubtful cases shall be resolved in favor of coverage.  For a particular
 | 
			
		||||
product received by a particular user, "normally used" refers to a
 | 
			
		||||
typical or common use of that class of product, regardless of the status
 | 
			
		||||
of the particular user or of the way in which the particular user
 | 
			
		||||
actually uses, or expects or is expected to use, the product.  A product
 | 
			
		||||
is a consumer product regardless of whether the product has substantial
 | 
			
		||||
commercial, industrial or non-consumer uses, unless such uses represent
 | 
			
		||||
the only significant mode of use of the product.
 | 
			
		||||
 | 
			
		||||
  "Installation Information" for a User Product means any methods,
 | 
			
		||||
procedures, authorization keys, or other information required to install
 | 
			
		||||
and execute modified versions of a covered work in that User Product from
 | 
			
		||||
a modified version of its Corresponding Source.  The information must
 | 
			
		||||
suffice to ensure that the continued functioning of the modified object
 | 
			
		||||
code is in no case prevented or interfered with solely because
 | 
			
		||||
modification has been made.
 | 
			
		||||
 | 
			
		||||
  If you convey an object code work under this section in, or with, or
 | 
			
		||||
specifically for use in, a User Product, and the conveying occurs as
 | 
			
		||||
part of a transaction in which the right of possession and use of the
 | 
			
		||||
User Product is transferred to the recipient in perpetuity or for a
 | 
			
		||||
fixed term (regardless of how the transaction is characterized), the
 | 
			
		||||
Corresponding Source conveyed under this section must be accompanied
 | 
			
		||||
by the Installation Information.  But this requirement does not apply
 | 
			
		||||
if neither you nor any third party retains the ability to install
 | 
			
		||||
modified object code on the User Product (for example, the work has
 | 
			
		||||
been installed in ROM).
 | 
			
		||||
 | 
			
		||||
  The requirement to provide Installation Information does not include a
 | 
			
		||||
requirement to continue to provide support service, warranty, or updates
 | 
			
		||||
for a work that has been modified or installed by the recipient, or for
 | 
			
		||||
the User Product in which it has been modified or installed.  Access to a
 | 
			
		||||
network may be denied when the modification itself materially and
 | 
			
		||||
adversely affects the operation of the network or violates the rules and
 | 
			
		||||
protocols for communication across the network.
 | 
			
		||||
 | 
			
		||||
  Corresponding Source conveyed, and Installation Information provided,
 | 
			
		||||
in accord with this section must be in a format that is publicly
 | 
			
		||||
documented (and with an implementation available to the public in
 | 
			
		||||
source code form), and must require no special password or key for
 | 
			
		||||
unpacking, reading or copying.
 | 
			
		||||
 | 
			
		||||
  7. Additional Terms.
 | 
			
		||||
 | 
			
		||||
  "Additional permissions" are terms that supplement the terms of this
 | 
			
		||||
License by making exceptions from one or more of its conditions.
 | 
			
		||||
Additional permissions that are applicable to the entire Program shall
 | 
			
		||||
be treated as though they were included in this License, to the extent
 | 
			
		||||
that they are valid under applicable law.  If additional permissions
 | 
			
		||||
apply only to part of the Program, that part may be used separately
 | 
			
		||||
under those permissions, but the entire Program remains governed by
 | 
			
		||||
this License without regard to the additional permissions.
 | 
			
		||||
 | 
			
		||||
  When you convey a copy of a covered work, you may at your option
 | 
			
		||||
remove any additional permissions from that copy, or from any part of
 | 
			
		||||
it.  (Additional permissions may be written to require their own
 | 
			
		||||
removal in certain cases when you modify the work.)  You may place
 | 
			
		||||
additional permissions on material, added by you to a covered work,
 | 
			
		||||
for which you have or can give appropriate copyright permission.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, for material you
 | 
			
		||||
add to a covered work, you may (if authorized by the copyright holders of
 | 
			
		||||
that material) supplement the terms of this License with terms:
 | 
			
		||||
 | 
			
		||||
    a) Disclaiming warranty or limiting liability differently from the
 | 
			
		||||
    terms of sections 15 and 16 of this License; or
 | 
			
		||||
 | 
			
		||||
    b) Requiring preservation of specified reasonable legal notices or
 | 
			
		||||
    author attributions in that material or in the Appropriate Legal
 | 
			
		||||
    Notices displayed by works containing it; or
 | 
			
		||||
 | 
			
		||||
    c) Prohibiting misrepresentation of the origin of that material, or
 | 
			
		||||
    requiring that modified versions of such material be marked in
 | 
			
		||||
    reasonable ways as different from the original version; or
 | 
			
		||||
 | 
			
		||||
    d) Limiting the use for publicity purposes of names of licensors or
 | 
			
		||||
    authors of the material; or
 | 
			
		||||
 | 
			
		||||
    e) Declining to grant rights under trademark law for use of some
 | 
			
		||||
    trade names, trademarks, or service marks; or
 | 
			
		||||
 | 
			
		||||
    f) Requiring indemnification of licensors and authors of that
 | 
			
		||||
    material by anyone who conveys the material (or modified versions of
 | 
			
		||||
    it) with contractual assumptions of liability to the recipient, for
 | 
			
		||||
    any liability that these contractual assumptions directly impose on
 | 
			
		||||
    those licensors and authors.
 | 
			
		||||
 | 
			
		||||
  All other non-permissive additional terms are considered "further
 | 
			
		||||
restrictions" within the meaning of section 10.  If the Program as you
 | 
			
		||||
received it, or any part of it, contains a notice stating that it is
 | 
			
		||||
governed by this License along with a term that is a further
 | 
			
		||||
restriction, you may remove that term.  If a license document contains
 | 
			
		||||
a further restriction but permits relicensing or conveying under this
 | 
			
		||||
License, you may add to a covered work material governed by the terms
 | 
			
		||||
of that license document, provided that the further restriction does
 | 
			
		||||
not survive such relicensing or conveying.
 | 
			
		||||
 | 
			
		||||
  If you add terms to a covered work in accord with this section, you
 | 
			
		||||
must place, in the relevant source files, a statement of the
 | 
			
		||||
additional terms that apply to those files, or a notice indicating
 | 
			
		||||
where to find the applicable terms.
 | 
			
		||||
 | 
			
		||||
  Additional terms, permissive or non-permissive, may be stated in the
 | 
			
		||||
form of a separately written license, or stated as exceptions;
 | 
			
		||||
the above requirements apply either way.
 | 
			
		||||
 | 
			
		||||
  8. Termination.
 | 
			
		||||
 | 
			
		||||
  You may not propagate or modify a covered work except as expressly
 | 
			
		||||
provided under this License.  Any attempt otherwise to propagate or
 | 
			
		||||
modify it is void, and will automatically terminate your rights under
 | 
			
		||||
this License (including any patent licenses granted under the third
 | 
			
		||||
paragraph of section 11).
 | 
			
		||||
 | 
			
		||||
  However, if you cease all violation of this License, then your
 | 
			
		||||
license from a particular copyright holder is reinstated (a)
 | 
			
		||||
provisionally, unless and until the copyright holder explicitly and
 | 
			
		||||
finally terminates your license, and (b) permanently, if the copyright
 | 
			
		||||
holder fails to notify you of the violation by some reasonable means
 | 
			
		||||
prior to 60 days after the cessation.
 | 
			
		||||
 | 
			
		||||
  Moreover, your license from a particular copyright holder is
 | 
			
		||||
reinstated permanently if the copyright holder notifies you of the
 | 
			
		||||
violation by some reasonable means, this is the first time you have
 | 
			
		||||
received notice of violation of this License (for any work) from that
 | 
			
		||||
copyright holder, and you cure the violation prior to 30 days after
 | 
			
		||||
your receipt of the notice.
 | 
			
		||||
 | 
			
		||||
  Termination of your rights under this section does not terminate the
 | 
			
		||||
licenses of parties who have received copies or rights from you under
 | 
			
		||||
this License.  If your rights have been terminated and not permanently
 | 
			
		||||
reinstated, you do not qualify to receive new licenses for the same
 | 
			
		||||
material under section 10.
 | 
			
		||||
 | 
			
		||||
  9. Acceptance Not Required for Having Copies.
 | 
			
		||||
 | 
			
		||||
  You are not required to accept this License in order to receive or
 | 
			
		||||
run a copy of the Program.  Ancillary propagation of a covered work
 | 
			
		||||
occurring solely as a consequence of using peer-to-peer transmission
 | 
			
		||||
to receive a copy likewise does not require acceptance.  However,
 | 
			
		||||
nothing other than this License grants you permission to propagate or
 | 
			
		||||
modify any covered work.  These actions infringe copyright if you do
 | 
			
		||||
not accept this License.  Therefore, by modifying or propagating a
 | 
			
		||||
covered work, you indicate your acceptance of this License to do so.
 | 
			
		||||
 | 
			
		||||
  10. Automatic Licensing of Downstream Recipients.
 | 
			
		||||
 | 
			
		||||
  Each time you convey a covered work, the recipient automatically
 | 
			
		||||
receives a license from the original licensors, to run, modify and
 | 
			
		||||
propagate that work, subject to this License.  You are not responsible
 | 
			
		||||
for enforcing compliance by third parties with this License.
 | 
			
		||||
 | 
			
		||||
  An "entity transaction" is a transaction transferring control of an
 | 
			
		||||
organization, or substantially all assets of one, or subdividing an
 | 
			
		||||
organization, or merging organizations.  If propagation of a covered
 | 
			
		||||
work results from an entity transaction, each party to that
 | 
			
		||||
transaction who receives a copy of the work also receives whatever
 | 
			
		||||
licenses to the work the party's predecessor in interest had or could
 | 
			
		||||
give under the previous paragraph, plus a right to possession of the
 | 
			
		||||
Corresponding Source of the work from the predecessor in interest, if
 | 
			
		||||
the predecessor has it or can get it with reasonable efforts.
 | 
			
		||||
 | 
			
		||||
  You may not impose any further restrictions on the exercise of the
 | 
			
		||||
rights granted or affirmed under this License.  For example, you may
 | 
			
		||||
not impose a license fee, royalty, or other charge for exercise of
 | 
			
		||||
rights granted under this License, and you may not initiate litigation
 | 
			
		||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
 | 
			
		||||
any patent claim is infringed by making, using, selling, offering for
 | 
			
		||||
sale, or importing the Program or any portion of it.
 | 
			
		||||
 | 
			
		||||
  11. Patents.
 | 
			
		||||
 | 
			
		||||
  A "contributor" is a copyright holder who authorizes use under this
 | 
			
		||||
License of the Program or a work on which the Program is based.  The
 | 
			
		||||
work thus licensed is called the contributor's "contributor version".
 | 
			
		||||
 | 
			
		||||
  A contributor's "essential patent claims" are all patent claims
 | 
			
		||||
owned or controlled by the contributor, whether already acquired or
 | 
			
		||||
hereafter acquired, that would be infringed by some manner, permitted
 | 
			
		||||
by this License, of making, using, or selling its contributor version,
 | 
			
		||||
but do not include claims that would be infringed only as a
 | 
			
		||||
consequence of further modification of the contributor version.  For
 | 
			
		||||
purposes of this definition, "control" includes the right to grant
 | 
			
		||||
patent sublicenses in a manner consistent with the requirements of
 | 
			
		||||
this License.
 | 
			
		||||
 | 
			
		||||
  Each contributor grants you a non-exclusive, worldwide, royalty-free
 | 
			
		||||
patent license under the contributor's essential patent claims, to
 | 
			
		||||
make, use, sell, offer for sale, import and otherwise run, modify and
 | 
			
		||||
propagate the contents of its contributor version.
 | 
			
		||||
 | 
			
		||||
  In the following three paragraphs, a "patent license" is any express
 | 
			
		||||
agreement or commitment, however denominated, not to enforce a patent
 | 
			
		||||
(such as an express permission to practice a patent or covenant not to
 | 
			
		||||
sue for patent infringement).  To "grant" such a patent license to a
 | 
			
		||||
party means to make such an agreement or commitment not to enforce a
 | 
			
		||||
patent against the party.
 | 
			
		||||
 | 
			
		||||
  If you convey a covered work, knowingly relying on a patent license,
 | 
			
		||||
and the Corresponding Source of the work is not available for anyone
 | 
			
		||||
to copy, free of charge and under the terms of this License, through a
 | 
			
		||||
publicly available network server or other readily accessible means,
 | 
			
		||||
then you must either (1) cause the Corresponding Source to be so
 | 
			
		||||
available, or (2) arrange to deprive yourself of the benefit of the
 | 
			
		||||
patent license for this particular work, or (3) arrange, in a manner
 | 
			
		||||
consistent with the requirements of this License, to extend the patent
 | 
			
		||||
license to downstream recipients.  "Knowingly relying" means you have
 | 
			
		||||
actual knowledge that, but for the patent license, your conveying the
 | 
			
		||||
covered work in a country, or your recipient's use of the covered work
 | 
			
		||||
in a country, would infringe one or more identifiable patents in that
 | 
			
		||||
country that you have reason to believe are valid.
 | 
			
		||||
 | 
			
		||||
  If, pursuant to or in connection with a single transaction or
 | 
			
		||||
arrangement, you convey, or propagate by procuring conveyance of, a
 | 
			
		||||
covered work, and grant a patent license to some of the parties
 | 
			
		||||
receiving the covered work authorizing them to use, propagate, modify
 | 
			
		||||
or convey a specific copy of the covered work, then the patent license
 | 
			
		||||
you grant is automatically extended to all recipients of the covered
 | 
			
		||||
work and works based on it.
 | 
			
		||||
 | 
			
		||||
  A patent license is "discriminatory" if it does not include within
 | 
			
		||||
the scope of its coverage, prohibits the exercise of, or is
 | 
			
		||||
conditioned on the non-exercise of one or more of the rights that are
 | 
			
		||||
specifically granted under this License.  You may not convey a covered
 | 
			
		||||
work if you are a party to an arrangement with a third party that is
 | 
			
		||||
in the business of distributing software, under which you make payment
 | 
			
		||||
to the third party based on the extent of your activity of conveying
 | 
			
		||||
the work, and under which the third party grants, to any of the
 | 
			
		||||
parties who would receive the covered work from you, a discriminatory
 | 
			
		||||
patent license (a) in connection with copies of the covered work
 | 
			
		||||
conveyed by you (or copies made from those copies), or (b) primarily
 | 
			
		||||
for and in connection with specific products or compilations that
 | 
			
		||||
contain the covered work, unless you entered into that arrangement,
 | 
			
		||||
or that patent license was granted, prior to 28 March 2007.
 | 
			
		||||
 | 
			
		||||
  Nothing in this License shall be construed as excluding or limiting
 | 
			
		||||
any implied license or other defenses to infringement that may
 | 
			
		||||
otherwise be available to you under applicable patent law.
 | 
			
		||||
 | 
			
		||||
  12. No Surrender of Others' Freedom.
 | 
			
		||||
 | 
			
		||||
  If conditions are imposed on you (whether by court order, agreement or
 | 
			
		||||
otherwise) that contradict the conditions of this License, they do not
 | 
			
		||||
excuse you from the conditions of this License.  If you cannot convey a
 | 
			
		||||
covered work so as to satisfy simultaneously your obligations under this
 | 
			
		||||
License and any other pertinent obligations, then as a consequence you may
 | 
			
		||||
not convey it at all.  For example, if you agree to terms that obligate you
 | 
			
		||||
to collect a royalty for further conveying from those to whom you convey
 | 
			
		||||
the Program, the only way you could satisfy both those terms and this
 | 
			
		||||
License would be to refrain entirely from conveying the Program.
 | 
			
		||||
 | 
			
		||||
  13. Remote Network Interaction; Use with the GNU General Public License.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, if you modify the
 | 
			
		||||
Program, your modified version must prominently offer all users
 | 
			
		||||
interacting with it remotely through a computer network (if your version
 | 
			
		||||
supports such interaction) an opportunity to receive the Corresponding
 | 
			
		||||
Source of your version by providing access to the Corresponding Source
 | 
			
		||||
from a network server at no charge, through some standard or customary
 | 
			
		||||
means of facilitating copying of software.  This Corresponding Source
 | 
			
		||||
shall include the Corresponding Source for any work covered by version 3
 | 
			
		||||
of the GNU General Public License that is incorporated pursuant to the
 | 
			
		||||
following paragraph.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, you have
 | 
			
		||||
permission to link or combine any covered work with a work licensed
 | 
			
		||||
under version 3 of the GNU General Public License into a single
 | 
			
		||||
combined work, and to convey the resulting work.  The terms of this
 | 
			
		||||
License will continue to apply to the part which is the covered work,
 | 
			
		||||
but the work with which it is combined will remain governed by version
 | 
			
		||||
3 of the GNU General Public License.
 | 
			
		||||
 | 
			
		||||
  14. Revised Versions of this License.
 | 
			
		||||
 | 
			
		||||
  The Free Software Foundation may publish revised and/or new versions of
 | 
			
		||||
the GNU Affero General Public License from time to time.  Such new versions
 | 
			
		||||
will be similar in spirit to the present version, but may differ in detail to
 | 
			
		||||
address new problems or concerns.
 | 
			
		||||
 | 
			
		||||
  Each version is given a distinguishing version number.  If the
 | 
			
		||||
Program specifies that a certain numbered version of the GNU Affero General
 | 
			
		||||
Public License "or any later version" applies to it, you have the
 | 
			
		||||
option of following the terms and conditions either of that numbered
 | 
			
		||||
version or of any later version published by the Free Software
 | 
			
		||||
Foundation.  If the Program does not specify a version number of the
 | 
			
		||||
GNU Affero General Public License, you may choose any version ever published
 | 
			
		||||
by the Free Software Foundation.
 | 
			
		||||
 | 
			
		||||
  If the Program specifies that a proxy can decide which future
 | 
			
		||||
versions of the GNU Affero General Public License can be used, that proxy's
 | 
			
		||||
public statement of acceptance of a version permanently authorizes you
 | 
			
		||||
to choose that version for the Program.
 | 
			
		||||
 | 
			
		||||
  Later license versions may give you additional or different
 | 
			
		||||
permissions.  However, no additional obligations are imposed on any
 | 
			
		||||
author or copyright holder as a result of your choosing to follow a
 | 
			
		||||
later version.
 | 
			
		||||
 | 
			
		||||
  15. Disclaimer of Warranty.
 | 
			
		||||
 | 
			
		||||
  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
 | 
			
		||||
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
 | 
			
		||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
 | 
			
		||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
			
		||||
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
 | 
			
		||||
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
 | 
			
		||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 | 
			
		||||
 | 
			
		||||
  16. Limitation of Liability.
 | 
			
		||||
 | 
			
		||||
  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
			
		||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
 | 
			
		||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
 | 
			
		||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
 | 
			
		||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
 | 
			
		||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
 | 
			
		||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
 | 
			
		||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
SUCH DAMAGES.
 | 
			
		||||
 | 
			
		||||
  17. Interpretation of Sections 15 and 16.
 | 
			
		||||
 | 
			
		||||
  If the disclaimer of warranty and limitation of liability provided
 | 
			
		||||
above cannot be given local legal effect according to their terms,
 | 
			
		||||
reviewing courts shall apply local law that most closely approximates
 | 
			
		||||
an absolute waiver of all civil liability in connection with the
 | 
			
		||||
Program, unless a warranty or assumption of liability accompanies a
 | 
			
		||||
copy of the Program in return for a fee.
 | 
			
		||||
 | 
			
		||||
                     END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
            How to Apply These Terms to Your New Programs
 | 
			
		||||
 | 
			
		||||
  If you develop a new program, and you want it to be of the greatest
 | 
			
		||||
possible use to the public, the best way to achieve this is to make it
 | 
			
		||||
free software which everyone can redistribute and change under these terms.
 | 
			
		||||
 | 
			
		||||
  To do so, attach the following notices to the program.  It is safest
 | 
			
		||||
to attach them to the start of each source file to most effectively
 | 
			
		||||
state the exclusion of warranty; and each file should have at least
 | 
			
		||||
the "copyright" line and a pointer to where the full notice is found.
 | 
			
		||||
 | 
			
		||||
    <one line to give the program's name and a brief idea of what it does.>
 | 
			
		||||
    Copyright (C) <year>  <name of author>
 | 
			
		||||
 | 
			
		||||
    This program is free software: you can redistribute it and/or modify
 | 
			
		||||
    it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
    the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
    (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
    This program is distributed in the hope that it will be useful,
 | 
			
		||||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
    GNU Affero General Public License for more details.
 | 
			
		||||
 | 
			
		||||
    You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
Also add information on how to contact you by electronic and paper mail.
 | 
			
		||||
 | 
			
		||||
  If your software can interact with users remotely through a computer
 | 
			
		||||
network, you should also make sure that it provides a way for users to
 | 
			
		||||
get its source.  For example, if your program is a web application, its
 | 
			
		||||
interface could display a "Source" link that leads users to an archive
 | 
			
		||||
of the code.  There are many ways you could offer source, and different
 | 
			
		||||
solutions will be better for different programs; see section 13 for the
 | 
			
		||||
specific requirements.
 | 
			
		||||
 | 
			
		||||
  You should also get your employer (if you work as a programmer) or school,
 | 
			
		||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
 | 
			
		||||
For more information on this, and how to apply and follow the GNU AGPL, see
 | 
			
		||||
<http://www.gnu.org/licenses/>.
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
 | 
			
		||||
 | 
			
		||||
SUBDIRS = include src tests
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# package the contrib and doc
 | 
			
		||||
EXTRA_DIST = \
 | 
			
		||||
	contrib/dump_docs.py contrib/screenrc-l1fwd contrib/osmo-bts-sysmo.service \
 | 
			
		||||
	contrib/l1fwd.init contrib/screenrc-sysmobts contrib/respawn.sh \
 | 
			
		||||
	doc/examples/sysmo/osmo-bts.cfg \
 | 
			
		||||
	doc/examples/sysmo/sysmobts-mgr.cfg \
 | 
			
		||||
	doc/examples/virtual/openbsc-virtual.cfg \
 | 
			
		||||
	doc/examples/virtual/osmobts-virtual.cfg \
 | 
			
		||||
	git-version-gen .version \
 | 
			
		||||
	README.md
 | 
			
		||||
 | 
			
		||||
@RELMAKE@
 | 
			
		||||
 | 
			
		||||
BUILT_SOURCES = $(top_srcdir)/.version
 | 
			
		||||
 | 
			
		||||
$(top_srcdir)/.version:
 | 
			
		||||
	echo $(VERSION) > $@-t && mv $@-t $@
 | 
			
		||||
dist-hook:
 | 
			
		||||
	echo $(VERSION) > $(distdir)/.tarball-version
 | 
			
		||||
@@ -0,0 +1,127 @@
 | 
			
		||||
osmo-bts - Osmocom BTS Implementation
 | 
			
		||||
====================================
 | 
			
		||||
 | 
			
		||||
This repository contains a C-language implementation of a GSM Base
 | 
			
		||||
Transceiver Station (BTS). It is part of the
 | 
			
		||||
[Osmocom](https://osmocom.org/) Open Source Mobile Communications
 | 
			
		||||
project.
 | 
			
		||||
 | 
			
		||||
This code implements Layer 2 and higher of a more or less conventional GSM BTS
 | 
			
		||||
(Base Transceiver Station) - however, using an Abis/IP interface, rather than
 | 
			
		||||
the old-fashioned E1/T1.
 | 
			
		||||
 | 
			
		||||
Specifically, this includes
 | 
			
		||||
 * BTS-side implementation of TS 08.58 (RSL) and TS 12.21 (OML)
 | 
			
		||||
 * BTS-side implementation of LAPDm (using libosmocore/libosmogsm)
 | 
			
		||||
 * A somewhat separated interface between those higher layer parts and the
 | 
			
		||||
   Layer1 interface.
 | 
			
		||||
 | 
			
		||||
Several kinds of BTS hardware are supported:
 | 
			
		||||
 * sysmocom sysmoBTS
 | 
			
		||||
 * Octasic octphy
 | 
			
		||||
 * Nutaq litecell 1.5
 | 
			
		||||
 * software-defined radio based osmo-bts-trx (e.g. USRP B210, UmTRX)
 | 
			
		||||
 | 
			
		||||
Homepage
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
The official homepage of the project is
 | 
			
		||||
https://osmocom.org/projects/osmobts/wiki
 | 
			
		||||
 | 
			
		||||
GIT Repository
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
You can clone from the official osmo-bts.git repository using
 | 
			
		||||
 | 
			
		||||
	git clone git://git.osmocom.org/osmo-bts.git
 | 
			
		||||
 | 
			
		||||
There is a cgit interface at http://git.osmocom.org/osmo-bts/
 | 
			
		||||
 | 
			
		||||
Documentation
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
We provide a 
 | 
			
		||||
[User Manual](http://ftp.osmocom.org/docs/latest/osmobts-usermanual.pdf)
 | 
			
		||||
as well as a
 | 
			
		||||
[VTY Reference Manual](http://ftp.osmocom.org/docs/latest/osmobsc-vty-reference.pdf)
 | 
			
		||||
and a
 | 
			
		||||
[Abis refrence MAnual](http://ftp.osmocom.org/docs/latest/osmobts-abis.pdf)
 | 
			
		||||
describing the OsmoBTS specific A-bis dialect.
 | 
			
		||||
 | 
			
		||||
Mailing List
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Discussions related to osmo-bts 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-bts can be seen at
 | 
			
		||||
https://gerrit.osmocom.org/#/q/project:osmo-bts+status:open
 | 
			
		||||
 | 
			
		||||
Known Limitations
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
As of March 17, 2017, the following known limitations exist in this
 | 
			
		||||
implementation:
 | 
			
		||||
 | 
			
		||||
Common Core
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
 * No Extended BCCH support
 | 
			
		||||
 * System Information limited to 1,2,2bis,2ter,2quater,3,4,5,6,9,13
 | 
			
		||||
 * No RATSCCH in AMR
 | 
			
		||||
 * Will reject TS 12.21 STARTING TIME in SET BTS ATTR / SET CHAN ATTR
 | 
			
		||||
 * No support for frequency hopping
 | 
			
		||||
 * No reporting of interference levels as part of TS 08.58 RF RES IND
 | 
			
		||||
 * No error reporting in case PAGING COMMAND fails due to queue overflow
 | 
			
		||||
 * No use of TS 08.58 BS Power and MS Power parameters
 | 
			
		||||
 * No support of TS 08.58 MultiRate Control
 | 
			
		||||
 * No support of TS 08.58 Supported Codec Types
 | 
			
		||||
 * No support of Bter frame / ENHANCED MEASUREMENT REPORT
 | 
			
		||||
 | 
			
		||||
osmo-bts-sysmo
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
 * No CSD / ECSD support (not planned)
 | 
			
		||||
 * GSM-R frequency band supported, but no NCH/ASCI/SoLSA
 | 
			
		||||
 * All timeslots on one TRX have to use same training sequence (TSC)
 | 
			
		||||
 * No multi-TRX support yet, though hardware+L1 support stacking
 | 
			
		||||
 * Makes no use of 12.21 Intave Parameters and Interference
 | 
			
		||||
   Level Boundaries
 | 
			
		||||
 * MphConfig.CNF can be returned to the wrong callback. E.g. with Tx Power
 | 
			
		||||
   and ciphering. The dispatch should take a look at the hLayer3.
 | 
			
		||||
 | 
			
		||||
osmo-bts-octphy
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
 * No support of EFR, HR voice codec (lack of PHY support?)
 | 
			
		||||
 * No re-transmission of PHY primitives in case of time-out
 | 
			
		||||
 * Link Quality / Measurement processing incomplete
 | 
			
		||||
 * impossible to modify encryption parameters using RSL MODE MODIFY
 | 
			
		||||
 * no clear indication of nominal transmit power, various power related
 | 
			
		||||
   computations are likely off
 | 
			
		||||
 * no OML attribute validation during bts_model_check_oml()
 | 
			
		||||
 | 
			
		||||
osmo-bts-trx
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
 * TCH/F_PDCH cannel not working as voice (https://osmocom.org/issues/1865)
 | 
			
		||||
 * No BER value delivered to OsmoPCU (https://osmocom.org/issues/1855)
 | 
			
		||||
 * No 11bit RACH support (https://osmocom.org/issues/1854)
 | 
			
		||||
 * No CBCH support (https://osmocom.org/issues/1617)
 | 
			
		||||
@@ -0,0 +1,302 @@
 | 
			
		||||
dnl Process this file with autoconf to produce a configure script
 | 
			
		||||
AC_INIT([osmo-bts],
 | 
			
		||||
	m4_esyscmd([./git-version-gen .tarball-version]),
 | 
			
		||||
	[openbsc@lists.osmocom.org])
 | 
			
		||||
 | 
			
		||||
dnl *This* is the root dir, even if an install-sh exists in ../ or ../../
 | 
			
		||||
AC_CONFIG_AUX_DIR([.])
 | 
			
		||||
 | 
			
		||||
AM_INIT_AUTOMAKE([dist-bzip2])
 | 
			
		||||
AC_CONFIG_TESTDIR(tests)
 | 
			
		||||
 | 
			
		||||
dnl kernel style compile messages
 | 
			
		||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 | 
			
		||||
 | 
			
		||||
dnl include release helper
 | 
			
		||||
RELMAKE='-include osmo-release.mk'
 | 
			
		||||
AC_SUBST([RELMAKE])
 | 
			
		||||
 | 
			
		||||
dnl checks for programs
 | 
			
		||||
AC_PROG_MAKE_SET
 | 
			
		||||
AC_PROG_CC
 | 
			
		||||
AC_PROG_INSTALL
 | 
			
		||||
LT_INIT
 | 
			
		||||
 | 
			
		||||
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
 | 
			
		||||
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
 | 
			
		||||
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
 | 
			
		||||
        AC_MSG_WARN([You need to install pkg-config])
 | 
			
		||||
fi
 | 
			
		||||
PKG_PROG_PKG_CONFIG([0.20])
 | 
			
		||||
 | 
			
		||||
dnl checks for header files
 | 
			
		||||
AC_HEADER_STDC
 | 
			
		||||
 | 
			
		||||
dnl Checks for typedefs, structures and compiler characteristics
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(sanitize,
 | 
			
		||||
		[AS_HELP_STRING([--enable-sanitize], [Compile with address sanitizer enabled], )],
 | 
			
		||||
		[sanitize=$enableval], [sanitize="no"])
 | 
			
		||||
if test x"$sanitize" = x"yes"
 | 
			
		||||
then
 | 
			
		||||
	CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
 | 
			
		||||
	CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(werror,
 | 
			
		||||
	[AS_HELP_STRING(
 | 
			
		||||
		[--enable-werror],
 | 
			
		||||
		[Turn all compiler warnings into errors, with exceptions:
 | 
			
		||||
		 a) deprecation (allow upstream to mark deprecation without breaking builds);
 | 
			
		||||
		 b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
 | 
			
		||||
		]
 | 
			
		||||
	)],
 | 
			
		||||
	[werror=$enableval], [werror="no"])
 | 
			
		||||
if test x"$werror" = x"yes"
 | 
			
		||||
then
 | 
			
		||||
	WERROR_FLAGS="-Werror"
 | 
			
		||||
	WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
			
		||||
	WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
			
		||||
	CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
			
		||||
	CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl checks for libraries
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore  >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.5.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 0.5.0)
 | 
			
		||||
PKG_CHECK_MODULES(ORTP, ortp)
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([whether to enable support for sysmobts calibration tool])
 | 
			
		||||
AC_ARG_ENABLE(sysmobts-calib,
 | 
			
		||||
		AC_HELP_STRING([--enable-sysmobts-calib],
 | 
			
		||||
				[enable code for sysmobts calibration tool [default=no]]),
 | 
			
		||||
		[enable_sysmobts_calib="yes"],[enable_sysmobts_calib="no"])
 | 
			
		||||
AC_MSG_RESULT([$enable_sysmobts_calib])
 | 
			
		||||
AM_CONDITIONAL(ENABLE_SYSMOBTS_CALIB, test "x$enable_sysmobts_calib" = "xyes")
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([whether to enable support for sysmoBTS L1/PHY support])
 | 
			
		||||
AC_ARG_ENABLE(sysmocom-bts,
 | 
			
		||||
		AC_HELP_STRING([--enable-sysmocom-bts],
 | 
			
		||||
				[enable code for sysmoBTS L1/PHY [default=no]]),
 | 
			
		||||
		[enable_sysmocom_bts="yes"],[enable_sysmocom_bts="no"])
 | 
			
		||||
AC_ARG_WITH([sysmobts], [AS_HELP_STRING([--with-sysmobts=INCLUDE_DIR], [Location of the sysmobts API header files, implies --enable-sysmocom-bts])],
 | 
			
		||||
			 [sysmobts_incdir="$withval"],[sysmobts_incdir="$incdir"])
 | 
			
		||||
if test "x$sysmobts_incdir" != "x"; then
 | 
			
		||||
	# --with-sysmobts was passed, imply enable_sysmocom_bts
 | 
			
		||||
	enable_sysmocom_bts="yes"
 | 
			
		||||
fi
 | 
			
		||||
AC_SUBST([SYSMOBTS_INCDIR], -I$sysmobts_incdir)
 | 
			
		||||
AC_MSG_RESULT([$enable_sysmocom_bts])
 | 
			
		||||
AM_CONDITIONAL(ENABLE_SYSMOBTS, test "x$enable_sysmocom_bts" = "xyes")
 | 
			
		||||
if test "$enable_sysmocom_bts" = "yes"; then
 | 
			
		||||
	oldCPPFLAGS=$CPPFLAGS
 | 
			
		||||
	CPPFLAGS="$CPPFLAGS $SYSMOBTS_INCDIR -I$srcdir/include"
 | 
			
		||||
	AC_CHECK_HEADER([sysmocom/femtobts/superfemto.h],[],
 | 
			
		||||
			[AC_MSG_ERROR([sysmocom/femtobts/superfemto.h can not be found in $sysmobts_incdir])],
 | 
			
		||||
			[#include <sysmocom/femtobts/superfemto.h>])
 | 
			
		||||
 | 
			
		||||
	# Check for the sbts2050_header.h that was added after the 3.6 release
 | 
			
		||||
	AC_CHECK_HEADER([sysmocom/femtobts/sbts2050_header.h], [sysmo_uc_header="yes"], [])
 | 
			
		||||
	if test "$sysmo_uc_header" = "yes" ; then
 | 
			
		||||
	   	AC_DEFINE(BUILD_SBTS2050, 1, [Define if we want to build SBTS2050])
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
	PKG_CHECK_MODULES(LIBGPS, libgps)
 | 
			
		||||
	CPPFLAGS=$oldCPPFLAGS
 | 
			
		||||
fi
 | 
			
		||||
AM_CONDITIONAL(BUILD_SBTS2050, test "x$sysmo_uc_header" = "xyes")
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([whether to enable support for osmo-trx based L1/PHY support])
 | 
			
		||||
AC_ARG_ENABLE(trx,
 | 
			
		||||
		AC_HELP_STRING([--enable-trx],
 | 
			
		||||
				[enable code for osmo-trx L1/PHY [default=no]]),
 | 
			
		||||
		[enable_trx="yes"],[enable_trx="no"])
 | 
			
		||||
AC_MSG_RESULT([$enable_trx])
 | 
			
		||||
AM_CONDITIONAL(ENABLE_TRX, test "x$enable_trx" = "xyes")
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([whether to enable support for Octasic OCTPHY-2G])
 | 
			
		||||
AC_ARG_ENABLE(octphy,
 | 
			
		||||
		AC_HELP_STRING([--enable-octphy],
 | 
			
		||||
				[enable code for Octasic OCTPHY-2G [default=no]]),
 | 
			
		||||
		[enable_octphy="yes"],[enable_octphy="no"])
 | 
			
		||||
AC_ARG_WITH([octsdr-2g], [AS_HELP_STRING([--with-octsdr-2g], [Location of the OCTSDR-2G API header files])],
 | 
			
		||||
			 [octsdr2g_incdir="$withval"],[octsdr2g_incdir="`cd $srcdir; pwd`/src/osmo-bts-octphy/"])
 | 
			
		||||
AC_SUBST([OCTSDR2G_INCDIR], -I$octsdr2g_incdir)
 | 
			
		||||
AC_MSG_RESULT([$enable_octphy])
 | 
			
		||||
AM_CONDITIONAL(ENABLE_OCTPHY, test "x$enable_octphy" = "xyes")
 | 
			
		||||
if test "$enable_octphy" = "yes" ; then
 | 
			
		||||
	oldCPPFLAGS=$CPPFLAGS
 | 
			
		||||
	CPPFLAGS="$CPPFLAGS $OCTSDR2G_INCDIR -I$srcdir/include"
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_HEADER([octphy/octvc1/gsm/octvc1_gsm_default.h],[],
 | 
			
		||||
			[AC_MSG_ERROR([octphy/octvc1/gsm/octvc1_gsm_default.h can not be found in $octsdr2g_incdir])],
 | 
			
		||||
			[#include <octphy/octvc1/gsm/octvc1_gsm_default.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_GSM_TRX_CONFIG.usCentreArfcn],
 | 
			
		||||
			AC_DEFINE([OCTPHY_MULTI_TRX],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files support multi-trx]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/gsm/octvc1_gsm_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_RF_PORT_RX_STATS.Frequency],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_FREQUENCY],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files support tOCTVC1_RADIO_FREQUENCY_VALUE type]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_RSP.TxConfig],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_TX_CONFIG],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files support tOCTVC1_HW_RF_PORT_ANTENNA_TX_CONFIG type]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_RSP.RxConfig],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_RX_CONFIG],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files support tOCTVC1_HW_RF_PORT_ANTENNA_RX_CONFIG type]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_GSM_RF_CONFIG.ulTxAntennaId],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_ANTENNA_ID],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files support antenna ids in tOCTVC1_GSM_RF_CONFIG]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/gsm/octvc1_gsm_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP.ulClkSourceSelection],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLK_SOURCE_SELECTION],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulClkSourceSelection in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.lClockError],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_CLOCK_ERROR],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports lClockError in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.lDroppedCycles],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_DROPPED_CYCLES],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports lDroppedCycles in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.ulPllFreqHz],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_PLL_FREQ_HZ],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulPllFreqHz in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.ulPllFractionalFreqHz],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_PLL_FRACTIONAL_FREQ_HZ],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulPllFractionalFreqHz in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.ulSlipCnt],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_SLIP_CNT],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulSlipCnt in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.ulSyncLosseCnt],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_SYNC_LOSSE_CNT],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulSyncLosseCnt in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.ulSyncLossCnt],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_SYNC_LOSS_CNT],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulSyncLossCnt in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.ulSourceState],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_SOURCE_STATE],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulSourceState in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.ulDacState],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_DAC_STATE],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulDacState in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	AC_CHECK_MEMBER([tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP.ulDriftElapseTimeUs],
 | 
			
		||||
			AC_DEFINE([OCTPHY_USE_CLOCK_SYNC_MGR_STATS_DRIFT_ELAPSE_TIME_US],
 | 
			
		||||
			[1],
 | 
			
		||||
			[Define to 1 if your octphy header files supports ulDriftElapseTimeUs in tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP]),
 | 
			
		||||
			[],
 | 
			
		||||
			[#include <octphy/octvc1/hw/octvc1_hw_api.h>])
 | 
			
		||||
 | 
			
		||||
	CPPFLAGS=$oldCPPFLAGS
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([whether to enable NuRAN Wireless Litecell 1.5 hardware support])
 | 
			
		||||
AC_ARG_ENABLE(litecell15,
 | 
			
		||||
		AC_HELP_STRING([--enable-litecell15],
 | 
			
		||||
				[enable code for NuRAN Wireless Litecell15 bts [default=no]]),
 | 
			
		||||
		[enable_litecell15="yes"],[enable_litecell15="no"])
 | 
			
		||||
AC_ARG_WITH([litecell15], [AS_HELP_STRING([--with-litecell15=INCLUDE_DIR], [Location of the litecell 1.5 API header files])],
 | 
			
		||||
			 [litecell15_incdir="$withval"],[litecell15_incdir="$incdir"])
 | 
			
		||||
AC_SUBST([LITECELL15_INCDIR], -I$litecell15_incdir)
 | 
			
		||||
AC_MSG_RESULT([$enable_litecell15])
 | 
			
		||||
AM_CONDITIONAL(ENABLE_LC15BTS, test "x$enable_litecell15" = "xyes")
 | 
			
		||||
if test "$enable_litecell15" = "yes"; then
 | 
			
		||||
	oldCPPFLAGS=$CPPFLAGS
 | 
			
		||||
	CPPFLAGS="$CPPFLAGS $LITECELL15_INCDIR -I$srcdir/include"
 | 
			
		||||
	AC_CHECK_HEADER([nrw/litecell15/litecell15.h],[],
 | 
			
		||||
			[AC_MSG_ERROR([nrw/litecell15/litecell15.h can not be found in $litecell15_incdir])],
 | 
			
		||||
			[#include <nrw/litecell15/litecell15.h>])
 | 
			
		||||
	PKG_CHECK_MODULES(LIBSYSTEMD, libsystemd)
 | 
			
		||||
	CPPFLAGS=$oldCPPFLAGS
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AC_MSG_RESULT([CFLAGS="$CFLAGS"])
 | 
			
		||||
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
 | 
			
		||||
 | 
			
		||||
AM_CONFIG_HEADER(btsconfig.h)
 | 
			
		||||
 | 
			
		||||
AC_OUTPUT(
 | 
			
		||||
    src/Makefile
 | 
			
		||||
    src/common/Makefile
 | 
			
		||||
    src/osmo-bts-virtual/Makefile
 | 
			
		||||
    src/osmo-bts-omldummy/Makefile
 | 
			
		||||
    src/osmo-bts-sysmo/Makefile
 | 
			
		||||
    src/osmo-bts-litecell15/Makefile
 | 
			
		||||
    src/osmo-bts-trx/Makefile
 | 
			
		||||
    src/osmo-bts-octphy/Makefile
 | 
			
		||||
    include/Makefile
 | 
			
		||||
    include/osmo-bts/Makefile
 | 
			
		||||
    tests/Makefile
 | 
			
		||||
    tests/paging/Makefile
 | 
			
		||||
    tests/agch/Makefile
 | 
			
		||||
    tests/cipher/Makefile
 | 
			
		||||
    tests/sysmobts/Makefile
 | 
			
		||||
    tests/misc/Makefile
 | 
			
		||||
    tests/handover/Makefile
 | 
			
		||||
    tests/tx_power/Makefile
 | 
			
		||||
    tests/power/Makefile
 | 
			
		||||
    tests/meas/Makefile
 | 
			
		||||
    Makefile)
 | 
			
		||||
@@ -0,0 +1,89 @@
 | 
			
		||||
#!/usr/bin/gawk -f
 | 
			
		||||
 | 
			
		||||
# Expected input format: FN TYPE
 | 
			
		||||
 | 
			
		||||
BEGIN {
 | 
			
		||||
	DELTA = 0
 | 
			
		||||
	ERR = 0
 | 
			
		||||
	FORCE = 0
 | 
			
		||||
	FN = 0
 | 
			
		||||
	SILENCE = 0
 | 
			
		||||
	TYPE = ""
 | 
			
		||||
	CHK = ""
 | 
			
		||||
	U_MAX = 8 * 20 + 120 / 26
 | 
			
		||||
	U_MIN = 8 * 20 - 120 / 26
 | 
			
		||||
	F_MAX = 3 * 20 + 120 / 26
 | 
			
		||||
	F_MIN = 3 * 20 - 120 / 26
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
	if (NR > 2) { # we have data from previous record to compare to
 | 
			
		||||
		DELTA = ($1 - FN) * 120 / 26
 | 
			
		||||
		CHK = "OK"
 | 
			
		||||
		if ("FACCH" == $2 && "ONSET" == TYPE) { # ONSET due to FACCH is NOT a talkspurt
 | 
			
		||||
			SILENCE = 1
 | 
			
		||||
		}
 | 
			
		||||
		if (("UPDATE" == TYPE || "FIRST" == TYPE) && ("FACCH" == $2 || "SPEECH" == $2)) { # check for missing ONSET:
 | 
			
		||||
				CHK = "FAIL: missing ONSET (" $2 ") after " TYPE "."
 | 
			
		||||
				ERR++
 | 
			
		||||
		}
 | 
			
		||||
		if ("SID_P1" == $2) {
 | 
			
		||||
			CHK = "FAIL: regular AMR payload with FT SID and STI=0 (should be either pyaload Update or STI=1)."
 | 
			
		||||
			ERR++
 | 
			
		||||
		}
 | 
			
		||||
		if ("FORCED_FIRST" == $2 || "FORCED_NODATA" == $2 || "FORCED_F_P2" == $2 || "FORCED_F_INH" == $2 || "FORCED_U_INH" == $2) {
 | 
			
		||||
			CHK = "FAIL: event " $2 " inserted by DSP."
 | 
			
		||||
			FORCE++
 | 
			
		||||
			ERR++
 | 
			
		||||
		}
 | 
			
		||||
		if ("FIRST_P2" != $2 && "FIRST_P1" == TYPE) {
 | 
			
		||||
			CHK = "FAIL: " TYPE " followed by " $2 " instead of P2."
 | 
			
		||||
			ERR++
 | 
			
		||||
		}
 | 
			
		||||
		if ("FIRST" == $2 && "FIRST" == TYPE) {
 | 
			
		||||
			CHK = "FAIL: multiple SID FIRST in a row."
 | 
			
		||||
			ERR++
 | 
			
		||||
		}
 | 
			
		||||
		if ("OK" == CHK && "ONSET" != $2) { # check inter-SID distances:
 | 
			
		||||
			if ("UPDATE" == TYPE) {
 | 
			
		||||
				if (DELTA > U_MAX) {
 | 
			
		||||
					CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too big " DELTA "ms > " U_MAX "ms."
 | 
			
		||||
					ERR++
 | 
			
		||||
				}
 | 
			
		||||
				if ("UPDATE" == $2 && DELTA < U_MIN) {
 | 
			
		||||
					CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too small " DELTA "ms < " U_MIN "ms."
 | 
			
		||||
					ERR++
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if ("FIRST" == TYPE) {
 | 
			
		||||
				if (DELTA > F_MAX) {
 | 
			
		||||
					CHK = "FAIL: delta (" $1 - FN "fn) from previous SID FIRST (@" FN ") too big " DELTA "ms > " F_MAX "ms."
 | 
			
		||||
					ERR++
 | 
			
		||||
				}
 | 
			
		||||
				if ("UPDATE" == $2 && DELTA < F_MIN) {
 | 
			
		||||
					CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too small " DELTA "ms < " F_MIN "ms."
 | 
			
		||||
					ERR++
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if ("FACCH" == TYPE && "FIRST" != $2 && "FACCH" != $2 && 1 == SILENCE) { # check FACCH handling
 | 
			
		||||
			CHK = "FAIL: incorrect silence resume with " $2 " after FACCH."
 | 
			
		||||
			ERR++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ("SPEECH" == $2 || "ONSET" == $2) { # talkspurt
 | 
			
		||||
		SILENCE = 0
 | 
			
		||||
	}
 | 
			
		||||
	if ("UPDATE" == $2 || "FIRST" == $2) { # silence
 | 
			
		||||
		SILENCE = 1
 | 
			
		||||
	}
 | 
			
		||||
	print $1, $2, CHK
 | 
			
		||||
	if ($2 != "EMPTY") { # skip over EMPTY records
 | 
			
		||||
		TYPE = $2
 | 
			
		||||
		FN = $1
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
END {
 | 
			
		||||
	print "Check completed: found " ERR " errors (" FORCE " events inserted by DSP) in " NR " records."
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Start the process and dump the documentation to the doc dir
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import socket, subprocess, time,os
 | 
			
		||||
 | 
			
		||||
env = os.environ
 | 
			
		||||
env['L1FWD_BTS_HOST'] = '127.0.0.1'
 | 
			
		||||
 | 
			
		||||
bts_proc = subprocess.Popen(["./src/osmo-bts-sysmo/sysmobts-remote",
 | 
			
		||||
		"-c", "./doc/examples/sysmo/osmo-bts.cfg"], env = env,
 | 
			
		||||
		stdin=None, stdout=None)
 | 
			
		||||
time.sleep(1)
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
	sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 | 
			
		||||
	sck.setblocking(1)
 | 
			
		||||
	sck.connect(("localhost", 4241))
 | 
			
		||||
	sck.recv(4096)
 | 
			
		||||
 | 
			
		||||
	# Now send the command
 | 
			
		||||
	sck.send("show online-help\r")
 | 
			
		||||
	xml = ""
 | 
			
		||||
	while True:
 | 
			
		||||
		data = sck.recv(4096)
 | 
			
		||||
		xml = "%s%s" % (xml, data)
 | 
			
		||||
		if data.endswith('\r\nOsmoBTS> '):
 | 
			
		||||
			break
 | 
			
		||||
 | 
			
		||||
	# Now write everything until the end to the file
 | 
			
		||||
	out = open('doc/vty_reference.xml', 'w')
 | 
			
		||||
	out.write(xml[18:-11])
 | 
			
		||||
	out.close()
 | 
			
		||||
finally:
 | 
			
		||||
	# Clean-up
 | 
			
		||||
	bts_proc.kill()
 | 
			
		||||
	bts_proc.wait()
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,91 @@
 | 
			
		||||
/* GPLv3+ to read sysmobts-v2 revD or later EEPROM from userspace */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <linux/i2c.h>
 | 
			
		||||
#include <linux/i2c-dev.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Can read a 16bit at24 eeprom with 8192 byte in storage (24c64) */
 | 
			
		||||
static int dump_eeprom(int fd, int out)
 | 
			
		||||
{
 | 
			
		||||
#define STEP 8192
 | 
			
		||||
#define SIZE 8192
 | 
			
		||||
	uint8_t buf[STEP + 2];
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < SIZE; i += STEP) {
 | 
			
		||||
		/* write the address */
 | 
			
		||||
		buf[0] = i >> 8;
 | 
			
		||||
		buf[1] = i;
 | 
			
		||||
		rc = write(fd, buf, 2);
 | 
			
		||||
		if (rc != 2) {
 | 
			
		||||
			fprintf(stderr, "writing address failed: %d/%d/%s\n", rc, errno, strerror(errno));
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* execute step amount of reads */
 | 
			
		||||
		rc = read(fd, buf, STEP);
 | 
			
		||||
		if (rc != STEP) {
 | 
			
		||||
			fprintf(stderr, "Failed to read: %d/%d/%s\n", rc, errno, strerror(errno));
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		write(out, buf, STEP);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	int i2c_fd, out_fd;
 | 
			
		||||
	char *filename = "/dev/i2c-1";
 | 
			
		||||
	char *out_file = "eeprom.out";
 | 
			
		||||
	int addr = 0x50;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	i2c_fd = open(filename, O_RDWR);
 | 
			
		||||
	if (i2c_fd < 0) {
 | 
			
		||||
		fprintf(stderr, "Failed to open i2c device %d/%d/%s\n",
 | 
			
		||||
			i2c_fd, errno, strerror(errno));
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* force using that address it is already bound with a driver */
 | 
			
		||||
	rc = ioctl(i2c_fd, I2C_SLAVE_FORCE, addr);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "Failed to claim i2c device %d/%d/%s\n",
 | 
			
		||||
			rc, errno, strerror(errno));
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (argc >= 2)
 | 
			
		||||
		out_file = argv[1];
 | 
			
		||||
	out_fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
 | 
			
		||||
	if (out_fd < 0) {
 | 
			
		||||
		fprintf(stderr, "Failed to open out device %s %d/%d/%s\n",
 | 
			
		||||
			out_file, rc, errno, strerror(errno));
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dump_eeprom(i2c_fd, out_fd) != 0) {
 | 
			
		||||
		unlink(out_file);
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# this is a dispatcher script which will call the bts-model-specific
 | 
			
		||||
# script based on the bts model specified as command line argument
 | 
			
		||||
 | 
			
		||||
bts_model="$1"
 | 
			
		||||
 | 
			
		||||
if [ "x$bts_model" = "x" ]; then
 | 
			
		||||
	echo "Error: You have to specify the BTS model as first argument, e.g. $0 sysmo"
 | 
			
		||||
	exit 2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ ! -d "./contrib" ]; then
 | 
			
		||||
  echo "Run ./contrib/jenkins_bts_model.sh from the root of the osmo-bts tree"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
set -x -e
 | 
			
		||||
 | 
			
		||||
case "$bts_model" in
 | 
			
		||||
 | 
			
		||||
  sysmo)
 | 
			
		||||
    ./contrib/jenkins_sysmobts.sh
 | 
			
		||||
  ;;
 | 
			
		||||
 | 
			
		||||
  oct)
 | 
			
		||||
    ./contrib/jenkins_oct.sh
 | 
			
		||||
  ;;
 | 
			
		||||
 | 
			
		||||
  lc15)
 | 
			
		||||
    ./contrib/jenkins_lc15.sh
 | 
			
		||||
  ;;
 | 
			
		||||
 | 
			
		||||
  trx)
 | 
			
		||||
    ./contrib/jenkins_bts_trx.sh
 | 
			
		||||
  ;;
 | 
			
		||||
 | 
			
		||||
  oct+trx)
 | 
			
		||||
    ./contrib/jenkins_oct_and_bts_trx.sh
 | 
			
		||||
  ;;
 | 
			
		||||
 | 
			
		||||
  *)
 | 
			
		||||
    set +x
 | 
			
		||||
    echo "Unknown BTS model '$bts_model'"
 | 
			
		||||
  ;;
 | 
			
		||||
esac
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# jenkins build helper script for osmo-bts-trx
 | 
			
		||||
 | 
			
		||||
# shellcheck source=contrib/jenkins_common.sh
 | 
			
		||||
. $(dirname "$0")/jenkins_common.sh
 | 
			
		||||
 | 
			
		||||
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
			
		||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmocore "" --disable-doxygen
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmo-abis
 | 
			
		||||
 | 
			
		||||
cd "$deps"
 | 
			
		||||
 | 
			
		||||
configure_flags="\
 | 
			
		||||
  --with-osmo-pcu=$deps/osmo-pcu/include \
 | 
			
		||||
  --enable-trx \
 | 
			
		||||
  --enable-sanitize \
 | 
			
		||||
  "
 | 
			
		||||
 | 
			
		||||
build_bts "osmo-bts-trx" "$configure_flags"
 | 
			
		||||
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
@@ -0,0 +1,47 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
# this is a common helper script that is shared among all BTS model
 | 
			
		||||
# specific helper scripts like jenkins_sysmobts.sh.  You shouldn't call
 | 
			
		||||
# this directly, but rather indirectly via the bts-specific scripts
 | 
			
		||||
 | 
			
		||||
if ! [ -x "$(command -v osmo-deps.sh)" ]; then
 | 
			
		||||
	echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
 | 
			
		||||
	exit 2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
set -ex
 | 
			
		||||
 | 
			
		||||
base="$PWD"
 | 
			
		||||
deps="$base/deps"
 | 
			
		||||
inst="$deps/install"
 | 
			
		||||
 | 
			
		||||
export deps inst
 | 
			
		||||
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
 | 
			
		||||
mkdir -p "$deps"
 | 
			
		||||
 | 
			
		||||
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
			
		||||
 | 
			
		||||
# generic project build function, usage:
 | 
			
		||||
# build "PROJECT-NAME" "CONFIGURE OPTIONS"
 | 
			
		||||
build_bts() {
 | 
			
		||||
    set +x
 | 
			
		||||
    echo
 | 
			
		||||
    echo
 | 
			
		||||
    echo
 | 
			
		||||
    echo " =============================== $1 ==============================="
 | 
			
		||||
    echo
 | 
			
		||||
    set -x
 | 
			
		||||
 | 
			
		||||
    cd $deps
 | 
			
		||||
    osmo-deps.sh libosmocore
 | 
			
		||||
    cd $base
 | 
			
		||||
    shift
 | 
			
		||||
    conf_flags="$*"
 | 
			
		||||
    autoreconf --install --force
 | 
			
		||||
    ./configure $conf_flags
 | 
			
		||||
    $MAKE $PARALLEL_MAKE
 | 
			
		||||
    $MAKE check || cat-testlogs.sh
 | 
			
		||||
    DISTCHECK_CONFIGURE_FLAGS="$conf_flags" $MAKE distcheck || cat-testlogs.sh
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# jenkins build helper script for osmo-bts-lc15
 | 
			
		||||
 | 
			
		||||
# shellcheck source=contrib/jenkins_common.sh
 | 
			
		||||
. $(dirname "$0")/jenkins_common.sh
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmocore "" --disable-doxygen
 | 
			
		||||
 | 
			
		||||
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
			
		||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmo-abis
 | 
			
		||||
 | 
			
		||||
cd "$deps"
 | 
			
		||||
osmo-layer1-headers.sh lc15 "$FIRMWARE_VERSION"
 | 
			
		||||
 | 
			
		||||
configure_flags="--enable-sanitize --with-litecell15=$deps/layer1-headers/inc/ --enable-litecell15"
 | 
			
		||||
 | 
			
		||||
build_bts "osmo-bts-lc15" "$configure_flags"
 | 
			
		||||
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# jenkins build helper script for osmo-bts-octphy
 | 
			
		||||
 | 
			
		||||
# shellcheck source=contrib/jenkins_common.sh
 | 
			
		||||
. $(dirname "$0")/jenkins_common.sh
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmocore "" --disable-doxygen
 | 
			
		||||
 | 
			
		||||
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
			
		||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmo-abis
 | 
			
		||||
 | 
			
		||||
cd "$deps"
 | 
			
		||||
osmo-layer1-headers.sh oct "$FIRMWARE_VERSION"
 | 
			
		||||
 | 
			
		||||
configure_flags="--enable-sanitize --with-octsdr-2g=$deps/layer1-headers/ --enable-octphy"
 | 
			
		||||
 | 
			
		||||
build_bts "osmo-bts-octphy" "$configure_flags"
 | 
			
		||||
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# jenkins build helper script for osmo-bts-octphy + osmo-bts-trx
 | 
			
		||||
 | 
			
		||||
# shellcheck source=contrib/jenkins_common.sh
 | 
			
		||||
. $(dirname "$0")/jenkins_common.sh
 | 
			
		||||
 | 
			
		||||
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
			
		||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmocore "" --disable-doxygen
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmo-abis
 | 
			
		||||
 | 
			
		||||
cd "$deps"
 | 
			
		||||
 | 
			
		||||
osmo-layer1-headers.sh oct "$FIRMWARE_VERSION"
 | 
			
		||||
 | 
			
		||||
configure_flags="\
 | 
			
		||||
  --with-osmo-pcu=$deps/osmo-pcu/include \
 | 
			
		||||
  --with-octsdr-2g=$deps/layer1-headers/ \
 | 
			
		||||
  --enable-octphy \
 | 
			
		||||
  --enable-trx \
 | 
			
		||||
  "
 | 
			
		||||
 | 
			
		||||
build_bts "osmo-bts-octphy+trx" "$configure_flags"
 | 
			
		||||
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# jenkins build helper script for osmo-bts-sysmo
 | 
			
		||||
 | 
			
		||||
# shellcheck source=contrib/jenkins_common.sh
 | 
			
		||||
. $(dirname "$0")/jenkins_common.sh
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmocore "" --disable-doxygen
 | 
			
		||||
 | 
			
		||||
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
 | 
			
		||||
export LD_LIBRARY_PATH="$inst/lib"
 | 
			
		||||
 | 
			
		||||
osmo-build-dep.sh libosmo-abis
 | 
			
		||||
 | 
			
		||||
cd "$deps"
 | 
			
		||||
osmo-layer1-headers.sh sysmo "$FIRMWARE_VERSION"
 | 
			
		||||
mkdir -p "$inst/include/sysmocom/femtobts"
 | 
			
		||||
ln -s $deps/layer1-headers/include/* "$inst/include/sysmocom/femtobts/"
 | 
			
		||||
 | 
			
		||||
configure_flags="--enable-sanitize --enable-sysmocom-bts --with-sysmobts=$inst/include/"
 | 
			
		||||
 | 
			
		||||
# This will not work for the femtobts
 | 
			
		||||
if [ $FIRMWARE_VERSION != "femtobts_v2.7" ]; then
 | 
			
		||||
    configure_flags="$configure_flags --enable-sysmobts-calib"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
build_bts "osmo-bts-sysmo" "$configure_flags"
 | 
			
		||||
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
### BEGIN INIT INFO
 | 
			
		||||
# Provides:          l1fwd
 | 
			
		||||
# Required-Start:    
 | 
			
		||||
# Required-Stop:     $local_fs
 | 
			
		||||
# Default-Start:     5
 | 
			
		||||
# Default-Stop:      0 6
 | 
			
		||||
# Short-Description: Start screen session with l1fwd software
 | 
			
		||||
# Description:       
 | 
			
		||||
### END INIT INFO
 | 
			
		||||
 | 
			
		||||
. /etc/default/rcS
 | 
			
		||||
 | 
			
		||||
case "$1" in
 | 
			
		||||
        start)
 | 
			
		||||
		/usr/bin/screen -d -m -c /etc/osmocom/screenrc-l1fwd
 | 
			
		||||
                ;;
 | 
			
		||||
	stop)
 | 
			
		||||
		echo "This script doesn't support stop"
 | 
			
		||||
                exit 1
 | 
			
		||||
		;;
 | 
			
		||||
        restart|reload|force-reload)
 | 
			
		||||
                exit 0
 | 
			
		||||
                ;;
 | 
			
		||||
	show)
 | 
			
		||||
		;;
 | 
			
		||||
        *)
 | 
			
		||||
                echo "Usage: sysmobts {start|stop|show|reload|restart}" >&2
 | 
			
		||||
                exit 1
 | 
			
		||||
                ;;
 | 
			
		||||
esac
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=osmo-bts manager for LC15 / sysmoBTS 2100
 | 
			
		||||
After=lc15-sysdev-remap.service
 | 
			
		||||
Wants=lc15-sysdev-remap.service
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
NotifyAccess=all
 | 
			
		||||
WatchdogSec=21780s
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
 | 
			
		||||
# Make sure directories and symbolic link exist
 | 
			
		||||
ExecStartPre=/bin/sh -c 'test -d /mnt/storage/var/run/lc15bts-mgr || mkdir -p /mnt/storage/var/run/lc15bts-mgr ; test -d /var/run/lc15bts-mgr || ln -sf /mnt/storage/var/run/lc15bts-mgr/ /var/run'
 | 
			
		||||
# Make sure BTS operation hour exist
 | 
			
		||||
ExecStartPre=/bin/sh -c 'test -f /mnt/storage/var/run/lc15bts-mgr/hours-running || echo 0 > /mnt/storage/var/run/lc15bts-mgr/hours-running'
 | 
			
		||||
# Shutdown all PA correctly
 | 
			
		||||
ExecStartPre=/bin/sh -c 'echo disabled > /var/lc15/pa-state/pa0/state; echo disabled > /var/lc15/pa-state/pa1/state'
 | 
			
		||||
ExecStartPre=/bin/sh -c 'echo 0 > /var/lc15/pa-supply/max_microvolts; echo 0 > /var/lc15/pa-supply/min_microvolts'
 | 
			
		||||
 | 
			
		||||
ExecStart=/usr/bin/lc15bts-mgr -s -c /etc/osmocom/lc15bts-mgr.cfg
 | 
			
		||||
 | 
			
		||||
# Shutdown all PA correctly
 | 
			
		||||
ExecStopPost=/bin/sh -c 'echo disabled > /var/lc15/pa-state/pa0/state; echo disabled > /var/lc15/pa-state/pa1/state'
 | 
			
		||||
ExecStopPost=/bin/sh -c 'echo 0 > /var/lc15/pa-supply/max_microvolts; echo 0 > /var/lc15/pa-supply/min_microvolts'
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
Alias=osmo-bts-mgr.service
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=osmo-bts for LC15 / sysmoBTS 2100
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStartPre=/bin/sh -c 'echo 1 > /sys/class/leds/usr0/brightness'
 | 
			
		||||
ExecStartPre=/bin/sh -c 'echo 1 > /sys/class/leds/usr1/brightness'
 | 
			
		||||
ExecStart=/usr/bin/osmo-bts-lc15 -t 2 -s -c /etc/osmocom/osmo-bts.cfg -M
 | 
			
		||||
ExecStopPost=/bin/sh -c 'echo 1 > /sys/class/leds/usr0/brightness'
 | 
			
		||||
ExecStopPost=/bin/sh -c 'echo 0 > /sys/class/leds/usr1/brightness'
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
RestartPreventExitStatus=1
 | 
			
		||||
 | 
			
		||||
# The msg queues must be read fast enough
 | 
			
		||||
CPUSchedulingPolicy=rr
 | 
			
		||||
CPUSchedulingPriority=1
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
Alias=osmo-bts.service
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=osmo-bts for sysmocom sysmoBTS
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStartPre=/bin/sh -c 'echo 0 > /sys/class/leds/activity_led/brightness'
 | 
			
		||||
ExecStart=/usr/bin/osmo-bts-sysmo -s -c /etc/osmocom/osmo-bts.cfg -M
 | 
			
		||||
ExecStopPost=/bin/sh -c 'echo 0 > /sys/class/leds/activity_led/brightness'
 | 
			
		||||
ExecStopPost=/bin/sh -c 'cat /lib/firmware/sysmobts-v?.bit > /dev/fpgadl_par0 ; sleep 3s; cat /lib/firmware/sysmobts-v?.out > /dev/dspdl_dm644x_0; sleep 1s'
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
RestartPreventExitStatus=1
 | 
			
		||||
 | 
			
		||||
# The msg queues must be read fast enough
 | 
			
		||||
CPUSchedulingPolicy=rr
 | 
			
		||||
CPUSchedulingPriority=1
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
Alias=sysmobts.service
 | 
			
		||||
Alias=osmo-bts.service
 | 
			
		||||
@@ -0,0 +1,13 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
PID=$$
 | 
			
		||||
echo "-1000" > /proc/$PID/oom_score_adj
 | 
			
		||||
 | 
			
		||||
trap "{ kill 0; kill -2 0; }" EXIT
 | 
			
		||||
 | 
			
		||||
while [ -f $1 ]; do
 | 
			
		||||
	(echo "0" > /proc/self/oom_score_adj && exec nice -n -20 $*) &
 | 
			
		||||
	LAST_PID=$!
 | 
			
		||||
	wait $LAST_PID
 | 
			
		||||
	sleep 10s
 | 
			
		||||
done
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
PID=$$
 | 
			
		||||
echo "-1000" > /proc/$PID/oom_score_adj
 | 
			
		||||
 | 
			
		||||
trap "kill 0" EXIT
 | 
			
		||||
 | 
			
		||||
while [ -e /etc/passwd ]; do
 | 
			
		||||
	cat /lib/firmware/sysmobts-v?.bit > /dev/fpgadl_par0
 | 
			
		||||
	sleep 2s
 | 
			
		||||
	cat /lib/firmware/sysmobts-v?.out > /dev/dspdl_dm644x_0
 | 
			
		||||
	sleep 1s
 | 
			
		||||
	echo "0" > /sys/class/leds/activity_led/brightness
 | 
			
		||||
	(echo "0" > /proc/self/oom_score_adj && exec nice -n -20 $*) &
 | 
			
		||||
	LAST_PID=$!
 | 
			
		||||
	wait $LAST_PID
 | 
			
		||||
	sleep 10s
 | 
			
		||||
done
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
chdir /tmp
 | 
			
		||||
screen -t BTS 0 /etc/osmocom/respawn.sh /usr/bin/l1fwd-proxy
 | 
			
		||||
detach
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
chdir /tmp
 | 
			
		||||
screen -t BTS 0 /etc/osmocom/respawn.sh /usr/bin/osmo-bts-sysmo -c /etc/osmocom/osmo-bts.cfg -r 1 -M
 | 
			
		||||
screen -t PCU 1 /etc/osmocom/respawn-only.sh /usr/bin/osmo-pcu -c /etc/osmocom/osmo-pcu.cfg -e
 | 
			
		||||
screen -t MGR 2 /etc/osmocom/respawn-only.sh /usr/bin/sysmobts-mgr -n -c /etc/osmocom/sysmobts-mgr.cfg
 | 
			
		||||
detach
 | 
			
		||||
@@ -0,0 +1,91 @@
 | 
			
		||||
#!/usr/bin/gawk -f
 | 
			
		||||
 | 
			
		||||
# Usage example:
 | 
			
		||||
# tshark -2 -t r -E 'header=n' -E 'separator=,' -E 'quote=n' -T fields -e gsmtap.frame_nr -e gsmtap.ts -e gsmtap.arfcn -e _ws.col.Info -Y 'gsmtap' -r test.pcapng.gz | grep Information | env ARFCN=878 ./si_check.gawk
 | 
			
		||||
# read summary on number of bis/ter messages and adjust BT_BOTH and BT_NONE environment variables accordingly
 | 
			
		||||
 | 
			
		||||
BEGIN {
 | 
			
		||||
	FS = ","
 | 
			
		||||
	FAILED = 0
 | 
			
		||||
	IGNORE = 0
 | 
			
		||||
	BIS = 0
 | 
			
		||||
	TER = 0
 | 
			
		||||
	QUA = 0
 | 
			
		||||
	BT_BOTH = ENVIRON["BOTH"]
 | 
			
		||||
	BT_NONE = ENVIRON["NONE"]
 | 
			
		||||
	TC_INDEX = 0
 | 
			
		||||
	TC4[4] = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
{ # expected .csv input as follows: gsmtap.frame_nr,gsmtap.ts,gsmtap.arfcn,_ws.col.Info
 | 
			
		||||
	if ("ARFCN" in ENVIRON) { # ARFCN filtering is enabled
 | 
			
		||||
		if (ENVIRON["ARFCN"] != $3) { # ignore other ARFCNs
 | 
			
		||||
			IGNORE++
 | 
			
		||||
			next
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	type = get_si_type($4)
 | 
			
		||||
	tc = get_tc($1)
 | 
			
		||||
	result = "FAIL"
 | 
			
		||||
 | 
			
		||||
	if (1 == check_si_tc(tc, type)) { result = "OK" }
 | 
			
		||||
	else { FAILED++ }
 | 
			
		||||
 | 
			
		||||
	if (4 == tc) {
 | 
			
		||||
		TC4[TC_INDEX] = type
 | 
			
		||||
		TC_INDEX = int((TC_INDEX + 1) % 4)
 | 
			
		||||
		if (0 == check_tc4c(type) && "OK" == result) {
 | 
			
		||||
			result = "FAIL"
 | 
			
		||||
			FAILED++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (type == "2bis") { BIS++ }
 | 
			
		||||
	if (type == "2ter") { TER++ }
 | 
			
		||||
	if (type == "2quater") { QUA++ }
 | 
			
		||||
	# for (i in TC4) print TC4[i] # debugging
 | 
			
		||||
	printf "ARFCN=%d FN=%d TS=%d TC=%d TYPE=%s %s\n", $3, $1, $2, tc, type, result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
END {
 | 
			
		||||
	printf "check completed: total %d, failed %d, ignored %d, ok %d\nSI2bis = %d, SI2ter = %d, SI2quater = %d\n", NR, FAILED, IGNORE, NR - FAILED - IGNORE, BIS, TER, QUA
 | 
			
		||||
	if ((BIS > 0 || TER > 0) && BT_NONE) { printf "please re-run with correct environment: unset 'NONE' variable\n" }
 | 
			
		||||
	if ((BIS > 0 && TER > 0) && !BT_BOTH) { printf "please re-run with correct environment: set 'BOTH' variable\n" }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func get_si_type(s, x) { # we rely on format of Info column in wireshark output - if it's changed we're screwed
 | 
			
		||||
	return x[split(s, x, " ")]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func get_tc(f) { # N. B: all numbers in awk are float
 | 
			
		||||
	return int(int(f / 51) % 8)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func check_tc4c(si, count) { # check for "once in 4 consecutive occurrences" rule
 | 
			
		||||
	count = 0
 | 
			
		||||
	if ("2quater" != si || "2ter" != si) { return 1 } # rules is not applicable to other types
 | 
			
		||||
	if (BT_NONE && "2quater" == si) { return 0 } # should be on TC=5 instead
 | 
			
		||||
	if (!BT_BOTH && "2ter" == si) { return 0 } # should be on TC=5 instead
 | 
			
		||||
	if (0 in TC4 && 1 in TC4 && 2 in TC4 && 3 in TC4) { # only check if we have 4 consecutive occurrences already
 | 
			
		||||
		if (si == TC4[0]) { count++ }
 | 
			
		||||
		if (si == TC4[1]) { count++ }
 | 
			
		||||
		if (si == TC4[2]) { count++ }
 | 
			
		||||
		if (si == TC4[3]) { count++ }
 | 
			
		||||
		if (0 == count) { return 0 }
 | 
			
		||||
	}
 | 
			
		||||
	return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func check_si_tc(tc, si) { # check that SI scheduling on BCCH Norm is matching rules from 3GPP TS 05.02 § 6.3.1.3
 | 
			
		||||
	switch (si) {
 | 
			
		||||
	case "1":       return (0 == tc) ? 1 : 0
 | 
			
		||||
	case "2":       return (1 == tc) ? 1 : 0
 | 
			
		||||
	case "2bis":    return (5 == tc) ? 1 : 0
 | 
			
		||||
	case "13":      return (4 == tc) ? 1 : 0
 | 
			
		||||
	case "9":       return (4 == tc) ? 1 : 0
 | 
			
		||||
	case "2ter":    if (BT_BOTH) { return (4 == tc) ? 1 : 0 } else { return (5 == tc) ? 1 : 0 }
 | 
			
		||||
	case "2quater": if (BT_NONE) { return (5 == tc) ? 1 : 0 } else { return (4 == tc) ? 1 : 0 }
 | 
			
		||||
	case "3":       return (2 == tc || 6 == tc) ? 1 : 0
 | 
			
		||||
	case "4":       return (3 == tc || 7 == tc) ? 1 : 0
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,110 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
# Split common DSP call log file (produced by superfemto-compatible firmware) into 4 separate call leg files (MO/MT & DL/UL) with events in format "FN EVENT_TYPE":
 | 
			
		||||
# MO Mobile Originated
 | 
			
		||||
# MT Mobile Terminated
 | 
			
		||||
# DL DownLink (BTS -> L1)
 | 
			
		||||
# UL UpLink (L1 -> BTS)
 | 
			
		||||
 | 
			
		||||
if [ -z $1 ]; then
 | 
			
		||||
    echo "expecting DSP log file name as parameter"
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# MO handle appear 1st in the logs
 | 
			
		||||
MO=$(grep 'h=' $1 | head -n 1 | cut -f2 -d',' | cut -f2 -d= | cut -f1 -d']')
 | 
			
		||||
 | 
			
		||||
# direction markers:
 | 
			
		||||
DLST="_CodeBurst"
 | 
			
		||||
ULST="_DecodeAndIdentify"
 | 
			
		||||
 | 
			
		||||
# DL sed filters:
 | 
			
		||||
D_EMP='s/ Empty frame request!/EMPTY/i'
 | 
			
		||||
D_FAC='s/ Coding a FACCH\/. frame !!/FACCH/i'
 | 
			
		||||
D_FST='s/ Coding a RTP SID First frame !!/FIRST/i'
 | 
			
		||||
D_FS1='s/ Coding a SID First P1 frame !!/FIRST_P1/i'
 | 
			
		||||
D_FS2='s/ Coding a SID First P2 frame !!/FIRST_P2/i'
 | 
			
		||||
D_RP1='s/ Coding a RTP SID P1 frame !!/SID_P1/i'
 | 
			
		||||
D_UPD='s/ Coding a RTP SID Update frame !!/UPDATE/i'
 | 
			
		||||
D_SPE='s/ Coding a RTP Speech frame !!/SPEECH/i'
 | 
			
		||||
D_ONS='s/ Coding a Onset frame !!/ONSET/i'
 | 
			
		||||
D_FO1='s/ A speech frame is following a NoData or SID First without an Onset./FORCED_FIRST/i'
 | 
			
		||||
D_FO2='s/ A speech frame is following a NoData without an Onset./FORCED_NODATA/i'
 | 
			
		||||
D_FP2='s/ A speech frame is following a NoData or SID_FIRST_P2 without an Onset./FORCED_F_P2/i'
 | 
			
		||||
D_FIN='s/ A speech frame is following a SID_FIRST without inhibit. A SID_FIRST_INH will be inserted./FORCED_F_INH/i'
 | 
			
		||||
D_UIN='s/ A speech frame is following a SID_UPDATE without inhibit. A SID_UPDATE_INH will be inserted./FORCED_U_INH/i'
 | 
			
		||||
 | 
			
		||||
# UL sed filters:
 | 
			
		||||
U_NOD='s/ It is a No Data frame !!/NODATA/i'
 | 
			
		||||
U_ONS='s/ It is an ONSET frame !!/ONSET/i'
 | 
			
		||||
U_UPD='s/ It is a SID UPDATE frame !!/UPDATE/i'
 | 
			
		||||
U_FST='s/ It is a SID FIRST frame !!/FIRST/i'
 | 
			
		||||
U_FP1='s/ It is a SID-First P1 frame !!/FIRST_P1/i'
 | 
			
		||||
U_FP2='s/ It is a SID-First P2 frame !!/FIRST_P2/i'
 | 
			
		||||
U_SPE='s/ It is a SPEECH frame *!!/SPEECH/i'
 | 
			
		||||
U_UIN='s/ It is a SID update InH frame !!/UPD_INH/i'
 | 
			
		||||
U_FIN='s/ It is a SID-First InH frame !!/FST_INH/i'
 | 
			
		||||
U_RAT='s/ It is a RATSCCH data frame !!/RATSCCH/i'
 | 
			
		||||
 | 
			
		||||
DL () { # filter downlink-related entries
 | 
			
		||||
    grep $DLST $1 > $1.DL.tmp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UL () { # uplink does not require special fix
 | 
			
		||||
    grep $ULST $1 > $1.UL.tmp.fix
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DL $1
 | 
			
		||||
UL $1
 | 
			
		||||
 | 
			
		||||
FIX() { # add MO/MT marker from preceding line to inserted ONSETs so filtering works as expected
 | 
			
		||||
    cat $1.DL.tmp | awk 'BEGIN{ FS=" h="; H="" } { if (NF > 1) { H = $2; print $1 "h=" $2 } else { print $1 ", h=" H } }' > $1.DL.tmp.fix
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FIX $1
 | 
			
		||||
 | 
			
		||||
MO() { # filter MO call DL or UL logs
 | 
			
		||||
    grep "h=$MO" $1.tmp.fix > $1.MO.raw
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MT() { # filter MT call DL or UL logs
 | 
			
		||||
    grep -v "h=$MO" $1.tmp.fix > $1.MT.raw
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MO $1.DL
 | 
			
		||||
MT $1.DL
 | 
			
		||||
MO $1.UL
 | 
			
		||||
MT $1.UL
 | 
			
		||||
 | 
			
		||||
PREP() { # prepare logs for reformatting
 | 
			
		||||
    cat $1.raw | cut -f2 -d')' | cut -f1 -d',' | cut -f2 -d'>' | sed 's/\[u32Fn/fn/' | sed 's/\[ u32Fn/fn/' | sed 's/fn = /fn=/' | sed 's/fn=//' | sed 's/\[Fn=//' | sed 's/ An Onset will be inserted.//' > $1.tmp1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PREP "$1.DL.MT"
 | 
			
		||||
PREP "$1.DL.MO"
 | 
			
		||||
PREP "$1.UL.MT"
 | 
			
		||||
PREP "$1.UL.MO"
 | 
			
		||||
 | 
			
		||||
RD() { # reformat DL logs for consistency checks
 | 
			
		||||
    cat $1.tmp1 | sed "$D_FST" | sed "$D_SPE" | sed "$D_FS1" | sed "$D_FS2" | sed "$D_UIN" | sed "$D_FIN" | sed "$D_UPD" | sed "$D_INH" | sed "$D_RP1" | sed "$D_ONS" | sed "$D_EMP" | sed "$D_FAC" | sed "$D_FO1" | sed "$D_FO2" | sed "$D_FP2" > $1.tmp2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RU() { # reformat UL logs for consistency checks
 | 
			
		||||
    cat $1.tmp1 | sed "$U_FST" | sed "$U_SPE" | sed "$U_FP1" | sed "$U_FP2" | sed "$U_UPD" | sed "$U_ONS" | sed "$U_NOD" | sed "$U_UIN" | sed "$U_FIN" | sed "$U_RAT" > $1.tmp2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RD "$1.DL.MT"
 | 
			
		||||
RD "$1.DL.MO"
 | 
			
		||||
RU "$1.UL.MT"
 | 
			
		||||
RU "$1.UL.MO"
 | 
			
		||||
 | 
			
		||||
SW() { # swap fields
 | 
			
		||||
    cat $1.tmp2 | awk '{ print $2, $1 }' > $1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SW "$1.DL.MT"
 | 
			
		||||
SW "$1.DL.MO"
 | 
			
		||||
SW "$1.UL.MT"
 | 
			
		||||
SW "$1.UL.MO"
 | 
			
		||||
 | 
			
		||||
rm $1.*.tmp*
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=osmo-bts manager for sysmoBTS
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStart=/usr/bin/sysmobts-mgr -ns -c /etc/osmocom/sysmobts-mgr.cfg
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
Alias=osmo-bts-mgr.service
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
### BEGIN INIT INFO
 | 
			
		||||
# Provides:          sysmobts
 | 
			
		||||
# Required-Start:    
 | 
			
		||||
# Required-Stop:     $local_fs
 | 
			
		||||
# Default-Start:     5
 | 
			
		||||
# Default-Stop:      0 6
 | 
			
		||||
# Short-Description: Start screen session with sysmobts software
 | 
			
		||||
# Description:       
 | 
			
		||||
### END INIT INFO
 | 
			
		||||
 | 
			
		||||
case "$1" in
 | 
			
		||||
        start)
 | 
			
		||||
		/usr/bin/screen -d -m -c /etc/osmocom/screenrc-sysmobts -S sysmobts
 | 
			
		||||
                ;;
 | 
			
		||||
	stop)
 | 
			
		||||
		/usr/bin/screen -d -r sysmobts -X quit
 | 
			
		||||
                exit 1
 | 
			
		||||
		;;
 | 
			
		||||
        restart|reload|force-reload)
 | 
			
		||||
                exit 0
 | 
			
		||||
                ;;
 | 
			
		||||
	show)
 | 
			
		||||
		;;
 | 
			
		||||
        *)
 | 
			
		||||
                echo "Usage: sysmobts {start|stop|show|reload|restart}" >&2
 | 
			
		||||
                exit 1
 | 
			
		||||
                ;;
 | 
			
		||||
esac
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=sysmocom sysmoBTS
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStartPre=/bin/sh -c 'echo 0 > /sys/class/leds/activity_led/brightness'
 | 
			
		||||
ExecStart=/usr/bin/osmo-bts-sysmo -s -c /etc/osmocom/osmo-bts.cfg -M
 | 
			
		||||
ExecStopPost=/bin/sh -c 'echo 0 > /sys/class/leds/activity_led/brightness'
 | 
			
		||||
ExecStopPost=/bin/sh -c 'cat /lib/firmware/sysmobts-v?.bit > /dev/fpgadl_par0 ; sleep 3s; cat /lib/firmware/sysmobts-v?.out > /dev/dspdl_dm644x_0; sleep 1s'
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
RestartPreventExitStatus=1
 | 
			
		||||
 | 
			
		||||
# The msg queues must be read fast enough
 | 
			
		||||
CPUSchedulingPolicy=rr
 | 
			
		||||
CPUSchedulingPriority=1
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
Alias=osmo-bts-sysmo.service
 | 
			
		||||
@@ -0,0 +1,755 @@
 | 
			
		||||
osmo-bts (0.8.1) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Neels Hofmeyr ]
 | 
			
		||||
  * cosmetic: dyn TS: clarify rsl_tx_rf_rel_ack() with a switch
 | 
			
		||||
  * dyn TS: fix TCH/F_TCH/H_PDCH: properly record release of PDCH TS
 | 
			
		||||
  * dyn TS: rx_rf_chan_rel: properly mark PDCH rel when no PCU, clarify
 | 
			
		||||
  * dyn TS: clear TCH state upon reconnecting as PDCH
 | 
			
		||||
  * cosmetic: dyn TS: clarify chan_nr composition
 | 
			
		||||
  * ignore RSL RF CHAN REL for inactive lchans
 | 
			
		||||
  * fix RSL Chan Activ Nack messages
 | 
			
		||||
  * ip.access dyn ts: properly NACK a PDCH ACT on a still active lchan
 | 
			
		||||
  * add/improve various logging around dyn ts
 | 
			
		||||
  * dyn TS: be less strict on chan_nr, to allow arbitrary pchan switches
 | 
			
		||||
 | 
			
		||||
  [ Stefan Sperling ]
 | 
			
		||||
  * send a State Changed Event Report when rf is locked/unlocked
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * rsl: log errors when parsing of  encryption information fails
 | 
			
		||||
  * rsl: Make channel activation fail if encryption algorithm not supported
 | 
			
		||||
  * rsl: Properly NACK CHAN_ACKT / MODE_MODIFY
 | 
			
		||||
  * rsl: If CHAN ACT or MODE MODIF fails, send respective NACK
 | 
			
		||||
  * osmo-bts-trx: Enable A5/3 cipher support
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 15 May 2018 14:08:47 +0200
 | 
			
		||||
 | 
			
		||||
osmo-bts (0.8.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Neels Hofmeyr ]
 | 
			
		||||
  * vty: skip installing cmds now always installed by default
 | 
			
		||||
  * jenkins_common.sh: fix build_bts distcheck for more than one conf_flag
 | 
			
		||||
  * fix build: tests/sysmobts: add missing -I$(SYSMOBTS_INCDIR)
 | 
			
		||||
  * fix handover: handle_ph_ra_ind(): evaluate ra_ind before msgb_trim()
 | 
			
		||||
  * implement support for 3-digit MNC with leading zeros
 | 
			
		||||
  * configure: add --enable-werror
 | 
			
		||||
  * use osmo_init_logging2() with proper talloc ctx
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * lc15: Fix cfg indentation
 | 
			
		||||
  * l1sap: Fix abort on big RTP packet received
 | 
			
		||||
  * bts-trx: trx_ctrl_cmd: Simplify var assignment logic
 | 
			
		||||
  * bts-trx: Avoid enqueueing consecutive duplicate messages to TRX
 | 
			
		||||
  * Fix malformed Resource Indication packet
 | 
			
		||||
  * debian/control: Remove uneeded dep libosmo-netif-dev
 | 
			
		||||
  * jenkins.sh: Disable building doxygen for deps
 | 
			
		||||
  * oml.c: Fix use of htons instead of ntohs
 | 
			
		||||
  * bts-trx: trx_if.c: Log timedout+retransmitted CMD
 | 
			
		||||
  * bts-trx: trx_if.c: trx_ctrl_read_cb: Move error handling to end of func
 | 
			
		||||
  * bts-trx: trx_if.c: Improve parsing of received RSP messages from TRX
 | 
			
		||||
  * bts-trx: Detect duplicated responses for retransmitted commands
 | 
			
		||||
  * gsm_pchan2chan_nr: move warning to pragma message and track issue
 | 
			
		||||
  * Remove unused variables
 | 
			
		||||
  * bts-trx: scheduler_trx.c: Fix missing header
 | 
			
		||||
  * l1sap.c: l1sap_tch_rts_ind: Remove unused variables
 | 
			
		||||
  * octphy: octpkt.c: Remove unused static functions
 | 
			
		||||
  * vty.c: Remove warning message
 | 
			
		||||
  * virtual: l1_if.c: Remove unneeded warning message
 | 
			
		||||
  * main.c: bts_main: fix typo in error message
 | 
			
		||||
  * l1sap: Validate incoming RTP payload, drop bw-efficient AMR
 | 
			
		||||
  * l1sap: Avoid assumption that l1sap is at head of msgb
 | 
			
		||||
  * contrib: jenkins_bts_model: Fix bashism expr
 | 
			
		||||
  * Include missing headers for osmo_init_logging2
 | 
			
		||||
  * common/sysinfo.c: Fix no return on on-void function
 | 
			
		||||
  * gsm_data_shared.h: Remove unused enum gsm_paging_event
 | 
			
		||||
  * scheduler_trx: Fix signed integer overflow in clock calculations
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * trx: Better be safe than sorry before calling strlen
 | 
			
		||||
  * trx: Avoid NULL+1 dereference in trx_ctrl_read_cb()
 | 
			
		||||
  * trx: Don't call osmo_fr_check_sid with negative 'rc'
 | 
			
		||||
  * trx: Don't assume phy_instance_by_num() returns non-NULL
 | 
			
		||||
  * l1sap: fix wrong return value of is_fill_frame()
 | 
			
		||||
  * measurement.c: Fix various typos in comments
 | 
			
		||||
  * Comments on individual members of struct gsm_abis_mo
 | 
			
		||||
  * scheduler: Harmonize log line format; Always print TS name + decoded FN
 | 
			
		||||
  * scheduler_trx: L1P is for PH (data), L1M for MPH (control)
 | 
			
		||||
  * l1sap: Fix log subsystem: Use DRTP for RTP related bits, L1C for MPH
 | 
			
		||||
  * measurment.c: Introduce INFO category for DMEAS logging
 | 
			
		||||
  * osmo-bts-octphy: Remove bogus warning about BS_AG_BLKS_RES
 | 
			
		||||
  * rsl.c: Log RTP socket related errors as DRTP, not DRSL
 | 
			
		||||
  * Put useful information in RTCP SDES.
 | 
			
		||||
  * osmo-bts-trx: Fix reported frame number during PRIM_INFO_MEAS
 | 
			
		||||
  * DTX: avoid illegal character contained in DTX FSM allocation which causes BTS crash
 | 
			
		||||
  * gsm_lchan: remove unused member fields
 | 
			
		||||
  * Add 'show (bts|trx|ts|lchan)' commands
 | 
			
		||||
  * Print much more information during 'show lchan'
 | 
			
		||||
  * vty: don't print "Bound IP / Port" if it isn't bound [yet]
 | 
			
		||||
  * osmo-bts: Add talloc context introspection via VTY
 | 
			
		||||
  * sysmo: Fix compiler warnings in eeprom.c
 | 
			
		||||
  * sysmo+lc15: Add missign include for readv/writev
 | 
			
		||||
  * trx: make l1if_fill_meas_res() static
 | 
			
		||||
  * RSL: Properly reject RSL CHAN_NR IE for incompatible PCHAN
 | 
			
		||||
  * RSL: Ensure we don't accept DCHAN messages for CCHAN
 | 
			
		||||
  * osmo-bts-virtual: Shut down gracefully on socket creation failure
 | 
			
		||||
  * osmo-bts-virtual: Generate PRIM_INFO_MEAS (with bogus values)
 | 
			
		||||
  * Introduce + use LOG/DEBUGP with frame number prefixing/printing
 | 
			
		||||
  * osmo-bts-virtual: Make use of LOGL1S() macro for context
 | 
			
		||||
  * osmo-bts-virtual: Make sure PRIM_INFO_MEAS have non-zero frame number
 | 
			
		||||
  * scheduler.c: Factor out find_sched_mframe_idx() function
 | 
			
		||||
  * scheduler: add trx_sched_is_sacch_fn() function
 | 
			
		||||
  * Revert "measurement: fix measurement computation"
 | 
			
		||||
  * measurement.c: Hand Frame Number into measurement computation
 | 
			
		||||
  * l1sap: Pass is_sub from L1 primitive into the Uplink Measurement
 | 
			
		||||
  * osmo-bts-trx: Add missing frame number to l1if_process_meas_res()
 | 
			
		||||
  * scheduler.c: Print message when burst substitution happens
 | 
			
		||||
  * load_indication: Fix start of load indication timer
 | 
			
		||||
  * RSL: Implement DELETE INDICATION on AGCH overflow
 | 
			
		||||
  * RSL: Send ERROR REPORT on too short/truncated messages + wrong discriminator
 | 
			
		||||
  * BTS: add rate_ctr about CCCH (paging, agch, pch)
 | 
			
		||||
  * paging: Drop + Log paging requests for non-existant paging groups
 | 
			
		||||
  * paging.c: Fix encoding of optional Mobile ID RR PAGING TYPE 1 / 2
 | 
			
		||||
  * rsl: Improve ERROR REPORTing
 | 
			
		||||
  * paging: Fix encoding of PAGING TYPE 3 Rest Octets
 | 
			
		||||
  * RSL IPA DLCX: Avoid null-pointer dereference
 | 
			
		||||
  * RSL: Fix encoding of ConnectionID in IPA_DLCX_ACK
 | 
			
		||||
  * RSL IPA DLCX: Avoid another null-pointer dereference
 | 
			
		||||
  * measurement.c: Fix sdcch4_meas_rep_fn102 / sdcch8_meas_rep_fn102
 | 
			
		||||
  * counters: split rach:sent into rach:drop, rach:ho, rach:cs and rach:ps
 | 
			
		||||
  * octphy: Remove code duplication for BER / RSSI conversion
 | 
			
		||||
  * {sysmo,lc15}: Correctly report BER to L1SAP in INFO_MEAS_IND
 | 
			
		||||
  * {sysmo,lc15}: Fix RACH reporting in combined CBCH case
 | 
			
		||||
  * split scheduler_mframe.c from scheduler.c
 | 
			
		||||
  * measurement: Compute RX{LEV,QUAL}-SUB for SDCCH and non-AMR TCH
 | 
			
		||||
  * measurement.c: Don't silently copy "FULL" measurements to "SUB"
 | 
			
		||||
  * scheduler: Add missing \n at end of LOG statement
 | 
			
		||||
  * Move rach_busy counting above L1SAP
 | 
			
		||||
  * RACH decoding: Use BER threshold for RACH ghost detection
 | 
			
		||||
  * trx/scheduler: Use integer math for TOA (Timing of Arrival)
 | 
			
		||||
  * measurement.c: higher-precision TA/TOA math
 | 
			
		||||
  * L1SAP: Increase resolution of reported burst timing
 | 
			
		||||
  * measurement: Keep average of high-accurate ToA value in lchan
 | 
			
		||||
  * Add high-accuracy ToA value to Uplink Measurement Reports
 | 
			
		||||
  * pcu_sock: Discard messages that are too short
 | 
			
		||||
  * pcu_sock: Don't overflow the timeslot array
 | 
			
		||||
  * pcu_sock: Log an error message and discard PCU primitives for BTS != 0
 | 
			
		||||
  * pcu_sock: LOG + drop DATA.req from PCU for non-PDCH timeslot
 | 
			
		||||
  * pcu_sock: LOG + drop PCU DATA.req for inactive lchan
 | 
			
		||||
  * sysinfo.c: SI1 is optional; Send SI2 at TC=0 if no SI1 exists
 | 
			
		||||
  * sysmobts: Compatibility with older firmware versions
 | 
			
		||||
  * cosmetic: Document some SI scheduling related function API
 | 
			
		||||
  * sysinfo: Fix scheduling of downlink SACCH information
 | 
			
		||||
  * gsm_data_shared: Remove unused definitions/members/functions
 | 
			
		||||
  * cosmetic: Move agch_queue to sub-structure of gsm_bts_role_bts
 | 
			
		||||
  * Get rid of 'struct gsm_bts_role_bts'
 | 
			
		||||
  * virtual: Correctly set+report BTS variant in OML attributes
 | 
			
		||||
  * Add 'osmo-bts-omldummy' to bring up only OML without RSL
 | 
			
		||||
  * fix inverted logic bug in omldummy patch
 | 
			
		||||
  * omldummy: Suppress RSL transmission errors
 | 
			
		||||
  * debian: Split osmo-bts-virtual from osmo-bts-trx
 | 
			
		||||
  * fox chan_nr_is_dchan() for RSL_CHAN_OSMO_PDCH
 | 
			
		||||
  * rsl_tx_dyn_pdch_ack: Add missing FRAME_NR information element
 | 
			
		||||
  * fix activation of osmocom-style dynamic PDCH as TCH/F or TCH/H
 | 
			
		||||
 | 
			
		||||
  [ Philipp Maier ]
 | 
			
		||||
  * octphy: override firmware version check
 | 
			
		||||
  * cosmetic: meas_test: fix section comment
 | 
			
		||||
  * cosmetic: tests/Makefile.am: remove excess whitespace
 | 
			
		||||
  * cosmetic: tests/power: remove unused var "ret"
 | 
			
		||||
  * cosmetic: tests/agch: remove unused var "static_ilv"
 | 
			
		||||
  * octphy: l1_oml: check returncode of trx_by_l1h()
 | 
			
		||||
  * meas_test: fix header file references
 | 
			
		||||
  * rsl: fix double-free in rsl_rx_mode_modif()
 | 
			
		||||
  * fix nullpointer deref in rsl_tx_mode_modif_nack()
 | 
			
		||||
  * rsl: do not allow MODE MODIFY request with unsupp. codec/rate
 | 
			
		||||
  * gsm_data_shared: extend bts feature list with speech codecs
 | 
			
		||||
  * octphy: ensure all BTS models set features
 | 
			
		||||
  * vty: display bts features in vty command show bts
 | 
			
		||||
  * bts: use feature list instead of speech codec table
 | 
			
		||||
  * octphy: replace #warning with #pragma message
 | 
			
		||||
  * ipac: fix log output
 | 
			
		||||
  * rsl: remove unused variable
 | 
			
		||||
  * l1_tch: remove dead code
 | 
			
		||||
  * cosmetic: remove dead code
 | 
			
		||||
  * cosmetic: remove unused variable
 | 
			
		||||
  * cosmetic: remove unused variable in osmo-bts-omldummy/main.c
 | 
			
		||||
  * octphy: integrate octasics latest header release
 | 
			
		||||
  * osmo-bts-trx: perform error concealment for FR frames
 | 
			
		||||
 | 
			
		||||
  [ Max ]
 | 
			
		||||
  * Remove leftover comments and checks
 | 
			
		||||
  * Log filenames on L1 errors
 | 
			
		||||
  * Add --enable-sanitize configure option
 | 
			
		||||
  * Use existing function to obtain TSC
 | 
			
		||||
  * Remove BSC-specific parts
 | 
			
		||||
  * Print FN delta on L1 errors
 | 
			
		||||
  * Move sysmobts-calib into osmo-bts-sysmo
 | 
			
		||||
  * Allow specifying sysmocom headers explicitly
 | 
			
		||||
  * fix build: tests/misc: missing libosmo-abis and -trau flags
 | 
			
		||||
  * Enable optional static builds
 | 
			
		||||
  * Remove unneeded LIBOSMOCORE_CFLAGS from tests
 | 
			
		||||
  * sysmobts: use proper includes for sbts2050 test
 | 
			
		||||
  * Move -I inside *INCDIR variable
 | 
			
		||||
  * sysmobts: remove weird default header location
 | 
			
		||||
  * sysmobts: move header check to appropriate place
 | 
			
		||||
  * CI: drop unused OsmoPCU dependency
 | 
			
		||||
  * Enable sanitize for CI tests
 | 
			
		||||
  * Add helper to get BCC from BSIC
 | 
			
		||||
  * osmo-bts-trx: init nbits to know value
 | 
			
		||||
  * osmo-bts-trx: ignore frame offset error on startup
 | 
			
		||||
 | 
			
		||||
  [ Vadim Yanitskiy ]
 | 
			
		||||
  * doc/examples: add CalypsoBTS configuration example
 | 
			
		||||
  * common/pcu_sock.c: fix double field assignment
 | 
			
		||||
  * scheduler_trx.c: remove ToA (Time of Arrival) hack
 | 
			
		||||
  * common/l1sap.c: increase the BTS_CTR_RACH_DROP in RACH BER check
 | 
			
		||||
  * common/l1sap.c: increment valid RACH counter after all checks
 | 
			
		||||
  * common/l1sap.c: clean up noise / ghost RACH filtering
 | 
			
		||||
  * common/l1sap.c: perform noise / ghost filtering for handover RACH
 | 
			
		||||
  * common/l1sap.c: limit the minimal ToA for RACH bursts
 | 
			
		||||
  * common/vty.c: remove unused variables
 | 
			
		||||
  * common/main.c: track talloc NULL contexts by default
 | 
			
		||||
 | 
			
		||||
  [ Alexander Huemer ]
 | 
			
		||||
  * cosmetic: Makefile.am whitespace
 | 
			
		||||
  * various Makefile.am: add missing CFLAGS
 | 
			
		||||
  * gitignore: add missing entries
 | 
			
		||||
 | 
			
		||||
  [ Stefan Sperling ]
 | 
			
		||||
  * Cosmetic fixes for power ramping code.
 | 
			
		||||
  * respond with NACK for non-hopping BTS with multiple ARFCN
 | 
			
		||||
  * cosmetic: fix typos in src/common/oml.c
 | 
			
		||||
  * return NACK codes instead of errno values from oml_tx_attr_resp()
 | 
			
		||||
 | 
			
		||||
  [ Alexander Couzens ]
 | 
			
		||||
  * pcuif_proto: correct indention of gsm_pcu_if_data
 | 
			
		||||
  * pcu_if: move definition PCU_SOCK_DEFAULT into pcuif_proto.h
 | 
			
		||||
  * pcuif_proto: add version 8 features
 | 
			
		||||
 | 
			
		||||
  [ Keith ]
 | 
			
		||||
  * osmo-bts-sysmo eeprom.c Restore ability to read/write EEPROM
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Thu, 03 May 2018 17:02:19 +0200
 | 
			
		||||
 | 
			
		||||
osmo-bts (0.7.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Max ]
 | 
			
		||||
  * Use value string check from osmo-ci
 | 
			
		||||
  * Support sending SI13 to PCU
 | 
			
		||||
  * Support removing SI13 from PCU
 | 
			
		||||
  * trx: avoid deactivating lchan on LCHAN_REL_ACT_REACT
 | 
			
		||||
  * Check readv() return value to prevent crash
 | 
			
		||||
  * OML: print actual type of report sent to BSC
 | 
			
		||||
  * Replace dead code
 | 
			
		||||
  * vty: print version and description for each phy
 | 
			
		||||
  * Remove build dependency on legacy OpenBSC
 | 
			
		||||
  * Fix multiple SI2q reception
 | 
			
		||||
  * jenkins: remove openbsc dependency
 | 
			
		||||
  * sysmo: use clock calibration source wrapper
 | 
			
		||||
  * sysmo: don't override clock source with defaults
 | 
			
		||||
  * Fix race condition in attribute reporting
 | 
			
		||||
  * Move power loop to generic tests
 | 
			
		||||
  * Make power test more verbose
 | 
			
		||||
 | 
			
		||||
  [ Neels Hofmeyr ]
 | 
			
		||||
  * vty: mgr: sysmobts, lc15: install default commands for ACT_NORM_NODE
 | 
			
		||||
  * osmo-bts-trx: vty: various fixes of 'write file' and doc
 | 
			
		||||
  * jenkins: use osmo-clean-workspace.sh before and after build
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * l1sap: Improve log msg when frame diff >1
 | 
			
		||||
  * vty: Print string for Administrative state
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * Fix Downlink AMR FSM name to avoid illegal space character
 | 
			
		||||
  * update dependencies to latest libosmo-*
 | 
			
		||||
  * configure.ac: Fix Mailing list address
 | 
			
		||||
 | 
			
		||||
 -- Harald Welte <laforge@gnumonks.org>  Sat, 28 Oct 2017 20:53:21 +0200
 | 
			
		||||
 | 
			
		||||
osmo-bts (0.6.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Holger Hans Peter Freyther ]
 | 
			
		||||
  * Initial release.
 | 
			
		||||
  * misc: Ignore files generated by a debian packaging build
 | 
			
		||||
  * jenkins: Add the build script from jenkins here
 | 
			
		||||
  * jenkins: Add the build script from jenkins here
 | 
			
		||||
  * sysmobts: Add the barebox boot state reservation
 | 
			
		||||
  * sysmobts: Fix eeprom padding before gpg key
 | 
			
		||||
  * ci/spatch: Remove the "static" analysis handling
 | 
			
		||||
  * oct: Attempt to enable the Octphy for the osmo-bts-oct build
 | 
			
		||||
  * debian: Use the header files installed by openbsc-dev
 | 
			
		||||
  * build: Do not require more headers from OpenBSC
 | 
			
		||||
  * sysmobts: Make reservation for mode/netmask/ip and suc
 | 
			
		||||
  * sysmobts: Store a simple network config in the EEPROM as well
 | 
			
		||||
 | 
			
		||||
  [ Max ]
 | 
			
		||||
  * Ensure TRX invariant
 | 
			
		||||
  * Use libosmocore function for uplink measurements
 | 
			
		||||
  * Fix debug output
 | 
			
		||||
  * Fix RTP timestamps in case of DTX
 | 
			
		||||
  * Add DTXd support for sysmoBTS and LC15
 | 
			
		||||
  * Use libosmocodec for AMR RTP
 | 
			
		||||
  * octphy: Use the app. info. defaults as base
 | 
			
		||||
  * Fix debug output
 | 
			
		||||
  * DTXd: store/repeat last SID
 | 
			
		||||
  * DTXd: store/repeat last SID
 | 
			
		||||
  * DTXu: mark beginning of speech burst in RTP
 | 
			
		||||
  * Fix OML activation
 | 
			
		||||
  * TRX: Add vty command to power on/off transceiver
 | 
			
		||||
  * TRX: add configuration example
 | 
			
		||||
  * Add .gitreview
 | 
			
		||||
  * DTX: add support for AMR/HR
 | 
			
		||||
  * Move copy-pasted code into common part
 | 
			
		||||
  * Use libosmocodec functions for AMR
 | 
			
		||||
  * Use error values instead of number for RSL error
 | 
			
		||||
  * Clarify logging message
 | 
			
		||||
  * Make get_lchan_by_chan_nr globally available
 | 
			
		||||
  * DTXu: move copy-pasted code to common part
 | 
			
		||||
  * Remove duplicated nibble shift code
 | 
			
		||||
  * TRX: add Uplink DTX support for FR/HR
 | 
			
		||||
  * Mark array as static const
 | 
			
		||||
  * sysmobts: dump PRACH and PTCCH parameters
 | 
			
		||||
  * Activate PTCCH UL
 | 
			
		||||
  * Fix dsp tracing at phy config
 | 
			
		||||
  * octphy: fix build
 | 
			
		||||
  * Fill measurements data for L1SAP
 | 
			
		||||
  * sysmo: ts_connect: log channel combination name instead of number
 | 
			
		||||
  * DTX: fix last SID saving
 | 
			
		||||
  * DTX: fix SID repeat scheduling
 | 
			
		||||
  * DTX: fix SID logic
 | 
			
		||||
  * lc15, sysmo: Use SID_FIRST_P1 to initiate DTX
 | 
			
		||||
  * DTX: check Marker bit to send ONSET to L1
 | 
			
		||||
  * DTX: remove misleading comment
 | 
			
		||||
  * LC15: Clarify msgb ownership / fix memory leaks
 | 
			
		||||
  * DTX: move scheduling check inside repeat_last_sid
 | 
			
		||||
  * DTX: further AMR SID cache fixes (lc15, sysmo)
 | 
			
		||||
  * DTX: move ONSET detection into separate function
 | 
			
		||||
  * DTX: send AMR voice alongside with ONSET
 | 
			
		||||
  * DTX: fix conversion from fn to ms
 | 
			
		||||
  * Move copy-pasted array into shared header
 | 
			
		||||
  * DTX DL: use FSM for AMR
 | 
			
		||||
  * TRX: fix building with latest DTX changes
 | 
			
		||||
  * DTX: fix array size calculation
 | 
			
		||||
  * DTX AMR - fix buffer length check
 | 
			
		||||
  * Replace magic number with define
 | 
			
		||||
  * Fix lc15 build
 | 
			
		||||
  * Extend RTP RX callback parameters
 | 
			
		||||
  * DTX HR - fix array size calculation
 | 
			
		||||
  * Fix DTX DL AMR SIDscheduling logic
 | 
			
		||||
  * Add tools to check DTX operation
 | 
			
		||||
  * DTX DL: split ONSET state handling
 | 
			
		||||
  * Remove obsolete define
 | 
			
		||||
  * DTX DL: add AMR HR support to scheduling check
 | 
			
		||||
  * DTX fix ONSET handling
 | 
			
		||||
  * dtx_check.gawk: Fix false-positives in DTX check
 | 
			
		||||
  * Fix tests linking with libosmocodec
 | 
			
		||||
  * DTX DL: tighten check for enabled operation
 | 
			
		||||
  * DTX: wrap FSM signal dispatching
 | 
			
		||||
  * Add libosmocodec for octphy build
 | 
			
		||||
  * dtx_check.gawk: add check for repetitive SID FIRST
 | 
			
		||||
  * Remove duplicated code
 | 
			
		||||
  * Replace link_id constant with define
 | 
			
		||||
  * DTX DL AMR: rewrite FSM recursion
 | 
			
		||||
  * Remove duplicated code
 | 
			
		||||
  * Fix AGCH/PCH proportional allocation
 | 
			
		||||
  * TRX: prevent segfault upon phy init
 | 
			
		||||
  * DTX: add explicit check if DTX enabled
 | 
			
		||||
  * Save RTP metadata in Control Buffer
 | 
			
		||||
  * osmo-bts-trx: fix lchan deactivation
 | 
			
		||||
  * DTX: fix TS adjustment for ONSET
 | 
			
		||||
  * Optionally use adaptive RTP jitter buffering
 | 
			
		||||
  * Integrate Debian packaging changes
 | 
			
		||||
  * DTX AMR HR: fix inhibition
 | 
			
		||||
  * Add copyright for .deb packages
 | 
			
		||||
  * Move code to libosmocore
 | 
			
		||||
  * Log socket path on error
 | 
			
		||||
  * Add Abis OML failure event reporting
 | 
			
		||||
  * Alarm on various errors
 | 
			
		||||
  * Remove obsolete define TLVP_PRES_LEN
 | 
			
		||||
  * scheduler: log lchan on which prim error occured
 | 
			
		||||
  * deb: use gsm_data_shared.* from openbsc-dev
 | 
			
		||||
  * OML: internalize failure reporting
 | 
			
		||||
  * Add ctrl command to send OML alert
 | 
			
		||||
  * Fix typo in TCH/H interleaving table
 | 
			
		||||
  * Use oml-alert CTRL command for temp report
 | 
			
		||||
  * Remove code duplication
 | 
			
		||||
  * Handle ctrl cmd allocation failures
 | 
			
		||||
  * Check for suitable lchan type when detecting HO
 | 
			
		||||
  * osmo-bts-trx: fix scheduling of broken frames
 | 
			
		||||
  * Sync protocol with OsmoPCU
 | 
			
		||||
  * vty: reduce code duplication
 | 
			
		||||
  * Handle TXT indication from OsmoPCU
 | 
			
		||||
  * Add MS TO to RSL measurements
 | 
			
		||||
  * Signal to BSC when PCU disconnects
 | 
			
		||||
  * Prepare for extended SI2quater support
 | 
			
		||||
  * Set BTS variant while initializing BTS model
 | 
			
		||||
  * Prepare for BTS attribute reporting via OML
 | 
			
		||||
  * osmo-bts-trx: use libosmocoding
 | 
			
		||||
  * Remove redundant test
 | 
			
		||||
  * Implement basic Get Attribute responder
 | 
			
		||||
  * Add version to phy_instance
 | 
			
		||||
  * OML: fix Coverity-reported issues
 | 
			
		||||
  * Re-add version to phy_instance
 | 
			
		||||
  * Use systemd template specifiers
 | 
			
		||||
  * Place *-mgr config examples according to BTS model
 | 
			
		||||
  * lc15: add example systemd service file
 | 
			
		||||
  * Extend Get Attribute responder
 | 
			
		||||
  * Set and report BTS features
 | 
			
		||||
  * Cleanup SI scheduling
 | 
			
		||||
  * RSL: receive and send multiple SI2q messages
 | 
			
		||||
  * RSL: check for abnormal SI2q values
 | 
			
		||||
  * lc15bts-mgr: use extended config file example
 | 
			
		||||
  * Move parameter file opening into separate function
 | 
			
		||||
  * Move common steps into common jenkins helper
 | 
			
		||||
  * lc15: add jenkins helper
 | 
			
		||||
  * Use generic L1 headers helper
 | 
			
		||||
  * Copy sysmobts.service to osmo-bts-sysmo
 | 
			
		||||
  * OML: move BTS number check into separate function
 | 
			
		||||
  * lc15: make jenkins helper executable
 | 
			
		||||
  * lc15: fix jenkins build
 | 
			
		||||
  * Add missing include for abis.h header file
 | 
			
		||||
  * RSL: receive and send multiple SI2q messages
 | 
			
		||||
  * Use release helper from libosmocore
 | 
			
		||||
  * si2q: do not consider count update as error
 | 
			
		||||
  * Cleanup example config files
 | 
			
		||||
  * Fix .deb build
 | 
			
		||||
  * Unify *.service files
 | 
			
		||||
  * lc15: cleanup board parameters reading
 | 
			
		||||
  * lc15-mgr: update parameter read/write
 | 
			
		||||
  * lc15: fix BTS revision and hw options
 | 
			
		||||
  * lc15: make default config usable
 | 
			
		||||
  * lc15: port lc15bts-mgr changes
 | 
			
		||||
  * lc15bts-mgr: separate service file
 | 
			
		||||
  * lc15: port lc15bts-mgr dependency changes
 | 
			
		||||
  * Simplify jenkins build scripts
 | 
			
		||||
  * OML: use fom_hdr while handling attr. request
 | 
			
		||||
  * osmo-bts-trx: fix 'osmotrx legacy-setbsic'
 | 
			
		||||
  * osmo-bts-trx: remove global variables from loops
 | 
			
		||||
 | 
			
		||||
  [ Daniel Laszlo Sitzer ]
 | 
			
		||||
  * octphy: Update outdated config param name in error message.
 | 
			
		||||
 | 
			
		||||
  [ Jason DSouza ]
 | 
			
		||||
  * Close TRX session before opening new one
 | 
			
		||||
 | 
			
		||||
  [ Minh-Quang Nguyen ]
 | 
			
		||||
  * l1sap.h: fix wrong L1SAP_FN2PTCCHBLOCK calculation according to TS 45.002 Table 6
 | 
			
		||||
  * common/abis.c: fix 100% CPU usage after disconnecting OML/RSL link (Bug #1703)
 | 
			
		||||
  * LC15: Bring back DSP trace argument
 | 
			
		||||
  * LC15: Hardware changes
 | 
			
		||||
  * LC15: TRX nominal TX power can be used from EEPROM or from BTS configuration
 | 
			
		||||
  * rsl: Fix dropping of LAPDm UA message.
 | 
			
		||||
  * LC15: properly handle BS-AG-BLKS-RES as received from BSC
 | 
			
		||||
 | 
			
		||||
  [ Neels Hofmeyr ]
 | 
			
		||||
  * sysmo: add L3 handle to l1prim messages
 | 
			
		||||
  * pcu_sock: add pcu_connected() to query PCU availability
 | 
			
		||||
  * tests/stubs.c: remove unused stubs
 | 
			
		||||
  * fix typo in error message ('at lEast')
 | 
			
		||||
  * oml, Set Chan Attr: treat unknown PCHAN types as error
 | 
			
		||||
  * dyn PDCH: rsl rx dchan: also log ip.access message names
 | 
			
		||||
  * doc: add ladder diagram on dynamic PDCH, add msc-README
 | 
			
		||||
  * add missing DSUM entry to bts_log_info_cat
 | 
			
		||||
  * fix compiler warning: printf format for sizeof()
 | 
			
		||||
  * fix compiler warning: add missing case (PHY_LINK_CONNECTING)
 | 
			
		||||
  * fix two compiler warnings: add two opaque struct declarations
 | 
			
		||||
  * dyn PDCH: add bts_model_ts_connect() and _disconnect() stubs
 | 
			
		||||
  * dyn PDCH: conf_lchans_for_pchan(): handle TCH/F_PDCH
 | 
			
		||||
  * dyn PDCH: pcu_tx_info_ind(): handle TCH/F_PDCH in PDCH mode
 | 
			
		||||
  * dyn PDCH: chan_nr_by_sapi(): handle TCH/F_PDCH according to ts->flags
 | 
			
		||||
  * dyn PDCH: implement main dyn PDCH logic in common/
 | 
			
		||||
  * dyn PDCH: sysmo-bts/oml.c: add ts_connect_as(), absorbing ts_connect() guts
 | 
			
		||||
  * dyn PDCH: sysmo: handle TCH/F_PDCH init like TCH/F
 | 
			
		||||
  * dyn PDCH: complete for sysmo-bts: implement bts_model_ts_*()
 | 
			
		||||
  * error log: two minor clarifications
 | 
			
		||||
  * debug log: log lchan state transitions
 | 
			
		||||
  * debug log: log TS pchan type on connect
 | 
			
		||||
  * fix lc15 build: put src/common/libbts.a left of -losmogsm
 | 
			
		||||
  * lc15: add L3 handle to l1prim messages
 | 
			
		||||
  * dyn PDCH: lc15: chan_nr_by_sapi(): handle TCH/F_PDCH according to ts->flags
 | 
			
		||||
  * dyn PDCH: lc15: add ts_connect_as(), absorbing ts_connect() guts
 | 
			
		||||
  * dyn PDCH: lc15: handle TCH/F_PDCH init like TCH/F
 | 
			
		||||
  * dyn PDCH: lc15: complete for litecell15-bts: implement bts_model_ts_*()
 | 
			
		||||
  * dyn PDCH: safeguard: exit if nothing pending in dyn_pdch_ts_disconnected()
 | 
			
		||||
  * vty: install orphaned trx nominal power command
 | 
			
		||||
  * fix compiler warnings: include bts_model.h in phy_link.c
 | 
			
		||||
  * fix compiler warning: remove useless 'static' storage class for struct decl
 | 
			
		||||
  * fix compiler warning: remove unused variable 'i' in calib_verify()
 | 
			
		||||
  * log: osmo-bts-trx: change access burst logs to DEBUG level
 | 
			
		||||
  * log: osmo-bts-trx: change PDTCH block logs to DEBUG level
 | 
			
		||||
  * osmo-bts-trx: init OML only once by sending AVSTATE_OK with OPSTATE_ENABLED
 | 
			
		||||
  * doc: move dyn_pdch.msc to osmo-gsm-manuals.git
 | 
			
		||||
  * error log: rsl.c: typo x2
 | 
			
		||||
  * info log: l1sap.c: add '0x' to hex output
 | 
			
		||||
  * fix compiler warning: msg_utils.c: fn_chk() constify arg
 | 
			
		||||
  * fix compiler warning: msg_utils.c: fn_chk() constify arg
 | 
			
		||||
  * info log: l1sap.c: add '0x' to hex output
 | 
			
		||||
  * error log: rsl.c: typo x2
 | 
			
		||||
  * dyn PDCH: code dup: use conf_lchans_as_pchan()
 | 
			
		||||
  * prepare dyn TS: split/replace conf_lchans_for_pchan()
 | 
			
		||||
  * code dup: join [rsl_]lchan_lookup() from libbsc and osmo-bts
 | 
			
		||||
  * dyn TS: common TCH/F_TCH/H_PDCH implementation
 | 
			
		||||
  * sysmo/oml.c: rename ts_connect() to ts_opstart()
 | 
			
		||||
  * dyn TS: implement SysmoBTS specifics
 | 
			
		||||
  * lc15/oml.c: rename ts_connect() to ts_opstart()
 | 
			
		||||
  * dyn TS: implement litecell15 specifics
 | 
			
		||||
  * comment typo: common/l1sap.c
 | 
			
		||||
  * log typo: trx_sched_set_pchan()
 | 
			
		||||
  * dyn TS: sysmo,lc15: chan_nr_by_sapi(): add missing assertion
 | 
			
		||||
  * fix comment in common/l1sap.c, function name changed
 | 
			
		||||
  * dyn TS, dyn PDCH: common/l1sap.c: properly notice PDCH
 | 
			
		||||
  * dyn PDCH: trx l1_if.c: factor out trx_set_ts_as_pchan() from trx_set_ts()
 | 
			
		||||
  * dyn PDCH: complete for trx: implement bts_model_ts_[dis]connect()
 | 
			
		||||
  * dyn PDCH: trx l1_if.c: drop fixme, add comment
 | 
			
		||||
  * dyn TS: complete for TRX
 | 
			
		||||
  * dyn TS: measurement.c: replace fixme with comment
 | 
			
		||||
  * sysmo,lc15: ts_connect_as(): log error also for pchan_as == TCH/F_PDCH
 | 
			
		||||
  * sysmo: fix dyn TS: Revert "Activate PTCCH UL" [in sysmobts]
 | 
			
		||||
  * log: l1sap: add 0x to hex output of chan_nr, 5 times
 | 
			
		||||
  * dyn TS: measurement: use correct nr of subslots, rm code dup
 | 
			
		||||
  * dyn TS: sysmo,lc15: ph_data_req: fix PDCH mode detection
 | 
			
		||||
  * Fix ip.access style dyn PDCH, broken in 37af36e85eca546595081246aec010fa7f6fd0be
 | 
			
		||||
  * common/rsl: move decision whether to chan act ack/nack to common function
 | 
			
		||||
  * octphy: fix build: Revert "octphy: fix for multiple trx with more than 1 dsp"
 | 
			
		||||
  * octphy: fix build: Revert "octphy: add support for multiple trx ids"
 | 
			
		||||
  * octphy: fix build with OCTSDR-OPENBSC-02.07.00-B708: name changed
 | 
			
		||||
  * dyn TS: if PCU is not connected, allow operation as TCH
 | 
			
		||||
  * log: sysmo,lc15: tweak log about sapi_cmds queue
 | 
			
		||||
  * log causing rx event for lchan_lookup errors
 | 
			
		||||
  * heed VTY 'line vty'/'bind' command
 | 
			
		||||
  * sysmobts_mgr, lc15bts_mgr: fix tall context for telnet vty
 | 
			
		||||
  * build: be robust against install-sh files above the root dir
 | 
			
		||||
  * configure: check for pkg-config presence
 | 
			
		||||
  * jenkins.sh: use osmo-build-dep.sh, log test failures
 | 
			
		||||
  * msgb ctx: use new msgb_talloc_ctx_init() in various main()s
 | 
			
		||||
  * jenkins-oct.sh: fix build: typo in deps path
 | 
			
		||||
  * fix 'osmo-bts-* --version' segfault
 | 
			
		||||
  * osmo-bts-trx: remove obsolete include of netif/rtp.h
 | 
			
		||||
  * add jenkins_bts_trx.sh
 | 
			
		||||
  * add jenkins_oct_and_bts_trx.sh
 | 
			
		||||
  * jenkins: add jenkins_bts_model.sh
 | 
			
		||||
  * bursts test: test_pdtch: pre-init result mem
 | 
			
		||||
  * fix: dyn ts: uplink measurement report
 | 
			
		||||
  * fix missing ~ in bit logic for lchan->si.valid in rsl_rx_sacch_inf_mod()
 | 
			
		||||
  * SACCH: fix sending of SI with an enum value > 7
 | 
			
		||||
  * SACCH SI: assert that SI enum vals fit in bit mask
 | 
			
		||||
  * all models: fix vty write: bts_model_config_write_phy
 | 
			
		||||
  * jenkins: add value_string termination check
 | 
			
		||||
  * Revert "Add version to phy_instance"
 | 
			
		||||
  * Revert "RSL: check for abnormal SI2q values"
 | 
			
		||||
  * Revert "RSL: receive and send multiple SI2q messages"
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * sysmobts: screnrc/systemd-service: Use osmo-bts-sysmo instead of sysmobts
 | 
			
		||||
  * Add .mailmap for mapping mail addresses in shortlog
 | 
			
		||||
  * vty: Ensure to not use negative (error) sapi value
 | 
			
		||||
  * sysmobts: Add correct nominal transmit power for sysmoBTS 1020
 | 
			
		||||
  * sysmobts_eeprom.h: Fix/extend model number definitions
 | 
			
		||||
  * Revert "sysmobts: Add correct nominal transmit power for sysmoBTS 1020"
 | 
			
		||||
  * tx_power: Change PA calibration tables to use delta vales
 | 
			
		||||
  * Add new unit-test for transmit power computation code
 | 
			
		||||
  * sysmobts: fully support trx_power_params
 | 
			
		||||
  * README: Add general project information and convert to markdown
 | 
			
		||||
  * README: update some of the limitations
 | 
			
		||||
  * sysmobts: Don't start with 0dBm TRX output power before ramping
 | 
			
		||||
  * Remove unusued left-over gsm0503_conv.c
 | 
			
		||||
  * scheduler_trx.c: Avoid code duplication for BER10k computation
 | 
			
		||||
  * scheduler_trx: Avoid copy+pasting determining CMR from FN
 | 
			
		||||
  * rx_tchh_fn(): Avoid copy+pasting formula to determine odd-ness of fn
 | 
			
		||||
  * Consistently check for minimum attribute/TLV length in RSL and OML
 | 
			
		||||
  * l1sap.c: Add spec reference to link timeout implementation
 | 
			
		||||
  * osmo-bts-trx: Remove duplicate parsing of NM_ATT_CONN_FAIL_CRIT
 | 
			
		||||
  * vty: Remove command for manual channel activation/deactivation
 | 
			
		||||
  * l1_if: Add inline functions to check dsp/fgpa version at runtime
 | 
			
		||||
  * sysmobts: Re-order the bit-endianness of every HR codec parameter
 | 
			
		||||
  * OML Add osmocom-specific way to deactivate radio link timeout
 | 
			
		||||
  * measurement: Remove dead code
 | 
			
		||||
  * l1sap.c: Factor out function to limit message queue
 | 
			
		||||
  * osmo-bts-sysmo/l1_if.c: PH-DATA.ind belongs to L1P, not L1C
 | 
			
		||||
  * l1sap: if lchan is in loopback, don't accept incoming RTP
 | 
			
		||||
  * TRX: Use timerfd and CLOCK_MONOTONIC for GSM frame timer (Closes: #2325)
 | 
			
		||||
  * Add loopback support for PDTCH
 | 
			
		||||
  * TRX: trx_if: Improve code description / comments
 | 
			
		||||
  * trx_if: Improve error handling
 | 
			
		||||
  * TRX: Rename trx_if_data() -> trx_if_send_burst()
 | 
			
		||||
  * TRX: merge/simplify l1_if and trx_if code
 | 
			
		||||
  * TRX: don't free l1h in trx_phy_inst_close()
 | 
			
		||||
  * l1sap: Don't enqueue PTCCH blocks for loopback
 | 
			
		||||
  * TRX: permit transmission of all-zero loopback frames
 | 
			
		||||
  * jenkins helpers: some minimal documentation/comments + print errors
 | 
			
		||||
  * VIRT-PHY: Initial check-in of a new virtual BTS
 | 
			
		||||
  * VIRT-PHY: Fix handling of default values for vty configuration
 | 
			
		||||
  * VIRT-PHY: Use IPv4 multicast groups for private / local scope
 | 
			
		||||
  * VIRT-PHY: cause BTS to terminate in case of recv()/send() on udp socket returns 0
 | 
			
		||||
  * Ensure we don't send dummy UI frames on BCCH for TC=5
 | 
			
		||||
  * virt: Don't print NOTICE log message if ARFCN doesn't match
 | 
			
		||||
  * VIRT-PHY: Report virtual RACH bursts with plausible burst type
 | 
			
		||||
  * scheduler: Fix wrong log subsystem: L1C is L1 *control* not user data
 | 
			
		||||
  * VIRT-PHY: Print NOTICE log message from unimplemented stubs
 | 
			
		||||
  * TRX / VIRT-PHY: Make check for BCCH/CCCH more specific
 | 
			
		||||
  * L1SAP: Print chan_nr and link_id always as hex
 | 
			
		||||
  * VIRT-BTS: Support for GPRS
 | 
			
		||||
  * L1SAP: Use RSL_CHAN_OSMO_PDCH across L1SAP
 | 
			
		||||
  * GSMTAP: Don't log fill frames via GSMTAP
 | 
			
		||||
  * TRX: Remove bogus extern global variable declarations
 | 
			
		||||
  * l1sap/osmo-bts-sysmo: Improve logging
 | 
			
		||||
  * TRX: Remove global variables, move SETBSIC/SETTSC handling into phy_link
 | 
			
		||||
  * Fix build after recent gsm_bts_alloc() change
 | 
			
		||||
  * Treat SIGTERM just like SIGINT in our programs
 | 
			
		||||
 | 
			
		||||
  [ Tom Tsou ]
 | 
			
		||||
  * trx: Add EGPRS tables, sequences, and mappings
 | 
			
		||||
  * trx: Add EGPRS coding and decoding procedures
 | 
			
		||||
  * trx: Enable EGPRS handling through burst lengths
 | 
			
		||||
  * trx: Fix coverity BER calculation NULL dereference
 | 
			
		||||
 | 
			
		||||
  [ Vadim Yanitskiy ]
 | 
			
		||||
  * pcu_sock: use osmo_sock_unix_init() from libosmocore
 | 
			
		||||
  * osmo-bts-trx/l1_if.c: use channel combination III for TCH/H
 | 
			
		||||
  * scheduler_trx.c: strip unused variable
 | 
			
		||||
 | 
			
		||||
  [ Mike McTernan ]
 | 
			
		||||
  * osmo-bts-trx: Fix PCS1900 operation
 | 
			
		||||
  * osmo-bts-trx: log decoder bit errors as DEBUG, not NOTICE
 | 
			
		||||
 | 
			
		||||
  [ bhargava ]
 | 
			
		||||
  * Change interface in osmo-bts for 11 bit RACH
 | 
			
		||||
  * Update parameters in osmo-bts-sysmo for 11bit RACH
 | 
			
		||||
  * 11bit RACH support for osmo-bts-litecell15
 | 
			
		||||
  * Initialize parameters in osmo-trx for 11bit RACH
 | 
			
		||||
 | 
			
		||||
  [ Philipp ]
 | 
			
		||||
  * octphy: Fixing missing payload type in ph. chan. activation
 | 
			
		||||
  * octphy: Fixing band selection for ARFCN 0
 | 
			
		||||
  * octphy: reintroducing multi-trx support
 | 
			
		||||
  * octopy: fixing renamed constant
 | 
			
		||||
  * octphy: prevent mismatch between dsp-firmware and octphy headers
 | 
			
		||||
  * rsl: improving the log output
 | 
			
		||||
  * octphy: multi-trx support: fix AC_CHECK order
 | 
			
		||||
  * RSL: drop obsolete NULL check
 | 
			
		||||
  * RSL: add assertions to check args of public API
 | 
			
		||||
  * OML: fix possible segfault: add NULL check in oml_ipa_set_attr()
 | 
			
		||||
  * CTRL: make the CTRL-Interface IP address configurable
 | 
			
		||||
  * l1sap: Fix expired rach slot counting
 | 
			
		||||
  * l1sap: fix missing 'else's causing wrong rach frame expiry counts
 | 
			
		||||
  * octphy: set tx attenuation via VTY
 | 
			
		||||
  * octphy: Improve OML ADM state handling
 | 
			
		||||
 | 
			
		||||
  [ Yves Godin ]
 | 
			
		||||
  * DTX: fix 1st RTP packet drop
 | 
			
		||||
 | 
			
		||||
  [ Alexander Chemeris ]
 | 
			
		||||
  * l1sap: Fix use-after-free in loopback mode.
 | 
			
		||||
  * vty: Add commands to manually activate/deactivate a channel.
 | 
			
		||||
  * trx: Add "maxdlynb" VTY command to control max TA for Normal Bursts.
 | 
			
		||||
  * rsl: Output RTP stats before closing the socket.
 | 
			
		||||
  * osmo-bts-trx: Fix MS power control loop.
 | 
			
		||||
  * osmo-bts-trx: Remove an unused variable. Resolves a compiler warning.
 | 
			
		||||
  * osmo-bts-trx: Increase a maximum allowed MS power reduction step from 2dB to 4dB.
 | 
			
		||||
  * Fix static build of osmo-bts-trx and osmo-bts-virtual.
 | 
			
		||||
 | 
			
		||||
  [ Jean-Francois Dionne ]
 | 
			
		||||
  * DTX: don't always perform AMR HR specific check
 | 
			
		||||
  * DTX: fix SID-FIRST detection
 | 
			
		||||
  * lc15,sysmobts l1_if: fix memleak in handle_mph_time_ind()
 | 
			
		||||
  * sysmo,lc15: fix memory leak at each call placed
 | 
			
		||||
  * DTX: fix "unexpected burst" error
 | 
			
		||||
  * Fix AMR HR DTX FSM logic.
 | 
			
		||||
  * Fix SACCH channel release indication not sent to BSC after location update.
 | 
			
		||||
  * Fix RTP duration adjustment not done when speech resumes in DTX mode.
 | 
			
		||||
 | 
			
		||||
  [ Ruben Undheim ]
 | 
			
		||||
  * Fix some spelling errors
 | 
			
		||||
 | 
			
		||||
  [ Holger Freyther ]
 | 
			
		||||
  * Revert "deb: use gsm_data_shared.* from openbsc-dev"
 | 
			
		||||
 | 
			
		||||
  [ Philipp Maier ]
 | 
			
		||||
  * octphy VTY: fix vty write output for octphy's phy section
 | 
			
		||||
  * octphy: Fix VTY commands
 | 
			
		||||
  * l1sap: fix rach reason (ra) parsing
 | 
			
		||||
  * l1sap: fix PTCCH detection
 | 
			
		||||
  * octphy: fix usage of wrong define constant
 | 
			
		||||
  * octphy: add CBCH support
 | 
			
		||||
  * l1sap: improve log output
 | 
			
		||||
  * octphy: print log message for multi-trx support
 | 
			
		||||
  * octphy: display hint in case of wrongly configured transceiver number
 | 
			
		||||
  * octphy: add conditional compilation to support latest octasic header release
 | 
			
		||||
  * octphy: set tx/rx antenne IDs via VTY
 | 
			
		||||
  * bts: revert trx shutdown order
 | 
			
		||||
  * octphy: activate CBCH after all physical channels are activated
 | 
			
		||||
  * octphy: align frame number for new firmware versions
 | 
			
		||||
  * octphy: ensure that 11 bit rach flag is not set
 | 
			
		||||
  * measurement: fix measurement reporting period
 | 
			
		||||
  * measurement: make lchan_meas_check_compute() available to l1sap.c
 | 
			
		||||
  * measurement: Compute measurement results on measurement idication
 | 
			
		||||
  * measurement: exclude idle channels from uplink measurement
 | 
			
		||||
  * octphy: integrate channel measurement handling
 | 
			
		||||
  * octphy: remove old event control code
 | 
			
		||||
  * osmo-bts-sysmo: Include frame number in MEAS IND
 | 
			
		||||
  * measurement: fix measurement computation
 | 
			
		||||
  * octphy: fix segfault
 | 
			
		||||
  * Revert "measurement: exclude idle channels from uplink measurement"
 | 
			
		||||
  * sysmobts: normalize frame number in measurement indication
 | 
			
		||||
  * measurement: Improve log output
 | 
			
		||||
  * measurement: improve log output
 | 
			
		||||
  * octphy: improve log output
 | 
			
		||||
  * octphy: initalize l1msg and only when needed
 | 
			
		||||
  * octphy: initalize nmsg only when needed
 | 
			
		||||
  * octphy: remove log output
 | 
			
		||||
  * Revert "sysmobts: normalize frame number in measurement indication"
 | 
			
		||||
  * osmo-bts-trx: fix missing frame number in MEAS IND
 | 
			
		||||
  * osmo-bts-litecell15: Fix missing frame number in MEAS IND
 | 
			
		||||
  * Revert "osmo-bts-sysmo: Include frame number in MEAS IND"
 | 
			
		||||
  * octphy: complete value strings (octphy_cid_vals)
 | 
			
		||||
  * octphy: do not send empty frames to phy
 | 
			
		||||
  * osmo-bts-sysmo: Include frame number in MEAS IND
 | 
			
		||||
  * measurement: fix measurment report
 | 
			
		||||
  * octphy: remap frame number in MEAS_IND
 | 
			
		||||
  * octphy: implement support for dynamic timeslots
 | 
			
		||||
 | 
			
		||||
  [ Ivan Klyuchnikov ]
 | 
			
		||||
  * osmo-trx-bts: Fix incorrect setting of RXGAIN and POWER parameters on second channel (TRX1) of osmo-trx
 | 
			
		||||
  * osmo-trx-bts: Fix osmo-bts-trx crash on startup during reading phy instance parameters from config file
 | 
			
		||||
  * osmo-trx-bts: Fix incorrect bts shutdown procedure in case of abis connection closure
 | 
			
		||||
  * osmo-trx-bts: Fix incorrect bts shutdown procedure in case of clock loss from osmo-trx
 | 
			
		||||
 | 
			
		||||
  [ Ivan Kluchnikov ]
 | 
			
		||||
  * oml: Fix incorrect usage of const variable abis_nm_att_tlvdef_ipa
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * phy_link: Fix typo in state being printed
 | 
			
		||||
  * trx: Allow BTS and TRX to be on different IPs
 | 
			
		||||
  * trx: Save osmotrx base-port vty properties
 | 
			
		||||
  * sysmo/tch.c: Clean up use of empty buffer
 | 
			
		||||
  * litecell15/tch.c: Clean up use of empty buffer
 | 
			
		||||
  * Use L1P instead of L1C for TCH logging and allocation
 | 
			
		||||
  * Fix annoying trailing whitespace
 | 
			
		||||
  * sysmo, litecell15: Make sure all TCH events are triggered
 | 
			
		||||
  * sysmo: Remove non longer valid -p option from help
 | 
			
		||||
  * Allow passing low link quality buffers to upper layers
 | 
			
		||||
  * l1sap.c: Avoid sending RTP frame with empty payload
 | 
			
		||||
  * l1sap.c: fn_ms_adj: Add err logging and always return GSM_RTP_DURATION
 | 
			
		||||
  * Move dump_gsmtime to libosmocore as osmo_dump_gsmtime
 | 
			
		||||
  * Use osmo_dump_gsmtime to log fn across different layers
 | 
			
		||||
  * lc15bts-mgr.cfg: Set default vswr to a value inside valid range
 | 
			
		||||
  * litecell15: Register in vty limits for paX_pwr
 | 
			
		||||
  * lc15: Tweak led colors used in service file
 | 
			
		||||
  * lc-15, sysmo: l1_if: print name on PH-DATA.ind unknwon sapi
 | 
			
		||||
  * lc15bts-mgr.service: Prepare dirs and sysctls for the process
 | 
			
		||||
  * osmo-bts-trx: Enable osmotrx tx-attenuation oml by default
 | 
			
		||||
  * osmo-bts-trx: Relax validation to allow TRX data bursts without padding
 | 
			
		||||
 | 
			
		||||
  [ Sebastian Stumpf ]
 | 
			
		||||
  * VIRT-PHY: Added example configurations for openbsc and osmobts.
 | 
			
		||||
  * VIRT-PHY: Fixed timeslot in gsmtap-msg on downlink which was always 0.
 | 
			
		||||
  * VIRT-PHY: Added test option for fast hyperframe repeat.
 | 
			
		||||
 | 
			
		||||
 -- Max <msuraev@sysmocom.de>  Fri, 25 Aug 2017 15:16:56 +0200
 | 
			
		||||
 | 
			
		||||
osmo-bts (0.5.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  * Initial release.
 | 
			
		||||
 | 
			
		||||
 -- Holger Hans Peter Freyther <holger@moiji-mobile.com>  Fri, 01 Apr 2016 16:13:40 +0200
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
9
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
Source: osmo-bts
 | 
			
		||||
Maintainer: Holger Hans Peter Freyther <holger@moiji-mobile.com>
 | 
			
		||||
Section: net
 | 
			
		||||
Priority: optional
 | 
			
		||||
Build-Depends: debhelper (>= 9),
 | 
			
		||||
               pkg-config,
 | 
			
		||||
               dh-autoreconf,
 | 
			
		||||
               dh-systemd (>= 1.5),
 | 
			
		||||
               autotools-dev,
 | 
			
		||||
               pkg-config,
 | 
			
		||||
               libosmocore-dev,
 | 
			
		||||
               libosmo-abis-dev,
 | 
			
		||||
               libgps-dev,
 | 
			
		||||
               libortp-dev,
 | 
			
		||||
               txt2man
 | 
			
		||||
Standards-Version: 3.9.8
 | 
			
		||||
Vcs-Browser: http://git.osmocom.org/osmo-bts/
 | 
			
		||||
Vcs-Git: git://git.osmocom.org/osmo-bts
 | 
			
		||||
Homepage: https://projects.osmocom.org/projects/osmobts
 | 
			
		||||
 | 
			
		||||
Package: osmo-bts-trx
 | 
			
		||||
Architecture: any
 | 
			
		||||
Depends: ${shlibs:Depends}, ${misc:Depends}
 | 
			
		||||
Description: osmo-bts-trx GSM BTS with osmo-trx
 | 
			
		||||
 osmo-bts-trx to be used with the osmo-trx application
 | 
			
		||||
 | 
			
		||||
Package: osmo-bts-trx-dbg
 | 
			
		||||
Architecture: any
 | 
			
		||||
Section: debug
 | 
			
		||||
Priority: extra
 | 
			
		||||
Depends: osmo-bts-trx (= ${binary:Version}), ${misc:Depends}
 | 
			
		||||
Description: Debug symbols for the osmo-bts-trx
 | 
			
		||||
 Make debugging possible
 | 
			
		||||
 | 
			
		||||
Package: osmo-bts-virtual
 | 
			
		||||
Architecture: any
 | 
			
		||||
Depends: ${shlibs:Depends}, ${misc:Depends}
 | 
			
		||||
Description: Virtual Osmocom GSM BTS (no RF hardware; GSMTAP/UDP)
 | 
			
		||||
 This version of OsmoBTS doesn't use actual GSM PHY/Hardware/RF, but
 | 
			
		||||
 utilizes GSMTAP-over-UDP frames for the Um interface.  This is useful
 | 
			
		||||
 in fully virtualized setups e.g. in combination with OsmocomBB virt_phy.
 | 
			
		||||
@@ -0,0 +1,81 @@
 | 
			
		||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
			
		||||
Upstream-Name: osmo-bts
 | 
			
		||||
Source: http://cgit.osmocom.org/osmo-bts/
 | 
			
		||||
 | 
			
		||||
Files: *
 | 
			
		||||
Copyright: 2008-2014 Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
           2009,2011,2013 Andreas Eversberg <jolly@eversberg.eu>
 | 
			
		||||
           2010,2011 On-Waves
 | 
			
		||||
           2012-2015 Holger Hans Peter Freyther
 | 
			
		||||
           2014      sysmocom s.f.m.c. Gmbh
 | 
			
		||||
           2015      Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
 | 
			
		||||
License: AGPL-3+
 | 
			
		||||
 | 
			
		||||
Files: src/osmo-bts-sysmo/eeprom.c
 | 
			
		||||
       src/osmo-bts-sysmo/eeprom.h
 | 
			
		||||
Copyright: 2012     Nutaq
 | 
			
		||||
License: MIT
 | 
			
		||||
Comment: Yves Godin is the author
 | 
			
		||||
 | 
			
		||||
Files: src/common/pcu_sock.c
 | 
			
		||||
Copyright: 2008-2010 Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
           2009-2012 Andreas Eversberg <jolly@eversberg.eu>
 | 
			
		||||
           2012 Holger Hans Peter Freyther
 | 
			
		||||
License: GPL-2+
 | 
			
		||||
 | 
			
		||||
Files: debian/*
 | 
			
		||||
Copyright: 2015-2016 Ruben Undheim <ruben.undheim@gmail.com>
 | 
			
		||||
License: AGPL-3+
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
License: AGPL-3+
 | 
			
		||||
 This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 (at your option) any later version.
 | 
			
		||||
 .
 | 
			
		||||
 This program is distributed in the hope that it will be useful,
 | 
			
		||||
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 GNU General Public License for more details.
 | 
			
		||||
 .
 | 
			
		||||
 You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
License: GPL-2+
 | 
			
		||||
 This package is free software: you can redistribute it and/or modify
 | 
			
		||||
 it under the terms of the GNU General Public License as published by
 | 
			
		||||
 the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
 (at your option) any later version.
 | 
			
		||||
 .
 | 
			
		||||
 This program is distributed in the hope that it will be useful,
 | 
			
		||||
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 GNU General Public License for more details.
 | 
			
		||||
 .
 | 
			
		||||
 You should have received a copy of the GNU General Public License
 | 
			
		||||
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 .
 | 
			
		||||
 On Debian systems, the complete text of the GNU General
 | 
			
		||||
 Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
License: MIT
 | 
			
		||||
 Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 in the Software without restriction, including without limitation the rights to
 | 
			
		||||
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
			
		||||
 of the Software, and to permit persons to whom the Software is furnished to do
 | 
			
		||||
 so, subject to the following conditions:
 | 
			
		||||
 .
 | 
			
		||||
 The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 copies or substantial portions of the Software.
 | 
			
		||||
 .
 | 
			
		||||
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 SOFTWARE.
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
usr/bin/osmo-bts-trx
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Osmocom osmo-bts for osmo-trx
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStart=/usr/bin/osmo-bts-trx -s -c /etc/osmocom/osmo-bts.cfg
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
 | 
			
		||||
# Let it process messages quickly enough
 | 
			
		||||
CPUSchedulingPolicy=rr
 | 
			
		||||
CPUSchedulingPriority=1
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
usr/bin/osmo-bts-virtual
 | 
			
		||||
usr/bin/osmo-bts-omldummy
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Osmocom GSM BTS for virtual Um layer based on GSMTAP/UDP
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStart=/usr/bin/osmo-bts-virtual -s -c /etc/osmocom/osmo-bts-virtual.cfg
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=2
 | 
			
		||||
 | 
			
		||||
# Let it process messages quickly enough
 | 
			
		||||
CPUSchedulingPolicy=rr
 | 
			
		||||
CPUSchedulingPriority=1
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
#!/usr/bin/make -f
 | 
			
		||||
 | 
			
		||||
DEBIAN  := $(shell dpkg-parsechangelog | grep ^Version: | cut -d' ' -f2)
 | 
			
		||||
DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1)
 | 
			
		||||
VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g')
 | 
			
		||||
 | 
			
		||||
#export DH_VERBOSE=1
 | 
			
		||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
%:
 | 
			
		||||
	dh $@ --with=systemd --with autoreconf --fail-missing
 | 
			
		||||
 | 
			
		||||
override_dh_strip:
 | 
			
		||||
	dh_strip --dbg-package=osmo-bts-trx-dbg
 | 
			
		||||
 | 
			
		||||
override_dh_autoreconf:
 | 
			
		||||
	echo $(VERSION) > .tarball-version
 | 
			
		||||
	dh_autoreconf
 | 
			
		||||
 | 
			
		||||
override_dh_auto_configure:
 | 
			
		||||
	dh_auto_configure --  --enable-trx
 | 
			
		||||
 | 
			
		||||
override_dh_clean:
 | 
			
		||||
	dh_clean
 | 
			
		||||
	$(RM) tests/package.m4
 | 
			
		||||
	$(RM) tests/testsuite
 | 
			
		||||
 | 
			
		||||
# Print test results in case of a failure
 | 
			
		||||
override_dh_auto_test:
 | 
			
		||||
	dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
3.0 (native)
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
The osmo-bts control interface is currently supporting the following operations:
 | 
			
		||||
 | 
			
		||||
h2. generic
 | 
			
		||||
 | 
			
		||||
h3. trx.0.thermal-attenuation
 | 
			
		||||
 | 
			
		||||
The idea of this paramter is to attenuate the system output power as part of
 | 
			
		||||
thermal management.  In some cases the PA might be passing a critical level,
 | 
			
		||||
so an external control process can use this attribute to reduce the system
 | 
			
		||||
output power.
 | 
			
		||||
 | 
			
		||||
Please note that all values in the context of transmit power calculation
 | 
			
		||||
are integers in milli-dB (1/10000 bel), so the below example is setting
 | 
			
		||||
the attenuation at 3 dB:
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
bsc_control.py -d localhost -p 4238 -s trx.0.thermal-attenuation 3000
 | 
			
		||||
Got message: SET_REPLY 1 trx.0.thermal-attenuation 3000
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
bsc_control.py -d localhost -p 4238 -g trx.0.thermal-attenuation
 | 
			
		||||
Got message: GET_REPLY 1 trx.0.thermal-attenuation 3000
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
h2. sysmobts specific
 | 
			
		||||
 | 
			
		||||
h3. trx.0.clock-info
 | 
			
		||||
 | 
			
		||||
obtain information on the current clock status:
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
bsc_control.py -d localhost -p 4238 -g trx.0.clock-info
 | 
			
		||||
Got message: GET_REPLY 1 trx.0.clock-info -100,ocxo,0,0,gps
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
which is to be interpreted as:
 | 
			
		||||
* current clock correction value is -100 ppb
 | 
			
		||||
* current clock source is OCXO
 | 
			
		||||
* deviation between clock source and calibration source is 0 ppb
 | 
			
		||||
* resolution of clock error measurement is 0 ppt (0 means no result yet)
 | 
			
		||||
* current calibration source is GPS
 | 
			
		||||
 | 
			
		||||
When this attribute is set, any value passed on is discarded, but the clock
 | 
			
		||||
calibration process is re-started.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
h3. trx.0.clock-correction
 | 
			
		||||
 | 
			
		||||
This attribute can get and set the current clock correction value:
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
bsc_control.py -d localhost -p 4238 -g trx.0.clock-correction
 | 
			
		||||
Got message: GET_REPLY 1 trx.0.clock-correction -100
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
bsc_control.py -d localhost -p 4238 -s trx.0.clock-correction -- -99
 | 
			
		||||
Got message: SET_REPLY 1 trx.0.clock-correction success
 | 
			
		||||
</pre>
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
!
 | 
			
		||||
! OsmoBTS configuration example for CalypsoBTS
 | 
			
		||||
! http://osmocom.org/projects/baseband/wiki/CalypsoBTS
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level rsl notice
 | 
			
		||||
  logging level oml notice
 | 
			
		||||
  logging level rll notice
 | 
			
		||||
  logging level rr notice
 | 
			
		||||
  logging level meas error
 | 
			
		||||
  logging level pag error
 | 
			
		||||
  logging level l1c error
 | 
			
		||||
  logging level l1p error
 | 
			
		||||
  logging level dsp error
 | 
			
		||||
  logging level abis error
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
phy 0
 | 
			
		||||
 instance 0
 | 
			
		||||
  osmotrx rx-gain 1
 | 
			
		||||
 osmotrx ip local 127.0.0.1
 | 
			
		||||
 osmotrx ip remote 127.0.0.1
 | 
			
		||||
 osmotrx timing-advance-loop
 | 
			
		||||
 osmotrx ms-power-loop -65
 | 
			
		||||
 osmotrx legacy-setbsic
 | 
			
		||||
bts 0
 | 
			
		||||
 oml remote-ip 127.0.0.1
 | 
			
		||||
 ipa unit-id 1801 0
 | 
			
		||||
 gsmtap-sapi pdtch
 | 
			
		||||
 gsmtap-sapi ccch
 | 
			
		||||
 band 900
 | 
			
		||||
 trx 0
 | 
			
		||||
  phy 0 instance 0
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
!
 | 
			
		||||
! lc15bts-mgr (0.3.0.284-a7c2-dirty) configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging filter all 1
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging print category 0
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level temp info
 | 
			
		||||
  logging level fw info
 | 
			
		||||
  logging level find info
 | 
			
		||||
  logging level calib info
 | 
			
		||||
  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
 | 
			
		||||
  logging level lctrl notice
 | 
			
		||||
  logging level lgtp notice
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
lc15bts-mgr
 | 
			
		||||
 limits supply_volt
 | 
			
		||||
   threshold warning min 17500
 | 
			
		||||
   threshold critical min 19000
 | 
			
		||||
 limits tx0_vswr
 | 
			
		||||
   threshold warning max 1000
 | 
			
		||||
 limits tx1_vswr
 | 
			
		||||
   threshold warning max 1000
 | 
			
		||||
 limits supply_pwr
 | 
			
		||||
   threshold warning max 110
 | 
			
		||||
   threshold critical max 120
 | 
			
		||||
 limits pa0_pwr
 | 
			
		||||
   threshold warning max 50
 | 
			
		||||
   threshold critical max 60
 | 
			
		||||
 limits pa1_pwr
 | 
			
		||||
   threshold warning max 50
 | 
			
		||||
   threshold critical max 60
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
!
 | 
			
		||||
! OsmoBTS (0.0.1.100-0455-dirty) configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level rsl info
 | 
			
		||||
  logging level oml info
 | 
			
		||||
  logging level rll notice
 | 
			
		||||
  logging level rr notice
 | 
			
		||||
  logging level meas notice
 | 
			
		||||
  logging level pag info
 | 
			
		||||
  logging level l1c info
 | 
			
		||||
  logging level l1p info
 | 
			
		||||
  logging level dsp debug
 | 
			
		||||
  logging level abis notice
 | 
			
		||||
  logging level rtp notice
 | 
			
		||||
  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
 | 
			
		||||
!
 | 
			
		||||
phy 0
 | 
			
		||||
 instance 0
 | 
			
		||||
  trx-calibration-path /mnt/rom/factory/calib
 | 
			
		||||
phy 1
 | 
			
		||||
 instance 0
 | 
			
		||||
  trx-calibration-path /mnt/rom/factory/calib
 | 
			
		||||
bts 0
 | 
			
		||||
 band 900
 | 
			
		||||
 ipa unit-id 1500 0
 | 
			
		||||
 oml remote-ip 192.168.234.185
 | 
			
		||||
 trx 0
 | 
			
		||||
  phy 0 instance 0
 | 
			
		||||
 trx 1
 | 
			
		||||
  phy 1 instance 0
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
!
 | 
			
		||||
! OsmoBTS () configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level rsl info
 | 
			
		||||
  logging level oml info
 | 
			
		||||
  logging level rll notice
 | 
			
		||||
  logging level rr notice
 | 
			
		||||
  logging level meas notice
 | 
			
		||||
  logging level pag info
 | 
			
		||||
  logging level l1c info
 | 
			
		||||
  logging level l1p info
 | 
			
		||||
  logging level dsp info
 | 
			
		||||
  logging level abis notice
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
phy 0
 | 
			
		||||
 octphy hw-addr 00:0c:de:ad:fa:ce
 | 
			
		||||
 octphy net-device eth2
 | 
			
		||||
 instance 0
 | 
			
		||||
 instance 1
 | 
			
		||||
bts 0
 | 
			
		||||
 band 1800
 | 
			
		||||
 ipa unit-id 1234 0
 | 
			
		||||
 oml remote-ip 127.0.0.1
 | 
			
		||||
 trx 0
 | 
			
		||||
  phy 0 instance 0
 | 
			
		||||
 trx 1
 | 
			
		||||
  phy 0 instance 1
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
!
 | 
			
		||||
! OsmoBTS () configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level rsl info
 | 
			
		||||
  logging level oml info
 | 
			
		||||
  logging level rll notice
 | 
			
		||||
  logging level rr notice
 | 
			
		||||
  logging level meas notice
 | 
			
		||||
  logging level pag info
 | 
			
		||||
  logging level l1c info
 | 
			
		||||
  logging level l1p info
 | 
			
		||||
  logging level dsp info
 | 
			
		||||
  logging level abis notice
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
phy 0
 | 
			
		||||
 octphy hw-addr 00:0C:90:2e:80:1e
 | 
			
		||||
 octphy net-device eth0.2342
 | 
			
		||||
 instance 0
 | 
			
		||||
bts 0
 | 
			
		||||
 band 1800
 | 
			
		||||
 ipa unit-id 1234 0
 | 
			
		||||
 oml remote-ip 127.0.0.1
 | 
			
		||||
 trx 0
 | 
			
		||||
  phy 0 instance 0
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
!
 | 
			
		||||
! OsmoBTS () configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level rsl info
 | 
			
		||||
  logging level oml info
 | 
			
		||||
  logging level rll notice
 | 
			
		||||
  logging level rr notice
 | 
			
		||||
  logging level meas notice
 | 
			
		||||
  logging level pag info
 | 
			
		||||
  logging level l1c info
 | 
			
		||||
  logging level l1p info
 | 
			
		||||
  logging level dsp info
 | 
			
		||||
  logging level abis notice
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
phy 0
 | 
			
		||||
 instance 0
 | 
			
		||||
bts 0
 | 
			
		||||
 band 1800
 | 
			
		||||
 ipa unit-id 666 0
 | 
			
		||||
 oml remote-ip 10.1.2.3
 | 
			
		||||
 trx 0
 | 
			
		||||
  phy 0 instance 0
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
!
 | 
			
		||||
! SysmoMgr (0.3.0.141-33e5) configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging filter all 1
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level temp info
 | 
			
		||||
  logging level fw info
 | 
			
		||||
  logging level find info
 | 
			
		||||
  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
 | 
			
		||||
!
 | 
			
		||||
sysmobts-mgr
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
!
 | 
			
		||||
! OsmoBTS () configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level rsl notice
 | 
			
		||||
  logging level oml notice
 | 
			
		||||
  logging level rll notice
 | 
			
		||||
  logging level rr notice
 | 
			
		||||
  logging level meas error
 | 
			
		||||
  logging level pag error
 | 
			
		||||
  logging level l1c error
 | 
			
		||||
  logging level l1p error
 | 
			
		||||
  logging level dsp error
 | 
			
		||||
  logging level abis error
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
phy 0
 | 
			
		||||
 instance 0
 | 
			
		||||
  osmotrx rx-gain 1
 | 
			
		||||
 osmotrx ip local 127.0.0.1
 | 
			
		||||
 osmotrx ip remote 127.0.0.1
 | 
			
		||||
bts 0
 | 
			
		||||
 band 1800
 | 
			
		||||
 ipa unit-id 6969 0
 | 
			
		||||
 oml remote-ip 192.168.122.1
 | 
			
		||||
 gsmtap-sapi ccch
 | 
			
		||||
 gsmtap-sapi pdtch
 | 
			
		||||
 trx 0
 | 
			
		||||
  phy 0 instance 0
 | 
			
		||||
@@ -0,0 +1,151 @@
 | 
			
		||||
!
 | 
			
		||||
! OpenBSC (0.15.0.629-34f0-dirty) configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging filter all 1
 | 
			
		||||
  logging color 0
 | 
			
		||||
  logging print category 1
 | 
			
		||||
  logging timestamp 1
 | 
			
		||||
  logging level all info
 | 
			
		||||
  logging level rll notice
 | 
			
		||||
  logging level cc notice
 | 
			
		||||
  logging level mm debug
 | 
			
		||||
  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 filter debug
 | 
			
		||||
  logging level ranap debug
 | 
			
		||||
  logging level sua 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
 | 
			
		||||
  logging level lctrl notice
 | 
			
		||||
  logging level lgtp notice
 | 
			
		||||
  logging level lstats notice
 | 
			
		||||
  logging level lgsup notice
 | 
			
		||||
  logging level loap notice
 | 
			
		||||
!
 | 
			
		||||
stats interval 5
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
e1_input
 | 
			
		||||
 e1_line 0 driver ipa
 | 
			
		||||
 e1_line 0 port 0
 | 
			
		||||
 no e1_line 0 keepalive
 | 
			
		||||
network
 | 
			
		||||
 network country code 262
 | 
			
		||||
 mobile network code 42
 | 
			
		||||
 short name OpenBSC
 | 
			
		||||
 long name OpenBSC
 | 
			
		||||
 auth policy accept-all
 | 
			
		||||
 authorized-regexp .*
 | 
			
		||||
 location updating reject cause 13
 | 
			
		||||
 encryption a5 0
 | 
			
		||||
 neci 1
 | 
			
		||||
 paging any use tch 0
 | 
			
		||||
 rrlp mode ms-based
 | 
			
		||||
 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
 | 
			
		||||
 timer t3101 10
 | 
			
		||||
 timer t3103 0
 | 
			
		||||
 timer t3105 0
 | 
			
		||||
 timer t3107 0
 | 
			
		||||
 timer t3109 4
 | 
			
		||||
 timer t3111 0
 | 
			
		||||
 timer t3113 60
 | 
			
		||||
 timer t3115 0
 | 
			
		||||
 timer t3117 0
 | 
			
		||||
 timer t3119 0
 | 
			
		||||
 timer t3122 10
 | 
			
		||||
 timer t3141 0
 | 
			
		||||
 subscriber-keep-in-ram 0
 | 
			
		||||
 bts 0
 | 
			
		||||
  type sysmobts
 | 
			
		||||
  band DCS1800
 | 
			
		||||
  cell_identity 6969
 | 
			
		||||
  location_area_code 1
 | 
			
		||||
  base_station_id_code 63
 | 
			
		||||
  ms max power 0
 | 
			
		||||
  cell reselection hysteresis 4
 | 
			
		||||
  rxlev access min 0
 | 
			
		||||
  periodic location update 30
 | 
			
		||||
  radio-link-timeout 32
 | 
			
		||||
  channel allocator descending
 | 
			
		||||
  rach tx integer 9
 | 
			
		||||
  rach max transmission 7
 | 
			
		||||
  channel-descrption attach 1
 | 
			
		||||
  channel-descrption bs-pa-mfrms 5
 | 
			
		||||
  channel-descrption bs-ag-blks-res 1
 | 
			
		||||
  ip.access unit_id 6969 0
 | 
			
		||||
  oml ip.access stream_id 255 line 0
 | 
			
		||||
  neighbor-list mode automatic
 | 
			
		||||
  codec-support fr
 | 
			
		||||
  gprs mode none
 | 
			
		||||
  no force-combined-si
 | 
			
		||||
  trx 0
 | 
			
		||||
   rf_locked 0
 | 
			
		||||
   arfcn 666
 | 
			
		||||
   nominal power 0
 | 
			
		||||
   max_power_red 0
 | 
			
		||||
   rsl e1 tei 0
 | 
			
		||||
   timeslot 0
 | 
			
		||||
    phys_chan_config CCCH+SDCCH4
 | 
			
		||||
    hopping enabled 0
 | 
			
		||||
   timeslot 1
 | 
			
		||||
    phys_chan_config SDCCH8
 | 
			
		||||
    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
 | 
			
		||||
mncc-int
 | 
			
		||||
 default-codec tch-f fr
 | 
			
		||||
 default-codec tch-h hr
 | 
			
		||||
nitb
 | 
			
		||||
 subscriber-create-on-demand
 | 
			
		||||
 subscriber-create-on-demand random 1 24
 | 
			
		||||
 assign-tmsi
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
!
 | 
			
		||||
! OsmoBTS (0.4.0.216-bc49-dirty) configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
  logging filter all 0
 | 
			
		||||
  logging color 0
 | 
			
		||||
  logging print category 1
 | 
			
		||||
  logging timestamp 0
 | 
			
		||||
  logging level rsl info
 | 
			
		||||
  logging level oml info
 | 
			
		||||
  logging level rll notice
 | 
			
		||||
  logging level rr notice
 | 
			
		||||
  logging level meas notice
 | 
			
		||||
  logging level pag info
 | 
			
		||||
  logging level l1c info
 | 
			
		||||
  logging level l1p info
 | 
			
		||||
  logging level dsp error
 | 
			
		||||
  logging level pcu notice
 | 
			
		||||
  logging level ho debug
 | 
			
		||||
  logging level trx notice
 | 
			
		||||
  logging level loop notice
 | 
			
		||||
  logging level abis debug
 | 
			
		||||
  logging level rtp notice
 | 
			
		||||
  logging level sum error
 | 
			
		||||
  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
 | 
			
		||||
  logging level lctrl notice
 | 
			
		||||
  logging level lgtp notice
 | 
			
		||||
  logging level lstats error
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
e1_input
 | 
			
		||||
 e1_line 0 driver ipa
 | 
			
		||||
 e1_line 0 port 0
 | 
			
		||||
 no e1_line 0 keepalive
 | 
			
		||||
phy 0
 | 
			
		||||
 instance 0
 | 
			
		||||
bts 0
 | 
			
		||||
 band DCS1800
 | 
			
		||||
 ipa unit-id 6969 0
 | 
			
		||||
 oml remote-ip 127.0.0.1
 | 
			
		||||
 rtp jitter-buffer 100
 | 
			
		||||
 paging queue-size 200
 | 
			
		||||
 paging lifetime 0
 | 
			
		||||
 uplink-power-target -75
 | 
			
		||||
 min-qual-rach 50
 | 
			
		||||
 min-qual-norm -5
 | 
			
		||||
 trx 0
 | 
			
		||||
  power-ramp max-initial 23000 mdBm
 | 
			
		||||
  power-ramp step-size 2000 mdB
 | 
			
		||||
  power-ramp step-interval 1
 | 
			
		||||
  ms-power-control dsp
 | 
			
		||||
  phy 0 instance 0
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
 | 
			
		||||
== OsmoBTS PHY interface abstraction
 | 
			
		||||
 | 
			
		||||
The OsmoBTS PHY interface serves as an abstraction layer between given
 | 
			
		||||
PHY hardware and the actual logical transceivers (TRXs) of a BTS inside
 | 
			
		||||
the OsmoBTS code base.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=== PHY link
 | 
			
		||||
 | 
			
		||||
A PHY link is a physical connection / link towards a given PHY.  This
 | 
			
		||||
might be, for example,
 | 
			
		||||
 | 
			
		||||
* a set of file descriptors to device nodes in the /dev/ directory
 | 
			
		||||
  (sysmobts, litecell15)
 | 
			
		||||
* a packet socket for sending raw Ethernet frames to an OCTPHY
 | 
			
		||||
* a set of UDP sockets for interacting with OsmoTRX
 | 
			
		||||
 | 
			
		||||
Each PHY interface has a set of attribute/parameters and a list of 1 to
 | 
			
		||||
n PHY instances.
 | 
			
		||||
 | 
			
		||||
PHY links are numbered 0..n globally inside OsmoBTS.
 | 
			
		||||
 | 
			
		||||
Each PHY link is configured via the VTY using its individual top-level
 | 
			
		||||
vty node.  Given the different bts-model / phy specific properties, the
 | 
			
		||||
VTY configuration options (if any) of the PHY instance differ between
 | 
			
		||||
BTS models.
 | 
			
		||||
 | 
			
		||||
The PHY links and instances must be configured above the BTS/TRX nodes
 | 
			
		||||
in the configuration file.  If the file is saved via the VTY, the code
 | 
			
		||||
automatically ensures this.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=== PHY instance
 | 
			
		||||
 | 
			
		||||
A PHY instance is an instance of a PHY, accessed via a PHY link.
 | 
			
		||||
 | 
			
		||||
In the case of osmo-bts-sysmo and osmo-bts-trx, there is only one
 | 
			
		||||
instance in every PHY link.  This is due to the fact that the API inside
 | 
			
		||||
that PHY link does not permit for distinguishing multiple different
 | 
			
		||||
logical TRXs.
 | 
			
		||||
 | 
			
		||||
Other PHY implementations like the OCTPHY however do support addressing
 | 
			
		||||
multiple PHY instances via a single PHY link.
 | 
			
		||||
 | 
			
		||||
PHY instances are numbered 0..n inside each PHY link.
 | 
			
		||||
 | 
			
		||||
Each PHY instance is configured via the VTY as a separate node beneath each
 | 
			
		||||
PHY link.  Given the different bts-model / phy specific properties, the
 | 
			
		||||
VTY configuration options (if any) of the PHY instance differ between
 | 
			
		||||
BTS models.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=== Mapping PHY instances to TRXs
 | 
			
		||||
 | 
			
		||||
Each TRX node in the VTY must use the 'phy N instance M' command in
 | 
			
		||||
order to specify which PHY instance is allocated to this specific TRX.
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
 | 
			
		||||
== start-up / sequencing during OsmoBTS start
 | 
			
		||||
 | 
			
		||||
The start-up procedure of OsmoBTS can be described as follows:
 | 
			
		||||
 | 
			
		||||
|===
 | 
			
		||||
| bts-specific | main() |
 | 
			
		||||
| common | bts_main() | initialization of talloc contexts
 | 
			
		||||
| common | osmo_init_logging2() | initialization of logging
 | 
			
		||||
| common | handle_options() | common option parsing
 | 
			
		||||
| bts-specific | bts_model_handle_options() | model-specific option parsing
 | 
			
		||||
| common | gsm_bts_alloc() | allocation of BTS/TRX/TS data structures
 | 
			
		||||
| common | vty_init() | Initialziation of VTY core, libosmo-abis and osmo-bts VTY
 | 
			
		||||
| common | main() | Setting of scheduler RR priority (if configured)
 | 
			
		||||
| common | main() | Initialization of GSMTAP (if configured)
 | 
			
		||||
| common | bts_init() | configuration of defaults in bts/trx/s object
 | 
			
		||||
| bts-specific | bts_model_init | ?
 | 
			
		||||
| common | abis_init() | Initialization of libosmo-abis
 | 
			
		||||
| common | vty_read_config_file() | Reading of configuration file
 | 
			
		||||
| bts-specific | bts_model_phy_link_set_defaults() | Called for every PHY link created
 | 
			
		||||
| bts-specific | bts_model_phy_instance_set_defaults() | Called for every PHY Instance created
 | 
			
		||||
| common | bts_controlif_setup() | Initialization of Control Interface
 | 
			
		||||
| bts-specific | bts_model_ctrl_cmds_install()
 | 
			
		||||
| common | telnet_init() | Initialization of telnet interface
 | 
			
		||||
| common | pcu_sock_init() | Initializaiton of PCU socket
 | 
			
		||||
| common | main() | Installation of signal handlers
 | 
			
		||||
| common | abis_open() | Start of the A-bis connection to BSC
 | 
			
		||||
| common | phy_links_open() | Iterate over list of configured PHY links
 | 
			
		||||
| bts-specific | bts_model_phy_link_open() | Open each of the configured PHY links
 | 
			
		||||
| common | write_pid_file() | Generate the pid file
 | 
			
		||||
| common | osmo_daemonize() | Fork as daemon in background (if configured)
 | 
			
		||||
| common | bts_main() | Run main loop until global variable quit >= 2
 | 
			
		||||
| bts-specific | bts_model_oml_estab() | Called by core once OML link is established
 | 
			
		||||
| bts-specific | bts_model_check_oml() | called each time OML sets some attributes on a MO, checks if attributes are valid
 | 
			
		||||
| bts-specific | bts_model_apply_oml() | called each time OML sets some attributes on a MO, stores attribute contents in data structures
 | 
			
		||||
| bts-specific | bts_model_opstart() | for NM_OC_BTS, NM_OC_SITE_MANAGER, NM_OC_GPRS_NSE, NM_OC_GPRS_CELL, NMO_OC_GPRS_NSVC
 | 
			
		||||
| bts-specific | bts_model_opstart() | for NM_OC_RADIO_CARRIER for each trx
 | 
			
		||||
| bts-specific | bts_model_opstart() | for NM_OC_BASEB_TRANSC for each trx
 | 
			
		||||
| bts-specific | bts_model_opstart() | for NM_OC_CHANNEL for each timeslot on each trx
 | 
			
		||||
| bts-specific | bts_model_change_power() | change transmit power for each trx (power ramp-up/ramp-down
 | 
			
		||||
 | 
			
		||||
| bts-specific | bts_model_abis_close() | called when either one of the RSL links or the OML link are down
 | 
			
		||||
@@ -0,0 +1,151 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
# Print a version string.
 | 
			
		||||
scriptversion=2010-01-28.01
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
 | 
			
		||||
#
 | 
			
		||||
# 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, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
 | 
			
		||||
# It may be run two ways:
 | 
			
		||||
# - from a git repository in which the "git describe" command below
 | 
			
		||||
#   produces useful output (thus requiring at least one signed tag)
 | 
			
		||||
# - from a non-git-repo directory containing a .tarball-version file, which
 | 
			
		||||
#   presumes this script is invoked like "./git-version-gen .tarball-version".
 | 
			
		||||
 | 
			
		||||
# In order to use intra-version strings in your project, you will need two
 | 
			
		||||
# separate generated version string files:
 | 
			
		||||
#
 | 
			
		||||
# .tarball-version - present only in a distribution tarball, and not in
 | 
			
		||||
#   a checked-out repository.  Created with contents that were learned at
 | 
			
		||||
#   the last time autoconf was run, and used by git-version-gen.  Must not
 | 
			
		||||
#   be present in either $(srcdir) or $(builddir) for git-version-gen to
 | 
			
		||||
#   give accurate answers during normal development with a checked out tree,
 | 
			
		||||
#   but must be present in a tarball when there is no version control system.
 | 
			
		||||
#   Therefore, it cannot be used in any dependencies.  GNUmakefile has
 | 
			
		||||
#   hooks to force a reconfigure at distribution time to get the value
 | 
			
		||||
#   correct, without penalizing normal development with extra reconfigures.
 | 
			
		||||
#
 | 
			
		||||
# .version - present in a checked-out repository and in a distribution
 | 
			
		||||
#   tarball.  Usable in dependencies, particularly for files that don't
 | 
			
		||||
#   want to depend on config.h but do want to track version changes.
 | 
			
		||||
#   Delete this file prior to any autoconf run where you want to rebuild
 | 
			
		||||
#   files to pick up a version string change; and leave it stale to
 | 
			
		||||
#   minimize rebuild time after unrelated changes to configure sources.
 | 
			
		||||
#
 | 
			
		||||
# It is probably wise to add these two files to .gitignore, so that you
 | 
			
		||||
# don't accidentally commit either generated file.
 | 
			
		||||
#
 | 
			
		||||
# Use the following line in your configure.ac, so that $(VERSION) will
 | 
			
		||||
# automatically be up-to-date each time configure is run (and note that
 | 
			
		||||
# since configure.ac no longer includes a version string, Makefile rules
 | 
			
		||||
# should not depend on configure.ac for version updates).
 | 
			
		||||
#
 | 
			
		||||
# AC_INIT([GNU project],
 | 
			
		||||
#         m4_esyscmd([build-aux/git-version-gen .tarball-version]),
 | 
			
		||||
#         [bug-project@example])
 | 
			
		||||
#
 | 
			
		||||
# Then use the following lines in your Makefile.am, so that .version
 | 
			
		||||
# will be present for dependencies, and so that .tarball-version will
 | 
			
		||||
# exist in distribution tarballs.
 | 
			
		||||
#
 | 
			
		||||
# BUILT_SOURCES = $(top_srcdir)/.version
 | 
			
		||||
# $(top_srcdir)/.version:
 | 
			
		||||
#	echo $(VERSION) > $@-t && mv $@-t $@
 | 
			
		||||
# dist-hook:
 | 
			
		||||
#	echo $(VERSION) > $(distdir)/.tarball-version
 | 
			
		||||
 | 
			
		||||
case $# in
 | 
			
		||||
    1) ;;
 | 
			
		||||
    *) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
tarball_version_file=$1
 | 
			
		||||
nl='
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
# First see if there is a tarball-only version file.
 | 
			
		||||
# then try "git describe", then default.
 | 
			
		||||
if test -f $tarball_version_file
 | 
			
		||||
then
 | 
			
		||||
    v=`cat $tarball_version_file` || exit 1
 | 
			
		||||
    case $v in
 | 
			
		||||
	*$nl*) v= ;; # reject multi-line output
 | 
			
		||||
	[0-9]*) ;;
 | 
			
		||||
	*) v= ;;
 | 
			
		||||
    esac
 | 
			
		||||
    test -z "$v" \
 | 
			
		||||
	&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test -n "$v"
 | 
			
		||||
then
 | 
			
		||||
    : # use $v
 | 
			
		||||
elif
 | 
			
		||||
       v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
 | 
			
		||||
	  || git describe --abbrev=4 HEAD 2>/dev/null` \
 | 
			
		||||
    && case $v in
 | 
			
		||||
	 [0-9]*) ;;
 | 
			
		||||
	 v[0-9]*) ;;
 | 
			
		||||
	 *) (exit 1) ;;
 | 
			
		||||
       esac
 | 
			
		||||
then
 | 
			
		||||
    # Is this a new git that lists number of commits since the last
 | 
			
		||||
    # tag or the previous older version that did not?
 | 
			
		||||
    #   Newer: v6.10-77-g0f8faeb
 | 
			
		||||
    #   Older: v6.10-g0f8faeb
 | 
			
		||||
    case $v in
 | 
			
		||||
	*-*-*) : git describe is okay three part flavor ;;
 | 
			
		||||
	*-*)
 | 
			
		||||
	    : git describe is older two part flavor
 | 
			
		||||
	    # Recreate the number of commits and rewrite such that the
 | 
			
		||||
	    # result is the same as if we were using the newer version
 | 
			
		||||
	    # of git describe.
 | 
			
		||||
	    vtag=`echo "$v" | sed 's/-.*//'`
 | 
			
		||||
	    numcommits=`git rev-list "$vtag"..HEAD | wc -l`
 | 
			
		||||
	    v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
 | 
			
		||||
	    ;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
    # Change the first '-' to a '.', so version-comparing tools work properly.
 | 
			
		||||
    # Remove the "g" in git describe's output string, to save a byte.
 | 
			
		||||
    v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
 | 
			
		||||
else
 | 
			
		||||
    v=UNKNOWN
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
v=`echo "$v" |sed 's/^v//'`
 | 
			
		||||
 | 
			
		||||
# Don't declare a version "dirty" merely because a time stamp has changed.
 | 
			
		||||
git status > /dev/null 2>&1
 | 
			
		||||
 | 
			
		||||
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
 | 
			
		||||
case "$dirty" in
 | 
			
		||||
    '') ;;
 | 
			
		||||
    *) # Append the suffix only if there isn't one already.
 | 
			
		||||
	case $v in
 | 
			
		||||
	  *-dirty) ;;
 | 
			
		||||
	  *) v="$v-dirty" ;;
 | 
			
		||||
	esac ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
 | 
			
		||||
echo "$v" | tr -d '\012'
 | 
			
		||||
 | 
			
		||||
# Local variables:
 | 
			
		||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
 | 
			
		||||
# time-stamp-start: "scriptversion="
 | 
			
		||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
 | 
			
		||||
# time-stamp-end: "$"
 | 
			
		||||
# End:
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
SUBDIRS = osmo-bts
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h gsm_data_shared.h logging.h measurement.h \
 | 
			
		||||
		 oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \
 | 
			
		||||
		 handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \
 | 
			
		||||
		 power_control.h scheduler.h scheduler_backend.h phy_link.h \
 | 
			
		||||
		 dtx_dl_amr_fsm.h
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
#ifndef _ABIS_H
 | 
			
		||||
#define _ABIS_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/select.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
 | 
			
		||||
#define	OML_RETRY_TIMER		5
 | 
			
		||||
#define	OML_PING_TIMER		20
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	LINK_STATE_IDLE = 0,
 | 
			
		||||
	LINK_STATE_RETRYING,
 | 
			
		||||
	LINK_STATE_CONNECTING,
 | 
			
		||||
	LINK_STATE_CONNECT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void abis_init(struct gsm_bts *bts);
 | 
			
		||||
struct e1inp_line *abis_open(struct gsm_bts *bts, char *dst_host,
 | 
			
		||||
			     char *model_name);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int abis_oml_sendmsg(struct msgb *msg);
 | 
			
		||||
int abis_bts_rsl_sendmsg(struct msgb *msg);
 | 
			
		||||
 | 
			
		||||
uint32_t get_signlink_remote_ip(struct e1inp_sign_link *link);
 | 
			
		||||
 | 
			
		||||
#endif /* _ABIS_H */
 | 
			
		||||
@@ -0,0 +1,18 @@
 | 
			
		||||
#ifndef _OSMO_BTS_AMR_H
 | 
			
		||||
#define _OSMO_BTS_AMR_H
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
 | 
			
		||||
#define AMR_TOC_QBIT	0x04
 | 
			
		||||
#define AMR_CMR_NONE	0xF
 | 
			
		||||
 | 
			
		||||
void amr_log_mr_conf(int ss, int logl, const char *pfx,
 | 
			
		||||
		     struct amr_multirate_conf *amr_mrc);
 | 
			
		||||
 | 
			
		||||
int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc,
 | 
			
		||||
		      const uint8_t *mr_conf, unsigned int len);
 | 
			
		||||
void amr_set_mode_pref(uint8_t *data, const struct amr_multirate_conf *amr_mrc,
 | 
			
		||||
		       uint8_t cmi, uint8_t cmr);
 | 
			
		||||
unsigned int amr_get_initial_mode(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
#endif /* _OSMO_BTS_AMR_H */
 | 
			
		||||
@@ -0,0 +1,67 @@
 | 
			
		||||
#ifndef _BTS_H
 | 
			
		||||
#define _BTS_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
 | 
			
		||||
enum bts_global_status {
 | 
			
		||||
	BTS_STATUS_RF_ACTIVE,
 | 
			
		||||
	BTS_STATUS_RF_MUTE,
 | 
			
		||||
	BTS_STATUS_LAST,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	BTS_CTR_PAGING_RCVD,
 | 
			
		||||
	BTS_CTR_PAGING_DROP,
 | 
			
		||||
	BTS_CTR_PAGING_SENT,
 | 
			
		||||
	BTS_CTR_RACH_RCVD,
 | 
			
		||||
	BTS_CTR_RACH_DROP,
 | 
			
		||||
	BTS_CTR_RACH_HO,
 | 
			
		||||
	BTS_CTR_RACH_CS,
 | 
			
		||||
	BTS_CTR_RACH_PS,
 | 
			
		||||
	BTS_CTR_AGCH_RCVD,
 | 
			
		||||
	BTS_CTR_AGCH_SENT,
 | 
			
		||||
	BTS_CTR_AGCH_DELETED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern void *tall_bts_ctx;
 | 
			
		||||
 | 
			
		||||
int bts_init(struct gsm_bts *bts);
 | 
			
		||||
void bts_shutdown(struct gsm_bts *bts, const char *reason);
 | 
			
		||||
 | 
			
		||||
struct gsm_bts *create_bts(uint8_t num_trx, char *id);
 | 
			
		||||
int create_ms(struct gsm_bts_trx *trx, int maskc, uint8_t *maskv_tx,
 | 
			
		||||
	uint8_t *maskv_rx);
 | 
			
		||||
void destroy_bts(struct gsm_bts *bts);
 | 
			
		||||
int work_bts(struct gsm_bts *bts);
 | 
			
		||||
int bts_link_estab(struct gsm_bts *bts);
 | 
			
		||||
int trx_link_estab(struct gsm_bts_trx *trx);
 | 
			
		||||
int trx_set_available(struct gsm_bts_trx *trx, int avail);
 | 
			
		||||
void bts_new_si(void *arg);
 | 
			
		||||
void bts_setup_slot(struct gsm_bts_trx_ts *slot, uint8_t comb);
 | 
			
		||||
 | 
			
		||||
int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg);
 | 
			
		||||
struct msgb *bts_agch_dequeue(struct gsm_bts *bts);
 | 
			
		||||
int bts_agch_max_queue_length(int T, int bcch_conf);
 | 
			
		||||
int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
 | 
			
		||||
		      int is_ag_res);
 | 
			
		||||
 | 
			
		||||
uint8_t *bts_sysinfo_get(struct gsm_bts *bts, const struct gsm_time *g_time);
 | 
			
		||||
uint8_t *lchan_sacch_get(struct gsm_lchan *lchan);
 | 
			
		||||
int lchan_init_lapdm(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
void load_timer_start(struct gsm_bts *bts);
 | 
			
		||||
uint8_t num_agch(struct gsm_bts_trx *trx, const char * arg);
 | 
			
		||||
void bts_update_status(enum bts_global_status which, int on);
 | 
			
		||||
 | 
			
		||||
int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx);
 | 
			
		||||
 | 
			
		||||
struct gsm_time *get_time(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
int bts_main(int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
int bts_supports_cm(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,
 | 
			
		||||
		    enum gsm48_chan_mode cm);
 | 
			
		||||
 | 
			
		||||
#endif /* _BTS_H */
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
#ifndef BTS_MODEL_H
 | 
			
		||||
#define BTS_MODEL_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/tlv.h>
 | 
			
		||||
#include <osmocom/gsm/gsm_utils.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
 | 
			
		||||
struct phy_link;
 | 
			
		||||
struct phy_instance;
 | 
			
		||||
 | 
			
		||||
/* BTS model specific functions needed by the common code */
 | 
			
		||||
 | 
			
		||||
int bts_model_init(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type,
 | 
			
		||||
			struct tlv_parsed *old_attr, struct tlv_parsed *new_attr,
 | 
			
		||||
			void *obj);
 | 
			
		||||
 | 
			
		||||
int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
 | 
			
		||||
			struct tlv_parsed *new_attr, int obj_kind, void *obj);
 | 
			
		||||
 | 
			
		||||
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo,
 | 
			
		||||
		      void *obj);
 | 
			
		||||
 | 
			
		||||
int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo,
 | 
			
		||||
			    void *obj, uint8_t adm_state);
 | 
			
		||||
 | 
			
		||||
int bts_model_trx_deact_rf(struct gsm_bts_trx *trx);
 | 
			
		||||
int bts_model_trx_close(struct gsm_bts_trx *trx);
 | 
			
		||||
 | 
			
		||||
int bts_model_vty_init(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts);
 | 
			
		||||
void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx);
 | 
			
		||||
void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink);
 | 
			
		||||
void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst);
 | 
			
		||||
 | 
			
		||||
int bts_model_oml_estab(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm);
 | 
			
		||||
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
 | 
			
		||||
 | 
			
		||||
int bts_model_lchan_deactivate(struct gsm_lchan *lchan);
 | 
			
		||||
int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
void bts_model_abis_close(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
int bts_model_ctrl_cmds_install(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
int bts_model_handle_options(int argc, char **argv);
 | 
			
		||||
void bts_model_print_help();
 | 
			
		||||
 | 
			
		||||
void bts_model_phy_link_set_defaults(struct phy_link *plink);
 | 
			
		||||
void bts_model_phy_instance_set_defaults(struct phy_instance *pinst);
 | 
			
		||||
 | 
			
		||||
int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts);
 | 
			
		||||
int bts_model_ts_connect(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/gsm_utils.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_08_58.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
#include <osmo-bts/bts.h>
 | 
			
		||||
 | 
			
		||||
/* incoming SMS broadcast command from RSL */
 | 
			
		||||
int bts_process_smscb_cmd(struct gsm_bts *bts,
 | 
			
		||||
			  struct rsl_ie_cb_cmd_type cmd_type,
 | 
			
		||||
			  uint8_t msg_len, const uint8_t *msg);
 | 
			
		||||
 | 
			
		||||
/* call-back from bts model specific code when it wants to obtain a CBCH
 | 
			
		||||
 * block for a given gsm_time.  outbuf must have 23 bytes of space. */
 | 
			
		||||
int bts_cbch_get(struct gsm_bts *bts, uint8_t *outbuf, struct gsm_time *g_time);
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
int bts_ctrl_cmds_install(struct gsm_bts *bts);
 | 
			
		||||
struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts,
 | 
			
		||||
					const char *bind_addr, uint16_t port);
 | 
			
		||||
@@ -0,0 +1,44 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/fsm.h>
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
 | 
			
		||||
/* DTX DL AMR FSM */
 | 
			
		||||
 | 
			
		||||
#define X(s) (1 << (s))
 | 
			
		||||
 | 
			
		||||
enum dtx_dl_amr_fsm_states {
 | 
			
		||||
	ST_VOICE,
 | 
			
		||||
	ST_SID_F1,
 | 
			
		||||
	ST_SID_F2,
 | 
			
		||||
	ST_F1_INH_V,
 | 
			
		||||
	ST_F1_INH_F,
 | 
			
		||||
	ST_U_INH_V,
 | 
			
		||||
	ST_U_INH_F,
 | 
			
		||||
	ST_U_NOINH,
 | 
			
		||||
	ST_F1_INH_V_REC,
 | 
			
		||||
	ST_F1_INH_F_REC,
 | 
			
		||||
	ST_U_INH_V_REC,
 | 
			
		||||
	ST_U_INH_F_REC,
 | 
			
		||||
	ST_SID_U,
 | 
			
		||||
	ST_ONSET_V,
 | 
			
		||||
	ST_ONSET_F,
 | 
			
		||||
	ST_ONSET_V_REC,
 | 
			
		||||
	ST_ONSET_F_REC,
 | 
			
		||||
	ST_FACCH,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum dtx_dl_amr_fsm_events {
 | 
			
		||||
	E_VOICE,
 | 
			
		||||
	E_ONSET,
 | 
			
		||||
	E_FACCH,
 | 
			
		||||
	E_COMPL,
 | 
			
		||||
	E_FIRST,
 | 
			
		||||
	E_INHIB,
 | 
			
		||||
	E_SID_F,
 | 
			
		||||
	E_SID_U,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct value_string dtx_dl_amr_fsm_event_names[];
 | 
			
		||||
extern struct osmo_fsm dtx_dl_amr_fsm;
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
#ifndef _GSM_DATA_H
 | 
			
		||||
#define _GSM_DATA_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/gsm/lapdm.h>
 | 
			
		||||
#include <osmocom/gsm/gsm23003.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/paging.h>
 | 
			
		||||
#include <osmo-bts/tx_power.h>
 | 
			
		||||
 | 
			
		||||
#define GSM_FR_BITS	260
 | 
			
		||||
#define GSM_EFR_BITS	244
 | 
			
		||||
 | 
			
		||||
#define GSM_FR_BYTES	33	/* TS 101318 Chapter 5.1: 260 bits + 4bit sig */
 | 
			
		||||
#define GSM_HR_BYTES	14	/* TS 101318 Chapter 5.2: 112 bits, no sig */
 | 
			
		||||
#define GSM_EFR_BYTES	31	/* TS 101318 Chapter 5.3: 244 bits + 4bit sig */
 | 
			
		||||
 | 
			
		||||
#define GSM_SUPERFRAME	(26*51)			/* 1326 TDMA frames */
 | 
			
		||||
#define GSM_HYPERFRAME	(2048*GSM_SUPERFRAME)	/* GSM_HYPERFRAME frames */
 | 
			
		||||
 | 
			
		||||
#define GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT 41
 | 
			
		||||
#define GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE 999999
 | 
			
		||||
#define GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT 41
 | 
			
		||||
#define GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT 91
 | 
			
		||||
 | 
			
		||||
struct gsm_network {
 | 
			
		||||
	struct llist_head bts_list;
 | 
			
		||||
	unsigned int num_bts;
 | 
			
		||||
	struct osmo_plmn_id plmn;
 | 
			
		||||
	struct pcu_sock_state *pcu_state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum lchan_ciph_state {
 | 
			
		||||
	LCHAN_CIPH_NONE,
 | 
			
		||||
	LCHAN_CIPH_RX_REQ,
 | 
			
		||||
	LCHAN_CIPH_RX_CONF,
 | 
			
		||||
	LCHAN_CIPH_RXTX_REQ,
 | 
			
		||||
	LCHAN_CIPH_RX_CONF_TX_REQ,
 | 
			
		||||
	LCHAN_CIPH_RXTX_CONF,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data_shared.h>
 | 
			
		||||
 | 
			
		||||
void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state);
 | 
			
		||||
int conf_lchans_as_pchan(struct gsm_bts_trx_ts *ts,
 | 
			
		||||
			 enum gsm_phys_chan_config pchan);
 | 
			
		||||
 | 
			
		||||
/* cipher code */
 | 
			
		||||
#define CIPHER_A5(x) (1 << (x-1))
 | 
			
		||||
 | 
			
		||||
int bts_supports_cipher(struct gsm_bts *bts, int rsl_cipher);
 | 
			
		||||
 | 
			
		||||
bool ts_is_pdch(const struct gsm_bts_trx_ts *ts);
 | 
			
		||||
 | 
			
		||||
int bts_model_check_cm_mode(enum gsm_phys_chan_config pchan, enum gsm48_chan_mode cm);
 | 
			
		||||
 | 
			
		||||
#endif /* _GSM_DATA_H */
 | 
			
		||||
@@ -0,0 +1,815 @@
 | 
			
		||||
#ifndef _GSM_DATA_SHAREDH
 | 
			
		||||
#define _GSM_DATA_SHAREDH
 | 
			
		||||
 | 
			
		||||
#include <regex.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/codec/ecu.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/core/bitvec.h>
 | 
			
		||||
#include <osmocom/core/statistics.h>
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/gsm/gsm_utils.h>
 | 
			
		||||
#include <osmocom/gsm/tlv.h>
 | 
			
		||||
#include <osmocom/gsm/rxlev_stat.h>
 | 
			
		||||
#include <osmocom/gsm/sysinfo.h>
 | 
			
		||||
#include <osmocom/gsm/meas_rep.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_08_58.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/abis/e1_input.h>
 | 
			
		||||
#include <osmocom/gsm/lapdm.h>
 | 
			
		||||
 | 
			
		||||
/* 16 is the max. number of SI2quater messages according to 3GPP TS 44.018 Table 10.5.2.33b.1:
 | 
			
		||||
   4-bit index is used (2#1111 = 10#15) */
 | 
			
		||||
#define SI2Q_MAX_NUM 16
 | 
			
		||||
/* length in bits (for single SI2quater message) */
 | 
			
		||||
#define SI2Q_MAX_LEN 160
 | 
			
		||||
#define SI2Q_MIN_LEN 18
 | 
			
		||||
 | 
			
		||||
/* Channel Request reason */
 | 
			
		||||
enum gsm_chreq_reason_t {
 | 
			
		||||
	GSM_CHREQ_REASON_EMERG,
 | 
			
		||||
	GSM_CHREQ_REASON_PAG,
 | 
			
		||||
	GSM_CHREQ_REASON_CALL,
 | 
			
		||||
	GSM_CHREQ_REASON_LOCATION_UPD,
 | 
			
		||||
	GSM_CHREQ_REASON_OTHER,
 | 
			
		||||
	GSM_CHREQ_REASON_PDCH,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* lchans 0..3 are SDCCH in combined channel configuration,
 | 
			
		||||
   use 4 as magic number for BCCH hack - see osmo-bts-../oml.c:opstart_compl() */
 | 
			
		||||
#define CCCH_LCHAN 4
 | 
			
		||||
 | 
			
		||||
#define TRX_NR_TS	8
 | 
			
		||||
#define TS_MAX_LCHAN	8
 | 
			
		||||
 | 
			
		||||
#define HARDCODED_ARFCN 123
 | 
			
		||||
#define HARDCODED_BSIC	0x3f	/* NCC = 7 / BCC = 7 */
 | 
			
		||||
 | 
			
		||||
/* for multi-drop config */
 | 
			
		||||
#define HARDCODED_BTS0_TS	1
 | 
			
		||||
#define HARDCODED_BTS1_TS	6
 | 
			
		||||
#define HARDCODED_BTS2_TS	11
 | 
			
		||||
 | 
			
		||||
#define MAX_VERSION_LENGTH 64
 | 
			
		||||
 | 
			
		||||
#define MAX_BTS_FEATURES 128
 | 
			
		||||
 | 
			
		||||
enum gsm_hooks {
 | 
			
		||||
	GSM_HOOK_NM_SWLOAD,
 | 
			
		||||
	GSM_HOOK_RR_PAGING,
 | 
			
		||||
	GSM_HOOK_RR_SECURITY,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum bts_gprs_mode {
 | 
			
		||||
	BTS_GPRS_NONE = 0,
 | 
			
		||||
	BTS_GPRS_GPRS = 1,
 | 
			
		||||
	BTS_GPRS_EGPRS = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gsm_lchan;
 | 
			
		||||
struct osmo_rtp_socket;
 | 
			
		||||
struct pcu_sock_state;
 | 
			
		||||
struct smscb_msg;
 | 
			
		||||
 | 
			
		||||
/* Network Management State */
 | 
			
		||||
struct gsm_nm_state {
 | 
			
		||||
	uint8_t operational;
 | 
			
		||||
	uint8_t administrative;
 | 
			
		||||
	uint8_t availability;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gsm_abis_mo {
 | 
			
		||||
	/* A-bis OML Object Class */
 | 
			
		||||
	uint8_t obj_class;
 | 
			
		||||
	/* is there still some procedure pending? */
 | 
			
		||||
	uint8_t procedure_pending;
 | 
			
		||||
	/* A-bis OML Object Instance */
 | 
			
		||||
	struct abis_om_obj_inst obj_inst;
 | 
			
		||||
	/* human-readable name */
 | 
			
		||||
	const char *name;
 | 
			
		||||
	/* NM State */
 | 
			
		||||
	struct gsm_nm_state nm_state;
 | 
			
		||||
	/* Attributes configured in this MO */
 | 
			
		||||
	struct tlv_parsed *nm_attr;
 | 
			
		||||
	/* BTS to which this MO belongs */
 | 
			
		||||
	struct gsm_bts *bts;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MAX_A5_KEY_LEN	(128/8)
 | 
			
		||||
#define A38_XOR_MIN_KEY_LEN	12
 | 
			
		||||
#define A38_XOR_MAX_KEY_LEN	16
 | 
			
		||||
#define A38_COMP128_KEY_LEN	16
 | 
			
		||||
#define RSL_ENC_ALG_A5(x)	(x+1)
 | 
			
		||||
#define MAX_EARFCN_LIST 32
 | 
			
		||||
 | 
			
		||||
/* is the data link established? who established it? */
 | 
			
		||||
#define LCHAN_SAPI_UNUSED	0
 | 
			
		||||
#define LCHAN_SAPI_MS		1
 | 
			
		||||
#define LCHAN_SAPI_NET		2
 | 
			
		||||
#define LCHAN_SAPI_REL		3
 | 
			
		||||
 | 
			
		||||
/* state of a logical channel */
 | 
			
		||||
enum gsm_lchan_state {
 | 
			
		||||
	LCHAN_S_NONE,		/* channel is not active */
 | 
			
		||||
	LCHAN_S_ACT_REQ,	/* channel activation requested */
 | 
			
		||||
	LCHAN_S_ACTIVE,		/* channel is active and operational */
 | 
			
		||||
	LCHAN_S_REL_REQ,	/* channel release has been requested */
 | 
			
		||||
	LCHAN_S_REL_ERR,	/* channel is in an error state */
 | 
			
		||||
	LCHAN_S_BROKEN,		/* channel is somehow unusable */
 | 
			
		||||
	LCHAN_S_INACTIVE,	/* channel is set inactive */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* BTS ONLY */
 | 
			
		||||
#define MAX_NUM_UL_MEAS	104
 | 
			
		||||
#define LC_UL_M_F_L1_VALID	(1 << 0)
 | 
			
		||||
#define LC_UL_M_F_RES_VALID	(1 << 1)
 | 
			
		||||
 | 
			
		||||
struct bts_ul_meas {
 | 
			
		||||
	/* BER in units of 0.01%: 10.000 == 100% ber, 0 == 0% ber */
 | 
			
		||||
	uint16_t ber10k;
 | 
			
		||||
	/* timing advance offset (in 1/256 bits) */
 | 
			
		||||
	int16_t ta_offs_256bits;
 | 
			
		||||
	/* C/I ratio in dB */
 | 
			
		||||
	float c_i;
 | 
			
		||||
	/* flags */
 | 
			
		||||
	uint8_t is_sub:1;
 | 
			
		||||
	/* RSSI in dBm * -1 */
 | 
			
		||||
	uint8_t inv_rssi;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct bts_codec_conf {
 | 
			
		||||
	uint8_t hr;
 | 
			
		||||
	uint8_t efr;
 | 
			
		||||
	uint8_t amr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct amr_mode {
 | 
			
		||||
	uint8_t mode;
 | 
			
		||||
	uint8_t threshold;
 | 
			
		||||
	uint8_t hysteresis;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct amr_multirate_conf {
 | 
			
		||||
	uint8_t gsm48_ie[2];
 | 
			
		||||
	struct amr_mode ms_mode[4];
 | 
			
		||||
	struct amr_mode bts_mode[4];
 | 
			
		||||
	uint8_t num_modes;
 | 
			
		||||
};
 | 
			
		||||
/* /BTS ONLY */
 | 
			
		||||
 | 
			
		||||
enum lchan_csd_mode {
 | 
			
		||||
	LCHAN_CSD_M_NT,
 | 
			
		||||
	LCHAN_CSD_M_T_1200_75,
 | 
			
		||||
	LCHAN_CSD_M_T_600,
 | 
			
		||||
	LCHAN_CSD_M_T_1200,
 | 
			
		||||
	LCHAN_CSD_M_T_2400,
 | 
			
		||||
	LCHAN_CSD_M_T_9600,
 | 
			
		||||
	LCHAN_CSD_M_T_14400,
 | 
			
		||||
	LCHAN_CSD_M_T_29000,
 | 
			
		||||
	LCHAN_CSD_M_T_32000,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* State of the SAPIs in the lchan */
 | 
			
		||||
enum lchan_sapi_state {
 | 
			
		||||
	LCHAN_SAPI_S_NONE,
 | 
			
		||||
	LCHAN_SAPI_S_REQ,
 | 
			
		||||
	LCHAN_SAPI_S_ASSIGNED,
 | 
			
		||||
	LCHAN_SAPI_S_REL,
 | 
			
		||||
	LCHAN_SAPI_S_ERROR,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gsm_lchan {
 | 
			
		||||
	/* The TS that we're part of */
 | 
			
		||||
	struct gsm_bts_trx_ts *ts;
 | 
			
		||||
	/* The logical subslot number in the TS */
 | 
			
		||||
	uint8_t nr;
 | 
			
		||||
	/* The logical channel type */
 | 
			
		||||
	enum gsm_chan_t type;
 | 
			
		||||
	/* RSL channel mode */
 | 
			
		||||
	enum rsl_cmod_spd rsl_cmode;
 | 
			
		||||
	/* If TCH, traffic channel mode */
 | 
			
		||||
	enum gsm48_chan_mode tch_mode;
 | 
			
		||||
	enum lchan_csd_mode csd_mode;
 | 
			
		||||
	/* State */
 | 
			
		||||
	enum gsm_lchan_state state;
 | 
			
		||||
	const char *broken_reason;
 | 
			
		||||
	/* Power levels for MS and BTS */
 | 
			
		||||
	uint8_t bs_power;
 | 
			
		||||
	uint8_t ms_power;
 | 
			
		||||
	/* Encryption information */
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t alg_id;
 | 
			
		||||
		uint8_t key_len;
 | 
			
		||||
		uint8_t key[MAX_A5_KEY_LEN];
 | 
			
		||||
	} encr;
 | 
			
		||||
 | 
			
		||||
	/* AMR bits */
 | 
			
		||||
	uint8_t mr_bts_lv[7];
 | 
			
		||||
 | 
			
		||||
	/* Established data link layer services */
 | 
			
		||||
	int sacch_deact;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		uint32_t bound_ip;
 | 
			
		||||
		uint32_t connect_ip;
 | 
			
		||||
		uint16_t bound_port;
 | 
			
		||||
		uint16_t connect_port;
 | 
			
		||||
		uint16_t conn_id;
 | 
			
		||||
		uint8_t rtp_payload;
 | 
			
		||||
		uint8_t rtp_payload2;
 | 
			
		||||
		uint8_t speech_mode;
 | 
			
		||||
		struct osmo_rtp_socket *rtp_socket;
 | 
			
		||||
	} abis_ip;
 | 
			
		||||
 | 
			
		||||
	uint8_t rqd_ta;
 | 
			
		||||
 | 
			
		||||
	char *name;
 | 
			
		||||
 | 
			
		||||
	/* Number of different GsmL1_Sapi_t used in osmo_bts_sysmo is 23.
 | 
			
		||||
	 * Currently we don't share these headers so this is a magic number. */
 | 
			
		||||
	struct llist_head sapi_cmds;
 | 
			
		||||
	uint8_t sapis_dl[23];
 | 
			
		||||
	uint8_t sapis_ul[23];
 | 
			
		||||
	struct lapdm_channel lapdm_ch;
 | 
			
		||||
	struct llist_head dl_tch_queue;
 | 
			
		||||
	struct {
 | 
			
		||||
		/* bitmask of all SI that are present/valid in si_buf */
 | 
			
		||||
		uint32_t valid;
 | 
			
		||||
		uint32_t last;
 | 
			
		||||
		/* buffers where we put the pre-computed SI:
 | 
			
		||||
		   SI2Q_MAX_NUM is the max number of SI2quater messages (see 3GPP TS 44.018) */
 | 
			
		||||
		sysinfo_buf_t buf[_MAX_SYSINFO_TYPE][SI2Q_MAX_NUM];
 | 
			
		||||
	} si;
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t flags;
 | 
			
		||||
		/* RSL measurment result number, 0 at lchan_act */
 | 
			
		||||
		uint8_t res_nr;
 | 
			
		||||
		/* current Tx power level of the BTS */
 | 
			
		||||
		uint8_t bts_tx_pwr;
 | 
			
		||||
		/* number of measurements stored in array below */
 | 
			
		||||
		uint8_t num_ul_meas;
 | 
			
		||||
		struct bts_ul_meas uplink[MAX_NUM_UL_MEAS];
 | 
			
		||||
		/* last L1 header from the MS */
 | 
			
		||||
		uint8_t l1_info[2];
 | 
			
		||||
		struct gsm_meas_rep_unidir ul_res;
 | 
			
		||||
		int16_t ms_toa256;
 | 
			
		||||
	} meas;
 | 
			
		||||
	struct {
 | 
			
		||||
		struct amr_multirate_conf amr_mr;
 | 
			
		||||
		struct {
 | 
			
		||||
			struct osmo_fsm_inst *dl_amr_fsm;
 | 
			
		||||
			/* TCH cache */
 | 
			
		||||
			uint8_t cache[20];
 | 
			
		||||
			/* FACCH cache */
 | 
			
		||||
			uint8_t facch[GSM_MACBLOCK_LEN];
 | 
			
		||||
			uint8_t len;
 | 
			
		||||
			uint32_t fn;
 | 
			
		||||
			bool is_update;
 | 
			
		||||
			/* set for each SID frame to detect talkspurt for codecs
 | 
			
		||||
			   without explicit ONSET event */
 | 
			
		||||
			bool ul_sid;
 | 
			
		||||
			/* indicates if DTXd was active during DL measurement
 | 
			
		||||
			   period */
 | 
			
		||||
			bool dl_active;
 | 
			
		||||
		} dtx;
 | 
			
		||||
		uint8_t last_cmr;
 | 
			
		||||
		uint32_t last_fn;
 | 
			
		||||
	} tch;
 | 
			
		||||
 | 
			
		||||
	/* 3GPP TS 48.058 § 9.3.37: [0; 255] ok, -1 means invalid*/
 | 
			
		||||
	int16_t ms_t_offs;
 | 
			
		||||
	/* 3GPP TS 45.010 § 1.2 round trip propagation delay (in symbols) or -1 */
 | 
			
		||||
	int16_t p_offs;
 | 
			
		||||
 | 
			
		||||
	/* BTS-side ciphering state (rx only, bi-directional, ...) */
 | 
			
		||||
	uint8_t ciph_state;
 | 
			
		||||
	uint8_t ciph_ns;
 | 
			
		||||
	uint8_t loopback;
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t active;
 | 
			
		||||
		uint8_t ref;
 | 
			
		||||
		/* T3105: PHYS INF retransmission */
 | 
			
		||||
		struct osmo_timer_list t3105;
 | 
			
		||||
		/* counts up to Ny1 */
 | 
			
		||||
		unsigned int phys_info_count;
 | 
			
		||||
	} ho;
 | 
			
		||||
	/* S counter for link loss */
 | 
			
		||||
	int s;
 | 
			
		||||
	/* Kind of the release/activation. E.g. RSL or PCU */
 | 
			
		||||
	int rel_act_kind;
 | 
			
		||||
	/* RTP header Marker bit to indicate beginning of speech after pause  */
 | 
			
		||||
	bool rtp_tx_marker;
 | 
			
		||||
	/* power handling */
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t current;
 | 
			
		||||
		uint8_t fixed;
 | 
			
		||||
	} ms_power_ctrl;
 | 
			
		||||
 | 
			
		||||
	struct msgb *pending_rel_ind_msg;
 | 
			
		||||
 | 
			
		||||
	/* ECU (Error Concealment Unit) state */
 | 
			
		||||
	union {
 | 
			
		||||
		struct osmo_ecu_fr_state fr;
 | 
			
		||||
	} ecu_state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct value_string lchan_ciph_state_names[];
 | 
			
		||||
static inline const char *lchan_ciph_state_name(uint8_t state) {
 | 
			
		||||
	return get_value_string(lchan_ciph_state_names, state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	TS_F_PDCH_ACTIVE =		0x1000,
 | 
			
		||||
	TS_F_PDCH_ACT_PENDING =		0x2000,
 | 
			
		||||
	TS_F_PDCH_DEACT_PENDING =	0x4000,
 | 
			
		||||
	TS_F_PDCH_PENDING_MASK =	0x6000 /*<
 | 
			
		||||
			TS_F_PDCH_ACT_PENDING | TS_F_PDCH_DEACT_PENDING */
 | 
			
		||||
} gsm_bts_trx_ts_flags;
 | 
			
		||||
 | 
			
		||||
/* One Timeslot in a TRX */
 | 
			
		||||
struct gsm_bts_trx_ts {
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
	/* number of this timeslot at the TRX */
 | 
			
		||||
	uint8_t nr;
 | 
			
		||||
 | 
			
		||||
	enum gsm_phys_chan_config pchan;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		enum gsm_phys_chan_config pchan_is;
 | 
			
		||||
		enum gsm_phys_chan_config pchan_want;
 | 
			
		||||
		struct msgb *pending_chan_activ;
 | 
			
		||||
	} dyn;
 | 
			
		||||
 | 
			
		||||
	unsigned int flags;
 | 
			
		||||
	struct gsm_abis_mo mo;
 | 
			
		||||
	struct tlv_parsed nm_attr;
 | 
			
		||||
	uint8_t nm_chan_comb;
 | 
			
		||||
	int tsc;		/* -1 == use BTS TSC */
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		/* Parameters below are configured by VTY */
 | 
			
		||||
		int enabled;
 | 
			
		||||
		uint8_t maio;
 | 
			
		||||
		uint8_t hsn;
 | 
			
		||||
		struct bitvec arfcns;
 | 
			
		||||
		uint8_t arfcns_data[1024/8];
 | 
			
		||||
		/* This is the pre-computed MA for channel assignments */
 | 
			
		||||
		struct bitvec ma;
 | 
			
		||||
		uint8_t ma_len;	/* part of ma_data that is used */
 | 
			
		||||
		uint8_t ma_data[8];	/* 10.5.2.21: max 8 bytes value part */
 | 
			
		||||
	} hopping;
 | 
			
		||||
 | 
			
		||||
	struct gsm_lchan lchan[TS_MAX_LCHAN];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* One TRX in a BTS */
 | 
			
		||||
struct gsm_bts_trx {
 | 
			
		||||
	/* list header in bts->trx_list */
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
 | 
			
		||||
	struct gsm_bts *bts;
 | 
			
		||||
	/* number of this TRX in the BTS */
 | 
			
		||||
	uint8_t nr;
 | 
			
		||||
	/* human readable name / description */
 | 
			
		||||
	char *description;
 | 
			
		||||
	/* how do we talk RSL with this TRX? */
 | 
			
		||||
	uint8_t rsl_tei;
 | 
			
		||||
	struct e1inp_sign_link *rsl_link;
 | 
			
		||||
 | 
			
		||||
	/* Some BTS (specifically Ericsson RBS) have a per-TRX OML Link */
 | 
			
		||||
	struct e1inp_sign_link *oml_link;
 | 
			
		||||
 | 
			
		||||
	struct gsm_abis_mo mo;
 | 
			
		||||
	struct tlv_parsed nm_attr;
 | 
			
		||||
	struct {
 | 
			
		||||
		struct gsm_abis_mo mo;
 | 
			
		||||
	} bb_transc;
 | 
			
		||||
 | 
			
		||||
	uint16_t arfcn;
 | 
			
		||||
	int nominal_power;		/* in dBm */
 | 
			
		||||
	unsigned int max_power_red;	/* in actual dB */
 | 
			
		||||
 | 
			
		||||
	struct trx_power_params power_params;
 | 
			
		||||
	int ms_power_control;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		void *l1h;
 | 
			
		||||
	} role_bts;
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
			unsigned int test_state;
 | 
			
		||||
			uint8_t test_nr;
 | 
			
		||||
			struct rxlev_stats rxlev_stat;
 | 
			
		||||
		} ipaccess;
 | 
			
		||||
	};
 | 
			
		||||
	struct gsm_bts_trx_ts ts[TRX_NR_TS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define GSM_BTS_SI2Q(bts, i)   (struct gsm48_system_information_type_2quater *)((bts)->si_buf[SYSINFO_TYPE_2quater][i])
 | 
			
		||||
#define GSM_BTS_HAS_SI(bts, i) ((bts)->si_valid & (1 << i))
 | 
			
		||||
#define GSM_BTS_SI(bts, i)     (void *)((bts)->si_buf[i][0])
 | 
			
		||||
#define GSM_LCHAN_SI(lchan, i) (void *)((lchan)->si.buf[i][0])
 | 
			
		||||
 | 
			
		||||
enum gsm_bts_type_variant {
 | 
			
		||||
	BTS_UNKNOWN,
 | 
			
		||||
	BTS_OSMO_LITECELL15,
 | 
			
		||||
	BTS_OSMO_OCTPHY,
 | 
			
		||||
	BTS_OSMO_SYSMO,
 | 
			
		||||
	BTS_OSMO_TRX,
 | 
			
		||||
	BTS_OSMO_VIRTUAL,
 | 
			
		||||
	BTS_OSMO_OMLDUMMY,
 | 
			
		||||
	_NUM_BTS_VARIANT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Used by OML layer for BTS Attribute reporting */
 | 
			
		||||
enum bts_attribute {
 | 
			
		||||
	BTS_TYPE_VARIANT,
 | 
			
		||||
	BTS_SUB_MODEL,
 | 
			
		||||
	TRX_PHY_VERSION,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vty;
 | 
			
		||||
 | 
			
		||||
/* N. B: always add new features to the end of the list (right before _NUM_BTS_FEAT) to avoid breaking compatibility
 | 
			
		||||
   with BTS compiled against earlier version of this header. Also make sure that the description strings
 | 
			
		||||
   gsm_bts_features_descs[] in gsm_data_shared.c are also updated accordingly! */
 | 
			
		||||
enum gsm_bts_features {
 | 
			
		||||
	BTS_FEAT_HSCSD,
 | 
			
		||||
	BTS_FEAT_GPRS,
 | 
			
		||||
	BTS_FEAT_EGPRS,
 | 
			
		||||
	BTS_FEAT_ECSD,
 | 
			
		||||
	BTS_FEAT_HOPPING,
 | 
			
		||||
	BTS_FEAT_MULTI_TSC,
 | 
			
		||||
	BTS_FEAT_OML_ALERTS,
 | 
			
		||||
	BTS_FEAT_AGCH_PCH_PROP,
 | 
			
		||||
	BTS_FEAT_CBCH,
 | 
			
		||||
	BTS_FEAT_SPEECH_F_V1,
 | 
			
		||||
	BTS_FEAT_SPEECH_H_V1,
 | 
			
		||||
	BTS_FEAT_SPEECH_F_EFR,
 | 
			
		||||
	BTS_FEAT_SPEECH_F_AMR,
 | 
			
		||||
	BTS_FEAT_SPEECH_H_AMR,
 | 
			
		||||
	_NUM_BTS_FEAT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct value_string gsm_bts_features_descs[];
 | 
			
		||||
 | 
			
		||||
struct gsm_bts_gprs_nsvc {
 | 
			
		||||
	struct gsm_bts *bts;
 | 
			
		||||
	/* data read via VTY config file, to configure the BTS
 | 
			
		||||
	 * via OML from BSC */
 | 
			
		||||
	int id;
 | 
			
		||||
	uint16_t nsvci;
 | 
			
		||||
	uint16_t local_port;	/* on the BTS */
 | 
			
		||||
	uint16_t remote_port;	/* on the SGSN */
 | 
			
		||||
	uint32_t remote_ip;	/* on the SGSN */
 | 
			
		||||
 | 
			
		||||
	struct gsm_abis_mo mo;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum gprs_rlc_par {
 | 
			
		||||
	RLC_T3142,
 | 
			
		||||
	RLC_T3169,
 | 
			
		||||
	RLC_T3191,
 | 
			
		||||
	RLC_T3193,
 | 
			
		||||
	RLC_T3195,
 | 
			
		||||
	RLC_N3101,
 | 
			
		||||
	RLC_N3103,
 | 
			
		||||
	RLC_N3105,
 | 
			
		||||
	CV_COUNTDOWN,
 | 
			
		||||
	T_DL_TBF_EXT,	/* ms */
 | 
			
		||||
	T_UL_TBF_EXT,	/* ms */
 | 
			
		||||
	_NUM_RLC_PAR
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum gprs_cs {
 | 
			
		||||
	GPRS_CS1,
 | 
			
		||||
	GPRS_CS2,
 | 
			
		||||
	GPRS_CS3,
 | 
			
		||||
	GPRS_CS4,
 | 
			
		||||
	GPRS_MCS1,
 | 
			
		||||
	GPRS_MCS2,
 | 
			
		||||
	GPRS_MCS3,
 | 
			
		||||
	GPRS_MCS4,
 | 
			
		||||
	GPRS_MCS5,
 | 
			
		||||
	GPRS_MCS6,
 | 
			
		||||
	GPRS_MCS7,
 | 
			
		||||
	GPRS_MCS8,
 | 
			
		||||
	GPRS_MCS9,
 | 
			
		||||
	_NUM_GRPS_CS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gprs_rlc_cfg {
 | 
			
		||||
	uint16_t parameter[_NUM_RLC_PAR];
 | 
			
		||||
	struct {
 | 
			
		||||
		uint16_t repeat_time; /* ms */
 | 
			
		||||
		uint8_t repeat_count;
 | 
			
		||||
	} paging;
 | 
			
		||||
	uint32_t cs_mask; /* bitmask of gprs_cs */
 | 
			
		||||
	uint8_t initial_cs;
 | 
			
		||||
	uint8_t initial_mcs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* One BTS */
 | 
			
		||||
struct gsm_bts {
 | 
			
		||||
	/* list header in net->bts_list */
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
 | 
			
		||||
	/* Geographical location of the BTS */
 | 
			
		||||
	struct llist_head loc_list;
 | 
			
		||||
 | 
			
		||||
	/* number of ths BTS in network */
 | 
			
		||||
	uint8_t nr;
 | 
			
		||||
	/* human readable name / description */
 | 
			
		||||
	char *description;
 | 
			
		||||
	/* Cell Identity */
 | 
			
		||||
	uint16_t cell_identity;
 | 
			
		||||
	/* location area code of this BTS */
 | 
			
		||||
	uint16_t location_area_code;
 | 
			
		||||
	/* Base Station Identification Code (BSIC), lower 3 bits is BCC,
 | 
			
		||||
	 * which is used as TSC for the CCCH */
 | 
			
		||||
	uint8_t bsic;
 | 
			
		||||
	/* type of BTS */
 | 
			
		||||
	enum gsm_bts_type_variant variant;
 | 
			
		||||
	enum gsm_band band;
 | 
			
		||||
	char version[MAX_VERSION_LENGTH];
 | 
			
		||||
	char sub_model[MAX_VERSION_LENGTH];
 | 
			
		||||
 | 
			
		||||
	/* features of a given BTS set/reported via OML */
 | 
			
		||||
	struct bitvec features;
 | 
			
		||||
	uint8_t _features_data[MAX_BTS_FEATURES/8];
 | 
			
		||||
 | 
			
		||||
	/* Connected PCU version (if any) */
 | 
			
		||||
	char pcu_version[MAX_VERSION_LENGTH];
 | 
			
		||||
 | 
			
		||||
	/* maximum Tx power that the MS is permitted to use in this cell */
 | 
			
		||||
	int ms_max_power;
 | 
			
		||||
 | 
			
		||||
	/* how do we talk OML with this TRX? */
 | 
			
		||||
	uint8_t oml_tei;
 | 
			
		||||
	struct e1inp_sign_link *oml_link;
 | 
			
		||||
 | 
			
		||||
	/* Abis network management O&M handle */
 | 
			
		||||
	struct abis_nm_h *nmh;
 | 
			
		||||
 | 
			
		||||
	struct gsm_abis_mo mo;
 | 
			
		||||
 | 
			
		||||
	/* number of this BTS on given E1 link */
 | 
			
		||||
	uint8_t bts_nr;
 | 
			
		||||
 | 
			
		||||
	/* DTX features of this BTS */
 | 
			
		||||
	enum gsm48_dtx_mode dtxu;
 | 
			
		||||
	bool dtxd;
 | 
			
		||||
 | 
			
		||||
	/* CCCH is on C0 */
 | 
			
		||||
	struct gsm_bts_trx *c0;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct gsm_abis_mo mo;
 | 
			
		||||
	} site_mgr;
 | 
			
		||||
 | 
			
		||||
	/* bitmask of all SI that are present/valid in si_buf */
 | 
			
		||||
	uint32_t si_valid;
 | 
			
		||||
	/* 3GPP TS 44.018 Table 10.5.2.33b.1 INDEX and COUNT for SI2quater */
 | 
			
		||||
	uint8_t si2q_index; /* distinguish individual SI2quater messages */
 | 
			
		||||
	uint8_t si2q_count; /* si2q_index for the last (highest indexed) individual SI2quater message */
 | 
			
		||||
	/* buffers where we put the pre-computed SI */
 | 
			
		||||
	sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE][SI2Q_MAX_NUM];
 | 
			
		||||
	/* offsets used while generating SI2quater */
 | 
			
		||||
	size_t e_offset;
 | 
			
		||||
	size_t u_offset;
 | 
			
		||||
 | 
			
		||||
	/* ip.accesss Unit ID's have Site/BTS/TRX layout */
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
			uint16_t site_id;
 | 
			
		||||
			uint16_t bts_id;
 | 
			
		||||
			uint32_t flags;
 | 
			
		||||
			uint32_t rsl_ip;
 | 
			
		||||
		} ip_access;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/* Not entirely sure how ip.access specific this is */
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t supports_egprs_11bit_rach;
 | 
			
		||||
		enum bts_gprs_mode mode;
 | 
			
		||||
		struct {
 | 
			
		||||
			struct gsm_abis_mo mo;
 | 
			
		||||
			uint16_t nsei;
 | 
			
		||||
			uint8_t timer[7];
 | 
			
		||||
		} nse;
 | 
			
		||||
		struct {
 | 
			
		||||
			struct gsm_abis_mo mo;
 | 
			
		||||
			uint16_t bvci;
 | 
			
		||||
			uint8_t timer[11];
 | 
			
		||||
			struct gprs_rlc_cfg rlc_cfg;
 | 
			
		||||
		} cell;
 | 
			
		||||
		struct gsm_bts_gprs_nsvc nsvc[2];
 | 
			
		||||
		uint8_t rac;
 | 
			
		||||
		uint8_t net_ctrl_ord;
 | 
			
		||||
		bool ctrl_ack_type_use_block;
 | 
			
		||||
	} gprs;
 | 
			
		||||
 | 
			
		||||
	/* RACH NM values */
 | 
			
		||||
	int rach_b_thresh;
 | 
			
		||||
	int rach_ldavg_slots;
 | 
			
		||||
 | 
			
		||||
	/* transceivers */
 | 
			
		||||
	int num_trx;
 | 
			
		||||
	struct llist_head trx_list;
 | 
			
		||||
 | 
			
		||||
	/* SI related items */
 | 
			
		||||
	int force_combined_si;
 | 
			
		||||
	int bcch_change_mark;
 | 
			
		||||
 | 
			
		||||
	struct rate_ctr_group *ctrs;
 | 
			
		||||
	bool supp_meas_toa256;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		/* Interference Boundaries for OML */
 | 
			
		||||
		int16_t boundary[6];
 | 
			
		||||
		uint8_t intave;
 | 
			
		||||
	} interference;
 | 
			
		||||
	unsigned int t200_ms[7];
 | 
			
		||||
	unsigned int t3105_ms;
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t overload_period;
 | 
			
		||||
		struct {
 | 
			
		||||
			/* Input parameters from OML */
 | 
			
		||||
			uint8_t load_ind_thresh;	/* percent */
 | 
			
		||||
			uint8_t load_ind_period;	/* seconds */
 | 
			
		||||
			/* Internal data */
 | 
			
		||||
			struct osmo_timer_list timer;
 | 
			
		||||
			unsigned int pch_total;
 | 
			
		||||
			unsigned int pch_used;
 | 
			
		||||
		} ccch;
 | 
			
		||||
		struct {
 | 
			
		||||
			/* Input parameters from OML */
 | 
			
		||||
			int16_t busy_thresh;		/* in dBm */
 | 
			
		||||
			uint16_t averaging_slots;
 | 
			
		||||
			/* Internal data */
 | 
			
		||||
			unsigned int total;	/* total nr */
 | 
			
		||||
			unsigned int busy;	/* above busy_thresh */
 | 
			
		||||
			unsigned int access;	/* access bursts */
 | 
			
		||||
		} rach;
 | 
			
		||||
	} load;
 | 
			
		||||
	uint8_t ny1;
 | 
			
		||||
	uint8_t max_ta;
 | 
			
		||||
 | 
			
		||||
	/* AGCH queuing */
 | 
			
		||||
	struct {
 | 
			
		||||
		struct llist_head queue;
 | 
			
		||||
		int length;
 | 
			
		||||
		int max_length;
 | 
			
		||||
 | 
			
		||||
		int thresh_level;	/* Cleanup threshold in percent of max len */
 | 
			
		||||
		int low_level;		/* Low water mark in percent of max len */
 | 
			
		||||
		int high_level;		/* High water mark in percent of max len */
 | 
			
		||||
 | 
			
		||||
		/* TODO: Use a rate counter group instead */
 | 
			
		||||
		uint64_t dropped_msgs;
 | 
			
		||||
		uint64_t merged_msgs;
 | 
			
		||||
		uint64_t rejected_msgs;
 | 
			
		||||
		uint64_t agch_msgs;
 | 
			
		||||
		uint64_t pch_msgs;
 | 
			
		||||
	} agch_queue;
 | 
			
		||||
 | 
			
		||||
	struct paging_state *paging_state;
 | 
			
		||||
	char *bsc_oml_host;
 | 
			
		||||
	struct llist_head oml_queue;
 | 
			
		||||
	unsigned int rtp_jitter_buf_ms;
 | 
			
		||||
	bool rtp_jitter_adaptive;
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t ciphers;	/* flags A5/1==0x1, A5/2==0x2, A5/3==0x4 */
 | 
			
		||||
	} support;
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t tc4_ctr;
 | 
			
		||||
	} si;
 | 
			
		||||
	struct gsm_time gsm_time;
 | 
			
		||||
	/* Radio Link Timeout counter. -1 disables timeout for
 | 
			
		||||
	 * lab/measurement purpose */
 | 
			
		||||
	int radio_link_timeout;
 | 
			
		||||
 | 
			
		||||
	int ul_power_target;		/* Uplink Rx power target */
 | 
			
		||||
 | 
			
		||||
	/* used by the sysmoBTS to adjust band */
 | 
			
		||||
	uint8_t auto_band;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct llist_head queue;	/* list of struct smscb_msg */
 | 
			
		||||
		struct smscb_msg *cur_msg;	/* current SMS-CB */
 | 
			
		||||
	} smscb_state;
 | 
			
		||||
 | 
			
		||||
	float min_qual_rach;	/* minimum quality for RACH bursts */
 | 
			
		||||
	float min_qual_norm;	/* minimum quality for normal daata */
 | 
			
		||||
	uint16_t max_ber10k_rach;	/* Maximum permitted RACH BER in 0.01% */
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		char *sock_path;
 | 
			
		||||
	} pcu;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		uint32_t last_fn;
 | 
			
		||||
		struct timeval tv_clock;
 | 
			
		||||
		struct osmo_timer_list fn_timer;
 | 
			
		||||
	} vbts;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct gsm_bts *gsm_bts_alloc(void *talloc_ctx, uint8_t bts_num);
 | 
			
		||||
struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num);
 | 
			
		||||
 | 
			
		||||
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
 | 
			
		||||
struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
 | 
			
		||||
 | 
			
		||||
enum bts_attribute str2btsattr(const char *s);
 | 
			
		||||
const char *btsatttr2str(enum bts_attribute v);
 | 
			
		||||
 | 
			
		||||
enum gsm_bts_type_variant str2btsvariant(const char *arg);
 | 
			
		||||
const char *btsvariant2str(enum gsm_bts_type_variant v);
 | 
			
		||||
 | 
			
		||||
extern const struct value_string gsm_chreq_descs[];
 | 
			
		||||
const struct value_string gsm_pchant_names[13];
 | 
			
		||||
const struct value_string gsm_pchant_descs[13];
 | 
			
		||||
const char *gsm_pchan_name(enum gsm_phys_chan_config c);
 | 
			
		||||
enum gsm_phys_chan_config gsm_pchan_parse(const char *name);
 | 
			
		||||
const char *gsm_lchant_name(enum gsm_chan_t c);
 | 
			
		||||
const char *gsm_chreq_name(enum gsm_chreq_reason_t c);
 | 
			
		||||
char *gsm_trx_name(const struct gsm_bts_trx *trx);
 | 
			
		||||
char *gsm_ts_name(const struct gsm_bts_trx_ts *ts);
 | 
			
		||||
char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts);
 | 
			
		||||
char *gsm_lchan_name_compute(const struct gsm_lchan *lchan);
 | 
			
		||||
const char *gsm_lchans_name(enum gsm_lchan_state s);
 | 
			
		||||
 | 
			
		||||
static inline char *gsm_lchan_name(const struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	return lchan->name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int gsm_bts_set_feature(struct gsm_bts *bts, enum gsm_bts_features feat)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_ASSERT(_NUM_BTS_FEAT < MAX_BTS_FEATURES);
 | 
			
		||||
	return bitvec_set_bit_pos(&bts->features, feat, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool gsm_bts_has_feature(const struct gsm_bts *bts, enum gsm_bts_features feat)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_ASSERT(_NUM_BTS_FEAT < MAX_BTS_FEATURES);
 | 
			
		||||
	return bitvec_get_bit_pos(&bts->features, feat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void gsm_abis_mo_reset(struct gsm_abis_mo *mo);
 | 
			
		||||
 | 
			
		||||
struct gsm_abis_mo *
 | 
			
		||||
gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
 | 
			
		||||
	    const struct abis_om_obj_inst *obj_inst);
 | 
			
		||||
 | 
			
		||||
struct gsm_nm_state *
 | 
			
		||||
gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
 | 
			
		||||
		 const struct abis_om_obj_inst *obj_inst);
 | 
			
		||||
void *
 | 
			
		||||
gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
 | 
			
		||||
	     const struct abis_om_obj_inst *obj_inst);
 | 
			
		||||
 | 
			
		||||
/* reset the state of all MO in the BTS */
 | 
			
		||||
void gsm_bts_mo_reset(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
 | 
			
		||||
			  uint8_t ts_nr, uint8_t lchan_nr);
 | 
			
		||||
uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan);
 | 
			
		||||
uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
 | 
			
		||||
				   enum gsm_phys_chan_config as_pchan);
 | 
			
		||||
 | 
			
		||||
/* return the gsm_lchan for the CBCH (if it exists at all) */
 | 
			
		||||
struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * help with parsing regexps
 | 
			
		||||
 */
 | 
			
		||||
int gsm_parse_reg(void *ctx, regex_t *reg, char **str,
 | 
			
		||||
		int argc, const char **argv) __attribute__ ((warn_unused_result));
 | 
			
		||||
 | 
			
		||||
#define BSIC2BCC(bsic) ((bsic) & 0x3)
 | 
			
		||||
 | 
			
		||||
static inline uint8_t gsm_ts_tsc(const struct gsm_bts_trx_ts *ts)
 | 
			
		||||
{
 | 
			
		||||
	if (ts->tsc != -1)
 | 
			
		||||
		return ts->tsc;
 | 
			
		||||
	else
 | 
			
		||||
		return ts->trx->bts->bsic & 7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
 | 
			
		||||
				   int *rc);
 | 
			
		||||
 | 
			
		||||
enum gsm_phys_chan_config ts_pchan(struct gsm_bts_trx_ts *ts);
 | 
			
		||||
uint8_t ts_subslots(struct gsm_bts_trx_ts *ts);
 | 
			
		||||
bool ts_is_tch(struct gsm_bts_trx_ts *ts);
 | 
			
		||||
const char *gsm_trx_unit_id(struct gsm_bts_trx *trx);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	HANDOVER_NONE = 0,
 | 
			
		||||
	HANDOVER_ENABLED,
 | 
			
		||||
	HANDOVER_WAIT_FRAME,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay);
 | 
			
		||||
void handover_frame(struct gsm_lchan *lchan);
 | 
			
		||||
void handover_reset(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,96 @@
 | 
			
		||||
#ifndef L1SAP_H
 | 
			
		||||
#define L1SAP_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
 | 
			
		||||
 | 
			
		||||
/* lchan link ID */
 | 
			
		||||
#define LID_SACCH 0x40
 | 
			
		||||
#define LID_DEDIC 0x00
 | 
			
		||||
 | 
			
		||||
/* timeslot and subslot from chan_nr */
 | 
			
		||||
#define L1SAP_CHAN2TS(chan_nr) (chan_nr & 7)
 | 
			
		||||
#define L1SAP_CHAN2SS_TCHH(chan_nr) ((chan_nr >> 3) & 1)
 | 
			
		||||
#define L1SAP_CHAN2SS_SDCCH4(chan_nr) ((chan_nr >> 3) & 3)
 | 
			
		||||
#define L1SAP_CHAN2SS_SDCCH8(chan_nr) ((chan_nr >> 3) & 7)
 | 
			
		||||
 | 
			
		||||
/* logical channel from chan_nr + link_id */
 | 
			
		||||
#define L1SAP_IS_LINK_SACCH(link_id) ((link_id & 0xC0) == LID_SACCH)
 | 
			
		||||
#define L1SAP_IS_CHAN_TCHF(chan_nr) ((chan_nr & 0xf8) == 0x08)
 | 
			
		||||
#define L1SAP_IS_CHAN_TCHH(chan_nr) ((chan_nr & 0xf0) == 0x10)
 | 
			
		||||
#define L1SAP_IS_CHAN_SDCCH4(chan_nr) ((chan_nr & 0xe0) == 0x20)
 | 
			
		||||
#define L1SAP_IS_CHAN_SDCCH8(chan_nr) ((chan_nr & 0xc0) == 0x40)
 | 
			
		||||
#define L1SAP_IS_CHAN_BCCH(chan_nr) ((chan_nr & 0xf8) == 0x80)
 | 
			
		||||
#define L1SAP_IS_CHAN_RACH(chan_nr) ((chan_nr & 0xf8) == 0x88)
 | 
			
		||||
#define L1SAP_IS_CHAN_AGCH_PCH(chan_nr) ((chan_nr & 0xf8) == 0x90)
 | 
			
		||||
#define L1SAP_IS_CHAN_PDCH(chan_nr) ((chan_nr & 0xf8) == 0xc0)
 | 
			
		||||
 | 
			
		||||
/* rach type from ra */
 | 
			
		||||
#define L1SAP_IS_PACKET_RACH(ra) ((ra & 0xf0) == 0x70 && (ra & 0x0f) != 0x0f)
 | 
			
		||||
 | 
			
		||||
/* CCCH block from frame number */
 | 
			
		||||
#define L1SAP_FN2CCCHBLOCK(fn) ((fn % 51) / 5 - 1)
 | 
			
		||||
 | 
			
		||||
/* PTCH layout from frame number */
 | 
			
		||||
#define L1SAP_FN2MACBLOCK(fn) ((fn % 52) / 4)
 | 
			
		||||
#define L1SAP_FN2PTCCHBLOCK(fn) ((fn / 104) & 3)
 | 
			
		||||
 | 
			
		||||
/* Calculate PTCCH occurrence, See also 3GPP TS 05.02, Clause 7, Table 6 of 9 */
 | 
			
		||||
#define L1SAP_IS_PTCCH(fn) (((fn % 52) == 12) || ((fn % 52) == 38))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = {
 | 
			
		||||
        0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B,
 | 
			
		||||
        0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B,
 | 
			
		||||
        0x2B, 0x2B, 0x2B
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* subslot from any chan_nr */
 | 
			
		||||
static inline uint8_t l1sap_chan2ss(uint8_t chan_nr)
 | 
			
		||||
{
 | 
			
		||||
	if (L1SAP_IS_CHAN_SDCCH8(chan_nr))
 | 
			
		||||
		return L1SAP_CHAN2SS_SDCCH8(chan_nr);
 | 
			
		||||
	if (L1SAP_IS_CHAN_SDCCH4(chan_nr))
 | 
			
		||||
		return L1SAP_CHAN2SS_SDCCH4(chan_nr);
 | 
			
		||||
	if (L1SAP_IS_CHAN_TCHH(chan_nr))
 | 
			
		||||
		return L1SAP_CHAN2SS_TCHH(chan_nr);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gsm_lchan *get_lchan_by_chan_nr(struct gsm_bts_trx *trx,
 | 
			
		||||
				       unsigned int chan_nr);
 | 
			
		||||
 | 
			
		||||
/* allocate a msgb containing a osmo_phsap_prim + optional l2 data */
 | 
			
		||||
struct msgb *l1sap_msgb_alloc(unsigned int l2_len);
 | 
			
		||||
 | 
			
		||||
/* any L1 prim received from bts model */
 | 
			
		||||
int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
 | 
			
		||||
 | 
			
		||||
/* pcu (socket interface) sends us a data request primitive */
 | 
			
		||||
int l1sap_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn,
 | 
			
		||||
	uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len);
 | 
			
		||||
 | 
			
		||||
/* call-back function for incoming RTP */
 | 
			
		||||
void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
 | 
			
		||||
		     unsigned int rtp_pl_len, uint16_t seq_number,
 | 
			
		||||
		     uint32_t timestamp, bool marker);
 | 
			
		||||
 | 
			
		||||
/* channel control */
 | 
			
		||||
int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *tp);
 | 
			
		||||
int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr);
 | 
			
		||||
int l1sap_chan_deact_sacch(struct gsm_bts_trx *trx, uint8_t chan_nr);
 | 
			
		||||
int l1sap_chan_modify(struct gsm_bts_trx *trx, uint8_t chan_nr);
 | 
			
		||||
 | 
			
		||||
extern const struct value_string gsmtap_sapi_names[];
 | 
			
		||||
extern struct gsmtap_inst *gsmtap;
 | 
			
		||||
extern uint32_t gsmtap_sapi_mask;
 | 
			
		||||
extern uint8_t gsmtap_sapi_acch;
 | 
			
		||||
 | 
			
		||||
int add_l1sap_header(struct gsm_bts_trx *trx, struct msgb *rmsg,
 | 
			
		||||
		     struct gsm_lchan *lchan, uint8_t chan_nr, uint32_t fn,
 | 
			
		||||
		     uint16_t ber10k, int16_t lqual_cb);
 | 
			
		||||
 | 
			
		||||
#define msgb_l1sap_prim(msg) ((struct osmo_phsap_prim *)(msg)->l1h)
 | 
			
		||||
 | 
			
		||||
int bts_check_for_first_ciphrd(struct gsm_lchan *lchan,
 | 
			
		||||
				uint8_t *data, int len);
 | 
			
		||||
#endif /* L1SAP_H */
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
#ifndef _LOGGING_H
 | 
			
		||||
#define _LOGGING_H
 | 
			
		||||
 | 
			
		||||
#define DEBUG
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	DRSL,
 | 
			
		||||
	DOML,
 | 
			
		||||
	DRLL,
 | 
			
		||||
	DRR,
 | 
			
		||||
	DMEAS,
 | 
			
		||||
	DPAG,
 | 
			
		||||
	DL1C,
 | 
			
		||||
	DL1P,
 | 
			
		||||
	DDSP,
 | 
			
		||||
	DPCU,
 | 
			
		||||
	DHO,
 | 
			
		||||
	DTRX,
 | 
			
		||||
	DLOOP,
 | 
			
		||||
	DABIS,
 | 
			
		||||
	DRTP,
 | 
			
		||||
	DSUM,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct log_info bts_log_info;
 | 
			
		||||
 | 
			
		||||
/* LOGP with gsm_time prefix */
 | 
			
		||||
#define LOGPGT(ss, lvl, gt, fmt, args...) \
 | 
			
		||||
	LOGP(ss, lvl, "%s " fmt, osmo_dump_gsmtime(gt), ## args)
 | 
			
		||||
#define DEBUGPGT(ss, gt, fmt, args...) \
 | 
			
		||||
	LOGP(ss, LOGL_DEBUG, "%s " fmt, osmo_dump_gsmtime(gt), ## args)
 | 
			
		||||
 | 
			
		||||
/* LOGP with frame number prefix */
 | 
			
		||||
#define LOGPFN(ss, lvl, fn, fmt, args...) \
 | 
			
		||||
	LOGP(ss, lvl, "%s " fmt, gsm_fn_as_gsmtime_str(fn), ## args)
 | 
			
		||||
#define DEBUGPFN(ss, fn, fmt, args...) \
 | 
			
		||||
	LOGP(ss, LOGL_DEBUG, "%s " fmt, gsm_fn_as_gsmtime_str(fn), ## args)
 | 
			
		||||
 | 
			
		||||
#endif /* _LOGGING_H */
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef OSMO_BTS_MEAS_H
 | 
			
		||||
#define OSMO_BTS_MEAS_H
 | 
			
		||||
 | 
			
		||||
#define MEAS_MAX_TIMING_ADVANCE 63
 | 
			
		||||
#define MEAS_MIN_TIMING_ADVANCE 0
 | 
			
		||||
 | 
			
		||||
int lchan_new_ul_meas(struct gsm_lchan *lchan, struct bts_ul_meas *ulm, uint32_t fn);
 | 
			
		||||
 | 
			
		||||
int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Routines to check the structurally integrity of messages
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
#include <osmo-bts/dtx_dl_amr_fsm.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/codec/codec.h>
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
struct msgb;
 | 
			
		||||
 | 
			
		||||
/* Access 1st part of msgb control buffer */
 | 
			
		||||
#define rtpmsg_marker_bit(x) ((x)->cb[0])
 | 
			
		||||
 | 
			
		||||
/* Access 2nd part of msgb control buffer */
 | 
			
		||||
#define rtpmsg_seq(x) ((x)->cb[1])
 | 
			
		||||
 | 
			
		||||
/* Access 3rd part of msgb control buffer */
 | 
			
		||||
#define rtpmsg_ts(x) ((x)->cb[2])
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Classification of OML message. ETSI for plain GSM 12.21
 | 
			
		||||
 * messages and IPA/Osmo for manufacturer messages.
 | 
			
		||||
 */
 | 
			
		||||
enum {
 | 
			
		||||
	OML_MSG_TYPE_ETSI,
 | 
			
		||||
	OML_MSG_TYPE_IPA,
 | 
			
		||||
	OML_MSG_TYPE_OSMO,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void lchan_set_marker(bool t, struct gsm_lchan *lchan);
 | 
			
		||||
bool dtx_dl_amr_enabled(const struct gsm_lchan *lchan);
 | 
			
		||||
void dtx_dispatch(struct gsm_lchan *lchan, enum dtx_dl_amr_fsm_events e);
 | 
			
		||||
bool dtx_recursion(const struct gsm_lchan *lchan);
 | 
			
		||||
void dtx_int_signal(struct gsm_lchan *lchan);
 | 
			
		||||
bool dtx_is_first_p1(const struct gsm_lchan *lchan);
 | 
			
		||||
void dtx_cache_payload(struct gsm_lchan *lchan, const uint8_t *l1_payload,
 | 
			
		||||
		       size_t length, uint32_t fn, int update);
 | 
			
		||||
int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
 | 
			
		||||
			size_t rtp_pl_len, uint32_t fn, uint8_t *l1_payload,
 | 
			
		||||
			bool marker, uint8_t *len, uint8_t *ft_out);
 | 
			
		||||
uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn);
 | 
			
		||||
int msg_verify_ipa_structure(struct msgb *msg);
 | 
			
		||||
int msg_verify_oml_structure(struct msgb *msg);
 | 
			
		||||
@@ -0,0 +1,50 @@
 | 
			
		||||
#ifndef _OML_H
 | 
			
		||||
#define _OML_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
 | 
			
		||||
 | 
			
		||||
struct gsm_bts;
 | 
			
		||||
struct gsm_abis_mo;
 | 
			
		||||
struct msgb;
 | 
			
		||||
struct gsm_lchan;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int oml_init(struct gsm_abis_mo *mo);
 | 
			
		||||
int down_oml(struct gsm_bts *bts, struct msgb *msg);
 | 
			
		||||
 | 
			
		||||
struct msgb *oml_msgb_alloc(void);
 | 
			
		||||
int oml_send_msg(struct msgb *msg, int is_mauf);
 | 
			
		||||
int oml_mo_send_msg(struct gsm_abis_mo *mo, struct msgb *msg, uint8_t msg_type);
 | 
			
		||||
int oml_mo_opstart_ack(struct gsm_abis_mo *mo);
 | 
			
		||||
int oml_mo_opstart_nack(struct gsm_abis_mo *mo, uint8_t nack_cause);
 | 
			
		||||
int oml_mo_statechg_ack(struct gsm_abis_mo *mo);
 | 
			
		||||
int oml_mo_statechg_nack(struct gsm_abis_mo *mo, uint8_t nack_cause);
 | 
			
		||||
 | 
			
		||||
/* Change the state and send STATE CHG REP */
 | 
			
		||||
int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state);
 | 
			
		||||
 | 
			
		||||
/* First initialization of MO, does _not_ generate state changes */
 | 
			
		||||
void oml_mo_state_init(struct gsm_abis_mo *mo, int op_state, int avail_state);
 | 
			
		||||
 | 
			
		||||
/* Update admin state and send ACK/NACK */
 | 
			
		||||
int oml_mo_rf_lock_chg(struct gsm_abis_mo *mo, uint8_t mute_state[8],
 | 
			
		||||
		       int success);
 | 
			
		||||
 | 
			
		||||
/* Transmit STATE CHG REP even if there was no state change */
 | 
			
		||||
int oml_tx_state_changed(struct gsm_abis_mo *mo);
 | 
			
		||||
 | 
			
		||||
int oml_mo_tx_sw_act_rep(struct gsm_abis_mo *mo);
 | 
			
		||||
 | 
			
		||||
int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause);
 | 
			
		||||
 | 
			
		||||
int oml_mo_fom_ack_nack(struct gsm_abis_mo *mo, uint8_t orig_msg_type,
 | 
			
		||||
			uint8_t cause);
 | 
			
		||||
 | 
			
		||||
/* Configure LAPDm T200 timers for this lchan according to OML */
 | 
			
		||||
int oml_set_lchan_t200(struct gsm_lchan *lchan);
 | 
			
		||||
extern const unsigned int oml_default_t200_ms[7];
 | 
			
		||||
 | 
			
		||||
/* Transmit failure event report */
 | 
			
		||||
void oml_fail_rep(uint16_t cause_value, const char *fmt, ...);
 | 
			
		||||
 | 
			
		||||
#endif // _OML_H */
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
#ifndef OSMO_BTS_PAGING_H
 | 
			
		||||
#define OSMO_BTS_PAGING_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <osmocom/gsm/gsm_utils.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
 | 
			
		||||
 | 
			
		||||
struct paging_state;
 | 
			
		||||
struct gsm_bts;
 | 
			
		||||
 | 
			
		||||
/* initialize paging code */
 | 
			
		||||
struct paging_state *paging_init(struct gsm_bts *bts,
 | 
			
		||||
				 unsigned int num_paging_max,
 | 
			
		||||
				 unsigned int paging_lifetime);
 | 
			
		||||
 | 
			
		||||
/* (re) configure paging code */
 | 
			
		||||
void paging_config(struct paging_state *ps,
 | 
			
		||||
		  unsigned int num_paging_max,
 | 
			
		||||
		  unsigned int paging_lifetime);
 | 
			
		||||
 | 
			
		||||
void paging_reset(struct paging_state *ps);
 | 
			
		||||
 | 
			
		||||
/* The max number of paging entries */
 | 
			
		||||
unsigned int paging_get_queue_max(struct paging_state *ps);
 | 
			
		||||
void paging_set_queue_max(struct paging_state *ps, unsigned int queue_max);
 | 
			
		||||
 | 
			
		||||
/* The lifetime of a paging entry */
 | 
			
		||||
unsigned int paging_get_lifetime(struct paging_state *ps);
 | 
			
		||||
void paging_set_lifetime(struct paging_state *ps, unsigned int lifetime);
 | 
			
		||||
 | 
			
		||||
/* update with new SYSTEM INFORMATION parameters */
 | 
			
		||||
int paging_si_update(struct paging_state *ps, struct gsm48_control_channel_descr *chan_desc);
 | 
			
		||||
 | 
			
		||||
/* Add an identity to the paging queue */
 | 
			
		||||
int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
 | 
			
		||||
			const uint8_t *identity_lv, uint8_t chan_needed);
 | 
			
		||||
 | 
			
		||||
/* Add an IMM.ASS message to the paging queue */
 | 
			
		||||
int paging_add_imm_ass(struct paging_state *ps, const uint8_t *data,
 | 
			
		||||
                       uint8_t len);
 | 
			
		||||
 | 
			
		||||
/* generate paging message for given gsm time */
 | 
			
		||||
int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *gt,
 | 
			
		||||
		   int *is_empty);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* inspection methods below */
 | 
			
		||||
int paging_group_queue_empty(struct paging_state *ps, uint8_t group);
 | 
			
		||||
int paging_queue_length(struct paging_state *ps);
 | 
			
		||||
int paging_buffer_space(struct paging_state *ps);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -0,0 +1,24 @@
 | 
			
		||||
#ifndef _PCU_IF_H
 | 
			
		||||
#define _PCU_IF_H
 | 
			
		||||
 | 
			
		||||
extern int pcu_direct;
 | 
			
		||||
 | 
			
		||||
int pcu_tx_info_ind(void);
 | 
			
		||||
int pcu_tx_si13(const struct gsm_bts *bts, bool enable);
 | 
			
		||||
int pcu_tx_rts_req(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn,
 | 
			
		||||
	uint16_t arfcn, uint8_t block_nr);
 | 
			
		||||
int pcu_tx_data_ind(struct gsm_bts_trx_ts *ts, uint8_t is_ptcch, uint32_t fn,
 | 
			
		||||
	uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len,
 | 
			
		||||
		    int8_t rssi, uint16_t ber10k, int16_t bto, int16_t lqual);
 | 
			
		||||
int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn,
 | 
			
		||||
	uint8_t is_11bit, enum ph_burst_type burst_type);
 | 
			
		||||
int pcu_tx_time_ind(uint32_t fn);
 | 
			
		||||
int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed);
 | 
			
		||||
int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len);
 | 
			
		||||
 | 
			
		||||
int pcu_sock_init(const char *path);
 | 
			
		||||
void pcu_sock_exit(void);
 | 
			
		||||
 | 
			
		||||
bool pcu_connected(void);
 | 
			
		||||
 | 
			
		||||
#endif /* _PCU_IF_H */
 | 
			
		||||
@@ -0,0 +1,195 @@
 | 
			
		||||
#ifndef _PCUIF_PROTO_H
 | 
			
		||||
#define _PCUIF_PROTO_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/l1sap.h>
 | 
			
		||||
 | 
			
		||||
#define PCU_SOCK_DEFAULT	"/tmp/pcu_bts"
 | 
			
		||||
 | 
			
		||||
#define PCU_IF_VERSION		0x09
 | 
			
		||||
#define TXT_MAX_LEN	128
 | 
			
		||||
 | 
			
		||||
/* msg_type */
 | 
			
		||||
#define PCU_IF_MSG_DATA_REQ	0x00	/* send data to given channel */
 | 
			
		||||
#define PCU_IF_MSG_DATA_CNF	0x01	/* confirm (e.g. transmission on PCH) */
 | 
			
		||||
#define PCU_IF_MSG_DATA_IND	0x02	/* receive data from given channel */
 | 
			
		||||
#define PCU_IF_MSG_RTS_REQ	0x10	/* ready to send request */
 | 
			
		||||
#define PCU_IF_MSG_DATA_CNF_DT	0x11	/* confirm (with direct tlli) */
 | 
			
		||||
#define PCU_IF_MSG_RACH_IND	0x22	/* receive RACH */
 | 
			
		||||
#define PCU_IF_MSG_INFO_IND	0x32	/* retrieve BTS info */
 | 
			
		||||
#define PCU_IF_MSG_ACT_REQ	0x40	/* activate/deactivate PDCH */
 | 
			
		||||
#define PCU_IF_MSG_TIME_IND	0x52	/* GSM time indication */
 | 
			
		||||
#define PCU_IF_MSG_PAG_REQ	0x60	/* paging request */
 | 
			
		||||
#define PCU_IF_MSG_TXT_IND	0x70	/* Text indication for BTS */
 | 
			
		||||
 | 
			
		||||
/* sapi */
 | 
			
		||||
#define PCU_IF_SAPI_RACH	0x01	/* channel request on CCCH */
 | 
			
		||||
#define PCU_IF_SAPI_AGCH	0x02	/* assignment on AGCH */
 | 
			
		||||
#define PCU_IF_SAPI_PCH		0x03	/* paging/assignment on PCH */
 | 
			
		||||
#define PCU_IF_SAPI_BCCH	0x04	/* SI on BCCH */
 | 
			
		||||
#define PCU_IF_SAPI_PDTCH	0x05	/* packet data/control/ccch block */
 | 
			
		||||
#define PCU_IF_SAPI_PRACH	0x06	/* packet random access channel */
 | 
			
		||||
#define PCU_IF_SAPI_PTCCH	0x07	/* packet TA control channel */
 | 
			
		||||
#define PCU_IF_SAPI_AGCH_DT	0x08	/* assignment on AGCH but with additional TLLI */
 | 
			
		||||
 | 
			
		||||
/* flags */
 | 
			
		||||
#define PCU_IF_FLAG_ACTIVE	(1 << 0)/* BTS is active */
 | 
			
		||||
#define PCU_IF_FLAG_SYSMO	(1 << 1)/* access PDCH of sysmoBTS directly */
 | 
			
		||||
#define PCU_IF_FLAG_CS1		(1 << 16)
 | 
			
		||||
#define PCU_IF_FLAG_CS2		(1 << 17)
 | 
			
		||||
#define PCU_IF_FLAG_CS3		(1 << 18)
 | 
			
		||||
#define PCU_IF_FLAG_CS4		(1 << 19)
 | 
			
		||||
#define PCU_IF_FLAG_MCS1	(1 << 20)
 | 
			
		||||
#define PCU_IF_FLAG_MCS2	(1 << 21)
 | 
			
		||||
#define PCU_IF_FLAG_MCS3	(1 << 22)
 | 
			
		||||
#define PCU_IF_FLAG_MCS4	(1 << 23)
 | 
			
		||||
#define PCU_IF_FLAG_MCS5	(1 << 24)
 | 
			
		||||
#define PCU_IF_FLAG_MCS6	(1 << 25)
 | 
			
		||||
#define PCU_IF_FLAG_MCS7	(1 << 26)
 | 
			
		||||
#define PCU_IF_FLAG_MCS8	(1 << 27)
 | 
			
		||||
#define PCU_IF_FLAG_MCS9	(1 << 28)
 | 
			
		||||
 | 
			
		||||
enum gsm_pcu_if_text_type {
 | 
			
		||||
	PCU_VERSION,
 | 
			
		||||
	PCU_OML_ALERT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_txt_ind {
 | 
			
		||||
	uint8_t		type; /* gsm_pcu_if_text_type */
 | 
			
		||||
	char		text[TXT_MAX_LEN]; /* Text to be transmitted to BTS */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_data {
 | 
			
		||||
	uint8_t		sapi;
 | 
			
		||||
	uint8_t		len;
 | 
			
		||||
	uint8_t		data[162];
 | 
			
		||||
	uint32_t	fn;
 | 
			
		||||
	uint16_t	arfcn;
 | 
			
		||||
	uint8_t		trx_nr;
 | 
			
		||||
	uint8_t		ts_nr;
 | 
			
		||||
	uint8_t		block_nr;
 | 
			
		||||
	int8_t		rssi;
 | 
			
		||||
	uint16_t	ber10k;		/* !< \brief BER in units of 0.01% */
 | 
			
		||||
	int16_t		ta_offs_qbits;	/* !< \brief Burst TA Offset in quarter bits */
 | 
			
		||||
	int16_t		lqual_cb;	/* !< \brief Link quality in centiBel */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
/* data confirmation with direct tlli (instead of raw mac block with tlli) */
 | 
			
		||||
struct gsm_pcu_if_data_cnf_dt {
 | 
			
		||||
	uint8_t		sapi;
 | 
			
		||||
	uint32_t	tlli;
 | 
			
		||||
	uint32_t	fn;
 | 
			
		||||
	uint16_t	arfcn;
 | 
			
		||||
	uint8_t		trx_nr;
 | 
			
		||||
	uint8_t		ts_nr;
 | 
			
		||||
	uint8_t		block_nr;
 | 
			
		||||
	int8_t		rssi;
 | 
			
		||||
	uint16_t	ber10k;		/* !< \brief BER in units of 0.01% */
 | 
			
		||||
	int16_t		ta_offs_qbits;	/* !< \brief Burst TA Offset in quarter bits */
 | 
			
		||||
	int16_t		lqual_cb;	/* !< \brief Link quality in centiBel */
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_rts_req {
 | 
			
		||||
	uint8_t		sapi;
 | 
			
		||||
	uint8_t		spare[3];
 | 
			
		||||
	uint32_t	fn;
 | 
			
		||||
	uint16_t	arfcn;
 | 
			
		||||
	uint8_t		trx_nr;
 | 
			
		||||
	uint8_t		ts_nr;
 | 
			
		||||
	uint8_t		block_nr;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_rach_ind {
 | 
			
		||||
	uint8_t		sapi;
 | 
			
		||||
	uint16_t	ra;
 | 
			
		||||
	int16_t		qta;
 | 
			
		||||
	uint32_t	fn;
 | 
			
		||||
	uint16_t	arfcn;
 | 
			
		||||
	uint8_t		is_11bit;
 | 
			
		||||
	uint8_t		burst_type;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_info_trx {
 | 
			
		||||
	uint16_t	arfcn;
 | 
			
		||||
	uint8_t		pdch_mask;		/* PDCH channels per TS */
 | 
			
		||||
	uint8_t		spare;
 | 
			
		||||
	uint8_t		tsc[8];			/* TSC per channel */
 | 
			
		||||
	uint32_t	hlayer1;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_info_ind {
 | 
			
		||||
	uint32_t	version;
 | 
			
		||||
	uint32_t	flags;
 | 
			
		||||
	struct gsm_pcu_if_info_trx trx[8];	/* TRX infos per BTS */
 | 
			
		||||
	uint8_t		bsic;
 | 
			
		||||
	/* RAI */
 | 
			
		||||
	uint16_t	mcc, mnc;
 | 
			
		||||
	uint8_t		mnc_3_digits;
 | 
			
		||||
	uint16_t	lac, rac;
 | 
			
		||||
	/* NSE */
 | 
			
		||||
	uint16_t	nsei;
 | 
			
		||||
	uint8_t		nse_timer[7];
 | 
			
		||||
	uint8_t		cell_timer[11];
 | 
			
		||||
	/* cell */
 | 
			
		||||
	uint16_t	cell_id;
 | 
			
		||||
	uint16_t	repeat_time;
 | 
			
		||||
	uint8_t		repeat_count;
 | 
			
		||||
	uint16_t	bvci;
 | 
			
		||||
	uint8_t		t3142;
 | 
			
		||||
	uint8_t		t3169;
 | 
			
		||||
	uint8_t		t3191;
 | 
			
		||||
	uint8_t		t3193_10ms;
 | 
			
		||||
	uint8_t		t3195;
 | 
			
		||||
	uint8_t		n3101;
 | 
			
		||||
	uint8_t		n3103;
 | 
			
		||||
	uint8_t		n3105;
 | 
			
		||||
	uint8_t		cv_countdown;
 | 
			
		||||
	uint16_t	dl_tbf_ext;
 | 
			
		||||
	uint16_t	ul_tbf_ext;
 | 
			
		||||
	uint8_t		initial_cs;
 | 
			
		||||
	uint8_t		initial_mcs;
 | 
			
		||||
	/* NSVC */
 | 
			
		||||
	uint16_t	nsvci[2];
 | 
			
		||||
	uint16_t	local_port[2];
 | 
			
		||||
	uint16_t	remote_port[2];
 | 
			
		||||
	uint32_t	remote_ip[2];
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_act_req {
 | 
			
		||||
	uint8_t		activate;
 | 
			
		||||
	uint8_t		trx_nr;
 | 
			
		||||
	uint8_t		ts_nr;
 | 
			
		||||
	uint8_t		spare;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_time_ind {
 | 
			
		||||
	uint32_t	fn;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if_pag_req {
 | 
			
		||||
	uint8_t		sapi;
 | 
			
		||||
	uint8_t		chan_needed;
 | 
			
		||||
	uint8_t		identity_lv[9];
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
struct gsm_pcu_if {
 | 
			
		||||
	/* context based information */
 | 
			
		||||
	uint8_t		msg_type;	/* message type */
 | 
			
		||||
	uint8_t		bts_nr;		/* bts number */
 | 
			
		||||
	uint8_t		spare[2];
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		struct gsm_pcu_if_data		data_req;
 | 
			
		||||
		struct gsm_pcu_if_data		data_cnf;
 | 
			
		||||
		struct gsm_pcu_if_data_cnf_dt	data_cnf_dt;
 | 
			
		||||
		struct gsm_pcu_if_data		data_ind;
 | 
			
		||||
		struct gsm_pcu_if_rts_req	rts_req;
 | 
			
		||||
		struct gsm_pcu_if_rach_ind	rach_ind;
 | 
			
		||||
		struct gsm_pcu_if_txt_ind	txt_ind;
 | 
			
		||||
		struct gsm_pcu_if_info_ind	info_ind;
 | 
			
		||||
		struct gsm_pcu_if_act_req	act_req;
 | 
			
		||||
		struct gsm_pcu_if_time_ind	time_ind;
 | 
			
		||||
		struct gsm_pcu_if_pag_req	pag_req;
 | 
			
		||||
	} u;
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
#endif /* _PCUIF_PROTO_H */
 | 
			
		||||
@@ -0,0 +1,160 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/scheduler.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/if_packet.h>
 | 
			
		||||
#include "btsconfig.h"
 | 
			
		||||
 | 
			
		||||
struct gsm_bts_trx;
 | 
			
		||||
struct virt_um_inst;
 | 
			
		||||
 | 
			
		||||
enum phy_link_type {
 | 
			
		||||
	PHY_LINK_T_NONE,
 | 
			
		||||
	PHY_LINK_T_SYSMOBTS,
 | 
			
		||||
	PHY_LINK_T_OSMOTRX,
 | 
			
		||||
	PHY_LINK_T_VIRTUAL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum phy_link_state {
 | 
			
		||||
	PHY_LINK_SHUTDOWN,
 | 
			
		||||
	PHY_LINK_CONNECTING,
 | 
			
		||||
	PHY_LINK_CONNECTED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* A PHY link represents the connection to a given PHYsical layer
 | 
			
		||||
 * implementation.  That PHY link contains 1...N PHY instances, one for
 | 
			
		||||
 * each TRX */
 | 
			
		||||
struct phy_link {
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
	int num;
 | 
			
		||||
	enum phy_link_type type;
 | 
			
		||||
	enum phy_link_state state;
 | 
			
		||||
	struct llist_head instances;
 | 
			
		||||
	char *description;
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
		} sysmobts;
 | 
			
		||||
		struct {
 | 
			
		||||
			char *local_ip;
 | 
			
		||||
			char *remote_ip;
 | 
			
		||||
			uint16_t base_port_local;
 | 
			
		||||
			uint16_t base_port_remote;
 | 
			
		||||
			struct osmo_fd trx_ofd_clk;
 | 
			
		||||
			bool trx_ta_loop;
 | 
			
		||||
			bool trx_ms_power_loop;
 | 
			
		||||
			int8_t trx_target_rssi;
 | 
			
		||||
			uint32_t clock_advance;
 | 
			
		||||
			uint32_t rts_advance;
 | 
			
		||||
			bool use_legacy_setbsic;
 | 
			
		||||
		} osmotrx;
 | 
			
		||||
		struct {
 | 
			
		||||
			char *mcast_dev;		/* Network device for multicast */
 | 
			
		||||
			char *bts_mcast_group;		/* BTS are listening to this group */
 | 
			
		||||
			uint16_t bts_mcast_port;
 | 
			
		||||
			char *ms_mcast_group;		/* MS are listening to this group */
 | 
			
		||||
			uint16_t ms_mcast_port;
 | 
			
		||||
			struct virt_um_inst *virt_um;
 | 
			
		||||
		} virt;
 | 
			
		||||
		struct {
 | 
			
		||||
			/* MAC address of the PHY */
 | 
			
		||||
			struct sockaddr_ll phy_addr;
 | 
			
		||||
			/* Network device name */
 | 
			
		||||
			char *netdev_name;
 | 
			
		||||
 | 
			
		||||
			/* configuration */
 | 
			
		||||
			uint32_t rf_port_index;
 | 
			
		||||
#if OCTPHY_USE_ANTENNA_ID == 1
 | 
			
		||||
			uint32_t rx_ant_id;
 | 
			
		||||
			uint32_t tx_ant_id;
 | 
			
		||||
#endif
 | 
			
		||||
			uint32_t rx_gain_db;
 | 
			
		||||
			bool tx_atten_flag;
 | 
			
		||||
			uint32_t tx_atten_db;
 | 
			
		||||
#if OCTPHY_MULTI_TRX == 1
 | 
			
		||||
			/* arfcn used by TRX with id 0 */
 | 
			
		||||
			uint16_t center_arfcn;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			struct octphy_hdl *hdl;
 | 
			
		||||
		} octphy;
 | 
			
		||||
	} u;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct phy_instance {
 | 
			
		||||
	/* liked inside phy_link.linstances */
 | 
			
		||||
	struct llist_head list;
 | 
			
		||||
	int num;
 | 
			
		||||
	char *description;
 | 
			
		||||
	char version[MAX_VERSION_LENGTH];
 | 
			
		||||
	/* pointer to the PHY link to which we belong */
 | 
			
		||||
	struct phy_link *phy_link;
 | 
			
		||||
 | 
			
		||||
	/* back-pointer to the TRX to which we're associated */
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
			/* configuration */
 | 
			
		||||
			uint8_t clk_use_eeprom;
 | 
			
		||||
			uint32_t dsp_trace_f;
 | 
			
		||||
			int clk_cal;
 | 
			
		||||
			uint8_t clk_src;
 | 
			
		||||
			char *calib_path;
 | 
			
		||||
 | 
			
		||||
			struct femtol1_hdl *hdl;
 | 
			
		||||
		} sysmobts;
 | 
			
		||||
		struct {
 | 
			
		||||
			struct trx_l1h *hdl;
 | 
			
		||||
			bool sw_act_reported;
 | 
			
		||||
		} osmotrx;
 | 
			
		||||
		struct {
 | 
			
		||||
			struct l1sched_trx sched;
 | 
			
		||||
		} virt;
 | 
			
		||||
		struct {
 | 
			
		||||
			/* logical transceiver number within one PHY */
 | 
			
		||||
			uint32_t trx_id;
 | 
			
		||||
			/* trx lock state variable */
 | 
			
		||||
			int trx_locked;
 | 
			
		||||
		} octphy;
 | 
			
		||||
		struct {
 | 
			
		||||
			/* configuration */
 | 
			
		||||
			uint32_t dsp_trace_f;
 | 
			
		||||
			char *calib_path;
 | 
			
		||||
			int minTxPower;
 | 
			
		||||
			int maxTxPower;
 | 
			
		||||
			struct lc15l1_hdl *hdl;
 | 
			
		||||
			uint8_t max_cell_size;		/* 0:166 qbits*/
 | 
			
		||||
			uint8_t diversity_mode;		/* 0: SISO A, 1: SISO B, 2: MRC */
 | 
			
		||||
			uint8_t pedestal_mode;		/* 0: unused TS is OFF, 1: unused TS is in minimum Tx power */
 | 
			
		||||
			uint8_t dsp_alive_period;	/* DSP alive timer period  */
 | 
			
		||||
			uint8_t tx_pwr_adj_mode;	/* 0: no auto adjust power, 1: auto adjust power using RMS detector */
 | 
			
		||||
			uint8_t tx_pwr_red_8psk;	/* 8-PSK maximum Tx power reduction level in dB */
 | 
			
		||||
		} lc15;
 | 
			
		||||
	} u;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct phy_link *phy_link_by_num(int num);
 | 
			
		||||
struct phy_link *phy_link_create(void *ctx, int num);
 | 
			
		||||
void phy_link_destroy(struct phy_link *plink);
 | 
			
		||||
void phy_link_state_set(struct phy_link *plink, enum phy_link_state state);
 | 
			
		||||
int phy_links_open(void);
 | 
			
		||||
 | 
			
		||||
struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num);
 | 
			
		||||
struct phy_instance *phy_instance_create(struct phy_link *plink, int num);
 | 
			
		||||
void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx);
 | 
			
		||||
void phy_instance_destroy(struct phy_instance *pinst);
 | 
			
		||||
const char *phy_instance_name(struct phy_instance *pinst);
 | 
			
		||||
 | 
			
		||||
void phy_user_statechg_notif(struct phy_instance *pinst, enum phy_link_state link_state);
 | 
			
		||||
 | 
			
		||||
static inline struct phy_instance *trx_phy_instance(struct gsm_bts_trx *trx)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_ASSERT(trx);
 | 
			
		||||
	return trx->role_bts.l1h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bts_model_phy_link_open(struct phy_link *plink);
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
 | 
			
		||||
int lchan_ms_pwr_ctrl(struct gsm_lchan *lchan,
 | 
			
		||||
		      const uint8_t ms_power, const int rxLevel);
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
#ifndef _RSL_H
 | 
			
		||||
#define _RSL_H
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * What kind of release/activation is done? A silent one for
 | 
			
		||||
 * the PDCH or one triggered through RSL?
 | 
			
		||||
 */
 | 
			
		||||
enum {
 | 
			
		||||
	LCHAN_REL_ACT_RSL,
 | 
			
		||||
	LCHAN_REL_ACT_PCU,
 | 
			
		||||
	LCHAN_REL_ACT_OML,
 | 
			
		||||
	LCHAN_REL_ACT_REACT, /* remove once auto-activation hack is removed from opstart_compl() */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define LCHAN_FN_DUMMY 0xFFFFFFFF
 | 
			
		||||
#define LCHAN_FN_WAIT 0xFFFFFFFE
 | 
			
		||||
 | 
			
		||||
int msgb_queue_flush(struct llist_head *list);
 | 
			
		||||
 | 
			
		||||
int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg);
 | 
			
		||||
int rsl_tx_rf_res(struct gsm_bts_trx *trx);
 | 
			
		||||
int rsl_tx_chan_rqd(struct gsm_bts_trx *trx, struct gsm_time *gtime,
 | 
			
		||||
		    uint8_t ra, uint8_t acc_delay);
 | 
			
		||||
int rsl_tx_est_ind(struct gsm_lchan *lchan, uint8_t link_id, uint8_t *data, int len);
 | 
			
		||||
 | 
			
		||||
int rsl_tx_chan_act_acknack(struct gsm_lchan *lchan, uint8_t cause);
 | 
			
		||||
int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause);
 | 
			
		||||
int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan);
 | 
			
		||||
int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay);
 | 
			
		||||
 | 
			
		||||
int lchan_deactivate(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
/* call-back for LAPDm code, called when it wants to send msgs UP */
 | 
			
		||||
int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx);
 | 
			
		||||
 | 
			
		||||
int rsl_tx_ipac_dlcx_ind(struct gsm_lchan *lchan, uint8_t cause);
 | 
			
		||||
int rsl_tx_ccch_load_ind_pch(struct gsm_bts *bts, uint16_t paging_avail);
 | 
			
		||||
int rsl_tx_ccch_load_ind_rach(struct gsm_bts *bts, uint16_t total,
 | 
			
		||||
			      uint16_t busy, uint16_t access);
 | 
			
		||||
 | 
			
		||||
void cb_ts_disconnected(struct gsm_bts_trx_ts *ts);
 | 
			
		||||
void cb_ts_connected(struct gsm_bts_trx_ts *ts);
 | 
			
		||||
void ipacc_dyn_pdch_complete(struct gsm_bts_trx_ts *ts, int rc);
 | 
			
		||||
 | 
			
		||||
#endif // _RSL_H */
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,224 @@
 | 
			
		||||
#ifndef TRX_SCHEDULER_H
 | 
			
		||||
#define TRX_SCHEDULER_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
 | 
			
		||||
/* These types define the different channels on a multiframe.
 | 
			
		||||
 * Each channel has queues and can be activated individually.
 | 
			
		||||
 */
 | 
			
		||||
enum trx_chan_type {
 | 
			
		||||
	TRXC_IDLE = 0,
 | 
			
		||||
	TRXC_FCCH,
 | 
			
		||||
	TRXC_SCH,
 | 
			
		||||
	TRXC_BCCH,
 | 
			
		||||
	TRXC_RACH,
 | 
			
		||||
	TRXC_CCCH,
 | 
			
		||||
	TRXC_TCHF,
 | 
			
		||||
	TRXC_TCHH_0,
 | 
			
		||||
	TRXC_TCHH_1,
 | 
			
		||||
	TRXC_SDCCH4_0,
 | 
			
		||||
	TRXC_SDCCH4_1,
 | 
			
		||||
	TRXC_SDCCH4_2,
 | 
			
		||||
	TRXC_SDCCH4_3,
 | 
			
		||||
	TRXC_SDCCH8_0,
 | 
			
		||||
	TRXC_SDCCH8_1,
 | 
			
		||||
	TRXC_SDCCH8_2,
 | 
			
		||||
	TRXC_SDCCH8_3,
 | 
			
		||||
	TRXC_SDCCH8_4,
 | 
			
		||||
	TRXC_SDCCH8_5,
 | 
			
		||||
	TRXC_SDCCH8_6,
 | 
			
		||||
	TRXC_SDCCH8_7,
 | 
			
		||||
	TRXC_SACCHTF,
 | 
			
		||||
	TRXC_SACCHTH_0,
 | 
			
		||||
	TRXC_SACCHTH_1,
 | 
			
		||||
	TRXC_SACCH4_0,
 | 
			
		||||
	TRXC_SACCH4_1,
 | 
			
		||||
	TRXC_SACCH4_2,
 | 
			
		||||
	TRXC_SACCH4_3,
 | 
			
		||||
	TRXC_SACCH8_0,
 | 
			
		||||
	TRXC_SACCH8_1,
 | 
			
		||||
	TRXC_SACCH8_2,
 | 
			
		||||
	TRXC_SACCH8_3,
 | 
			
		||||
	TRXC_SACCH8_4,
 | 
			
		||||
	TRXC_SACCH8_5,
 | 
			
		||||
	TRXC_SACCH8_6,
 | 
			
		||||
	TRXC_SACCH8_7,
 | 
			
		||||
	TRXC_PDTCH,
 | 
			
		||||
	TRXC_PTCCH,
 | 
			
		||||
	_TRX_CHAN_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct value_string trx_chan_type_names[];
 | 
			
		||||
 | 
			
		||||
#define GSM_BURST_LEN		148
 | 
			
		||||
#define GPRS_BURST_LEN		GSM_BURST_LEN
 | 
			
		||||
#define EGPRS_BURST_LEN		444
 | 
			
		||||
 | 
			
		||||
enum trx_burst_type {
 | 
			
		||||
	TRX_BURST_GMSK,
 | 
			
		||||
	TRX_BURST_8PSK,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* States each channel on a multiframe */
 | 
			
		||||
struct l1sched_chan_state {
 | 
			
		||||
	/* scheduler */
 | 
			
		||||
	uint8_t			active;		/* Channel is active */
 | 
			
		||||
	ubit_t			*dl_bursts;	/* burst buffer for TX */
 | 
			
		||||
	enum trx_burst_type	dl_burst_type;  /* GMSK or 8PSK burst type */
 | 
			
		||||
	sbit_t			*ul_bursts;	/* burst buffer for RX */
 | 
			
		||||
	uint32_t		ul_first_fn;	/* fn of first burst */
 | 
			
		||||
	uint8_t			ul_mask;	/* mask of received bursts */
 | 
			
		||||
 | 
			
		||||
	/* RSSI / TOA */
 | 
			
		||||
	uint8_t			rssi_num;	/* number of RSSI values */
 | 
			
		||||
	float			rssi_sum;	/* sum of RSSI values */
 | 
			
		||||
	uint8_t			toa_num;	/* number of TOA values */
 | 
			
		||||
	int32_t			toa256_sum;	/* sum of TOA values (1/256 symbol) */
 | 
			
		||||
 | 
			
		||||
	/* loss detection */
 | 
			
		||||
	uint8_t			lost;		/* (SACCH) loss detection */
 | 
			
		||||
 | 
			
		||||
	/* mode */
 | 
			
		||||
	uint8_t			rsl_cmode, tch_mode; /* mode for TCH channels */
 | 
			
		||||
 | 
			
		||||
	/* AMR */
 | 
			
		||||
	uint8_t			codec[4];	/* 4 possible codecs for amr */
 | 
			
		||||
	int			codecs;		/* number of possible codecs */
 | 
			
		||||
	float			ber_sum;	/* sum of bit error rates */
 | 
			
		||||
	int			ber_num;	/* number of bit error rates */
 | 
			
		||||
	uint8_t			ul_ft;		/* current uplink FT index */
 | 
			
		||||
	uint8_t			dl_ft;		/* current downlink FT index */
 | 
			
		||||
	uint8_t			ul_cmr;		/* current uplink CMR index */
 | 
			
		||||
	uint8_t			dl_cmr;		/* current downlink CMR index */
 | 
			
		||||
	uint8_t			amr_loop;	/* if AMR loop is enabled */
 | 
			
		||||
 | 
			
		||||
	/* TCH/H */
 | 
			
		||||
	uint8_t			dl_ongoing_facch; /* FACCH/H on downlink */
 | 
			
		||||
	uint8_t			ul_ongoing_facch; /* FACCH/H on uplink */
 | 
			
		||||
 | 
			
		||||
	/* encryption */
 | 
			
		||||
	int			ul_encr_algo;	/* A5/x encry algo downlink */
 | 
			
		||||
	int			dl_encr_algo;	/* A5/x encry algo uplink */
 | 
			
		||||
	int			ul_encr_key_len;
 | 
			
		||||
	int			dl_encr_key_len;
 | 
			
		||||
	uint8_t			ul_encr_key[MAX_A5_KEY_LEN];
 | 
			
		||||
	uint8_t			dl_encr_key[MAX_A5_KEY_LEN];
 | 
			
		||||
 | 
			
		||||
	/* measurements */
 | 
			
		||||
	struct {
 | 
			
		||||
		uint8_t		clock;		/* cyclic clock counter */
 | 
			
		||||
		int8_t		rssi[32];	/* last RSSI values */
 | 
			
		||||
		int		rssi_count;	/* received RSSI values */
 | 
			
		||||
		int		rssi_valid_count; /* number of stored value */
 | 
			
		||||
		int		rssi_got_burst; /* any burst received so far */
 | 
			
		||||
		int32_t		toa256_sum;	/* sum of TOA values (1/256 symbol) */
 | 
			
		||||
		int		toa_num;	/* number of TOA value */
 | 
			
		||||
	} meas;
 | 
			
		||||
 | 
			
		||||
	/* handover */
 | 
			
		||||
	uint8_t			ho_rach_detect;	/* if rach detection is on */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct l1sched_ts {
 | 
			
		||||
	uint8_t 		mf_index;	/* selected multiframe index */
 | 
			
		||||
	uint32_t 		mf_last_fn;	/* last received frame number */
 | 
			
		||||
	uint8_t			mf_period;	/* period of multiframe */
 | 
			
		||||
	const struct trx_sched_frame *mf_frames; /* pointer to frame layout */
 | 
			
		||||
 | 
			
		||||
	struct llist_head	dl_prims;	/* Queue primitives for TX */
 | 
			
		||||
 | 
			
		||||
	/* Channel states for all logical channels */
 | 
			
		||||
	struct l1sched_chan_state chan_state[_TRX_CHAN_MAX];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct l1sched_trx {
 | 
			
		||||
	struct gsm_bts_trx	*trx;
 | 
			
		||||
	struct l1sched_ts       ts[TRX_NR_TS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn);
 | 
			
		||||
 | 
			
		||||
/*! \brief how many frame numbers in advance we should send bursts to PHY */
 | 
			
		||||
extern uint32_t trx_clock_advance;
 | 
			
		||||
/*! \brief advance RTS.ind to L2 by that many clocks */
 | 
			
		||||
extern uint32_t trx_rts_advance;
 | 
			
		||||
/*! \brief last frame number as received from PHY */
 | 
			
		||||
extern uint32_t transceiver_last_fn;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*! \brief Initialize the scheduler data structures */
 | 
			
		||||
int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx);
 | 
			
		||||
 | 
			
		||||
/*! \brief De-initialize the scheduler data structures */
 | 
			
		||||
void trx_sched_exit(struct l1sched_trx *l1t);
 | 
			
		||||
 | 
			
		||||
/*! \brief Handle a PH-DATA.req from L2 down to L1 */
 | 
			
		||||
int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
 | 
			
		||||
 | 
			
		||||
/*! \brief Handle a PH-TCH.req from L2 down to L1 */
 | 
			
		||||
int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
 | 
			
		||||
 | 
			
		||||
/*! \brief PHY informs us of new (current) GSM frame number */
 | 
			
		||||
int trx_sched_clock(struct gsm_bts *bts, uint32_t fn);
 | 
			
		||||
 | 
			
		||||
/*! \brief handle an UL burst received by PHY */
 | 
			
		||||
int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
        sbit_t *bits, uint16_t nbits, int8_t rssi, int16_t toa);
 | 
			
		||||
 | 
			
		||||
/*! \brief set multiframe scheduler to given physical channel config */
 | 
			
		||||
int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn,
 | 
			
		||||
        enum gsm_phys_chan_config pchan);
 | 
			
		||||
 | 
			
		||||
/*! \brief set all matching logical channels active/inactive */
 | 
			
		||||
int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id,
 | 
			
		||||
	int active);
 | 
			
		||||
 | 
			
		||||
/*! \brief set mode of all matching logical channels to given mode(s) */
 | 
			
		||||
int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode,
 | 
			
		||||
	uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1,
 | 
			
		||||
	uint8_t codec2, uint8_t codec3, uint8_t initial_codec,
 | 
			
		||||
	uint8_t handover);
 | 
			
		||||
 | 
			
		||||
/*! \brief set ciphering on given logical channels */
 | 
			
		||||
int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
 | 
			
		||||
        int algo, uint8_t *key, int key_len);
 | 
			
		||||
 | 
			
		||||
/* \brief close all logical channels and reset timeslots */
 | 
			
		||||
void trx_sched_reset(struct l1sched_trx *l1t);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* frame structures */
 | 
			
		||||
struct trx_sched_frame {
 | 
			
		||||
	/*! \brief downlink TRX channel type */
 | 
			
		||||
	enum trx_chan_type		dl_chan;
 | 
			
		||||
	/*! \brief downlink block ID */
 | 
			
		||||
	uint8_t				dl_bid;
 | 
			
		||||
	/*! \brief uplink TRX channel type */
 | 
			
		||||
	enum trx_chan_type		ul_chan;
 | 
			
		||||
	/*! \brief uplink block ID */
 | 
			
		||||
	uint8_t				ul_bid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* multiframe structure */
 | 
			
		||||
struct trx_sched_multiframe {
 | 
			
		||||
	/*! \brief physical channel config (channel combination) */
 | 
			
		||||
	enum gsm_phys_chan_config	pchan;
 | 
			
		||||
	/*! \brief applies to which timeslots? */
 | 
			
		||||
	uint8_t				slotmask;
 | 
			
		||||
	/*! \brief repeats how many frames */
 | 
			
		||||
	uint8_t				period;
 | 
			
		||||
	/*! \brief pointer to scheduling structure */
 | 
			
		||||
	const struct trx_sched_frame	*frames;
 | 
			
		||||
	/*! \brief human-readable name */
 | 
			
		||||
	const char 			*name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int find_sched_mframe_idx(enum gsm_phys_chan_config pchan, uint8_t tn);
 | 
			
		||||
 | 
			
		||||
/*! Determine if given frame number contains SACCH (true) or other (false) burst */
 | 
			
		||||
bool trx_sched_is_sacch_fn(struct gsm_bts_trx_ts *ts, uint32_t fn, bool uplink);
 | 
			
		||||
extern const struct trx_sched_multiframe trx_sched_multiframes[];
 | 
			
		||||
 | 
			
		||||
#endif /* TRX_SCHEDULER_H */
 | 
			
		||||
@@ -0,0 +1,94 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define LOGL1S(subsys, level, l1t, tn, chan, fn, fmt, args ...)	\
 | 
			
		||||
		LOGP(subsys, level, "%s %s %s: " fmt,		\
 | 
			
		||||
			gsm_fn_as_gsmtime_str(fn),		\
 | 
			
		||||
			gsm_ts_name(&(l1t)->trx->ts[tn]),	\
 | 
			
		||||
			chan >=0 ? trx_chan_desc[chan].name : "", ## args)
 | 
			
		||||
 | 
			
		||||
typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn,
 | 
			
		||||
			       uint32_t fn, enum trx_chan_type chan);
 | 
			
		||||
 | 
			
		||||
typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn,
 | 
			
		||||
				  uint32_t fn, enum trx_chan_type chan,
 | 
			
		||||
				  uint8_t bid, uint16_t *nbits);
 | 
			
		||||
 | 
			
		||||
typedef int trx_sched_ul_func(struct l1sched_trx *l1t, uint8_t tn,
 | 
			
		||||
			      uint32_t fn, enum trx_chan_type chan,
 | 
			
		||||
			      uint8_t bid, sbit_t *bits, uint16_t nbits,
 | 
			
		||||
			      int8_t rssi, int16_t toa256);
 | 
			
		||||
 | 
			
		||||
struct trx_chan_desc {
 | 
			
		||||
	/*! \brief Is this on a PDCH (PS) ? */
 | 
			
		||||
	int			pdch;
 | 
			
		||||
	/*! \brief TRX Channel Type */
 | 
			
		||||
	enum trx_chan_type	chan;
 | 
			
		||||
	/*! \brief Channel Number (like in RSL) */
 | 
			
		||||
	uint8_t			chan_nr;
 | 
			
		||||
	/*! \brief Link ID (like in RSL) */
 | 
			
		||||
	uint8_t			link_id;
 | 
			
		||||
	/*! \brief Human-readable name */
 | 
			
		||||
	const char		*name;
 | 
			
		||||
	/*! \brief function to call when we want to generate RTS.req to L2 */
 | 
			
		||||
	trx_sched_rts_func	*rts_fn;
 | 
			
		||||
	/*! \brief function to call when DATA.req received from L2 */
 | 
			
		||||
	trx_sched_dl_func	*dl_fn;
 | 
			
		||||
	/*! \brief function to call when burst received from PHY */
 | 
			
		||||
	trx_sched_ul_func	*ul_fn;
 | 
			
		||||
	/*! \brief is this channel automatically active at start? */
 | 
			
		||||
	int			auto_active;
 | 
			
		||||
};
 | 
			
		||||
extern const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX];
 | 
			
		||||
 | 
			
		||||
extern const ubit_t _sched_tsc[8][26];
 | 
			
		||||
extern const ubit_t _sched_egprs_tsc[8][78];
 | 
			
		||||
const ubit_t _sched_fcch_burst[148];
 | 
			
		||||
const ubit_t _sched_sch_train[64];
 | 
			
		||||
 | 
			
		||||
struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn,
 | 
			
		||||
				 enum trx_chan_type chan);
 | 
			
		||||
 | 
			
		||||
int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
			       enum trx_chan_type chan, uint8_t *l2,
 | 
			
		||||
			       uint8_t l2_len, float rssi,
 | 
			
		||||
			       int16_t ta_offs_256bits, int16_t link_qual_cb,
 | 
			
		||||
			       uint16_t ber10k,
 | 
			
		||||
			       enum osmo_ph_pres_info_type presence_info);
 | 
			
		||||
 | 
			
		||||
int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
		    enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len);
 | 
			
		||||
 | 
			
		||||
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
 | 
			
		||||
ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
 | 
			
		||||
ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
 | 
			
		||||
ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
 | 
			
		||||
ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
 | 
			
		||||
ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
 | 
			
		||||
ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
 | 
			
		||||
int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
 | 
			
		||||
	int8_t rssi, int16_t toa256);
 | 
			
		||||
int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
 | 
			
		||||
	int8_t rssi, int16_t toa256);
 | 
			
		||||
int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
 | 
			
		||||
	int8_t rssi, int16_t toa256);
 | 
			
		||||
int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
 | 
			
		||||
	int8_t rssi, int16_t toa256);
 | 
			
		||||
int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 | 
			
		||||
	enum trx_chan_type chan, uint8_t bid, sbit_t *bits, uint16_t nbits,
 | 
			
		||||
	int8_t rssi, int16_t toa256);
 | 
			
		||||
 | 
			
		||||
const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
 | 
			
		||||
			      uint32_t fn, uint16_t *nbits);
 | 
			
		||||
int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn);
 | 
			
		||||
void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate);
 | 
			
		||||
@@ -0,0 +1,19 @@
 | 
			
		||||
#ifndef OSMO_BTS_SIGNAL_H
 | 
			
		||||
#define OSMO_BTS_SIGNAL_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/signal.h>
 | 
			
		||||
 | 
			
		||||
enum sig_subsys {
 | 
			
		||||
	SS_GLOBAL,
 | 
			
		||||
	SS_FAIL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum signals_global {
 | 
			
		||||
	S_NEW_SYSINFO,
 | 
			
		||||
	S_NEW_OP_STATE,
 | 
			
		||||
	S_NEW_NSE_ATTR,
 | 
			
		||||
	S_NEW_CELL_ATTR,
 | 
			
		||||
	S_NEW_NSVC_ATTR,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -0,0 +1,78 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
 | 
			
		||||
/* our unit is 'milli dB" or "milli dBm", i.e. 1/1000 of a dB(m) */
 | 
			
		||||
#define to_mdB(x)	(x * 1000)
 | 
			
		||||
 | 
			
		||||
/* PA calibration table */
 | 
			
		||||
struct pa_calibration {
 | 
			
		||||
	int delta_mdB[1024];		/* gain delta at given ARFCN */
 | 
			
		||||
	/* FIXME: thermal calibration */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* representation of a RF power amplifier */
 | 
			
		||||
struct power_amp {
 | 
			
		||||
	/* nominal gain of the PA */
 | 
			
		||||
	int nominal_gain_mdB;
 | 
			
		||||
	/* table with calibrated actual gain for each ARFCN */
 | 
			
		||||
	struct pa_calibration calib;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Transmit power related parameters of a transceiver */
 | 
			
		||||
struct trx_power_params {
 | 
			
		||||
	/* specified maximum output of TRX at full power, has to be
 | 
			
		||||
	 * initialized by BTS model at startup*/
 | 
			
		||||
	int trx_p_max_out_mdBm;
 | 
			
		||||
 | 
			
		||||
	/* intended current total system output power */
 | 
			
		||||
	int p_total_tgt_mdBm;
 | 
			
		||||
 | 
			
		||||
	/* actual current total system output power, filled in by tx_power code */
 | 
			
		||||
	int p_total_cur_mdBm;
 | 
			
		||||
 | 
			
		||||
	/* current temporary attenuation due to thermal management,
 | 
			
		||||
	 * set by thermal management code via control interface */
 | 
			
		||||
	int thermal_attenuation_mdB;
 | 
			
		||||
 | 
			
		||||
	/* external gain (+) or attenuation (-) added by the user, configured
 | 
			
		||||
	 * by the user via VTY */
 | 
			
		||||
	int user_gain_mdB;
 | 
			
		||||
 | 
			
		||||
	/* calibration table of internal PA */
 | 
			
		||||
	struct power_amp pa;
 | 
			
		||||
 | 
			
		||||
	/* calibration table of user PA */
 | 
			
		||||
	struct power_amp user_pa;
 | 
			
		||||
 | 
			
		||||
	/* power ramping related data */
 | 
			
		||||
	struct {
 | 
			
		||||
		/* maximum initial Pout including all PAs */
 | 
			
		||||
		int max_initial_pout_mdBm;
 | 
			
		||||
		/* temporary attenuation due to power ramping */
 | 
			
		||||
		int attenuation_mdB;
 | 
			
		||||
		unsigned int step_size_mdB;
 | 
			
		||||
		unsigned int step_interval_sec;
 | 
			
		||||
		struct osmo_timer_list step_timer;
 | 
			
		||||
	} ramp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int get_p_max_out_mdBm(struct gsm_bts_trx *trx);
 | 
			
		||||
 | 
			
		||||
int get_p_nominal_mdBm(struct gsm_bts_trx *trx);
 | 
			
		||||
 | 
			
		||||
int get_p_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
 | 
			
		||||
int get_p_target_mdBm_lchan(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
int get_p_trxout_target_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
 | 
			
		||||
int get_p_trxout_target_mdBm_lchan(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
int get_p_trxout_actual_mdBm(struct gsm_bts_trx *trx, uint8_t bs_power_ie);
 | 
			
		||||
int get_p_trxout_actual_mdBm_lchan(struct gsm_lchan *lchan);
 | 
			
		||||
 | 
			
		||||
int power_ramp_start(struct gsm_bts_trx *trx, int p_total_tgt_mdBm, int bypass);
 | 
			
		||||
 | 
			
		||||
void power_trx_change_compl(struct gsm_bts_trx *trx, int p_trxout_cur_mdBm);
 | 
			
		||||
 | 
			
		||||
int power_ramp_initial_power_mdBm(struct gsm_bts_trx *trx);
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
#ifndef OSMOBTS_VTY_H
 | 
			
		||||
#define OSMOBTS_VTY_H
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/vty.h>
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
 | 
			
		||||
enum bts_vty_node {
 | 
			
		||||
	/* PHY_NODE must come before BTS node to ensure the phy
 | 
			
		||||
	 * instances are created at the time the TRX nodes want to refer
 | 
			
		||||
	 * to them */
 | 
			
		||||
	PHY_NODE = _LAST_OSMOVTY_NODE + 1,
 | 
			
		||||
	PHY_INST_NODE,
 | 
			
		||||
	BTS_NODE,
 | 
			
		||||
	TRX_NODE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct cmd_element ournode_exit_cmd;
 | 
			
		||||
extern struct cmd_element ournode_end_cmd;
 | 
			
		||||
 | 
			
		||||
extern struct cmd_element cfg_bts_auto_band_cmd;
 | 
			
		||||
extern struct cmd_element cfg_bts_no_auto_band_cmd;
 | 
			
		||||
 | 
			
		||||
struct phy_instance *vty_get_phy_instance(struct vty *vty, int phy_nr, int inst_nr);
 | 
			
		||||
 | 
			
		||||
int bts_vty_go_parent(struct vty *vty);
 | 
			
		||||
int bts_vty_is_config_node(struct vty *vty, int node);
 | 
			
		||||
 | 
			
		||||
int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat);
 | 
			
		||||
 | 
			
		||||
extern struct vty_app_info bts_vty_info;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
SUBDIRS = common osmo-bts-virtual osmo-bts-omldummy
 | 
			
		||||
 | 
			
		||||
if ENABLE_SYSMOBTS
 | 
			
		||||
SUBDIRS += osmo-bts-sysmo
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if ENABLE_TRX
 | 
			
		||||
SUBDIRS += osmo-bts-trx
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if ENABLE_OCTPHY
 | 
			
		||||
SUBDIRS += osmo-bts-octphy
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if ENABLE_LC15BTS
 | 
			
		||||
SUBDIRS += osmo-bts-litecell15
 | 
			
		||||
endif
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
 | 
			
		||||
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS)
 | 
			
		||||
LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOCODEC_LIBS)
 | 
			
		||||
 | 
			
		||||
if ENABLE_LC15BTS
 | 
			
		||||
AM_CFLAGS += -DENABLE_LC15BTS
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
noinst_LIBRARIES = libbts.a libl1sched.a
 | 
			
		||||
libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \
 | 
			
		||||
		   rsl.c vty.c paging.c measurement.c amr.c lchan.c \
 | 
			
		||||
		   load_indication.c pcu_sock.c handover.c msg_utils.c \
 | 
			
		||||
		   tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \
 | 
			
		||||
		   l1sap.c cbch.c power_control.c main.c phy_link.c \
 | 
			
		||||
		   dtx_dl_amr_fsm.c scheduler_mframe.c
 | 
			
		||||
 | 
			
		||||
libl1sched_a_SOURCES = scheduler.c
 | 
			
		||||
@@ -0,0 +1,276 @@
 | 
			
		||||
/* Abis/IP interface routines utilizing libosmo-abis (Pablo) */
 | 
			
		||||
 | 
			
		||||
/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
 | 
			
		||||
 * (C) 2011-2013 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "btsconfig.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/select.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/core/signal.h>
 | 
			
		||||
#include <osmocom/core/macaddr.h>
 | 
			
		||||
#include <osmocom/abis/abis.h>
 | 
			
		||||
#include <osmocom/abis/e1_input.h>
 | 
			
		||||
#include <osmocom/abis/ipaccess.h>
 | 
			
		||||
#include <osmocom/gsm/ipa.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
#include <osmo-bts/bts.h>
 | 
			
		||||
#include <osmo-bts/rsl.h>
 | 
			
		||||
#include <osmo-bts/oml.h>
 | 
			
		||||
#include <osmo-bts/bts_model.h>
 | 
			
		||||
 | 
			
		||||
static struct gsm_bts *g_bts;
 | 
			
		||||
 | 
			
		||||
int abis_oml_sendmsg(struct msgb *msg)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts *bts = msg->trx->bts;
 | 
			
		||||
 | 
			
		||||
	if (!bts->oml_link) {
 | 
			
		||||
		llist_add_tail(&msg->list, &bts->oml_queue);
 | 
			
		||||
		return 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* osmo-bts uses msg->trx internally, but libosmo-abis uses
 | 
			
		||||
		 * the signalling link at msg->dst */
 | 
			
		||||
		msg->dst = bts->oml_link;
 | 
			
		||||
		return abis_sendmsg(msg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void drain_oml_queue(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct msgb *msg, *msg2;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry_safe(msg, msg2, &bts->oml_queue, list) {
 | 
			
		||||
		/* osmo-bts uses msg->trx internally, but libosmo-abis uses
 | 
			
		||||
		 * the signalling link at msg->dst */
 | 
			
		||||
		llist_del(&msg->list);
 | 
			
		||||
		msg->dst = bts->oml_link;
 | 
			
		||||
		abis_sendmsg(msg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int abis_bts_rsl_sendmsg(struct msgb *msg)
 | 
			
		||||
{
 | 
			
		||||
	OSMO_ASSERT(msg->trx);
 | 
			
		||||
 | 
			
		||||
	if (msg->trx->bts->variant == BTS_OSMO_OMLDUMMY) {
 | 
			
		||||
		msgb_free(msg);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* osmo-bts uses msg->trx internally, but libosmo-abis uses
 | 
			
		||||
	 * the signalling link at msg->dst */
 | 
			
		||||
	msg->dst = msg->trx->rsl_link;
 | 
			
		||||
	return abis_sendmsg(msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct e1inp_sign_link *sign_link_up(void *unit, struct e1inp_line *line,
 | 
			
		||||
					    enum e1inp_sign_type type)
 | 
			
		||||
{
 | 
			
		||||
	struct e1inp_sign_link *sign_link = NULL;
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
	int trx_nr;
 | 
			
		||||
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case E1INP_SIGN_OML:
 | 
			
		||||
		LOGP(DABIS, LOGL_INFO, "OML Signalling link up\n");
 | 
			
		||||
		e1inp_ts_config_sign(&line->ts[E1INP_SIGN_OML-1], line);
 | 
			
		||||
		sign_link = g_bts->oml_link =
 | 
			
		||||
			e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML-1],
 | 
			
		||||
						E1INP_SIGN_OML, NULL, 255, 0);
 | 
			
		||||
		drain_oml_queue(g_bts);
 | 
			
		||||
		sign_link->trx = g_bts->c0;
 | 
			
		||||
		bts_link_estab(g_bts);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		trx_nr = type - E1INP_SIGN_RSL;
 | 
			
		||||
		LOGP(DABIS, LOGL_INFO, "RSL Signalling link for TRX%d up\n",
 | 
			
		||||
			trx_nr);
 | 
			
		||||
		trx = gsm_bts_trx_num(g_bts, trx_nr);
 | 
			
		||||
		if (!trx) {
 | 
			
		||||
			LOGP(DABIS, LOGL_ERROR, "TRX%d does not exixt!\n",
 | 
			
		||||
				trx_nr);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		e1inp_ts_config_sign(&line->ts[type-1], line);
 | 
			
		||||
		sign_link = trx->rsl_link =
 | 
			
		||||
			e1inp_sign_link_create(&line->ts[type-1],
 | 
			
		||||
						E1INP_SIGN_RSL, NULL, 0, 0);
 | 
			
		||||
		sign_link->trx = trx;
 | 
			
		||||
		trx_link_estab(trx);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sign_link;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sign_link_down(struct e1inp_line *line)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
	LOGP(DABIS, LOGL_ERROR, "Signalling link down\n");
 | 
			
		||||
 | 
			
		||||
	/* First remove the OML signalling link */
 | 
			
		||||
	if (g_bts->oml_link)
 | 
			
		||||
		e1inp_sign_link_destroy(g_bts->oml_link);
 | 
			
		||||
	g_bts->oml_link = NULL;
 | 
			
		||||
 | 
			
		||||
	/* Then iterate over the RSL signalling links */
 | 
			
		||||
	llist_for_each_entry(trx, &g_bts->trx_list, list) {
 | 
			
		||||
		if (trx->rsl_link) {
 | 
			
		||||
			e1inp_sign_link_destroy(trx->rsl_link);
 | 
			
		||||
			trx->rsl_link = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bts_model_abis_close(g_bts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* callback for incoming mesages from A-bis/IP */
 | 
			
		||||
static int sign_link_cb(struct msgb *msg)
 | 
			
		||||
{
 | 
			
		||||
	struct e1inp_sign_link *link = msg->dst;
 | 
			
		||||
 | 
			
		||||
	/* osmo-bts code assumes msg->trx is set, but libosmo-abis works
 | 
			
		||||
	 * with the sign_link stored in msg->dst, so we have to convert
 | 
			
		||||
	 * here */
 | 
			
		||||
	msg->trx = link->trx;
 | 
			
		||||
 | 
			
		||||
	switch (link->type) {
 | 
			
		||||
	case E1INP_SIGN_OML:
 | 
			
		||||
		down_oml(link->trx->bts, msg);
 | 
			
		||||
		break;
 | 
			
		||||
	case E1INP_SIGN_RSL:
 | 
			
		||||
		down_rsl(link->trx, msg);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		msgb_free(msg);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t get_signlink_remote_ip(struct e1inp_sign_link *link)
 | 
			
		||||
{
 | 
			
		||||
	int fd = link->ts->driver.ipaccess.fd.fd;
 | 
			
		||||
	struct sockaddr_in sin;
 | 
			
		||||
	socklen_t slen = sizeof(sin);
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	rc = getpeername(fd, (struct sockaddr *)&sin, &slen);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DOML, LOGL_ERROR, "Cannot determine remote IP Addr: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* we assume that the soket is AF_INET.  As Abis/IP contains
 | 
			
		||||
	 * lots of hard-coded IPv4 addresses, this safe */
 | 
			
		||||
	OSMO_ASSERT(sin.sin_family == AF_INET);
 | 
			
		||||
 | 
			
		||||
	return ntohl(sin.sin_addr.s_addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int inp_s_cbfn(unsigned int subsys, unsigned int signal,
 | 
			
		||||
		      void *hdlr_data, void *signal_data)
 | 
			
		||||
{
 | 
			
		||||
	if (subsys != SS_L_INPUT)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	DEBUGP(DABIS, "Input Signal %u received\n", signal);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static struct ipaccess_unit bts_dev_info = {
 | 
			
		||||
	.unit_name	= "sysmoBTS",
 | 
			
		||||
	.equipvers	= "",	/* FIXME: read this from hw */
 | 
			
		||||
	.swversion	= PACKAGE_VERSION,
 | 
			
		||||
	.location1	= "",
 | 
			
		||||
	.location2	= "",
 | 
			
		||||
	.serno		= "",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct e1inp_line_ops line_ops = {
 | 
			
		||||
	.cfg = {
 | 
			
		||||
		.ipa = {
 | 
			
		||||
			.role	= E1INP_LINE_R_BTS,
 | 
			
		||||
			.dev	= &bts_dev_info,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	.sign_link_up	= sign_link_up,
 | 
			
		||||
	.sign_link_down	= sign_link_down,
 | 
			
		||||
	.sign_link	= sign_link_cb,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void abis_init(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	g_bts = bts;
 | 
			
		||||
 | 
			
		||||
	oml_init(&bts->mo);
 | 
			
		||||
	libosmo_abis_init(NULL);
 | 
			
		||||
 | 
			
		||||
	osmo_signal_register_handler(SS_L_INPUT, &inp_s_cbfn, bts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct e1inp_line *abis_open(struct gsm_bts *bts, char *dst_host,
 | 
			
		||||
			     char *model_name)
 | 
			
		||||
{
 | 
			
		||||
	struct e1inp_line *line;
 | 
			
		||||
 | 
			
		||||
	/* patch in various data from VTY and othe sources */
 | 
			
		||||
	line_ops.cfg.ipa.addr = dst_host;
 | 
			
		||||
	osmo_get_macaddr(bts_dev_info.mac_addr, "eth0");
 | 
			
		||||
	bts_dev_info.site_id = bts->ip_access.site_id;
 | 
			
		||||
	bts_dev_info.bts_id = bts->ip_access.bts_id;
 | 
			
		||||
	bts_dev_info.unit_name = model_name;
 | 
			
		||||
	if (bts->description)
 | 
			
		||||
		bts_dev_info.unit_name = bts->description;
 | 
			
		||||
	bts_dev_info.location2 = model_name;
 | 
			
		||||
 | 
			
		||||
	line = e1inp_line_find(0);
 | 
			
		||||
	if (!line)
 | 
			
		||||
		line = e1inp_line_create(0, "ipa");
 | 
			
		||||
	if (!line)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	e1inp_line_bind_ops(line, &line_ops);
 | 
			
		||||
 | 
			
		||||
	/* This will open the OML connection now */
 | 
			
		||||
	if (e1inp_line_update(line) < 0)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return line;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,170 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/amr.h>
 | 
			
		||||
 | 
			
		||||
void amr_log_mr_conf(int ss, int logl, const char *pfx,
 | 
			
		||||
		     struct amr_multirate_conf *amr_mrc)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	LOGP(ss, logl, "%s AMR MR Conf: num_modes=%u",
 | 
			
		||||
		pfx, amr_mrc->num_modes);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < amr_mrc->num_modes; i++)
 | 
			
		||||
		LOGPC(ss, logl, ", mode[%u] = %u/%u/%u",
 | 
			
		||||
			i, amr_mrc->bts_mode[i].mode,
 | 
			
		||||
			amr_mrc->bts_mode[i].threshold,
 | 
			
		||||
			amr_mrc->bts_mode[i].hysteresis);
 | 
			
		||||
	LOGPC(ss, logl, "\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int get_amr_mode_idx(const struct amr_multirate_conf *amr_mrc,
 | 
			
		||||
				   uint8_t cmi)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	for (i = 0; i < amr_mrc->num_modes; i++) {
 | 
			
		||||
		if (amr_mrc->bts_mode[i].mode == cmi)
 | 
			
		||||
			return i;
 | 
			
		||||
	}
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint8_t set_cmr_mode_idx(const struct amr_multirate_conf *amr_mrc,
 | 
			
		||||
				       uint8_t cmr)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Codec Mode Request is in upper 4 bits of RTP payload header,
 | 
			
		||||
	 * and we simply copy the CMR into the CMC */
 | 
			
		||||
	if (cmr == 0xF) {
 | 
			
		||||
		/* FIXME: we need some state about the last codec mode */
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = get_amr_mode_idx(amr_mrc, cmr);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		/* FIXME: we need some state about the last codec mode */
 | 
			
		||||
		LOGP(DRTP, LOGL_INFO, "RTP->L1: overriding CMR %u\n", cmr);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint8_t set_cmi_mode_idx(const struct amr_multirate_conf *amr_mrc,
 | 
			
		||||
				       uint8_t cmi)
 | 
			
		||||
{
 | 
			
		||||
	int rc = get_amr_mode_idx(amr_mrc, cmi);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DRTP, LOGL_ERROR, "AMR CMI %u not part of AMR MR set\n",
 | 
			
		||||
		     cmi);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void amr_set_mode_pref(uint8_t *data, const struct amr_multirate_conf *amr_mrc,
 | 
			
		||||
		      uint8_t cmi, uint8_t cmr)
 | 
			
		||||
{
 | 
			
		||||
	data[0] = set_cmi_mode_idx(amr_mrc, cmi);
 | 
			
		||||
	data[1] = set_cmr_mode_idx(amr_mrc, cmr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* parse a GSM 04.08 MultiRate Config IE (10.5.2.21aa) in a more
 | 
			
		||||
 * comfortable internal data structure */
 | 
			
		||||
int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc,
 | 
			
		||||
		      const uint8_t *mr_conf, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t mr_version = mr_conf[0] >> 5;
 | 
			
		||||
	uint8_t num_codecs = 0;
 | 
			
		||||
	int i, j = 0;
 | 
			
		||||
 | 
			
		||||
	if (mr_version != 1) {
 | 
			
		||||
		LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknown\n",
 | 
			
		||||
			mr_version);
 | 
			
		||||
		goto ret_einval;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* check number of active codecs */
 | 
			
		||||
	for (i = 0; i < 8; i++) {
 | 
			
		||||
		if (mr_conf[1] & (1 << i))
 | 
			
		||||
			num_codecs++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* check for minimum length */
 | 
			
		||||
	if (num_codecs == 0 ||
 | 
			
		||||
	    (num_codecs == 1 && len < 2) ||
 | 
			
		||||
	    (num_codecs == 2 && len < 4) ||
 | 
			
		||||
	    (num_codecs == 3 && len < 5) ||
 | 
			
		||||
	    (num_codecs == 4 && len < 6) ||
 | 
			
		||||
	    (num_codecs > 4)) {
 | 
			
		||||
		LOGP(DRSL, LOGL_ERROR, "AMR Multirate with %u modes len=%u "
 | 
			
		||||
		     "not possible\n", num_codecs, len);
 | 
			
		||||
		goto ret_einval;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* copy the first two octets of the IE */
 | 
			
		||||
	amr_mrc->gsm48_ie[0] = mr_conf[0];
 | 
			
		||||
	amr_mrc->gsm48_ie[1] = mr_conf[1];
 | 
			
		||||
 | 
			
		||||
	amr_mrc->num_modes = num_codecs;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 8; i++) {
 | 
			
		||||
		if (mr_conf[1] & (1 << i)) {
 | 
			
		||||
			amr_mrc->bts_mode[j++].mode = i;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (num_codecs >= 2) {
 | 
			
		||||
		amr_mrc->bts_mode[0].threshold = mr_conf[1] & 0x3F;
 | 
			
		||||
		amr_mrc->bts_mode[0].hysteresis = mr_conf[2] >> 4;
 | 
			
		||||
	}
 | 
			
		||||
	if (num_codecs >= 3) {
 | 
			
		||||
		amr_mrc->bts_mode[1].threshold =
 | 
			
		||||
			((mr_conf[2] & 0xF) << 2) | (mr_conf[3] >> 6);
 | 
			
		||||
		amr_mrc->bts_mode[1].hysteresis = (mr_conf[3] >> 2) & 0xF;
 | 
			
		||||
	}
 | 
			
		||||
	if (num_codecs >= 4) {
 | 
			
		||||
		amr_mrc->bts_mode[2].threshold =
 | 
			
		||||
			((mr_conf[3] & 0x3) << 4) | (mr_conf[4] >> 4);
 | 
			
		||||
		amr_mrc->bts_mode[2].hysteresis = mr_conf[4] & 0xF;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return num_codecs;
 | 
			
		||||
 | 
			
		||||
ret_einval:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*! \brief determine AMR initial codec mode for given logical channel 
 | 
			
		||||
 *  \returns integer between 0..3 for AMR codce mode 1..4 */
 | 
			
		||||
unsigned int amr_get_initial_mode(struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr;
 | 
			
		||||
	struct gsm48_multi_rate_conf *mr_conf =
 | 
			
		||||
			(struct gsm48_multi_rate_conf *) amr_mrc->gsm48_ie;
 | 
			
		||||
 | 
			
		||||
	if (mr_conf->icmi) {
 | 
			
		||||
		/* initial mode given, coding in TS 05.09 3.4.1 */
 | 
			
		||||
		return mr_conf->smod;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* implicit rule according to TS 05.09 Chapter 3.4.3 */
 | 
			
		||||
		switch (amr_mrc->num_modes) {
 | 
			
		||||
		case 2:
 | 
			
		||||
		case 3:
 | 
			
		||||
			/* return the most robust */
 | 
			
		||||
			return 0;
 | 
			
		||||
		case 4:
 | 
			
		||||
			/* return the second-most robust */
 | 
			
		||||
			return 1;
 | 
			
		||||
		case 1:
 | 
			
		||||
		default:
 | 
			
		||||
			/* return the only mode we have */
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,740 @@
 | 
			
		||||
/* BTS support code common to all supported BTS models */
 | 
			
		||||
 | 
			
		||||
/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
 | 
			
		||||
 * (C) 2011 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/select.h>
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/core/talloc.h>
 | 
			
		||||
#include <osmocom/core/stats.h>
 | 
			
		||||
#include <osmocom/core/rate_ctr.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
 | 
			
		||||
#include <osmocom/gsm/lapdm.h>
 | 
			
		||||
#include <osmocom/trau/osmo_ortp.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/abis.h>
 | 
			
		||||
#include <osmo-bts/bts.h>
 | 
			
		||||
#include <osmo-bts/bts_model.h>
 | 
			
		||||
#include <osmo-bts/dtx_dl_amr_fsm.h>
 | 
			
		||||
#include <osmo-bts/pcuif_proto.h>
 | 
			
		||||
#include <osmo-bts/rsl.h>
 | 
			
		||||
#include <osmo-bts/oml.h>
 | 
			
		||||
#include <osmo-bts/signal.h>
 | 
			
		||||
#include <osmo-bts/dtx_dl_amr_fsm.h>
 | 
			
		||||
 | 
			
		||||
#define MIN_QUAL_RACH    5.0f   /* at least  5 dB C/I */
 | 
			
		||||
#define MIN_QUAL_NORM   -0.5f   /* at least -1 dB C/I */
 | 
			
		||||
 | 
			
		||||
static void bts_update_agch_max_queue_length(struct gsm_bts *bts);
 | 
			
		||||
 | 
			
		||||
struct gsm_network bts_gsmnet = {
 | 
			
		||||
	.bts_list = { &bts_gsmnet.bts_list, &bts_gsmnet.bts_list },
 | 
			
		||||
	.num_bts = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void *tall_bts_ctx;
 | 
			
		||||
 | 
			
		||||
/* Table 3.1 TS 04.08: Values of parameter S */
 | 
			
		||||
static const uint8_t tx_integer[] = {
 | 
			
		||||
	3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 25, 32, 50,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t s_values[][2] = {
 | 
			
		||||
	{ 55, 41 }, { 76, 52 }, { 109, 58 }, { 163, 86 }, { 217, 115 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int bts_signal_cbfn(unsigned int subsys, unsigned int signal,
 | 
			
		||||
			   void *hdlr_data, void *signal_data)
 | 
			
		||||
{
 | 
			
		||||
	if (subsys == SS_GLOBAL && signal == S_NEW_SYSINFO) {
 | 
			
		||||
		struct gsm_bts *bts = signal_data;
 | 
			
		||||
 | 
			
		||||
		bts_update_agch_max_queue_length(bts);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct rate_ctr_desc bts_ctr_desc[] = {
 | 
			
		||||
	[BTS_CTR_PAGING_RCVD] =		{"paging:rcvd", "Received paging requests (Abis)"},
 | 
			
		||||
	[BTS_CTR_PAGING_DROP] =		{"paging:drop", "Dropped paging requests (Abis)"},
 | 
			
		||||
	[BTS_CTR_PAGING_SENT] =		{"paging:sent", "Sent paging requests (Um)"},
 | 
			
		||||
 | 
			
		||||
	[BTS_CTR_RACH_RCVD] =		{"rach:rcvd", "Received RACH requests (Um)"},
 | 
			
		||||
	[BTS_CTR_RACH_DROP] =		{"rach:drop", "Dropped RACH requests (Um)"},
 | 
			
		||||
	[BTS_CTR_RACH_HO] =		{"rach:handover", "Received RACH requests (Handover)"},
 | 
			
		||||
	[BTS_CTR_RACH_CS] =		{"rach:cs", "Received RACH requests (CS/Abis)"},
 | 
			
		||||
	[BTS_CTR_RACH_PS] =		{"rach:ps", "Received RACH requests (PS/PCU)"},
 | 
			
		||||
 | 
			
		||||
	[BTS_CTR_AGCH_RCVD] =		{"agch:rcvd", "Received AGCH requests (Abis)"},
 | 
			
		||||
	[BTS_CTR_AGCH_SENT] =		{"agch:sent", "Sent AGCH requests (Abis)"},
 | 
			
		||||
	[BTS_CTR_AGCH_DELETED] =	{"agch:delete", "Sent AGCH DELETE IND (Abis)"},
 | 
			
		||||
};
 | 
			
		||||
static const struct rate_ctr_group_desc bts_ctrg_desc = {
 | 
			
		||||
	"bts",
 | 
			
		||||
	"base transceiver station",
 | 
			
		||||
	OSMO_STATS_CLASS_GLOBAL,
 | 
			
		||||
	ARRAY_SIZE(bts_ctr_desc),
 | 
			
		||||
	bts_ctr_desc
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Initialize the BTS (and TRX) data structures, called before config
 | 
			
		||||
 * file reading */
 | 
			
		||||
int bts_init(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
	int rc, i;
 | 
			
		||||
	static int initialized = 0;
 | 
			
		||||
	void *tall_rtp_ctx;
 | 
			
		||||
 | 
			
		||||
	/* add to list of BTSs */
 | 
			
		||||
	llist_add_tail(&bts->list, &bts_gsmnet.bts_list);
 | 
			
		||||
 | 
			
		||||
	bts->band = GSM_BAND_1800;
 | 
			
		||||
 | 
			
		||||
	INIT_LLIST_HEAD(&bts->agch_queue.queue);
 | 
			
		||||
	bts->agch_queue.length = 0;
 | 
			
		||||
 | 
			
		||||
	bts->ctrs = rate_ctr_group_alloc(bts, &bts_ctrg_desc, bts->nr);
 | 
			
		||||
 | 
			
		||||
	/* enable management with default levels,
 | 
			
		||||
	 * raise threshold to GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DISABLE to
 | 
			
		||||
	 * disable this feature.
 | 
			
		||||
	 */
 | 
			
		||||
	bts->agch_queue.low_level = GSM_BTS_AGCH_QUEUE_LOW_LEVEL_DEFAULT;
 | 
			
		||||
	bts->agch_queue.high_level = GSM_BTS_AGCH_QUEUE_HIGH_LEVEL_DEFAULT;
 | 
			
		||||
	bts->agch_queue.thresh_level = GSM_BTS_AGCH_QUEUE_THRESH_LEVEL_DEFAULT;
 | 
			
		||||
 | 
			
		||||
	/* configurable via VTY */
 | 
			
		||||
	bts->paging_state = paging_init(bts, 200, 0);
 | 
			
		||||
	bts->ul_power_target = -75;	/* dBm default */
 | 
			
		||||
	bts->rtp_jitter_adaptive = false;
 | 
			
		||||
 | 
			
		||||
	/* configurable via OML */
 | 
			
		||||
	bts->load.ccch.load_ind_period = 112;
 | 
			
		||||
	load_timer_start(bts);
 | 
			
		||||
	bts->rtp_jitter_buf_ms = 100;
 | 
			
		||||
	bts->max_ta = 63;
 | 
			
		||||
	bts->ny1 = 4;
 | 
			
		||||
	bts->t3105_ms = 300;
 | 
			
		||||
	bts->min_qual_rach = MIN_QUAL_RACH;
 | 
			
		||||
	bts->min_qual_norm = MIN_QUAL_NORM;
 | 
			
		||||
	bts->max_ber10k_rach = 1707; /* 7 of 41 bits is Eb/N0 of 0 dB = 0.1707 */
 | 
			
		||||
	bts->pcu.sock_path = talloc_strdup(bts, PCU_SOCK_DEFAULT);
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(bts->t200_ms); i++)
 | 
			
		||||
		bts->t200_ms[i] = oml_default_t200_ms[i];
 | 
			
		||||
 | 
			
		||||
	/* default RADIO_LINK_TIMEOUT */
 | 
			
		||||
	bts->radio_link_timeout = 32;
 | 
			
		||||
 | 
			
		||||
	/* Start with the site manager */
 | 
			
		||||
	oml_mo_state_init(&bts->site_mgr.mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
 | 
			
		||||
 | 
			
		||||
	/* set BTS to dependency */
 | 
			
		||||
	oml_mo_state_init(&bts->mo, -1, NM_AVSTATE_DEPENDENCY);
 | 
			
		||||
	oml_mo_state_init(&bts->gprs.nse.mo, -1, NM_AVSTATE_DEPENDENCY);
 | 
			
		||||
	oml_mo_state_init(&bts->gprs.cell.mo, -1, NM_AVSTATE_DEPENDENCY);
 | 
			
		||||
	oml_mo_state_init(&bts->gprs.nsvc[0].mo, -1, NM_AVSTATE_DEPENDENCY);
 | 
			
		||||
	oml_mo_state_init(&bts->gprs.nsvc[1].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
 | 
			
		||||
 | 
			
		||||
	/* initialize bts data structure */
 | 
			
		||||
	llist_for_each_entry(trx, &bts->trx_list, list) {
 | 
			
		||||
		struct trx_power_params *tpp = &trx->power_params;
 | 
			
		||||
		int i;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
 | 
			
		||||
			struct gsm_bts_trx_ts *ts = &trx->ts[i];
 | 
			
		||||
			int k;
 | 
			
		||||
 | 
			
		||||
			for (k = 0; k < ARRAY_SIZE(ts->lchan); k++) {
 | 
			
		||||
				struct gsm_lchan *lchan = &ts->lchan[k];
 | 
			
		||||
				INIT_LLIST_HEAD(&lchan->dl_tch_queue);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		/* Default values for the power adjustments */
 | 
			
		||||
		tpp->ramp.max_initial_pout_mdBm = to_mdB(0);
 | 
			
		||||
		tpp->ramp.step_size_mdB = to_mdB(2);
 | 
			
		||||
		tpp->ramp.step_interval_sec = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* allocate a talloc pool for ORTP to ensure it doesn't have to go back
 | 
			
		||||
	 * to the libc malloc all the time */
 | 
			
		||||
	tall_rtp_ctx = talloc_pool(tall_bts_ctx, 262144);
 | 
			
		||||
	osmo_rtp_init(tall_rtp_ctx);
 | 
			
		||||
 | 
			
		||||
	rc = bts_model_init(bts);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		llist_del(&bts->list);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bts_gsmnet.num_bts++;
 | 
			
		||||
 | 
			
		||||
	if (!initialized) {
 | 
			
		||||
		osmo_signal_register_handler(SS_GLOBAL, bts_signal_cbfn, NULL);
 | 
			
		||||
		initialized = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	INIT_LLIST_HEAD(&bts->smscb_state.queue);
 | 
			
		||||
	INIT_LLIST_HEAD(&bts->oml_queue);
 | 
			
		||||
 | 
			
		||||
	/* register DTX DL FSM */
 | 
			
		||||
	rc = osmo_fsm_register(&dtx_dl_amr_fsm);
 | 
			
		||||
	OSMO_ASSERT(rc == 0);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void shutdown_timer_cb(void *data)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "Shutdown timer expired\n");
 | 
			
		||||
	exit(42);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct osmo_timer_list shutdown_timer = {
 | 
			
		||||
	.cb = &shutdown_timer_cb,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void bts_shutdown(struct gsm_bts *bts, const char *reason)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
 | 
			
		||||
	if (osmo_timer_pending(&shutdown_timer)) {
 | 
			
		||||
		LOGP(DOML, LOGL_NOTICE,
 | 
			
		||||
			"BTS is already being shutdown.\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOGP(DOML, LOGL_NOTICE, "Shutting down BTS %u, Reason %s\n",
 | 
			
		||||
		bts->nr, reason);
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry_reverse(trx, &bts->trx_list, list) {
 | 
			
		||||
		bts_model_trx_deact_rf(trx);
 | 
			
		||||
		bts_model_trx_close(trx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* shedule a timer to make sure select loop logic can run again
 | 
			
		||||
	 * to dispatch any pending primitives */
 | 
			
		||||
	osmo_timer_schedule(&shutdown_timer, 3, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* main link is established, send status report */
 | 
			
		||||
int bts_link_estab(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	int i, j;
 | 
			
		||||
 | 
			
		||||
	LOGP(DSUM, LOGL_INFO, "Main link established, sending Status'.\n");
 | 
			
		||||
 | 
			
		||||
	/* BTS and SITE MGR are EANBLED, BTS is DEPENDENCY */
 | 
			
		||||
	oml_tx_state_changed(&bts->site_mgr.mo);
 | 
			
		||||
	oml_tx_state_changed(&bts->mo);
 | 
			
		||||
 | 
			
		||||
	/* those should all be in DEPENDENCY */
 | 
			
		||||
	oml_tx_state_changed(&bts->gprs.nse.mo);
 | 
			
		||||
	oml_tx_state_changed(&bts->gprs.cell.mo);
 | 
			
		||||
	oml_tx_state_changed(&bts->gprs.nsvc[0].mo);
 | 
			
		||||
	oml_tx_state_changed(&bts->gprs.nsvc[1].mo);
 | 
			
		||||
 | 
			
		||||
	/* All other objects start off-line until the BTS Model code says otherwise */
 | 
			
		||||
	for (i = 0; i < bts->num_trx; i++) {
 | 
			
		||||
		struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i);
 | 
			
		||||
 | 
			
		||||
		oml_tx_state_changed(&trx->mo);
 | 
			
		||||
		oml_tx_state_changed(&trx->bb_transc.mo);
 | 
			
		||||
 | 
			
		||||
		for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {
 | 
			
		||||
			struct gsm_bts_trx_ts *ts = &trx->ts[j];
 | 
			
		||||
 | 
			
		||||
			oml_tx_state_changed(&ts->mo);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bts_model_oml_estab(bts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* RSL link is established, send status report */
 | 
			
		||||
int trx_link_estab(struct gsm_bts_trx *trx)
 | 
			
		||||
{
 | 
			
		||||
	struct e1inp_sign_link *link = trx->rsl_link;
 | 
			
		||||
	uint8_t radio_state = link ?  NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	LOGP(DSUM, LOGL_INFO, "RSL link (TRX %02x) state changed to %s, sending Status'.\n",
 | 
			
		||||
		trx->nr, link ? "up" : "down");
 | 
			
		||||
 | 
			
		||||
	oml_mo_state_chg(&trx->mo, radio_state, NM_AVSTATE_OK);
 | 
			
		||||
 | 
			
		||||
	if (link)
 | 
			
		||||
		rc = rsl_tx_rf_res(trx);
 | 
			
		||||
	else
 | 
			
		||||
		rc = bts_model_trx_deact_rf(trx);
 | 
			
		||||
	if (rc < 0)
 | 
			
		||||
		oml_fail_rep(OSMO_EVT_MAJ_RSL_FAIL,
 | 
			
		||||
			     link ? "Failed to establish RSL link (%d)" :
 | 
			
		||||
			     "Failed to deactivate RF (%d)", rc);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* set the availability of the TRX (used by PHY driver) */
 | 
			
		||||
int trx_set_available(struct gsm_bts_trx *trx, int avail)
 | 
			
		||||
{
 | 
			
		||||
	int tn;
 | 
			
		||||
 | 
			
		||||
	LOGP(DSUM, LOGL_INFO, "TRX(%d): Setting available = %d\n",
 | 
			
		||||
		trx->nr, avail);
 | 
			
		||||
	if (avail) {
 | 
			
		||||
		/* FIXME: This needs to be sorted out */
 | 
			
		||||
#if 0
 | 
			
		||||
		oml_mo_state_chg(&trx->mo,  NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);
 | 
			
		||||
		oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE);
 | 
			
		||||
		for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++)
 | 
			
		||||
			oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
 | 
			
		||||
#endif
 | 
			
		||||
	} else {
 | 
			
		||||
		oml_mo_state_chg(&trx->mo,  NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
 | 
			
		||||
		oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_NOT_INSTALLED);
 | 
			
		||||
 | 
			
		||||
		for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++)
 | 
			
		||||
			oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lchan_init_lapdm(struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	struct lapdm_channel *lc = &lchan->lapdm_ch;
 | 
			
		||||
 | 
			
		||||
	lapdm_channel_init(lc, LAPDM_MODE_BTS);
 | 
			
		||||
	lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY);
 | 
			
		||||
	lapdm_channel_set_l1(lc, NULL, lchan);
 | 
			
		||||
	lapdm_channel_set_l3(lc, lapdm_rll_tx_cb, lchan);
 | 
			
		||||
	oml_set_lchan_t200(lchan);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define CCCH_RACH_RATIO_COMBINED256      (256*1/9)
 | 
			
		||||
#define CCCH_RACH_RATIO_SEPARATE256      (256*10/55)
 | 
			
		||||
 | 
			
		||||
int bts_agch_max_queue_length(int T, int bcch_conf)
 | 
			
		||||
{
 | 
			
		||||
	int S, ccch_rach_ratio256, i;
 | 
			
		||||
	int T_group = 0;
 | 
			
		||||
	int is_ccch_comb = 0;
 | 
			
		||||
 | 
			
		||||
	if (bcch_conf == RSL_BCCH_CCCH_CONF_1_C)
 | 
			
		||||
		is_ccch_comb = 1;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The calculation is based on the ratio of the number RACH slots and
 | 
			
		||||
	 * CCCH blocks per time:
 | 
			
		||||
	 *   Lmax = (T + 2*S) / R_RACH * R_CCCH
 | 
			
		||||
	 * where
 | 
			
		||||
	 *   T3126_min = (T + 2*S) / R_RACH, as defined in GSM 04.08, 11.1.1
 | 
			
		||||
	 *   R_RACH is the RACH slot rate (e.g. RACHs per multiframe)
 | 
			
		||||
	 *   R_CCCH is the CCCH block rate (same time base like R_RACH)
 | 
			
		||||
	 *   S and T are defined in GSM 04.08, 3.3.1.1.2
 | 
			
		||||
	 * The ratio is mainly influenced by the downlink only channels
 | 
			
		||||
	 * (BCCH, FCCH, SCH, CBCH) that can not be used for CCCH.
 | 
			
		||||
	 * An estimation with an error of < 10% is used:
 | 
			
		||||
	 *   ~ 1/9 if CCCH is combined with SDCCH, and
 | 
			
		||||
	 *   ~ 1/5.5 otherwise.
 | 
			
		||||
	 */
 | 
			
		||||
	ccch_rach_ratio256 = is_ccch_comb ?
 | 
			
		||||
		CCCH_RACH_RATIO_COMBINED256 :
 | 
			
		||||
		CCCH_RACH_RATIO_SEPARATE256;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(tx_integer); i++) {
 | 
			
		||||
		if (tx_integer[i] == T) {
 | 
			
		||||
			T_group = i % 5;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	S = s_values[T_group][is_ccch_comb];
 | 
			
		||||
 | 
			
		||||
	return (T + 2 * S) * ccch_rach_ratio256 / 256;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void bts_update_agch_max_queue_length(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm48_system_information_type_3 *si3;
 | 
			
		||||
	int old_max_length = bts->agch_queue.max_length;
 | 
			
		||||
 | 
			
		||||
	if (!(bts->si_valid & (1<<SYSINFO_TYPE_3)))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	si3 = GSM_BTS_SI(bts, SYSINFO_TYPE_3);
 | 
			
		||||
 | 
			
		||||
	bts->agch_queue.max_length =
 | 
			
		||||
		bts_agch_max_queue_length(si3->rach_control.tx_integer,
 | 
			
		||||
					  si3->control_channel_desc.ccch_conf);
 | 
			
		||||
 | 
			
		||||
	if (bts->agch_queue.max_length != old_max_length)
 | 
			
		||||
		LOGP(DRSL, LOGL_INFO, "Updated AGCH max queue length to %d\n",
 | 
			
		||||
		     bts->agch_queue.max_length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define REQ_REFS_PER_IMM_ASS_REJ 4
 | 
			
		||||
static int store_imm_ass_rej_refs(struct gsm48_imm_ass_rej *rej,
 | 
			
		||||
				    struct gsm48_req_ref *req_refs,
 | 
			
		||||
				    uint8_t *wait_inds,
 | 
			
		||||
				    int count)
 | 
			
		||||
{
 | 
			
		||||
	switch (count) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		/* TODO: Warning ? */
 | 
			
		||||
		return 0;
 | 
			
		||||
	default:
 | 
			
		||||
		count = 4;
 | 
			
		||||
		rej->req_ref4 = req_refs[3];
 | 
			
		||||
		rej->wait_ind4 = wait_inds[3];
 | 
			
		||||
		/* fall through */
 | 
			
		||||
	case 3:
 | 
			
		||||
		rej->req_ref3 = req_refs[2];
 | 
			
		||||
		rej->wait_ind3 = wait_inds[2];
 | 
			
		||||
		/* fall through */
 | 
			
		||||
	case 2:
 | 
			
		||||
		rej->req_ref2 = req_refs[1];
 | 
			
		||||
		rej->wait_ind2 = wait_inds[1];
 | 
			
		||||
		/* fall through */
 | 
			
		||||
	case 1:
 | 
			
		||||
		rej->req_ref1 = req_refs[0];
 | 
			
		||||
		rej->wait_ind1 = wait_inds[0];
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (count) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		rej->req_ref2 = req_refs[0];
 | 
			
		||||
		rej->wait_ind2 = wait_inds[0];
 | 
			
		||||
		/* fall through */
 | 
			
		||||
	case 2:
 | 
			
		||||
		rej->req_ref3 = req_refs[0];
 | 
			
		||||
		rej->wait_ind3 = wait_inds[0];
 | 
			
		||||
		/* fall through */
 | 
			
		||||
	case 3:
 | 
			
		||||
		rej->req_ref4 = req_refs[0];
 | 
			
		||||
		rej->wait_ind4 = wait_inds[0];
 | 
			
		||||
		/* fall through */
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int extract_imm_ass_rej_refs(struct gsm48_imm_ass_rej *rej,
 | 
			
		||||
				    struct gsm48_req_ref *req_refs,
 | 
			
		||||
				    uint8_t *wait_inds)
 | 
			
		||||
{
 | 
			
		||||
	int count = 0;
 | 
			
		||||
	req_refs[count] = rej->req_ref1;
 | 
			
		||||
	wait_inds[count] = rej->wait_ind1;
 | 
			
		||||
	count++;
 | 
			
		||||
 | 
			
		||||
	if (memcmp(&rej->req_ref1, &rej->req_ref2, sizeof(rej->req_ref2))) {
 | 
			
		||||
		req_refs[count] = rej->req_ref2;
 | 
			
		||||
		wait_inds[count] = rej->wait_ind2;
 | 
			
		||||
		count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (memcmp(&rej->req_ref1, &rej->req_ref3, sizeof(rej->req_ref3)) &&
 | 
			
		||||
	    memcmp(&rej->req_ref2, &rej->req_ref3, sizeof(rej->req_ref3))) {
 | 
			
		||||
		req_refs[count] = rej->req_ref3;
 | 
			
		||||
		wait_inds[count] = rej->wait_ind3;
 | 
			
		||||
		count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (memcmp(&rej->req_ref1, &rej->req_ref4, sizeof(rej->req_ref4)) &&
 | 
			
		||||
	    memcmp(&rej->req_ref2, &rej->req_ref4, sizeof(rej->req_ref4)) &&
 | 
			
		||||
	    memcmp(&rej->req_ref3, &rej->req_ref4, sizeof(rej->req_ref4))) {
 | 
			
		||||
		req_refs[count] = rej->req_ref4;
 | 
			
		||||
		wait_inds[count] = rej->wait_ind4;
 | 
			
		||||
		count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int try_merge_imm_ass_rej(struct gsm48_imm_ass_rej *old_rej,
 | 
			
		||||
				 struct gsm48_imm_ass_rej *new_rej)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm48_req_ref req_refs[2 * REQ_REFS_PER_IMM_ASS_REJ];
 | 
			
		||||
	uint8_t wait_inds[2 * REQ_REFS_PER_IMM_ASS_REJ];
 | 
			
		||||
	int count = 0;
 | 
			
		||||
	int stored = 0;
 | 
			
		||||
 | 
			
		||||
	if (new_rej->msg_type != GSM48_MT_RR_IMM_ASS_REJ)
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (old_rej->msg_type != GSM48_MT_RR_IMM_ASS_REJ)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* GSM 08.58, 5.7
 | 
			
		||||
	 * -> The BTS may combine serveral IMM.ASS.REJ messages
 | 
			
		||||
	 * -> Identical request refs in one message may be squeezed
 | 
			
		||||
	 *
 | 
			
		||||
	 * GSM 04.08, 9.1.20.2
 | 
			
		||||
	 * -> Request ref and wait ind are duplicated to fill the message
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* Extract all entries */
 | 
			
		||||
	count = extract_imm_ass_rej_refs(old_rej,
 | 
			
		||||
					 &req_refs[count], &wait_inds[count]);
 | 
			
		||||
	if (count == REQ_REFS_PER_IMM_ASS_REJ)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	count += extract_imm_ass_rej_refs(new_rej,
 | 
			
		||||
					  &req_refs[count], &wait_inds[count]);
 | 
			
		||||
 | 
			
		||||
	/* Store entries into old message */
 | 
			
		||||
	stored = store_imm_ass_rej_refs(old_rej,
 | 
			
		||||
					&req_refs[stored], &wait_inds[stored],
 | 
			
		||||
					count);
 | 
			
		||||
	count -= stored;
 | 
			
		||||
	if (count == 0)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	/* Store remaining entries into new message */
 | 
			
		||||
	stored += store_imm_ass_rej_refs(new_rej,
 | 
			
		||||
					 &req_refs[stored], &wait_inds[stored],
 | 
			
		||||
					 count);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg)
 | 
			
		||||
{
 | 
			
		||||
	int hard_limit = 1000;
 | 
			
		||||
	struct gsm48_imm_ass_rej *imm_ass_cmd = msgb_l3(msg);
 | 
			
		||||
 | 
			
		||||
	if (bts->agch_queue.length > hard_limit) {
 | 
			
		||||
		LOGP(DSUM, LOGL_ERROR,
 | 
			
		||||
		     "AGCH: too many messages in queue, "
 | 
			
		||||
		     "refusing message type 0x%02x, length = %d/%d\n",
 | 
			
		||||
		     ((struct gsm48_imm_ass *)msgb_l3(msg))->msg_type,
 | 
			
		||||
		     bts->agch_queue.length, bts->agch_queue.max_length);
 | 
			
		||||
 | 
			
		||||
		bts->agch_queue.rejected_msgs++;
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bts->agch_queue.length > 0) {
 | 
			
		||||
		struct msgb *last_msg =
 | 
			
		||||
			llist_entry(bts->agch_queue.queue.prev, struct msgb, list);
 | 
			
		||||
		struct gsm48_imm_ass_rej *last_imm_ass_rej = msgb_l3(last_msg);
 | 
			
		||||
 | 
			
		||||
		if (try_merge_imm_ass_rej(last_imm_ass_rej, imm_ass_cmd)) {
 | 
			
		||||
			bts->agch_queue.merged_msgs++;
 | 
			
		||||
			msgb_free(msg);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msgb_enqueue(&bts->agch_queue.queue, msg);
 | 
			
		||||
	bts->agch_queue.length++;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct msgb *bts_agch_dequeue(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct msgb *msg = msgb_dequeue(&bts->agch_queue.queue);
 | 
			
		||||
	if (!msg)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	bts->agch_queue.length--;
 | 
			
		||||
	return msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Remove lower prio messages if the queue has grown too long.
 | 
			
		||||
 *
 | 
			
		||||
 * \return 0 iff the number of messages in the queue would fit into the AGCH
 | 
			
		||||
 *         reserved part of the CCCH.
 | 
			
		||||
 */
 | 
			
		||||
static void compact_agch_queue(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct msgb *msg, *msg2;
 | 
			
		||||
	int max_len, slope, offs;
 | 
			
		||||
	int level_low = bts->agch_queue.low_level;
 | 
			
		||||
	int level_high = bts->agch_queue.high_level;
 | 
			
		||||
	int level_thres = bts->agch_queue.thresh_level;
 | 
			
		||||
 | 
			
		||||
	max_len = bts->agch_queue.max_length;
 | 
			
		||||
 | 
			
		||||
	if (max_len == 0)
 | 
			
		||||
		max_len = 1;
 | 
			
		||||
 | 
			
		||||
	if (bts->agch_queue.length < max_len * level_thres / 100)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* p^
 | 
			
		||||
	 * 1+      /'''''
 | 
			
		||||
	 *  |     /
 | 
			
		||||
	 *  |    /
 | 
			
		||||
	 * 0+---/--+----+--> Q length
 | 
			
		||||
	 *    low high max_len
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	offs = max_len * level_low / 100;
 | 
			
		||||
	if (level_high > level_low)
 | 
			
		||||
		slope = 0x10000 * 100 / (level_high - level_low);
 | 
			
		||||
	else
 | 
			
		||||
		slope = 0x10000 * max_len; /* p_drop >= 1 if len > offs */
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry_safe(msg, msg2, &bts->agch_queue.queue, list) {
 | 
			
		||||
		struct gsm48_imm_ass *imm_ass_cmd = msgb_l3(msg);
 | 
			
		||||
		int p_drop;
 | 
			
		||||
 | 
			
		||||
		if (imm_ass_cmd->msg_type != GSM48_MT_RR_IMM_ASS_REJ)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		/* IMMEDIATE ASSIGN REJECT */
 | 
			
		||||
 | 
			
		||||
		p_drop = (bts->agch_queue.length - offs) * slope / max_len;
 | 
			
		||||
 | 
			
		||||
		if ((random() & 0xffff) >= p_drop)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		llist_del(&msg->list);
 | 
			
		||||
		bts->agch_queue.length--;
 | 
			
		||||
		msgb_free(msg);
 | 
			
		||||
 | 
			
		||||
		bts->agch_queue.dropped_msgs++;
 | 
			
		||||
	}
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt,
 | 
			
		||||
		      int is_ag_res)
 | 
			
		||||
{
 | 
			
		||||
	struct msgb *msg = NULL;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	int is_empty = 1;
 | 
			
		||||
 | 
			
		||||
	/* Do queue house keeping.
 | 
			
		||||
	 * This needs to be done every time a CCCH message is requested, since
 | 
			
		||||
	 * the queue max length is calculated based on the CCCH block rate and
 | 
			
		||||
	 * PCH messages also reduce the drain of the AGCH queue.
 | 
			
		||||
	 */
 | 
			
		||||
	compact_agch_queue(bts);
 | 
			
		||||
 | 
			
		||||
	/* Check for paging messages first if this is PCH */
 | 
			
		||||
	if (!is_ag_res)
 | 
			
		||||
		rc = paging_gen_msg(bts->paging_state, out_buf, gt, &is_empty);
 | 
			
		||||
 | 
			
		||||
	/* Check whether the block may be overwritten */
 | 
			
		||||
	if (!is_empty)
 | 
			
		||||
		return rc;
 | 
			
		||||
 | 
			
		||||
	msg = bts_agch_dequeue(bts);
 | 
			
		||||
	if (!msg)
 | 
			
		||||
		return rc;
 | 
			
		||||
 | 
			
		||||
	rate_ctr_inc2(bts->ctrs, BTS_CTR_AGCH_SENT);
 | 
			
		||||
 | 
			
		||||
	/* Copy AGCH message */
 | 
			
		||||
	memcpy(out_buf, msgb_l3(msg), msgb_l3len(msg));
 | 
			
		||||
	rc = msgb_l3len(msg);
 | 
			
		||||
	msgb_free(msg);
 | 
			
		||||
 | 
			
		||||
	if (is_ag_res)
 | 
			
		||||
		bts->agch_queue.agch_msgs++;
 | 
			
		||||
	else
 | 
			
		||||
		bts->agch_queue.pch_msgs++;
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bts_supports_cipher(struct gsm_bts *bts, int rsl_cipher)
 | 
			
		||||
{
 | 
			
		||||
	int sup;
 | 
			
		||||
 | 
			
		||||
	if (rsl_cipher < 1 || rsl_cipher > 8)
 | 
			
		||||
		return -ENOTSUP;
 | 
			
		||||
 | 
			
		||||
	/* No encryption is always supported */
 | 
			
		||||
	if (rsl_cipher == 1)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	sup =  (1 << (rsl_cipher - 2)) & bts->support.ciphers;
 | 
			
		||||
	return sup > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx)
 | 
			
		||||
{
 | 
			
		||||
	return trx->ms_power_control == 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gsm_time *get_time(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	return &bts->gsm_time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bts_supports_cm(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,
 | 
			
		||||
		    enum gsm48_chan_mode cm)
 | 
			
		||||
{
 | 
			
		||||
	enum gsm_bts_features feature = _NUM_BTS_FEAT;
 | 
			
		||||
 | 
			
		||||
	/* Before the requested pchan/cm combination can be checked, we need to
 | 
			
		||||
	 * convert it to a feature identifier we can check */
 | 
			
		||||
	if (pchan == GSM_PCHAN_TCH_F) {
 | 
			
		||||
		switch(cm) {
 | 
			
		||||
		case GSM48_CMODE_SPEECH_V1:
 | 
			
		||||
			feature	= BTS_FEAT_SPEECH_F_V1;
 | 
			
		||||
			break;
 | 
			
		||||
		case GSM48_CMODE_SPEECH_EFR:
 | 
			
		||||
			feature	= BTS_FEAT_SPEECH_F_EFR;
 | 
			
		||||
			break;
 | 
			
		||||
		case GSM48_CMODE_SPEECH_AMR:
 | 
			
		||||
			feature = BTS_FEAT_SPEECH_F_AMR;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			/* Invalid speech codec type => Not supported! */
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (pchan == GSM_PCHAN_TCH_H) {
 | 
			
		||||
		switch(cm) {
 | 
			
		||||
		case GSM48_CMODE_SPEECH_V1:
 | 
			
		||||
			feature	= BTS_FEAT_SPEECH_H_V1;
 | 
			
		||||
			break;
 | 
			
		||||
		case GSM48_CMODE_SPEECH_AMR:
 | 
			
		||||
			feature = BTS_FEAT_SPEECH_H_AMR;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			/* Invalid speech codec type => Not supported! */
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check if the feature is supported by this BTS */
 | 
			
		||||
	if (gsm_bts_has_feature(bts, feature))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,93 @@
 | 
			
		||||
/* Control Interface for osmo-bts */
 | 
			
		||||
 | 
			
		||||
/* (C) 2014 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
 | 
			
		||||
#include <osmocom/ctrl/control_cmd.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
#include <osmo-bts/tx_power.h>
 | 
			
		||||
#include <osmo-bts/signal.h>
 | 
			
		||||
#include <osmo-bts/oml.h>
 | 
			
		||||
#include <osmo-bts/bts.h>
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE(therm_att, "thermal-attenuation");
 | 
			
		||||
static int get_therm_att(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx = cmd->node;
 | 
			
		||||
	struct trx_power_params *tpp = &trx->power_params;
 | 
			
		||||
 | 
			
		||||
	cmd->reply = talloc_asprintf(cmd, "%d", tpp->thermal_attenuation_mdB);
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int set_therm_att(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx = cmd->node;
 | 
			
		||||
	struct trx_power_params *tpp = &trx->power_params;
 | 
			
		||||
	int val = atoi(cmd->value);
 | 
			
		||||
 | 
			
		||||
	printf("set_therm_att(trx=%p, tpp=%p)\n", trx, tpp);
 | 
			
		||||
 | 
			
		||||
	tpp->thermal_attenuation_mdB = val;
 | 
			
		||||
 | 
			
		||||
	power_ramp_start(trx, tpp->p_total_cur_mdBm, 0);
 | 
			
		||||
 | 
			
		||||
	return get_therm_att(cmd, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int verify_therm_att(struct ctrl_cmd *cmd, const char *value, void *data)
 | 
			
		||||
{
 | 
			
		||||
	int val = atoi(value);
 | 
			
		||||
 | 
			
		||||
	/* permit between 0 to 40 dB attenuation */
 | 
			
		||||
	if (val < 0 || val > to_mdB(40))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_WO_NOVRF(oml_alert, "oml-alert");
 | 
			
		||||
static int set_oml_alert(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	/* Note: we expect signal dispatch to be synchronous */
 | 
			
		||||
	osmo_signal_dispatch(SS_FAIL, OSMO_EVT_EXT_ALARM, cmd->value);
 | 
			
		||||
 | 
			
		||||
	cmd->reply = "OK";
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bts_ctrl_cmds_install(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_therm_att);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_oml_alert);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,115 @@
 | 
			
		||||
/* Control Interface for osmo-bts */
 | 
			
		||||
 | 
			
		||||
/* (C) 2014 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
#include <osmocom/ctrl/control_if.h>
 | 
			
		||||
#include <osmocom/ctrl/ports.h>
 | 
			
		||||
#include <osmo-bts/bts_model.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
#include <osmo-bts/control_if.h>
 | 
			
		||||
 | 
			
		||||
extern vector ctrl_node_vec;
 | 
			
		||||
 | 
			
		||||
/*! \brief control interface lookup function for bsc/bts gsm_data
 | 
			
		||||
 * \param[in] data Private data passed to controlif_setup()
 | 
			
		||||
 * \param[in] vline Vector of the line holding the command string
 | 
			
		||||
 * \param[out] node_type type (CTRL_NODE_) that was determined
 | 
			
		||||
 * \param[out] node_data private dta of node that was determined
 | 
			
		||||
 * \param i Current index into vline, up to which it is parsed
 | 
			
		||||
 */
 | 
			
		||||
static int bts_ctrl_node_lookup(void *data, vector vline, int *node_type,
 | 
			
		||||
				void **node_data, int *i)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts *bts = data;
 | 
			
		||||
	struct gsm_bts_trx *trx = NULL;
 | 
			
		||||
	struct gsm_bts_trx_ts *ts = NULL;
 | 
			
		||||
	char *token = vector_slot(vline, *i);
 | 
			
		||||
	long num;
 | 
			
		||||
 | 
			
		||||
	/* TODO: We need to make sure that the following chars are digits
 | 
			
		||||
	 * and/or use strtol to check if number conversion was successful
 | 
			
		||||
	 * Right now something like net.bts_stats will not work */
 | 
			
		||||
	if (!strcmp(token, "trx")) {
 | 
			
		||||
		if (*node_type != CTRL_NODE_ROOT || !*node_data)
 | 
			
		||||
			goto err_missing;
 | 
			
		||||
		bts = *node_data;
 | 
			
		||||
		(*i)++;
 | 
			
		||||
		if (!ctrl_parse_get_num(vline, *i, &num))
 | 
			
		||||
			goto err_index;
 | 
			
		||||
 | 
			
		||||
		trx = gsm_bts_trx_num(bts, num);
 | 
			
		||||
		if (!trx)
 | 
			
		||||
			goto err_missing;
 | 
			
		||||
		*node_data = trx;
 | 
			
		||||
		*node_type = CTRL_NODE_TRX;
 | 
			
		||||
	} else if (!strcmp(token, "ts")) {
 | 
			
		||||
		if (*node_type != CTRL_NODE_TRX || !*node_data)
 | 
			
		||||
			goto err_missing;
 | 
			
		||||
		trx = *node_data;
 | 
			
		||||
		(*i)++;
 | 
			
		||||
		if (!ctrl_parse_get_num(vline, *i, &num))
 | 
			
		||||
			goto err_index;
 | 
			
		||||
 | 
			
		||||
		if ((num >= 0) && (num < TRX_NR_TS))
 | 
			
		||||
			ts = &trx->ts[num];
 | 
			
		||||
		if (!ts)
 | 
			
		||||
			goto err_missing;
 | 
			
		||||
		*node_data = ts;
 | 
			
		||||
		*node_type = CTRL_NODE_TS;
 | 
			
		||||
	} else
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
err_missing:
 | 
			
		||||
	return -ENODEV;
 | 
			
		||||
err_index:
 | 
			
		||||
	return -ERANGE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts,
 | 
			
		||||
					const char *bind_addr, uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
	struct ctrl_handle *hdl;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
 | 
			
		||||
	hdl = ctrl_interface_setup_dynip(bts, bind_addr, port,
 | 
			
		||||
					 bts_ctrl_node_lookup);
 | 
			
		||||
	if (!hdl)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	rc = bts_ctrl_cmds_install(bts);
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		/* FIXME: close control interface */
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = bts_model_ctrl_cmds_install(bts);
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		/* FIXME: cleanup generic control commands */
 | 
			
		||||
		/* FIXME: close control interface */
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return hdl;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,192 @@
 | 
			
		||||
/* Cell Broadcast routines */
 | 
			
		||||
 | 
			
		||||
/* (C) 2014 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_04_12.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/bts.h>
 | 
			
		||||
#include <osmo-bts/cbch.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
 | 
			
		||||
struct smscb_msg {
 | 
			
		||||
	struct llist_head list;		/* list in smscb_state.queue */
 | 
			
		||||
 | 
			
		||||
	uint8_t msg[GSM412_MSG_LEN];	/* message buffer */
 | 
			
		||||
	uint8_t next_seg;		/* next segment number */
 | 
			
		||||
	uint8_t num_segs;		/* total number of segments */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int get_smscb_null_block(uint8_t *out)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm412_block_type *block_type = (struct gsm412_block_type *) out;
 | 
			
		||||
 | 
			
		||||
	block_type->spare = 0;
 | 
			
		||||
	block_type->lpd = 1;
 | 
			
		||||
	block_type->seq_nr = GSM412_SEQ_NULL_MSG;
 | 
			
		||||
	block_type->lb = 0;
 | 
			
		||||
	memset(out+1, GSM_MACBLOCK_PADDING, GSM412_BLOCK_LEN);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* get the next block of the current CB message */
 | 
			
		||||
static int get_smscb_block(struct gsm_bts *bts, uint8_t *out)
 | 
			
		||||
{
 | 
			
		||||
	int to_copy;
 | 
			
		||||
	struct gsm412_block_type *block_type;
 | 
			
		||||
	struct smscb_msg *msg = bts->smscb_state.cur_msg;
 | 
			
		||||
 | 
			
		||||
	if (!msg) {
 | 
			
		||||
		/* No message: Send NULL mesage */
 | 
			
		||||
		return get_smscb_null_block(out);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block_type = (struct gsm412_block_type *) out++;
 | 
			
		||||
 | 
			
		||||
	/* LPD is always 01 */
 | 
			
		||||
	block_type->spare = 0;
 | 
			
		||||
	block_type->lpd = 1;
 | 
			
		||||
 | 
			
		||||
	/* determine how much data to copy */
 | 
			
		||||
	to_copy = GSM412_MSG_LEN - (msg->next_seg * GSM412_BLOCK_LEN);
 | 
			
		||||
	if (to_copy > GSM412_BLOCK_LEN)
 | 
			
		||||
		to_copy = GSM412_BLOCK_LEN;
 | 
			
		||||
 | 
			
		||||
	/* copy data and increment index */
 | 
			
		||||
	memcpy(out, &msg->msg[msg->next_seg * GSM412_BLOCK_LEN], to_copy);
 | 
			
		||||
 | 
			
		||||
	/* set + increment sequence number */
 | 
			
		||||
	block_type->seq_nr = msg->next_seg++;
 | 
			
		||||
 | 
			
		||||
	/* determine if this is the last block */
 | 
			
		||||
	if (block_type->seq_nr + 1 == msg->num_segs)
 | 
			
		||||
		block_type->lb = 1;
 | 
			
		||||
	else
 | 
			
		||||
		block_type->lb = 0;
 | 
			
		||||
 | 
			
		||||
	if (block_type->lb == 1) {
 | 
			
		||||
		/* remove/release the message memory */
 | 
			
		||||
		talloc_free(bts->smscb_state.cur_msg);
 | 
			
		||||
		bts->smscb_state.cur_msg = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return block_type->lb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const uint8_t last_block_rsl2um[4] = {
 | 
			
		||||
	[RSL_CB_CMD_LASTBLOCK_4]	= 4,
 | 
			
		||||
	[RSL_CB_CMD_LASTBLOCK_1]	= 1,
 | 
			
		||||
	[RSL_CB_CMD_LASTBLOCK_2]	= 2,
 | 
			
		||||
	[RSL_CB_CMD_LASTBLOCK_3]	= 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* incoming SMS broadcast command from RSL */
 | 
			
		||||
int bts_process_smscb_cmd(struct gsm_bts *bts,
 | 
			
		||||
			  struct rsl_ie_cb_cmd_type cmd_type,
 | 
			
		||||
			  uint8_t msg_len, const uint8_t *msg)
 | 
			
		||||
{
 | 
			
		||||
	struct smscb_msg *scm;
 | 
			
		||||
 | 
			
		||||
	if (msg_len > sizeof(scm->msg)) {
 | 
			
		||||
		LOGP(DLSMS, LOGL_ERROR,
 | 
			
		||||
		     "Cannot process SMSCB of %u bytes (max %zu)\n",
 | 
			
		||||
		     msg_len, sizeof(scm->msg));
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scm = talloc_zero_size(bts, sizeof(*scm));
 | 
			
		||||
 | 
			
		||||
	/* initialize entire message with default padding */
 | 
			
		||||
	memset(scm->msg, GSM_MACBLOCK_PADDING, sizeof(scm->msg));
 | 
			
		||||
	/* next segment is first segment */
 | 
			
		||||
	scm->next_seg = 0;
 | 
			
		||||
 | 
			
		||||
	switch (cmd_type.command) {
 | 
			
		||||
	case RSL_CB_CMD_TYPE_NORMAL:
 | 
			
		||||
	case RSL_CB_CMD_TYPE_SCHEDULE:
 | 
			
		||||
	case RSL_CB_CMD_TYPE_NULL:
 | 
			
		||||
		scm->num_segs = last_block_rsl2um[cmd_type.last_block&3];
 | 
			
		||||
		memcpy(scm->msg, msg, msg_len);
 | 
			
		||||
		/* def_bcast is ignored */
 | 
			
		||||
		break;
 | 
			
		||||
	case RSL_CB_CMD_TYPE_DEFAULT:
 | 
			
		||||
		/* use def_bcast, ignore command  */
 | 
			
		||||
		/* def_bcast == 0: normal mess */
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	llist_add_tail(&scm->list, &bts->smscb_state.queue);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct smscb_msg *select_next_smscb(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct smscb_msg *msg;
 | 
			
		||||
 | 
			
		||||
	if (llist_empty(&bts->smscb_state.queue))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	msg = llist_entry(bts->smscb_state.queue.next,
 | 
			
		||||
			  struct smscb_msg, list);
 | 
			
		||||
 | 
			
		||||
	llist_del(&msg->list);
 | 
			
		||||
 | 
			
		||||
	return msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* call-back from bts model specific code when it wants to obtain a CBCH
 | 
			
		||||
 * block for a given gsm_time.  outbuf must have 23 bytes of space. */
 | 
			
		||||
int bts_cbch_get(struct gsm_bts *bts, uint8_t *outbuf, struct gsm_time *g_time)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t fn = gsm_gsmtime2fn(g_time);
 | 
			
		||||
	/* According to 05.02 Section 6.5.4 */
 | 
			
		||||
	uint32_t tb = (fn / 51) % 8;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
 | 
			
		||||
	/* The multiframes used for the basic cell broadcast channel
 | 
			
		||||
	 * shall be those in * which TB = 0,1,2 and 3. The multiframes
 | 
			
		||||
	 * used for the extended cell broadcast channel shall be those
 | 
			
		||||
	 * in which TB = 4, 5, 6 and 7 */
 | 
			
		||||
 | 
			
		||||
	/* The SMSCB header shall be sent in the multiframe in which TB
 | 
			
		||||
	 * = 0 for the basic, and TB = 4 for the extended cell
 | 
			
		||||
	 * broadcast channel. */
 | 
			
		||||
 | 
			
		||||
	switch (tb) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		/* select a new SMSCB message */
 | 
			
		||||
		bts->smscb_state.cur_msg = select_next_smscb(bts);
 | 
			
		||||
		rc = get_smscb_block(bts, outbuf);
 | 
			
		||||
		break;
 | 
			
		||||
	case 1: case 2: case 3:
 | 
			
		||||
		rc = get_smscb_block(bts, outbuf);
 | 
			
		||||
		break;
 | 
			
		||||
	case 4: case 5: case 6: case 7:
 | 
			
		||||
		/* always send NULL frame in extended CBCH for now */
 | 
			
		||||
		rc = get_smscb_null_block(outbuf);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,477 @@
 | 
			
		||||
/* DTX DL AMR FSM */
 | 
			
		||||
 | 
			
		||||
/* (C) 2016 by 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 Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/dtx_dl_amr_fsm.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_voice(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_VOICE:
 | 
			
		||||
	case E_FACCH:
 | 
			
		||||
		break;
 | 
			
		||||
	case E_SID_F:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_SID_F1, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_SID_U:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_INHIB:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_F1_INH_V, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Inexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_sid_f1(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_SID_F:
 | 
			
		||||
/* FIXME: what shall we do if we get SID-FIRST _again_ (twice in a row)?
 | 
			
		||||
   Was observed during testing, let's just ignore it for now */
 | 
			
		||||
		break;
 | 
			
		||||
	case E_SID_U:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_FACCH:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_F1_INH_F, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_FIRST:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_SID_F2, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_ONSET:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_sid_f2(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_FACCH:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_ONSET:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_f1_inh_v(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_F1_INH_V_REC, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_f1_inh_f(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_F1_INH_F_REC, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_u_inh_v(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_U_INH_V_REC, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_u_inh_f(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_U_INH_F_REC, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_f1_inh_v_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_VOICE:
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_f1_inh_f_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_FACCH:
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_u_inh_v_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_VOICE:
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_u_inh_f_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_FACCH:
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_u_noinh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_FACCH:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_VOICE:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_SID_U, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_SID_U:
 | 
			
		||||
	case E_SID_F:
 | 
			
		||||
/* FIXME: what shall we do if we get SID-FIRST _after_ sending SID-UPDATE?
 | 
			
		||||
   Was observed during testing, let's just ignore it for now */
 | 
			
		||||
		break;
 | 
			
		||||
	case E_ONSET:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_sid_upd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_FACCH:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_U_INH_F, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_VOICE:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_INHIB:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_U_INH_V, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_SID_U:
 | 
			
		||||
	case E_SID_F:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_onset_v(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_ONSET_V_REC, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_onset_f(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_ONSET_F_REC, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_onset_v_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_onset_f_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dtx_fsm_facch(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 | 
			
		||||
{
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case E_SID_U:
 | 
			
		||||
	case E_SID_F:
 | 
			
		||||
	case E_FACCH:
 | 
			
		||||
		break;
 | 
			
		||||
	case E_VOICE:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	case E_COMPL:
 | 
			
		||||
		osmo_fsm_inst_state_chg(fi, ST_SID_F1, 0, 0);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
 | 
			
		||||
		OSMO_ASSERT(0);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
 | 
			
		||||
	/* default state for non-DTX and DTX when SPEECH is in progress */
 | 
			
		||||
	[ST_VOICE] = {
 | 
			
		||||
		.in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_INHIB),
 | 
			
		||||
		.out_state_mask = X(ST_SID_F1) | X(ST_U_NOINH) | X(ST_F1_INH_V),
 | 
			
		||||
		.name = "Voice",
 | 
			
		||||
		.action = dtx_fsm_voice,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-FIRST or SID-FIRST-P1 in case of AMR HR:
 | 
			
		||||
	   start of silence period (might be interrupted in case of AMR HR) */
 | 
			
		||||
	[ST_SID_F1]= {
 | 
			
		||||
		.in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_FACCH) | X(E_FIRST) | X(E_ONSET),
 | 
			
		||||
		.out_state_mask = X(ST_U_NOINH) | X(ST_ONSET_F) | X(ST_SID_F2) | X(ST_ONSET_V),
 | 
			
		||||
		.name = "SID-FIRST (P1)",
 | 
			
		||||
		.action = dtx_fsm_sid_f1,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-FIRST P2 (only for AMR HR):
 | 
			
		||||
	   actual start of silence period in case of AMR HR */
 | 
			
		||||
	[ST_SID_F2]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL) | X(E_FACCH) | X(E_ONSET),
 | 
			
		||||
		.out_state_mask = X(ST_U_NOINH) | X(ST_ONSET_F) | X(ST_ONSET_V),
 | 
			
		||||
		.name = "SID-FIRST (P2)",
 | 
			
		||||
		.action = dtx_fsm_sid_f2,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-FIRST Inhibited: incoming SPEECH (only for AMR HR) */
 | 
			
		||||
	[ST_F1_INH_V]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL),
 | 
			
		||||
		.out_state_mask = X(ST_F1_INH_V_REC),
 | 
			
		||||
		.name = "SID-FIRST (Inh, SPEECH)",
 | 
			
		||||
		.action = dtx_fsm_f1_inh_v,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-FIRST Inhibited: incoming FACCH frame (only for AMR HR) */
 | 
			
		||||
	[ST_F1_INH_F]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL),
 | 
			
		||||
		.out_state_mask = X(ST_F1_INH_F_REC),
 | 
			
		||||
		.name = "SID-FIRST (Inh, FACCH)",
 | 
			
		||||
		.action = dtx_fsm_f1_inh_f,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-UPDATE Inhibited: incoming SPEECH (only for AMR HR) */
 | 
			
		||||
	[ST_U_INH_V]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL),
 | 
			
		||||
		.out_state_mask = X(ST_U_INH_V_REC),
 | 
			
		||||
		.name = "SID-UPDATE (Inh, SPEECH)",
 | 
			
		||||
		.action = dtx_fsm_u_inh_v,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-UPDATE Inhibited: incoming FACCH frame (only for AMR HR) */
 | 
			
		||||
	[ST_U_INH_F]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL),
 | 
			
		||||
		.out_state_mask = X(ST_U_INH_F_REC),
 | 
			
		||||
		.name = "SID-UPDATE (Inh, FACCH)",
 | 
			
		||||
		.action = dtx_fsm_u_inh_f,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-UPDATE: Inhibited not allowed (only for AMR HR) */
 | 
			
		||||
	[ST_U_NOINH]= {
 | 
			
		||||
		.in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_COMPL) | X(E_SID_U) | X(E_SID_F) | X(E_ONSET),
 | 
			
		||||
		.out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_SID_U) | X(ST_ONSET_V),
 | 
			
		||||
		.name = "SID-UPDATE (NoInh)",
 | 
			
		||||
		.action = dtx_fsm_u_noinh,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-FIRST Inhibition recursion in progress:
 | 
			
		||||
	   Inhibit itself was already sent, now have to send the voice that caused it */
 | 
			
		||||
	[ST_F1_INH_V_REC]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL) | X(E_VOICE),
 | 
			
		||||
		.out_state_mask = X(ST_VOICE),
 | 
			
		||||
		.name = "SID-FIRST (Inh, SPEECH, Rec)",
 | 
			
		||||
		.action = dtx_fsm_f1_inh_v_rec,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-FIRST Inhibition recursion in progress:
 | 
			
		||||
	   Inhibit itself was already sent, now have to send the data that caused it */
 | 
			
		||||
	[ST_F1_INH_F_REC]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL) | X(E_FACCH),
 | 
			
		||||
		.out_state_mask = X(ST_FACCH),
 | 
			
		||||
		.name = "SID-FIRST (Inh, FACCH, Rec)",
 | 
			
		||||
		.action = dtx_fsm_f1_inh_f_rec,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-UPDATE Inhibition recursion in progress:
 | 
			
		||||
	   Inhibit itself was already sent, now have to send the voice that caused it */
 | 
			
		||||
	[ST_U_INH_V_REC]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL) | X(E_VOICE),
 | 
			
		||||
		.out_state_mask = X(ST_VOICE),
 | 
			
		||||
		.name = "SID-UPDATE (Inh, SPEECH, Rec)",
 | 
			
		||||
		.action = dtx_fsm_u_inh_v_rec,
 | 
			
		||||
	},
 | 
			
		||||
	/* SID-UPDATE Inhibition recursion in progress:
 | 
			
		||||
	   Inhibit itself was already sent, now have to send the data that caused it */
 | 
			
		||||
	[ST_U_INH_F_REC]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL) | X(E_FACCH),
 | 
			
		||||
		.out_state_mask = X(ST_FACCH),
 | 
			
		||||
		.name = "SID-UPDATE (Inh, FACCH, Rec)",
 | 
			
		||||
		.action = dtx_fsm_u_inh_f_rec,
 | 
			
		||||
	},
 | 
			
		||||
	/* Silence period with periodic comfort noise data updates */
 | 
			
		||||
	[ST_SID_U]= {
 | 
			
		||||
		.in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_INHIB) | X(E_SID_U) | X(E_SID_F),
 | 
			
		||||
		.out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_U_INH_V) | X(ST_U_INH_F) | X(ST_U_NOINH),
 | 
			
		||||
		.name = "SID-UPDATE (AMR/HR)",
 | 
			
		||||
		.action = dtx_fsm_sid_upd,
 | 
			
		||||
	},
 | 
			
		||||
	/* ONSET - end of silent period due to incoming SPEECH frame */
 | 
			
		||||
	[ST_ONSET_V]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL),
 | 
			
		||||
		.out_state_mask = X(ST_ONSET_V_REC),
 | 
			
		||||
		.name = "ONSET (SPEECH)",
 | 
			
		||||
		.action = dtx_fsm_onset_v,
 | 
			
		||||
	},
 | 
			
		||||
	/* ONSET - end of silent period due to incoming FACCH frame */
 | 
			
		||||
	[ST_ONSET_F]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL),
 | 
			
		||||
		.out_state_mask = X(ST_ONSET_F_REC),
 | 
			
		||||
		.name = "ONSET (FACCH)",
 | 
			
		||||
		.action = dtx_fsm_onset_f,
 | 
			
		||||
	},
 | 
			
		||||
	/* ONSET recursion in progress:
 | 
			
		||||
	   ONSET itself was already sent, now have to send the voice that caused it */
 | 
			
		||||
	[ST_ONSET_V_REC]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL),
 | 
			
		||||
		.out_state_mask = X(ST_VOICE),
 | 
			
		||||
		.name = "ONSET (SPEECH, Rec)",
 | 
			
		||||
		.action = dtx_fsm_onset_v_rec,
 | 
			
		||||
	},
 | 
			
		||||
	/* ONSET recursion in progress:
 | 
			
		||||
	   ONSET itself was already sent, now have to send the data that caused it */
 | 
			
		||||
	[ST_ONSET_F_REC]= {
 | 
			
		||||
		.in_event_mask = X(E_COMPL),
 | 
			
		||||
		.out_state_mask = X(ST_FACCH),
 | 
			
		||||
		.name = "ONSET (FACCH, Rec)",
 | 
			
		||||
		.action = dtx_fsm_onset_f_rec,
 | 
			
		||||
	},
 | 
			
		||||
	/* FACCH sending state */
 | 
			
		||||
	[ST_FACCH]= {
 | 
			
		||||
		.in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_COMPL) | X(E_SID_U) | X(E_SID_F),
 | 
			
		||||
		.out_state_mask = X(ST_VOICE) | X(ST_SID_F1),
 | 
			
		||||
		.name = "FACCH",
 | 
			
		||||
		.action = dtx_fsm_facch,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct value_string dtx_dl_amr_fsm_event_names[] = {
 | 
			
		||||
	{ E_VOICE,	"Voice" },
 | 
			
		||||
	{ E_ONSET,	"ONSET" },
 | 
			
		||||
	{ E_FACCH,	"FACCH" },
 | 
			
		||||
	{ E_COMPL,	"Complete" },
 | 
			
		||||
	{ E_FIRST,	"FIRST P1->P2" },
 | 
			
		||||
	{ E_INHIB,	"Inhibit" },
 | 
			
		||||
	{ E_SID_F,	"SID-FIRST" },
 | 
			
		||||
	{ E_SID_U,	"SID-UPDATE" },
 | 
			
		||||
	{ 0, 		NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct osmo_fsm dtx_dl_amr_fsm = {
 | 
			
		||||
	.name = "DTX_DL_AMR_FSM",
 | 
			
		||||
	.states = dtx_dl_amr_fsm_states,
 | 
			
		||||
	.num_states = ARRAY_SIZE(dtx_dl_amr_fsm_states),
 | 
			
		||||
	.event_names = dtx_dl_amr_fsm_event_names,
 | 
			
		||||
	.log_subsys = DL1C,
 | 
			
		||||
};
 | 
			
		||||
@@ -0,0 +1,829 @@
 | 
			
		||||
/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/core/talloc.h>
 | 
			
		||||
#include <osmocom/gsm/gsm_utils.h>
 | 
			
		||||
#include <osmocom/gsm/abis_nm.h>
 | 
			
		||||
#include <osmocom/core/statistics.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
 | 
			
		||||
void gsm_abis_mo_reset(struct gsm_abis_mo *mo)
 | 
			
		||||
{
 | 
			
		||||
	mo->nm_state.operational = NM_OPSTATE_NULL;
 | 
			
		||||
	mo->nm_state.availability = NM_AVSTATE_POWER_OFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gsm_mo_init(struct gsm_abis_mo *mo, struct gsm_bts *bts,
 | 
			
		||||
			uint8_t obj_class, uint8_t p1, uint8_t p2, uint8_t p3)
 | 
			
		||||
{
 | 
			
		||||
	mo->bts = bts;
 | 
			
		||||
	mo->obj_class = obj_class;
 | 
			
		||||
	mo->obj_inst.bts_nr = p1;
 | 
			
		||||
	mo->obj_inst.trx_nr = p2;
 | 
			
		||||
	mo->obj_inst.ts_nr = p3;
 | 
			
		||||
	gsm_abis_mo_reset(mo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct value_string bts_attribute_names[] = {
 | 
			
		||||
	OSMO_VALUE_STRING(BTS_TYPE_VARIANT),
 | 
			
		||||
	OSMO_VALUE_STRING(BTS_SUB_MODEL),
 | 
			
		||||
	OSMO_VALUE_STRING(TRX_PHY_VERSION),
 | 
			
		||||
	{ 0, NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum bts_attribute str2btsattr(const char *s)
 | 
			
		||||
{
 | 
			
		||||
	return get_string_value(bts_attribute_names, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *btsatttr2str(enum bts_attribute v)
 | 
			
		||||
{
 | 
			
		||||
	return get_value_string(bts_attribute_names, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct value_string osmo_bts_variant_names[_NUM_BTS_VARIANT + 1] = {
 | 
			
		||||
	{ BTS_UNKNOWN,		"unknown" },
 | 
			
		||||
	{ BTS_OSMO_LITECELL15,	"osmo-bts-lc15" },
 | 
			
		||||
	{ BTS_OSMO_OCTPHY,	"osmo-bts-octphy" },
 | 
			
		||||
	{ BTS_OSMO_SYSMO,	"osmo-bts-sysmo" },
 | 
			
		||||
	{ BTS_OSMO_TRX,		"omso-bts-trx" },
 | 
			
		||||
	{ BTS_OSMO_VIRTUAL,	"omso-bts-virtual" },
 | 
			
		||||
	{ BTS_OSMO_OMLDUMMY,	"omso-bts-omldummy" },
 | 
			
		||||
	{ 0, NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum gsm_bts_type_variant str2btsvariant(const char *arg)
 | 
			
		||||
{
 | 
			
		||||
	return get_string_value(osmo_bts_variant_names, arg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *btsvariant2str(enum gsm_bts_type_variant v)
 | 
			
		||||
{
 | 
			
		||||
	return get_value_string(osmo_bts_variant_names, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct value_string gsm_bts_features_descs[] = {
 | 
			
		||||
	{ BTS_FEAT_HSCSD,		"HSCSD" },
 | 
			
		||||
	{ BTS_FEAT_GPRS,		"GPRS" },
 | 
			
		||||
	{ BTS_FEAT_EGPRS,		"EGPRS" },
 | 
			
		||||
	{ BTS_FEAT_ECSD,		"ECSD" },
 | 
			
		||||
	{ BTS_FEAT_HOPPING,		"Frequency Hopping" },
 | 
			
		||||
	{ BTS_FEAT_MULTI_TSC,		"Multi-TSC" },
 | 
			
		||||
	{ BTS_FEAT_OML_ALERTS,		"OML Alerts" },
 | 
			
		||||
	{ BTS_FEAT_AGCH_PCH_PROP,	"AGCH/PCH proportional allocation" },
 | 
			
		||||
	{ BTS_FEAT_CBCH,		"CBCH" },
 | 
			
		||||
	{ BTS_FEAT_SPEECH_F_V1,		"Fullrate speech V1" },
 | 
			
		||||
	{ BTS_FEAT_SPEECH_H_V1,		"Halfrate speech V1" },
 | 
			
		||||
	{ BTS_FEAT_SPEECH_F_EFR,	"Fullrate speech EFR" },
 | 
			
		||||
	{ BTS_FEAT_SPEECH_F_AMR,	"Fullrate speech AMR" },
 | 
			
		||||
	{ BTS_FEAT_SPEECH_H_AMR,	"Halfrate speech AMR" },
 | 
			
		||||
	{ 0, NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct value_string gsm_chreq_descs[] = {
 | 
			
		||||
	{ GSM_CHREQ_REASON_EMERG,	"emergency call" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_PAG,		"answer to paging" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_CALL,	"call re-establishment" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_LOCATION_UPD,"Location updating" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_PDCH,	"one phase packet access" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_OTHER,	"other" },
 | 
			
		||||
	{ 0,				NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct value_string gsm_pchant_names[13] = {
 | 
			
		||||
	{ GSM_PCHAN_NONE,	"NONE" },
 | 
			
		||||
	{ GSM_PCHAN_CCCH,	"CCCH" },
 | 
			
		||||
	{ GSM_PCHAN_CCCH_SDCCH4,"CCCH+SDCCH4" },
 | 
			
		||||
	{ GSM_PCHAN_TCH_F,	"TCH/F" },
 | 
			
		||||
	{ GSM_PCHAN_TCH_H,	"TCH/H" },
 | 
			
		||||
	{ GSM_PCHAN_SDCCH8_SACCH8C, "SDCCH8" },
 | 
			
		||||
	{ GSM_PCHAN_PDCH,	"PDCH" },
 | 
			
		||||
	{ GSM_PCHAN_TCH_F_PDCH,	"TCH/F_PDCH" },
 | 
			
		||||
	{ GSM_PCHAN_UNKNOWN,	"UNKNOWN" },
 | 
			
		||||
	{ GSM_PCHAN_CCCH_SDCCH4_CBCH, "CCCH+SDCCH4+CBCH" },
 | 
			
		||||
	{ GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "SDCCH8+CBCH" },
 | 
			
		||||
	{ GSM_PCHAN_TCH_F_TCH_H_PDCH, "TCH/F_TCH/H_PDCH" },
 | 
			
		||||
	{ 0,			NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct value_string gsm_pchant_descs[13] = {
 | 
			
		||||
	{ GSM_PCHAN_NONE,	"Physical Channel not configured" },
 | 
			
		||||
	{ GSM_PCHAN_CCCH,	"FCCH + SCH + BCCH + CCCH (Comb. IV)" },
 | 
			
		||||
	{ GSM_PCHAN_CCCH_SDCCH4,
 | 
			
		||||
		"FCCH + SCH + BCCH + CCCH + 4 SDCCH + 2 SACCH (Comb. V)" },
 | 
			
		||||
	{ GSM_PCHAN_TCH_F,	"TCH/F + FACCH/F + SACCH (Comb. I)" },
 | 
			
		||||
	{ GSM_PCHAN_TCH_H,	"2 TCH/H + 2 FACCH/H + 2 SACCH (Comb. II)" },
 | 
			
		||||
	{ GSM_PCHAN_SDCCH8_SACCH8C, "8 SDCCH + 4 SACCH (Comb. VII)" },
 | 
			
		||||
	{ GSM_PCHAN_PDCH,	"Packet Data Channel for GPRS/EDGE" },
 | 
			
		||||
	{ GSM_PCHAN_TCH_F_PDCH,	"Dynamic TCH/F or GPRS PDCH" },
 | 
			
		||||
	{ GSM_PCHAN_UNKNOWN,	"Unknown / Unsupported channel combination" },
 | 
			
		||||
	{ GSM_PCHAN_CCCH_SDCCH4_CBCH, "FCCH + SCH + BCCH + CCCH + CBCH + 3 SDCCH + 2 SACCH (Comb. V)" },
 | 
			
		||||
	{ GSM_PCHAN_SDCCH8_SACCH8C_CBCH, "7 SDCCH + 4 SACCH + CBCH (Comb. VII)" },
 | 
			
		||||
	{ GSM_PCHAN_TCH_F_TCH_H_PDCH, "Dynamic TCH/F or TCH/H or GPRS PDCH" },
 | 
			
		||||
	{ 0,			NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char *gsm_pchan_name(enum gsm_phys_chan_config c)
 | 
			
		||||
{
 | 
			
		||||
	return get_value_string(gsm_pchant_names, c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum gsm_phys_chan_config gsm_pchan_parse(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	return get_string_value(gsm_pchant_names, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* TODO: move to libosmocore, next to gsm_chan_t_names? */
 | 
			
		||||
const char *gsm_lchant_name(enum gsm_chan_t c)
 | 
			
		||||
{
 | 
			
		||||
	return get_value_string(gsm_chan_t_names, c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct value_string lchan_s_names[] = {
 | 
			
		||||
	{ LCHAN_S_NONE,		"NONE" },
 | 
			
		||||
	{ LCHAN_S_ACT_REQ,	"ACTIVATION REQUESTED" },
 | 
			
		||||
	{ LCHAN_S_ACTIVE,	"ACTIVE" },
 | 
			
		||||
	{ LCHAN_S_INACTIVE,	"INACTIVE" },
 | 
			
		||||
	{ LCHAN_S_REL_REQ,	"RELEASE REQUESTED" },
 | 
			
		||||
	{ LCHAN_S_REL_ERR,	"RELEASE DUE ERROR" },
 | 
			
		||||
	{ LCHAN_S_BROKEN,	"BROKEN UNUSABLE" },
 | 
			
		||||
	{ 0,			NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char *gsm_lchans_name(enum gsm_lchan_state s)
 | 
			
		||||
{
 | 
			
		||||
	return get_value_string(lchan_s_names, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct value_string chreq_names[] = {
 | 
			
		||||
	{ GSM_CHREQ_REASON_EMERG,	"EMERGENCY" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_PAG,		"PAGING" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_CALL,	"CALL" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_LOCATION_UPD,"LOCATION_UPDATE" },
 | 
			
		||||
	{ GSM_CHREQ_REASON_OTHER,	"OTHER" },
 | 
			
		||||
	{ 0,				NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char *gsm_chreq_name(enum gsm_chreq_reason_t c)
 | 
			
		||||
{
 | 
			
		||||
	return get_value_string(chreq_names, c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts *bts;
 | 
			
		||||
 | 
			
		||||
	if (num >= net->num_bts)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(bts, &net->bts_list, list) {
 | 
			
		||||
		if (bts->nr == num)
 | 
			
		||||
			return bts;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);
 | 
			
		||||
	int k;
 | 
			
		||||
 | 
			
		||||
	if (!trx)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	trx->bts = bts;
 | 
			
		||||
	trx->nr = bts->num_trx++;
 | 
			
		||||
	trx->mo.nm_state.administrative = NM_STATE_UNLOCKED;
 | 
			
		||||
 | 
			
		||||
	gsm_mo_init(&trx->mo, bts, NM_OC_RADIO_CARRIER,
 | 
			
		||||
		    bts->nr, trx->nr, 0xff);
 | 
			
		||||
	gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC,
 | 
			
		||||
		    bts->nr, trx->nr, 0xff);
 | 
			
		||||
 | 
			
		||||
	for (k = 0; k < TRX_NR_TS; k++) {
 | 
			
		||||
		struct gsm_bts_trx_ts *ts = &trx->ts[k];
 | 
			
		||||
		int l;
 | 
			
		||||
 | 
			
		||||
		ts->trx = trx;
 | 
			
		||||
		ts->nr = k;
 | 
			
		||||
		ts->pchan = GSM_PCHAN_NONE;
 | 
			
		||||
		ts->dyn.pchan_is = GSM_PCHAN_NONE;
 | 
			
		||||
		ts->dyn.pchan_want = GSM_PCHAN_NONE;
 | 
			
		||||
		ts->tsc = -1;
 | 
			
		||||
 | 
			
		||||
		gsm_mo_init(&ts->mo, bts, NM_OC_CHANNEL,
 | 
			
		||||
			    bts->nr, trx->nr, ts->nr);
 | 
			
		||||
 | 
			
		||||
		ts->hopping.arfcns.data_len = sizeof(ts->hopping.arfcns_data);
 | 
			
		||||
		ts->hopping.arfcns.data = ts->hopping.arfcns_data;
 | 
			
		||||
		ts->hopping.ma.data_len = sizeof(ts->hopping.ma_data);
 | 
			
		||||
		ts->hopping.ma.data = ts->hopping.ma_data;
 | 
			
		||||
 | 
			
		||||
		for (l = 0; l < TS_MAX_LCHAN; l++) {
 | 
			
		||||
			struct gsm_lchan *lchan;
 | 
			
		||||
			char *name;
 | 
			
		||||
			lchan = &ts->lchan[l];
 | 
			
		||||
 | 
			
		||||
			lchan->ts = ts;
 | 
			
		||||
			lchan->nr = l;
 | 
			
		||||
			lchan->type = GSM_LCHAN_NONE;
 | 
			
		||||
 | 
			
		||||
			name = gsm_lchan_name_compute(lchan);
 | 
			
		||||
			lchan->name = talloc_strdup(trx, name);
 | 
			
		||||
			INIT_LLIST_HEAD(&lchan->sapi_cmds);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (trx->nr != 0)
 | 
			
		||||
		trx->nominal_power = bts->c0->nominal_power;
 | 
			
		||||
 | 
			
		||||
	llist_add_tail(&trx->list, &bts->trx_list);
 | 
			
		||||
 | 
			
		||||
	return trx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const uint8_t bts_nse_timer_default[] = { 3, 3, 3, 3, 30, 3, 10 };
 | 
			
		||||
static const uint8_t bts_cell_timer_default[] =
 | 
			
		||||
				{ 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 };
 | 
			
		||||
static const struct gprs_rlc_cfg rlc_cfg_default = {
 | 
			
		||||
	.parameter = {
 | 
			
		||||
		[RLC_T3142] = 20,
 | 
			
		||||
		[RLC_T3169] = 5,
 | 
			
		||||
		[RLC_T3191] = 5,
 | 
			
		||||
		[RLC_T3193] = 160, /* 10ms */
 | 
			
		||||
		[RLC_T3195] = 5,
 | 
			
		||||
		[RLC_N3101] = 10,
 | 
			
		||||
		[RLC_N3103] = 4,
 | 
			
		||||
		[RLC_N3105] = 8,
 | 
			
		||||
		[CV_COUNTDOWN] = 15,
 | 
			
		||||
		[T_DL_TBF_EXT] = 250 * 10, /* ms */
 | 
			
		||||
		[T_UL_TBF_EXT] = 250 * 10, /* ms */
 | 
			
		||||
	},
 | 
			
		||||
	.paging = {
 | 
			
		||||
		.repeat_time = 5 * 50, /* ms */
 | 
			
		||||
		.repeat_count = 3,
 | 
			
		||||
	},
 | 
			
		||||
	.cs_mask = 0x1fff,
 | 
			
		||||
	.initial_cs = 2,
 | 
			
		||||
	.initial_mcs = 6,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts *bts = talloc_zero(ctx, struct gsm_bts);
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!bts)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	bts->nr = bts_num;
 | 
			
		||||
	bts->num_trx = 0;
 | 
			
		||||
	INIT_LLIST_HEAD(&bts->trx_list);
 | 
			
		||||
	bts->ms_max_power = 15;	/* dBm */
 | 
			
		||||
 | 
			
		||||
	gsm_mo_init(&bts->mo, bts, NM_OC_BTS,
 | 
			
		||||
			bts->nr, 0xff, 0xff);
 | 
			
		||||
	gsm_mo_init(&bts->site_mgr.mo, bts, NM_OC_SITE_MANAGER,
 | 
			
		||||
			0xff, 0xff, 0xff);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
 | 
			
		||||
		bts->gprs.nsvc[i].bts = bts;
 | 
			
		||||
		bts->gprs.nsvc[i].id = i;
 | 
			
		||||
		gsm_mo_init(&bts->gprs.nsvc[i].mo, bts, NM_OC_GPRS_NSVC,
 | 
			
		||||
				bts->nr, i, 0xff);
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(&bts->gprs.nse.timer, bts_nse_timer_default,
 | 
			
		||||
		sizeof(bts->gprs.nse.timer));
 | 
			
		||||
	gsm_mo_init(&bts->gprs.nse.mo, bts, NM_OC_GPRS_NSE,
 | 
			
		||||
			bts->nr, 0xff, 0xff);
 | 
			
		||||
	memcpy(&bts->gprs.cell.timer, bts_cell_timer_default,
 | 
			
		||||
		sizeof(bts->gprs.cell.timer));
 | 
			
		||||
	gsm_mo_init(&bts->gprs.cell.mo, bts, NM_OC_GPRS_CELL,
 | 
			
		||||
			bts->nr, 0xff, 0xff);
 | 
			
		||||
	memcpy(&bts->gprs.cell.rlc_cfg, &rlc_cfg_default,
 | 
			
		||||
		sizeof(bts->gprs.cell.rlc_cfg));
 | 
			
		||||
 | 
			
		||||
	/* create our primary TRX */
 | 
			
		||||
	bts->c0 = gsm_bts_trx_alloc(bts);
 | 
			
		||||
	if (!bts->c0) {
 | 
			
		||||
		talloc_free(bts);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
 | 
			
		||||
 | 
			
		||||
	bts->rach_b_thresh = -1;
 | 
			
		||||
	bts->rach_ldavg_slots = -1;
 | 
			
		||||
	bts->features.data = &bts->_features_data[0];
 | 
			
		||||
	bts->features.data_len = sizeof(bts->_features_data);
 | 
			
		||||
 | 
			
		||||
	/* si handling */
 | 
			
		||||
	bts->bcch_change_mark = 1;
 | 
			
		||||
 | 
			
		||||
	return bts;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* reset the state of all MO in the BTS */
 | 
			
		||||
void gsm_bts_mo_reset(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	gsm_abis_mo_reset(&bts->mo);
 | 
			
		||||
	gsm_abis_mo_reset(&bts->site_mgr.mo);
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++)
 | 
			
		||||
		gsm_abis_mo_reset(&bts->gprs.nsvc[i].mo);
 | 
			
		||||
	gsm_abis_mo_reset(&bts->gprs.nse.mo);
 | 
			
		||||
	gsm_abis_mo_reset(&bts->gprs.cell.mo);
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(trx, &bts->trx_list, list) {
 | 
			
		||||
		gsm_abis_mo_reset(&trx->mo);
 | 
			
		||||
		gsm_abis_mo_reset(&trx->bb_transc.mo);
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
 | 
			
		||||
			struct gsm_bts_trx_ts *ts = &trx->ts[i];
 | 
			
		||||
			gsm_abis_mo_reset(&ts->mo);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
 | 
			
		||||
	if (num >= bts->num_trx)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(trx, &bts->trx_list, list) {
 | 
			
		||||
		if (trx->nr == num)
 | 
			
		||||
			return trx;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char ts2str[255];
 | 
			
		||||
 | 
			
		||||
char *gsm_trx_name(const struct gsm_bts_trx *trx)
 | 
			
		||||
{
 | 
			
		||||
	if (!trx)
 | 
			
		||||
		snprintf(ts2str, sizeof(ts2str), "(trx=NULL)");
 | 
			
		||||
	else
 | 
			
		||||
		snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d)",
 | 
			
		||||
			 trx->bts->nr, trx->nr);
 | 
			
		||||
 | 
			
		||||
	return ts2str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char *gsm_ts_name(const struct gsm_bts_trx_ts *ts)
 | 
			
		||||
{
 | 
			
		||||
	snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)",
 | 
			
		||||
		 ts->trx->bts->nr, ts->trx->nr, ts->nr);
 | 
			
		||||
 | 
			
		||||
	return ts2str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Log timeslot number with full pchan information */
 | 
			
		||||
char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts)
 | 
			
		||||
{
 | 
			
		||||
	switch (ts->pchan) {
 | 
			
		||||
	case GSM_PCHAN_TCH_F_TCH_H_PDCH:
 | 
			
		||||
		if (ts->dyn.pchan_is == ts->dyn.pchan_want)
 | 
			
		||||
			snprintf(ts2str, sizeof(ts2str),
 | 
			
		||||
				 "(bts=%d,trx=%d,ts=%d,pchan=%s as %s)",
 | 
			
		||||
				 ts->trx->bts->nr, ts->trx->nr, ts->nr,
 | 
			
		||||
				 gsm_pchan_name(ts->pchan),
 | 
			
		||||
				 gsm_pchan_name(ts->dyn.pchan_is));
 | 
			
		||||
		else
 | 
			
		||||
			snprintf(ts2str, sizeof(ts2str),
 | 
			
		||||
				 "(bts=%d,trx=%d,ts=%d,pchan=%s"
 | 
			
		||||
				 " switching %s -> %s)",
 | 
			
		||||
				 ts->trx->bts->nr, ts->trx->nr, ts->nr,
 | 
			
		||||
				 gsm_pchan_name(ts->pchan),
 | 
			
		||||
				 gsm_pchan_name(ts->dyn.pchan_is),
 | 
			
		||||
				 gsm_pchan_name(ts->dyn.pchan_want));
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_TCH_F_PDCH:
 | 
			
		||||
		if ((ts->flags & TS_F_PDCH_PENDING_MASK) == 0)
 | 
			
		||||
			snprintf(ts2str, sizeof(ts2str),
 | 
			
		||||
				 "(bts=%d,trx=%d,ts=%d,pchan=%s as %s)",
 | 
			
		||||
				 ts->trx->bts->nr, ts->trx->nr, ts->nr,
 | 
			
		||||
				 gsm_pchan_name(ts->pchan),
 | 
			
		||||
				 (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
 | 
			
		||||
							       : "TCH/F");
 | 
			
		||||
		else
 | 
			
		||||
			snprintf(ts2str, sizeof(ts2str),
 | 
			
		||||
				 "(bts=%d,trx=%d,ts=%d,pchan=%s"
 | 
			
		||||
				 " switching %s -> %s)",
 | 
			
		||||
				 ts->trx->bts->nr, ts->trx->nr, ts->nr,
 | 
			
		||||
				 gsm_pchan_name(ts->pchan),
 | 
			
		||||
				 (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
 | 
			
		||||
							       : "TCH/F",
 | 
			
		||||
				 (ts->flags & TS_F_PDCH_ACT_PENDING)? "PDCH"
 | 
			
		||||
								    : "TCH/F");
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,pchan=%s)",
 | 
			
		||||
			 ts->trx->bts->nr, ts->trx->nr, ts->nr,
 | 
			
		||||
			 gsm_pchan_name(ts->pchan));
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ts2str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *gsm_lchan_name_compute(const struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx_ts *ts = lchan->ts;
 | 
			
		||||
 | 
			
		||||
	snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,ss=%d)",
 | 
			
		||||
		 ts->trx->bts->nr, ts->trx->nr, ts->nr, lchan->nr);
 | 
			
		||||
 | 
			
		||||
	return ts2str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* obtain the MO structure for a given object instance */
 | 
			
		||||
struct gsm_abis_mo *
 | 
			
		||||
gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
 | 
			
		||||
	    const struct abis_om_obj_inst *obj_inst)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
	struct gsm_abis_mo *mo = NULL;
 | 
			
		||||
 | 
			
		||||
	switch (obj_class) {
 | 
			
		||||
	case NM_OC_BTS:
 | 
			
		||||
		mo = &bts->mo;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_RADIO_CARRIER:
 | 
			
		||||
		if (obj_inst->trx_nr >= bts->num_trx) {
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 | 
			
		||||
		mo = &trx->mo;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_BASEB_TRANSC:
 | 
			
		||||
		if (obj_inst->trx_nr >= bts->num_trx) {
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 | 
			
		||||
		mo = &trx->bb_transc.mo;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_CHANNEL:
 | 
			
		||||
		if (obj_inst->trx_nr >= bts->num_trx) {
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 | 
			
		||||
		if (obj_inst->ts_nr >= TRX_NR_TS)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		mo = &trx->ts[obj_inst->ts_nr].mo;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_SITE_MANAGER:
 | 
			
		||||
		mo = &bts->site_mgr.mo;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_GPRS_NSE:
 | 
			
		||||
		mo = &bts->gprs.nse.mo;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_GPRS_CELL:
 | 
			
		||||
		mo = &bts->gprs.cell.mo;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_GPRS_NSVC:
 | 
			
		||||
		if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
 | 
			
		||||
			return NULL;
 | 
			
		||||
		mo = &bts->gprs.nsvc[obj_inst->trx_nr].mo;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return mo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* obtain the gsm_nm_state data structure for a given object instance */
 | 
			
		||||
struct gsm_nm_state *
 | 
			
		||||
gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
 | 
			
		||||
		 const struct abis_om_obj_inst *obj_inst)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_abis_mo *mo;
 | 
			
		||||
 | 
			
		||||
	mo = gsm_objclass2mo(bts, obj_class, obj_inst);
 | 
			
		||||
	if (!mo)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return &mo->nm_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* obtain the in-memory data structure of a given object instance */
 | 
			
		||||
void *
 | 
			
		||||
gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
 | 
			
		||||
	     const struct abis_om_obj_inst *obj_inst)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
	void *obj = NULL;
 | 
			
		||||
 | 
			
		||||
	switch (obj_class) {
 | 
			
		||||
	case NM_OC_BTS:
 | 
			
		||||
		obj = bts;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_RADIO_CARRIER:
 | 
			
		||||
		if (obj_inst->trx_nr >= bts->num_trx) {
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 | 
			
		||||
		obj = trx;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_BASEB_TRANSC:
 | 
			
		||||
		if (obj_inst->trx_nr >= bts->num_trx) {
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 | 
			
		||||
		obj = &trx->bb_transc;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_CHANNEL:
 | 
			
		||||
		if (obj_inst->trx_nr >= bts->num_trx) {
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
 | 
			
		||||
		if (obj_inst->ts_nr >= TRX_NR_TS)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		obj = &trx->ts[obj_inst->ts_nr];
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_SITE_MANAGER:
 | 
			
		||||
		obj = &bts->site_mgr;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_GPRS_NSE:
 | 
			
		||||
		obj = &bts->gprs.nse;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_GPRS_CELL:
 | 
			
		||||
		obj = &bts->gprs.cell;
 | 
			
		||||
		break;
 | 
			
		||||
	case NM_OC_GPRS_NSVC:
 | 
			
		||||
		if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
 | 
			
		||||
			return NULL;
 | 
			
		||||
		obj = &bts->gprs.nsvc[obj_inst->trx_nr];
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* See Table 10.5.25 of GSM04.08 */
 | 
			
		||||
uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
 | 
			
		||||
			  uint8_t ts_nr, uint8_t lchan_nr)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t cbits, chan_nr;
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
 | 
			
		||||
	OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
 | 
			
		||||
 | 
			
		||||
	switch (pchan) {
 | 
			
		||||
	case GSM_PCHAN_TCH_F:
 | 
			
		||||
		OSMO_ASSERT(lchan_nr == 0);
 | 
			
		||||
		cbits = 0x01;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_PDCH:
 | 
			
		||||
		OSMO_ASSERT(lchan_nr == 0);
 | 
			
		||||
		cbits = RSL_CHAN_OSMO_PDCH >> 3;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_TCH_H:
 | 
			
		||||
		OSMO_ASSERT(lchan_nr < 2);
 | 
			
		||||
		cbits = 0x02;
 | 
			
		||||
		cbits += lchan_nr;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_CCCH_SDCCH4:
 | 
			
		||||
	case GSM_PCHAN_CCCH_SDCCH4_CBCH:
 | 
			
		||||
		/*
 | 
			
		||||
		 * As a special hack for BCCH, lchan_nr == 4 may be passed
 | 
			
		||||
		 * here. This should never be sent in an RSL message.
 | 
			
		||||
		 * See osmo-bts-xxx/oml.c:opstart_compl().
 | 
			
		||||
		 */
 | 
			
		||||
		if (lchan_nr == CCCH_LCHAN)
 | 
			
		||||
			chan_nr = 0;
 | 
			
		||||
		else
 | 
			
		||||
			OSMO_ASSERT(lchan_nr < 4);
 | 
			
		||||
		cbits = 0x04;
 | 
			
		||||
		cbits += lchan_nr;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_SDCCH8_SACCH8C:
 | 
			
		||||
	case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
 | 
			
		||||
		OSMO_ASSERT(lchan_nr < 8);
 | 
			
		||||
		cbits = 0x08;
 | 
			
		||||
		cbits += lchan_nr;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_CCCH:
 | 
			
		||||
	default:
 | 
			
		||||
		/* OSMO_ASSERT(lchan_nr == 0);
 | 
			
		||||
		 * FIXME: On octphy and litecell, we hit above assertion (see
 | 
			
		||||
		 * Max's comment at https://gerrit.osmocom.org/589 ); disabled
 | 
			
		||||
		 * for BTS until this is clarified; remove the #ifdef when it
 | 
			
		||||
		 * is fixed. Tracked in OS#2906.
 | 
			
		||||
		 */
 | 
			
		||||
#pragma message "fix caller that passes lchan_nr != 0"
 | 
			
		||||
		cbits = 0x10;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chan_nr = (cbits << 3) | (ts_nr & 0x7);
 | 
			
		||||
 | 
			
		||||
	return chan_nr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	switch (lchan->ts->pchan) {
 | 
			
		||||
	case GSM_PCHAN_TCH_F_TCH_H_PDCH:
 | 
			
		||||
		/* Return chan_nr reflecting the current TS pchan, either a standard TCH kind, or the
 | 
			
		||||
		 * nonstandard value reflecting PDCH for Osmocom style dyn TS. */
 | 
			
		||||
		return gsm_lchan_as_pchan2chan_nr(lchan,
 | 
			
		||||
						  lchan->ts->dyn.pchan_is);
 | 
			
		||||
	case GSM_PCHAN_TCH_F_PDCH:
 | 
			
		||||
		/* For ip.access style dyn TS, we always want to use the chan_nr as if it was TCH/F.
 | 
			
		||||
		 * We're using custom PDCH ACT and DEACT messages that use the usual chan_nr values. */
 | 
			
		||||
		return gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
 | 
			
		||||
	default:
 | 
			
		||||
		return gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
 | 
			
		||||
				   enum gsm_phys_chan_config as_pchan)
 | 
			
		||||
{
 | 
			
		||||
	if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
 | 
			
		||||
	    && as_pchan == GSM_PCHAN_PDCH)
 | 
			
		||||
		return RSL_CHAN_OSMO_PDCH | (lchan->ts->nr & ~RSL_CHAN_NR_MASK);
 | 
			
		||||
	return gsm_pchan2chan_nr(as_pchan, lchan->ts->nr, lchan->nr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* return the gsm_lchan for the CBCH (if it exists at all) */
 | 
			
		||||
struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_lchan *lchan = NULL;
 | 
			
		||||
	struct gsm_bts_trx *trx = bts->c0;
 | 
			
		||||
 | 
			
		||||
	if (trx->ts[0].pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH)
 | 
			
		||||
		lchan = &trx->ts[0].lchan[2];
 | 
			
		||||
	else {
 | 
			
		||||
		int i;
 | 
			
		||||
		for (i = 0; i < 8; i++) {
 | 
			
		||||
			if (trx->ts[i].pchan == GSM_PCHAN_SDCCH8_SACCH8C_CBCH) {
 | 
			
		||||
				lchan = &trx->ts[i].lchan[2];
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return lchan;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* determine logical channel based on TRX and channel number IE */
 | 
			
		||||
struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
 | 
			
		||||
				   int *rc)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t ts_nr = chan_nr & 0x07;
 | 
			
		||||
	uint8_t cbits = chan_nr >> 3;
 | 
			
		||||
	uint8_t lch_idx;
 | 
			
		||||
	struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
 | 
			
		||||
	bool ok = true;
 | 
			
		||||
 | 
			
		||||
	if (rc)
 | 
			
		||||
		*rc = -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (cbits == 0x01) {
 | 
			
		||||
		lch_idx = 0;	/* TCH/F */	
 | 
			
		||||
		if (ts->pchan != GSM_PCHAN_TCH_F &&
 | 
			
		||||
		    ts->pchan != GSM_PCHAN_PDCH &&
 | 
			
		||||
		    ts->pchan != GSM_PCHAN_TCH_F_PDCH &&
 | 
			
		||||
		    ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)
 | 
			
		||||
			ok = false;
 | 
			
		||||
	} else if ((cbits & 0x1e) == 0x02) {
 | 
			
		||||
		lch_idx = cbits & 0x1;	/* TCH/H */
 | 
			
		||||
		if (ts->pchan != GSM_PCHAN_TCH_H &&
 | 
			
		||||
		    ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)
 | 
			
		||||
			ok = false;
 | 
			
		||||
	} else if ((cbits & 0x1c) == 0x04) {
 | 
			
		||||
		lch_idx = cbits & 0x3;	/* SDCCH/4 */
 | 
			
		||||
		if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4 &&
 | 
			
		||||
		    ts->pchan != GSM_PCHAN_CCCH_SDCCH4_CBCH)
 | 
			
		||||
			ok = false;
 | 
			
		||||
	} else if ((cbits & 0x18) == 0x08) {
 | 
			
		||||
		lch_idx = cbits & 0x7;	/* SDCCH/8 */
 | 
			
		||||
		if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C &&
 | 
			
		||||
		    ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C_CBCH)
 | 
			
		||||
			ok = false;
 | 
			
		||||
	} else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) {
 | 
			
		||||
		lch_idx = 0;
 | 
			
		||||
		if (ts->pchan != GSM_PCHAN_CCCH &&
 | 
			
		||||
		    ts->pchan != GSM_PCHAN_CCCH_SDCCH4 &&
 | 
			
		||||
		    ts->pchan != GSM_PCHAN_CCCH_SDCCH4_CBCH)
 | 
			
		||||
			ok = false;
 | 
			
		||||
		/* FIXME: we should not return first sdcch4 !!! */
 | 
			
		||||
	} else if ((chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_OSMO_PDCH) {
 | 
			
		||||
		lch_idx = 0;
 | 
			
		||||
		if (ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)
 | 
			
		||||
			ok = false;
 | 
			
		||||
	} else
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (rc && ok)
 | 
			
		||||
		*rc = 0;
 | 
			
		||||
 | 
			
		||||
	return &ts->lchan[lch_idx];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const uint8_t subslots_per_pchan[] = {
 | 
			
		||||
	[GSM_PCHAN_NONE] = 0,
 | 
			
		||||
	[GSM_PCHAN_CCCH] = 0,
 | 
			
		||||
	[GSM_PCHAN_PDCH] = 0,
 | 
			
		||||
	[GSM_PCHAN_CCCH_SDCCH4] = 4,
 | 
			
		||||
	[GSM_PCHAN_TCH_F] = 1,
 | 
			
		||||
	[GSM_PCHAN_TCH_H] = 2,
 | 
			
		||||
	[GSM_PCHAN_SDCCH8_SACCH8C] = 8,
 | 
			
		||||
	[GSM_PCHAN_CCCH_SDCCH4_CBCH] = 4,
 | 
			
		||||
	[GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 8,
 | 
			
		||||
	/*
 | 
			
		||||
	 * GSM_PCHAN_TCH_F_PDCH and GSM_PCHAN_TCH_F_TCH_H_PDCH should not be
 | 
			
		||||
	 * part of this, those TS are handled according to their dynamic state.
 | 
			
		||||
	 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*! Return the actual pchan type, also heeding dynamic TS. */
 | 
			
		||||
enum gsm_phys_chan_config ts_pchan(struct gsm_bts_trx_ts *ts)
 | 
			
		||||
{
 | 
			
		||||
	switch (ts->pchan) {
 | 
			
		||||
	case GSM_PCHAN_TCH_F_TCH_H_PDCH:
 | 
			
		||||
		return ts->dyn.pchan_is;
 | 
			
		||||
	case GSM_PCHAN_TCH_F_PDCH:
 | 
			
		||||
		if (ts->flags & TS_F_PDCH_ACTIVE)
 | 
			
		||||
			return GSM_PCHAN_PDCH;
 | 
			
		||||
		else
 | 
			
		||||
			return GSM_PCHAN_TCH_F;
 | 
			
		||||
	default:
 | 
			
		||||
		return ts->pchan;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! According to ts->pchan and possibly ts->dyn_pchan, return the number of
 | 
			
		||||
 * logical channels available in the timeslot. */
 | 
			
		||||
uint8_t ts_subslots(struct gsm_bts_trx_ts *ts)
 | 
			
		||||
{
 | 
			
		||||
	return subslots_per_pchan[ts_pchan(ts)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool pchan_is_tch(enum gsm_phys_chan_config pchan)
 | 
			
		||||
{
 | 
			
		||||
	switch (pchan) {
 | 
			
		||||
	case GSM_PCHAN_TCH_F:
 | 
			
		||||
	case GSM_PCHAN_TCH_H:
 | 
			
		||||
		return true;
 | 
			
		||||
	default:
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ts_is_tch(struct gsm_bts_trx_ts *ts)
 | 
			
		||||
{
 | 
			
		||||
	return pchan_is_tch(ts_pchan(ts));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *gsm_trx_unit_id(struct gsm_bts_trx *trx)
 | 
			
		||||
{
 | 
			
		||||
	static char buf[23];
 | 
			
		||||
 | 
			
		||||
	snprintf(buf, sizeof(buf), "%u/%u/%u", trx->bts->ip_access.site_id,
 | 
			
		||||
		trx->bts->ip_access.bts_id, trx->nr);
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct value_string lchan_ciph_state_names[] = {
 | 
			
		||||
	{ LCHAN_CIPH_NONE,	"NONE" },
 | 
			
		||||
	{ LCHAN_CIPH_RX_REQ,	"RX_REQ" },
 | 
			
		||||
	{ LCHAN_CIPH_RX_CONF,	"RX_CONF" },
 | 
			
		||||
	{ LCHAN_CIPH_RXTX_REQ,	"RXTX_REQ" },
 | 
			
		||||
	{ LCHAN_CIPH_RX_CONF_TX_REQ,	"RX_CONF_TX_REQ" },
 | 
			
		||||
	{ LCHAN_CIPH_RXTX_CONF,	"RXTX_CONF" },
 | 
			
		||||
	{ 0, NULL }
 | 
			
		||||
};
 | 
			
		||||
@@ -0,0 +1,164 @@
 | 
			
		||||
/* Paging message encoding + queue management */
 | 
			
		||||
 | 
			
		||||
/* (C) 2012-2013 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *                  Andreas Eversberg <jolly@eversberg.eu>
 | 
			
		||||
 * (C) 2014 by Holger Hans Peter Freyther
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
 | 
			
		||||
#include <osmocom/gsm/rsl.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/bts.h>
 | 
			
		||||
#include <osmo-bts/bts_model.h>
 | 
			
		||||
#include <osmo-bts/rsl.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/handover.h>
 | 
			
		||||
#include <osmo-bts/l1sap.h>
 | 
			
		||||
 | 
			
		||||
/* Transmit a handover related PHYS INFO on given lchan */
 | 
			
		||||
static int ho_tx_phys_info(struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	struct msgb *msg = msgb_alloc_headroom(1024, 128, "PHYS INFO");
 | 
			
		||||
	struct gsm48_hdr *gh;
 | 
			
		||||
 | 
			
		||||
	if (!msg)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	LOGP(DHO, LOGL_INFO,
 | 
			
		||||
		"%s Sending PHYSICAL INFORMATION to MS.\n",
 | 
			
		||||
		gsm_lchan_name(lchan));
 | 
			
		||||
 | 
			
		||||
	/* Build RSL UNITDATA REQUEST message with 04.08 PHYS INFO */
 | 
			
		||||
	msg->l3h = msg->data;
 | 
			
		||||
	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 | 
			
		||||
	gh->proto_discr = GSM48_PDISC_RR;
 | 
			
		||||
	gh->msg_type = GSM48_MT_RR_HANDO_INFO;
 | 
			
		||||
	msgb_put_u8(msg, lchan->rqd_ta);
 | 
			
		||||
 | 
			
		||||
	rsl_rll_push_l3(msg, RSL_MT_UNIT_DATA_REQ, gsm_lchan2chan_nr(lchan),
 | 
			
		||||
		0x00, 0);
 | 
			
		||||
 | 
			
		||||
	lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* timer call-back for T3105 (handover PHYS INFO re-transmit) */
 | 
			
		||||
static void ho_t3105_cb(void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_lchan *lchan = data;
 | 
			
		||||
	struct gsm_bts *bts = lchan->ts->trx->bts;
 | 
			
		||||
 | 
			
		||||
	LOGP(DHO, LOGL_INFO, "%s T3105 timeout (%d resends left)\n",
 | 
			
		||||
		gsm_lchan_name(lchan), bts->ny1 - lchan->ho.phys_info_count);
 | 
			
		||||
 | 
			
		||||
	if (lchan->state != LCHAN_S_ACTIVE) {
 | 
			
		||||
		LOGP(DHO, LOGL_NOTICE,
 | 
			
		||||
			"%s is in not active. It is in state %s. Ignoring\n",
 | 
			
		||||
			gsm_lchan_name(lchan), gsm_lchans_name(lchan->state));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lchan->ho.phys_info_count >= bts->ny1) {
 | 
			
		||||
		/* HO Abort */
 | 
			
		||||
		LOGP(DHO, LOGL_NOTICE, "%s NY1 reached, sending CONNection "
 | 
			
		||||
			"FAILure to BSC.\n", gsm_lchan_name(lchan));
 | 
			
		||||
		rsl_tx_conn_fail(lchan, RSL_ERR_HANDOVER_ACC_FAIL);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ho_tx_phys_info(lchan);
 | 
			
		||||
	lchan->ho.phys_info_count++;
 | 
			
		||||
	osmo_timer_schedule(&lchan->ho.t3105, 0, bts->t3105_ms * 1000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* received random access on dedicated channel */
 | 
			
		||||
void handover_rach(struct gsm_lchan *lchan, uint8_t ra, uint8_t acc_delay)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts *bts = lchan->ts->trx->bts;
 | 
			
		||||
 | 
			
		||||
	/* Ignore invalid handover ref */
 | 
			
		||||
	if (lchan->ho.ref != ra) {
 | 
			
		||||
		LOGP(DHO, LOGL_INFO, "%s RACH on dedicated channel received, but "
 | 
			
		||||
			"ra=0x%02x != expected ref=0x%02x. (This is no bug)\n",
 | 
			
		||||
			gsm_lchan_name(lchan), ra, lchan->ho.ref);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Ignore handover on channels other than DCCH and SACCH */
 | 
			
		||||
	if (lchan->type != GSM_LCHAN_SDCCH && lchan->type != GSM_LCHAN_TCH_H &&
 | 
			
		||||
		lchan->type != GSM_LCHAN_TCH_F) {
 | 
			
		||||
		LOGP(DHO, LOGL_ERROR, "%s handover RACH received on %s?!\n",
 | 
			
		||||
		     gsm_lchan_name(lchan), gsm_lchant_name(lchan->type));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOGP(DHO, LOGL_NOTICE,
 | 
			
		||||
	     "%s RACH on dedicated channel type %s received with TA=%u, ref=%u\n",
 | 
			
		||||
	     gsm_lchan_name(lchan), gsm_lchant_name(lchan->type), acc_delay, ra);
 | 
			
		||||
 | 
			
		||||
	/* Set timing advance */
 | 
			
		||||
	lchan->rqd_ta = acc_delay;
 | 
			
		||||
 | 
			
		||||
	/* Stop handover detection, wait for valid frame */
 | 
			
		||||
	lchan->ho.active = HANDOVER_WAIT_FRAME;
 | 
			
		||||
	if (l1sap_chan_modify(lchan->ts->trx, gsm_lchan2chan_nr(lchan)) != 0) {
 | 
			
		||||
		LOGP(DHO, LOGL_ERROR,
 | 
			
		||||
			"%s failed to modify channel after handover\n",
 | 
			
		||||
			gsm_lchan_name(lchan));
 | 
			
		||||
		rsl_tx_conn_fail(lchan, RSL_ERR_HANDOVER_ACC_FAIL);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Send HANDover DETect to BSC */
 | 
			
		||||
	rsl_tx_hando_det(lchan, &lchan->rqd_ta);
 | 
			
		||||
 | 
			
		||||
	/* Send PHYS INFO */
 | 
			
		||||
	lchan->ho.phys_info_count = 1;
 | 
			
		||||
	ho_tx_phys_info(lchan);
 | 
			
		||||
 | 
			
		||||
	/* Start T3105 */
 | 
			
		||||
	LOGP(DHO, LOGL_DEBUG,
 | 
			
		||||
		"%s Starting T3105 with %u ms\n",
 | 
			
		||||
		gsm_lchan_name(lchan), bts->t3105_ms);
 | 
			
		||||
	lchan->ho.t3105.cb = ho_t3105_cb;
 | 
			
		||||
	lchan->ho.t3105.data = lchan;
 | 
			
		||||
	osmo_timer_schedule(&lchan->ho.t3105, 0, bts->t3105_ms * 1000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* received frist valid data frame on dedicated channel */
 | 
			
		||||
void handover_frame(struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	LOGP(DHO, LOGL_INFO,
 | 
			
		||||
		"%s First valid frame detected\n", gsm_lchan_name(lchan));
 | 
			
		||||
	handover_reset(lchan);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* release handover state */
 | 
			
		||||
void handover_reset(struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	/* Stop T3105 */
 | 
			
		||||
	osmo_timer_del(&lchan->ho.t3105);
 | 
			
		||||
 | 
			
		||||
	/* Handover process is done */
 | 
			
		||||
	lchan->ho.active = HANDOVER_NONE;
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
/* OsmoBTS lchan interface */
 | 
			
		||||
 | 
			
		||||
/* (C) 2012 by Holger Hans Peter Freyther
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
 | 
			
		||||
void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state)
 | 
			
		||||
{
 | 
			
		||||
	DEBUGP(DL1C, "%s state %s -> %s\n",
 | 
			
		||||
	       gsm_lchan_name(lchan),
 | 
			
		||||
	       gsm_lchans_name(lchan->state),
 | 
			
		||||
	       gsm_lchans_name(state));
 | 
			
		||||
	lchan->state = state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ts_is_pdch(const struct gsm_bts_trx_ts *ts)
 | 
			
		||||
{
 | 
			
		||||
	switch (ts->pchan) {
 | 
			
		||||
	case GSM_PCHAN_PDCH:
 | 
			
		||||
		return true;
 | 
			
		||||
	case GSM_PCHAN_TCH_F_PDCH:
 | 
			
		||||
		return (ts->flags & TS_F_PDCH_ACTIVE)
 | 
			
		||||
		       && !(ts->flags & TS_F_PDCH_PENDING_MASK);
 | 
			
		||||
	case GSM_PCHAN_TCH_F_TCH_H_PDCH:
 | 
			
		||||
		return ts->dyn.pchan_is == GSM_PCHAN_PDCH
 | 
			
		||||
		       && ts->dyn.pchan_want == ts->dyn.pchan_is;
 | 
			
		||||
	default:
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,94 @@
 | 
			
		||||
/* Support for generating RSL Load Indication */
 | 
			
		||||
 | 
			
		||||
/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/timer.h>
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
#include <osmo-bts/rsl.h>
 | 
			
		||||
#include <osmo-bts/paging.h>
 | 
			
		||||
 | 
			
		||||
static void reset_load_counters(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	/* re-set the counters */
 | 
			
		||||
	bts->load.ccch.pch_used = bts->load.ccch.pch_total = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void load_timer_cb(void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts *bts = data;
 | 
			
		||||
	unsigned int pch_percent, rach_percent;
 | 
			
		||||
 | 
			
		||||
	/* compute percentages */
 | 
			
		||||
	if (bts->load.ccch.pch_total == 0)
 | 
			
		||||
		pch_percent = 0;
 | 
			
		||||
	else
 | 
			
		||||
		pch_percent = (bts->load.ccch.pch_used * 100) /
 | 
			
		||||
					bts->load.ccch.pch_total;
 | 
			
		||||
 | 
			
		||||
	if (pch_percent >= bts->load.ccch.load_ind_thresh) {
 | 
			
		||||
		/* send RSL load indication message to BSC */
 | 
			
		||||
		uint16_t buffer_space = paging_buffer_space(bts->paging_state);
 | 
			
		||||
		rsl_tx_ccch_load_ind_pch(bts, buffer_space);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* This is an extenstion of TS 08.58.  We don't only
 | 
			
		||||
		 * send load indications if the load is above threshold,
 | 
			
		||||
		 * but we also explicitly indicate that we are below
 | 
			
		||||
		 * threshold by using the magic value 0xffff */
 | 
			
		||||
		rsl_tx_ccch_load_ind_pch(bts, 0xffff);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bts->load.rach.total == 0)
 | 
			
		||||
		rach_percent = 0;
 | 
			
		||||
	else
 | 
			
		||||
		rach_percent = (bts->load.rach.busy * 100) /
 | 
			
		||||
					bts->load.rach.total;
 | 
			
		||||
 | 
			
		||||
	if (rach_percent >= bts->load.ccch.load_ind_thresh) {
 | 
			
		||||
		/* send RSL load indication message to BSC */
 | 
			
		||||
		rsl_tx_ccch_load_ind_rach(bts, bts->load.rach.total,
 | 
			
		||||
					  bts->load.rach.busy,
 | 
			
		||||
					  bts->load.rach.access);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reset_load_counters(bts);
 | 
			
		||||
 | 
			
		||||
	/* re-schedule the timer */
 | 
			
		||||
	osmo_timer_schedule(&bts->load.ccch.timer,
 | 
			
		||||
			    bts->load.ccch.load_ind_period, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void load_timer_start(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	if (!bts->load.ccch.timer.data) {
 | 
			
		||||
		bts->load.ccch.timer.data = bts;
 | 
			
		||||
		bts->load.ccch.timer.cb = load_timer_cb;
 | 
			
		||||
		reset_load_counters(bts);
 | 
			
		||||
	}
 | 
			
		||||
	osmo_timer_schedule(&bts->load.ccch.timer, bts->load.ccch.load_ind_period, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void load_timer_stop(struct gsm_bts *bts)
 | 
			
		||||
{
 | 
			
		||||
	osmo_timer_del(&bts->load.ccch.timer);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,150 @@
 | 
			
		||||
/* libosmocore logging support */
 | 
			
		||||
 | 
			
		||||
/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
 | 
			
		||||
 * (C) 2011 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
#include <osmocom/core/application.h>
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/bts.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
 | 
			
		||||
static struct log_info_cat bts_log_info_cat[] = {
 | 
			
		||||
	[DRSL] = {
 | 
			
		||||
		.name = "DRSL",
 | 
			
		||||
		.description = "A-bis Radio Siganlling Link (RSL)",
 | 
			
		||||
		.color = "\033[1;35m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_INFO,
 | 
			
		||||
	},
 | 
			
		||||
	[DOML] =	{
 | 
			
		||||
		.name = "DOML",
 | 
			
		||||
		.description = "A-bis Network Management / O&M (NM/OML)",
 | 
			
		||||
		.color = "\033[1;36m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_INFO,
 | 
			
		||||
	},
 | 
			
		||||
	[DRLL] = {
 | 
			
		||||
		.name = "DRLL",
 | 
			
		||||
		.description = "A-bis Radio Link Layer (RLL)",
 | 
			
		||||
		.color = "\033[1;31m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DRR] = {
 | 
			
		||||
		.name = "DRR",
 | 
			
		||||
		.description = "Layer3 Radio Resource (RR)",
 | 
			
		||||
		.color = "\033[1;34m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DMEAS] = {
 | 
			
		||||
		.name = "DMEAS",
 | 
			
		||||
		.description = "Radio Measurement Processing",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DPAG]	= {
 | 
			
		||||
		.name = "DPAG",
 | 
			
		||||
		.description = "Paging Subsystem",
 | 
			
		||||
		.color = "\033[1;38m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_INFO,
 | 
			
		||||
	},
 | 
			
		||||
	[DL1C] = {
 | 
			
		||||
		.name = "DL1C",
 | 
			
		||||
		.description = "Layer 1 Control (MPH)",
 | 
			
		||||
		.loglevel = LOGL_INFO,
 | 
			
		||||
		.enabled = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[DL1P] = {
 | 
			
		||||
		.name = "DL1P",
 | 
			
		||||
		.description = "Layer 1 Primitives (PH)",
 | 
			
		||||
		.loglevel = LOGL_INFO,
 | 
			
		||||
		.enabled = 0,
 | 
			
		||||
	},
 | 
			
		||||
	[DDSP] = {
 | 
			
		||||
		.name = "DDSP",
 | 
			
		||||
		.description = "DSP Trace Messages",
 | 
			
		||||
		.loglevel = LOGL_DEBUG,
 | 
			
		||||
		.enabled = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[DABIS] = {
 | 
			
		||||
		.name = "DABIS",
 | 
			
		||||
		.description = "A-bis Intput Subsystem",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DRTP] = {
 | 
			
		||||
		.name = "DRTP",
 | 
			
		||||
		.description = "Realtime Transfer Protocol",
 | 
			
		||||
		.loglevel = LOGL_NOTICE,
 | 
			
		||||
		.enabled = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[DPCU] = {
 | 
			
		||||
		.name = "DPCU",
 | 
			
		||||
		.description = "PCU interface",
 | 
			
		||||
		.loglevel = LOGL_NOTICE,
 | 
			
		||||
		.enabled = 1,
 | 
			
		||||
	},
 | 
			
		||||
	[DHO] = {
 | 
			
		||||
		.name = "DHO",
 | 
			
		||||
		.description = "Handover",
 | 
			
		||||
		.color = "\033[0;37m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DTRX] = {
 | 
			
		||||
		.name = "DTRX",
 | 
			
		||||
		.description = "TRX interface",
 | 
			
		||||
		.color = "\033[1;33m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DLOOP] = {
 | 
			
		||||
		.name = "DLOOP",
 | 
			
		||||
		.description = "Control loops",
 | 
			
		||||
		.color = "\033[0;34m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
#if 0
 | 
			
		||||
	[DNS] = {
 | 
			
		||||
		.name = "DNS",
 | 
			
		||||
		.description = "GPRS Network Service (NS)",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_INFO,
 | 
			
		||||
	},
 | 
			
		||||
	[DBSSGP] = {
 | 
			
		||||
		.name = "DBSSGP",
 | 
			
		||||
		.description = "GPRS BSS Gateway Protocol (BSSGP)",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
			
		||||
	},
 | 
			
		||||
	[DLLC] = {
 | 
			
		||||
		.name = "DLLC",
 | 
			
		||||
		.description = "GPRS Logical Link Control Protocol (LLC)",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
			
		||||
	},
 | 
			
		||||
#endif
 | 
			
		||||
	[DSUM] = {
 | 
			
		||||
		.name = "DSUM",
 | 
			
		||||
		.description = "DSUM",
 | 
			
		||||
		.loglevel = LOGL_NOTICE,
 | 
			
		||||
		.enabled = 1,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const struct log_info bts_log_info = {
 | 
			
		||||
	.cat = bts_log_info_cat,
 | 
			
		||||
	.num_cat = ARRAY_SIZE(bts_log_info_cat),
 | 
			
		||||
};
 | 
			
		||||
@@ -0,0 +1,368 @@
 | 
			
		||||
/* Main program for Osmocom BTS */
 | 
			
		||||
 | 
			
		||||
/* (C) 2011-2016 by Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/signal.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sched.h>
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/talloc.h>
 | 
			
		||||
#include <osmocom/core/application.h>
 | 
			
		||||
#include <osmocom/vty/telnet_interface.h>
 | 
			
		||||
#include <osmocom/vty/logging.h>
 | 
			
		||||
#include <osmocom/core/gsmtap_util.h>
 | 
			
		||||
#include <osmocom/core/gsmtap.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
#include <osmo-bts/phy_link.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/abis.h>
 | 
			
		||||
#include <osmo-bts/bts.h>
 | 
			
		||||
#include <osmo-bts/vty.h>
 | 
			
		||||
#include <osmo-bts/l1sap.h>
 | 
			
		||||
#include <osmo-bts/bts_model.h>
 | 
			
		||||
#include <osmo-bts/pcu_if.h>
 | 
			
		||||
#include <osmo-bts/control_if.h>
 | 
			
		||||
#include <osmocom/ctrl/control_if.h>
 | 
			
		||||
#include <osmocom/ctrl/ports.h>
 | 
			
		||||
#include <osmocom/ctrl/control_vty.h>
 | 
			
		||||
#include <osmo-bts/oml.h>
 | 
			
		||||
 | 
			
		||||
int quit = 0;
 | 
			
		||||
static const char *config_file = "osmo-bts.cfg";
 | 
			
		||||
static int daemonize = 0;
 | 
			
		||||
static int rt_prio = -1;
 | 
			
		||||
static int trx_num = 1;
 | 
			
		||||
static char *gsmtap_ip = 0;
 | 
			
		||||
extern int g_vty_port_num;
 | 
			
		||||
 | 
			
		||||
static void print_help()
 | 
			
		||||
{
 | 
			
		||||
	printf( "Some useful options:\n"
 | 
			
		||||
		"  -h	--help		this text\n"
 | 
			
		||||
		"  -d	--debug MASK	Enable debugging (e.g. -d DRSL:DOML:DLAPDM)\n"
 | 
			
		||||
		"  -D	--daemonize	For the process into a background daemon\n"
 | 
			
		||||
		"  -c	--config-file 	Specify the filename of the config file\n"
 | 
			
		||||
		"  -s	--disable-color	Don't use colors in stderr log output\n"
 | 
			
		||||
		"  -T	--timestamp	Prefix every log line with a timestamp\n"
 | 
			
		||||
		"  -V	--version	Print version information and exit\n"
 | 
			
		||||
		"  -e 	--log-level	Set a global log-level\n"
 | 
			
		||||
		"  -r	--realtime PRIO	Use SCHED_RR with the specified priority\n"
 | 
			
		||||
		"  -i	--gsmtap-ip	The destination IP used for GSMTAP.\n"
 | 
			
		||||
		"  -t	--trx-num	Set number of TRX (default=%d)\n",
 | 
			
		||||
		trx_num
 | 
			
		||||
		);
 | 
			
		||||
	bts_model_print_help();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME: finally get some option parsing code into libosmocore */
 | 
			
		||||
static void handle_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	char *argv_out[argc];
 | 
			
		||||
	int argc_out = 0;
 | 
			
		||||
 | 
			
		||||
	argv_out[argc_out++] = argv[0];
 | 
			
		||||
 | 
			
		||||
	/* disable generation of error messages on encountering unknown
 | 
			
		||||
	 * options */
 | 
			
		||||
	opterr = 0;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		int option_idx = 0, c;
 | 
			
		||||
		static const struct option long_options[] = {
 | 
			
		||||
			/* FIXME: all those are generic Osmocom app options */
 | 
			
		||||
			{ "help", 0, 0, 'h' },
 | 
			
		||||
			{ "debug", 1, 0, 'd' },
 | 
			
		||||
			{ "daemonize", 0, 0, 'D' },
 | 
			
		||||
			{ "config-file", 1, 0, 'c' },
 | 
			
		||||
			{ "disable-color", 0, 0, 's' },
 | 
			
		||||
			{ "timestamp", 0, 0, 'T' },
 | 
			
		||||
			{ "version", 0, 0, 'V' },
 | 
			
		||||
			{ "log-level", 1, 0, 'e' },
 | 
			
		||||
			/* FIXME: generic BTS app options */
 | 
			
		||||
			{ "gsmtap-ip", 1, 0, 'i' },
 | 
			
		||||
			{ "trx-num", 1, 0, 't' },
 | 
			
		||||
			{ "realtime", 1, 0, 'r' },
 | 
			
		||||
			{ 0, 0, 0, 0 }
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		c = getopt_long(argc, argv, "-hc:d:Dc:sTVe:i:t:r:",
 | 
			
		||||
				long_options, &option_idx);
 | 
			
		||||
		if (c == -1)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'h':
 | 
			
		||||
			print_help();
 | 
			
		||||
			exit(0);
 | 
			
		||||
			break;
 | 
			
		||||
		case 's':
 | 
			
		||||
			log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'd':
 | 
			
		||||
			log_parse_category_mask(osmo_stderr_target, optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'D':
 | 
			
		||||
			daemonize = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'c':
 | 
			
		||||
			config_file = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'T':
 | 
			
		||||
			log_set_print_timestamp(osmo_stderr_target, 1);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'V':
 | 
			
		||||
			print_version(1);
 | 
			
		||||
			exit(0);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'e':
 | 
			
		||||
			log_set_log_level(osmo_stderr_target, atoi(optarg));
 | 
			
		||||
			break;
 | 
			
		||||
		case 'r':
 | 
			
		||||
			rt_prio = atoi(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'i':
 | 
			
		||||
			gsmtap_ip = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case 't':
 | 
			
		||||
			trx_num = atoi(optarg);
 | 
			
		||||
			if (trx_num < 1)
 | 
			
		||||
				trx_num = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case '?':
 | 
			
		||||
		case 1:
 | 
			
		||||
			/* prepare argv[] for bts_model */
 | 
			
		||||
			argv_out[argc_out++] = argv[optind-1];
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* re-set opt-ind for new parsig round */
 | 
			
		||||
	optind = 1;
 | 
			
		||||
	/* enable error-checking for the following getopt call */
 | 
			
		||||
	opterr = 1;
 | 
			
		||||
	if (bts_model_handle_options(argc_out, argv_out)) {
 | 
			
		||||
		print_help();
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct gsm_bts *bts;
 | 
			
		||||
 | 
			
		||||
static void signal_handler(int signal)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "signal %u received\n", signal);
 | 
			
		||||
 | 
			
		||||
	switch (signal) {
 | 
			
		||||
	case SIGINT:
 | 
			
		||||
	case SIGTERM:
 | 
			
		||||
		if (!quit) {
 | 
			
		||||
			oml_fail_rep(OSMO_EVT_CRIT_PROC_STOP,
 | 
			
		||||
				     "BTS: SIGINT received -> shutdown");
 | 
			
		||||
			bts_shutdown(bts, "SIGINT");
 | 
			
		||||
		}
 | 
			
		||||
		quit++;
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGABRT:
 | 
			
		||||
	case SIGUSR1:
 | 
			
		||||
	case SIGUSR2:
 | 
			
		||||
		oml_fail_rep(OSMO_EVT_CRIT_PROC_STOP,
 | 
			
		||||
			     "BTS: signal %d (%s) received", signal,
 | 
			
		||||
			     strsignal(signal));
 | 
			
		||||
		talloc_report_full(tall_bts_ctx, stderr);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int write_pid_file(char *procname)
 | 
			
		||||
{
 | 
			
		||||
	FILE *outf;
 | 
			
		||||
	char tmp[PATH_MAX+1];
 | 
			
		||||
 | 
			
		||||
	snprintf(tmp, sizeof(tmp)-1, "/var/run/%s.pid", procname);
 | 
			
		||||
	tmp[PATH_MAX-1] = '\0';
 | 
			
		||||
 | 
			
		||||
	outf = fopen(tmp, "w");
 | 
			
		||||
	if (!outf)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	fprintf(outf, "%d\n", getpid());
 | 
			
		||||
 | 
			
		||||
	fclose(outf);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bts_main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_bts_trx *trx;
 | 
			
		||||
	struct e1inp_line *line;
 | 
			
		||||
	int rc, i;
 | 
			
		||||
 | 
			
		||||
	printf("((*))\n  |\n / \\ OsmoBTS\n");
 | 
			
		||||
 | 
			
		||||
	/* Track the use of talloc NULL memory contexts */
 | 
			
		||||
	talloc_enable_null_tracking();
 | 
			
		||||
 | 
			
		||||
	tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context");
 | 
			
		||||
	msgb_talloc_ctx_init(tall_bts_ctx, 100*1024);
 | 
			
		||||
	bts_vty_info.tall_ctx = tall_bts_ctx;
 | 
			
		||||
 | 
			
		||||
	osmo_init_logging2(tall_bts_ctx, &bts_log_info);
 | 
			
		||||
	vty_init(&bts_vty_info);
 | 
			
		||||
	ctrl_vty_init(tall_bts_ctx);
 | 
			
		||||
	rate_ctr_init(tall_bts_ctx);
 | 
			
		||||
 | 
			
		||||
	handle_options(argc, argv);
 | 
			
		||||
 | 
			
		||||
	bts = gsm_bts_alloc(tall_bts_ctx, 0);
 | 
			
		||||
	if (!bts) {
 | 
			
		||||
		fprintf(stderr, "Failed to create BTS structure\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 1; i < trx_num; i++) {
 | 
			
		||||
		trx = gsm_bts_trx_alloc(bts);
 | 
			
		||||
		if (!trx) {
 | 
			
		||||
			fprintf(stderr, "Failed to create TRX structure\n");
 | 
			
		||||
			exit(1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	e1inp_vty_init();
 | 
			
		||||
	bts_vty_init(bts, &bts_log_info);
 | 
			
		||||
 | 
			
		||||
	/* enable realtime priority for us */
 | 
			
		||||
	if (rt_prio != -1) {
 | 
			
		||||
		struct sched_param param;
 | 
			
		||||
 | 
			
		||||
		memset(¶m, 0, sizeof(param));
 | 
			
		||||
		param.sched_priority = rt_prio;
 | 
			
		||||
		rc = sched_setscheduler(getpid(), SCHED_RR, ¶m);
 | 
			
		||||
		if (rc != 0) {
 | 
			
		||||
			fprintf(stderr, "Setting SCHED_RR priority(%d) failed: %s\n",
 | 
			
		||||
				param.sched_priority, strerror(errno));
 | 
			
		||||
			exit(1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        if (gsmtap_ip) {
 | 
			
		||||
		gsmtap = gsmtap_source_init(gsmtap_ip, GSMTAP_UDP_PORT, 1);
 | 
			
		||||
		if (!gsmtap) {
 | 
			
		||||
			fprintf(stderr, "Failed during gsmtap_init()\n");
 | 
			
		||||
			exit(1);
 | 
			
		||||
		}
 | 
			
		||||
		gsmtap_source_add_sink(gsmtap);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bts_init(bts) < 0) {
 | 
			
		||||
		fprintf(stderr, "unable to open bts\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	abis_init(bts);
 | 
			
		||||
 | 
			
		||||
	rc = vty_read_config_file(config_file, NULL);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "Failed to parse the config file: '%s'\n",
 | 
			
		||||
			config_file);
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!phy_link_by_num(0)) {
 | 
			
		||||
		fprintf(stderr, "You need to configure at least phy0\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(trx, &bts->trx_list, list) {
 | 
			
		||||
		if (!trx->role_bts.l1h) {
 | 
			
		||||
			fprintf(stderr, "TRX %u has no associated PHY instance\n",
 | 
			
		||||
				trx->nr);
 | 
			
		||||
			exit(1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	write_pid_file("osmo-bts");
 | 
			
		||||
 | 
			
		||||
	bts_controlif_setup(bts, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_BTS);
 | 
			
		||||
 | 
			
		||||
	rc = telnet_init_dynif(tall_bts_ctx, NULL, vty_get_bind_addr(),
 | 
			
		||||
			       g_vty_port_num);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "Error initializing telnet\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pcu_sock_init(bts->pcu.sock_path)) {
 | 
			
		||||
		fprintf(stderr, "PCU L1 socket failed\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	signal(SIGINT, &signal_handler);
 | 
			
		||||
	signal(SIGTERM, &signal_handler);
 | 
			
		||||
	//signal(SIGABRT, &signal_handler);
 | 
			
		||||
	signal(SIGUSR1, &signal_handler);
 | 
			
		||||
	signal(SIGUSR2, &signal_handler);
 | 
			
		||||
	osmo_init_ignore_signals();
 | 
			
		||||
 | 
			
		||||
	if (!bts->bsc_oml_host) {
 | 
			
		||||
		fprintf(stderr, "Cannot start BTS without knowing BSC OML IP\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	line = abis_open(bts, bts->bsc_oml_host, "sysmoBTS");
 | 
			
		||||
	if (!line) {
 | 
			
		||||
		fprintf(stderr, "unable to connect to BSC\n");
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = phy_links_open();
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "unable to open PHY link(s)\n");
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (daemonize) {
 | 
			
		||||
		rc = osmo_daemonize();
 | 
			
		||||
		if (rc < 0) {
 | 
			
		||||
			perror("Error during daemonize");
 | 
			
		||||
			exit(1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (quit < 2) {
 | 
			
		||||
		log_reset_context();
 | 
			
		||||
		osmo_select_main(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,418 @@
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/gsm_utils.h>
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/gsm_data.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/measurement.h>
 | 
			
		||||
#include <osmo-bts/scheduler.h>
 | 
			
		||||
 | 
			
		||||
/* Tables as per TS 45.008 Section 8.3 */
 | 
			
		||||
static const uint8_t ts45008_83_tch_f[] = { 52, 53, 54, 55, 56, 57, 58, 59 };
 | 
			
		||||
static const uint8_t ts45008_83_tch_hs0[] = { 0, 2, 4, 6, 52, 54, 56, 58 };
 | 
			
		||||
static const uint8_t ts45008_83_tch_hs1[] = { 14, 16, 18, 29, 66, 68, 70, 72 };
 | 
			
		||||
 | 
			
		||||
/* find out if an array contains a given key as element */
 | 
			
		||||
#define ARRAY_CONTAINS(arr, val) array_contains(arr, ARRAY_SIZE(arr), val)
 | 
			
		||||
static bool array_contains(const uint8_t *arr, unsigned int len, uint8_t val) {
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < len; i++) {
 | 
			
		||||
		if (arr[i] == val)
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Decide if a given frame number is part of the "-SUB" measurements (true) or not (false) */
 | 
			
		||||
static bool ts45008_83_is_sub(struct gsm_lchan *lchan, uint32_t fn, bool is_amr_sid_update)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t fn104 = fn % 104;
 | 
			
		||||
 | 
			
		||||
	/* See TS 45.008 Sections 8.3 and 8.4 for a detailed descriptions of the rules
 | 
			
		||||
	 * implemented here. We only implement the logic for Voice, not CSD */
 | 
			
		||||
 | 
			
		||||
	switch (lchan->type) {
 | 
			
		||||
	case GSM_LCHAN_TCH_F:
 | 
			
		||||
		switch (lchan->tch_mode) {
 | 
			
		||||
		case GSM48_CMODE_SIGN:
 | 
			
		||||
		case GSM48_CMODE_SPEECH_V1:
 | 
			
		||||
		case GSM48_CMODE_SPEECH_EFR:
 | 
			
		||||
			if (trx_sched_is_sacch_fn(lchan->ts, fn, true))
 | 
			
		||||
				return true;
 | 
			
		||||
			if (ARRAY_CONTAINS(ts45008_83_tch_f, fn104))
 | 
			
		||||
				return true;
 | 
			
		||||
			break;
 | 
			
		||||
		case GSM48_CMODE_SPEECH_AMR:
 | 
			
		||||
			if (trx_sched_is_sacch_fn(lchan->ts, fn, true))
 | 
			
		||||
				return true;
 | 
			
		||||
			if (is_amr_sid_update)
 | 
			
		||||
				return true;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			LOGPFN(DMEAS, LOGL_ERROR, fn, "%s: Unsupported lchan->tch_mode %u\n",
 | 
			
		||||
				gsm_lchan_name(lchan), lchan->tch_mode);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_LCHAN_TCH_H:
 | 
			
		||||
		switch (lchan->tch_mode) {
 | 
			
		||||
		case GSM48_CMODE_SPEECH_V1:
 | 
			
		||||
			if (trx_sched_is_sacch_fn(lchan->ts, fn, true))
 | 
			
		||||
				return true;
 | 
			
		||||
			switch (lchan->nr) {
 | 
			
		||||
			case 0:
 | 
			
		||||
				if (ARRAY_CONTAINS(ts45008_83_tch_hs0, fn104))
 | 
			
		||||
					return true;
 | 
			
		||||
				break;
 | 
			
		||||
			case 1:
 | 
			
		||||
				if (ARRAY_CONTAINS(ts45008_83_tch_hs1, fn104))
 | 
			
		||||
					return true;
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				OSMO_ASSERT(0);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case GSM48_CMODE_SPEECH_AMR:
 | 
			
		||||
			if (trx_sched_is_sacch_fn(lchan->ts, fn, true))
 | 
			
		||||
				return true;
 | 
			
		||||
			if (is_amr_sid_update)
 | 
			
		||||
				return true;
 | 
			
		||||
			break;
 | 
			
		||||
		case GSM48_CMODE_SIGN:
 | 
			
		||||
			/* No DTX allowed; SUB=FULL, therefore measurements at all frame numbers are
 | 
			
		||||
			 * SUB */
 | 
			
		||||
			return true;
 | 
			
		||||
		default:
 | 
			
		||||
			LOGPFN(DMEAS, LOGL_ERROR, fn, "%s: Unsupported lchan->tch_mode %u\n",
 | 
			
		||||
				gsm_lchan_name(lchan), lchan->tch_mode);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_LCHAN_SDCCH:
 | 
			
		||||
		/* No DTX allowed; SUB=FULL, therefore measurements at all frame numbers are SUB */
 | 
			
		||||
		return true;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Measurement reporting period and mapping of SACCH message block for TCHF
 | 
			
		||||
 * and TCHH chan As per in 3GPP TS 45.008, section 8.4.1.
 | 
			
		||||
 *
 | 
			
		||||
 *             Timeslot number (TN)        TDMA frame number (FN) modulo 104
 | 
			
		||||
 *             Half rate,    Half rate,     Reporting    SACCH
 | 
			
		||||
 * Full Rate   subch.0       subch.1        period       Message block
 | 
			
		||||
 * 0           0 and 1                      0 to 103     12,  38,  64,  90
 | 
			
		||||
 * 1                         0 and 1        13 to 12     25,  51,  77,  103
 | 
			
		||||
 * 2           2 and 3                      26 to 25     38,  64,  90,  12
 | 
			
		||||
 * 3                         2 and 3        39 to 38     51,  77,  103, 25
 | 
			
		||||
 * 4           4 and 5                      52 to 51     64,  90,  12,  38
 | 
			
		||||
 * 5                         4 and 5        65 to 64     77,  103, 25,  51
 | 
			
		||||
 * 6           6 and 7                      78 to 77     90,  12,  38,  64
 | 
			
		||||
 * 7                         6 and 7        91 to 90     103, 25,  51,  77 */
 | 
			
		||||
 | 
			
		||||
static const uint8_t tchf_meas_rep_fn104[] = {
 | 
			
		||||
	[0] =	90,
 | 
			
		||||
	[1] =	103,
 | 
			
		||||
	[2] =	12,
 | 
			
		||||
	[3] =	25,
 | 
			
		||||
	[4] =	38,
 | 
			
		||||
	[5] =	51,
 | 
			
		||||
	[6] =	64,
 | 
			
		||||
	[7] =	77,
 | 
			
		||||
};
 | 
			
		||||
static const uint8_t tchh0_meas_rep_fn104[] = {
 | 
			
		||||
	[0] =	90,
 | 
			
		||||
	[1] =	90,
 | 
			
		||||
	[2] =	12,
 | 
			
		||||
	[3] =	12,
 | 
			
		||||
	[4] =	38,
 | 
			
		||||
	[5] =	38,
 | 
			
		||||
	[6] =	64,
 | 
			
		||||
	[7] =	64,
 | 
			
		||||
};
 | 
			
		||||
static const uint8_t tchh1_meas_rep_fn104[] = {
 | 
			
		||||
	[0] =	103,
 | 
			
		||||
	[1] =	103,
 | 
			
		||||
	[2] =	25,
 | 
			
		||||
	[3] =	25,
 | 
			
		||||
	[4] =	51,
 | 
			
		||||
	[5] =	51,
 | 
			
		||||
	[6] =	77,
 | 
			
		||||
	[7] =	77,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Measurement reporting period for SDCCH8 and SDCCH4 chan
 | 
			
		||||
 * As per in 3GPP TS 45.008, section 8.4.2.
 | 
			
		||||
 *
 | 
			
		||||
 * Logical Chan		TDMA frame number
 | 
			
		||||
 *			(FN) modulo 102
 | 
			
		||||
 *
 | 
			
		||||
 * SDCCH/8		12 to 11
 | 
			
		||||
 * SDCCH/4		37 to 36
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* FN of the first burst whose block completes before reaching fn%102=11 */
 | 
			
		||||
static const uint8_t sdcch8_meas_rep_fn102[] = {
 | 
			
		||||
	[0] = 66,	/* 15(SDCCH), 47(SACCH), 66(SDCCH) */
 | 
			
		||||
	[1] = 70,	/* 19(SDCCH), 51(SACCH), 70(SDCCH) */
 | 
			
		||||
	[2] = 74,	/* 23(SDCCH), 55(SACCH), 74(SDCCH) */
 | 
			
		||||
	[3] = 78,	/* 27(SDCCH), 59(SACCH), 78(SDCCH) */
 | 
			
		||||
	[4] = 98,	/* 31(SDCCH), 98(SACCH), 82(SDCCH) */
 | 
			
		||||
	[5] = 0,	/* 35(SDCCH),  0(SACCH), 86(SDCCH) */
 | 
			
		||||
	[6] = 4,	/* 39(SDCCH),  4(SACCH), 90(SDCCH) */
 | 
			
		||||
	[7] = 8,	/* 43(SDCCH),  8(SACCH), 94(SDCCH) */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* FN of the first burst whose block completes before reaching fn%102=37 */
 | 
			
		||||
static const uint8_t sdcch4_meas_rep_fn102[] = {
 | 
			
		||||
	[0] = 88,	/* 37(SDCCH), 57(SACCH), 88(SDCCH) */
 | 
			
		||||
	[1] = 92,	/* 41(SDCCH), 61(SACCH), 92(SDCCH) */
 | 
			
		||||
	[2] = 6,	/*  6(SACCH), 47(SDCCH), 98(SDCCH) */
 | 
			
		||||
	[3] = 10	/* 10(SACCH),  0(SDCCH), 51(SDCCH) */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Note: The reporting of the measurement results is done via the SACCH channel.
 | 
			
		||||
 * The measurement interval is not aligned with the interval in which the
 | 
			
		||||
 * SACCH is transmitted. When we receive the measurement indication with the
 | 
			
		||||
 * SACCH block, the corresponding measurement interval will already have ended
 | 
			
		||||
 * and we will get the results late, but on spot with the beginning of the
 | 
			
		||||
 * next measurement interval.
 | 
			
		||||
 *
 | 
			
		||||
 * For example: We get a measurement indication on FN%104=38 in TS=2. Then we
 | 
			
		||||
 * will have to look at 3GPP TS 45.008, section 8.4.1 (or 3GPP TS 05.02 Clause 7
 | 
			
		||||
 * Table 1 of 9) what value we need to feed into the lookup tables in order to
 | 
			
		||||
 * detect the measurement period ending. In this example the "real" ending
 | 
			
		||||
 * was on FN%104=12. This is the value we have to look for in
 | 
			
		||||
 * tchf_meas_rep_fn104 to know that a measurement period has just ended. */
 | 
			
		||||
 | 
			
		||||
/* See also 3GPP TS 05.02 Clause 7 Table 1 of 9:
 | 
			
		||||
 * Mapping of logical channels onto physical channels (see subclauses 6.3, 6.4, 6.5) */
 | 
			
		||||
static uint8_t translate_tch_meas_rep_fn104(uint8_t fn_mod)
 | 
			
		||||
{
 | 
			
		||||
	switch (fn_mod) {
 | 
			
		||||
	case 25:
 | 
			
		||||
		return 103;
 | 
			
		||||
	case 38:
 | 
			
		||||
		return 12;
 | 
			
		||||
	case 51:
 | 
			
		||||
		return 25;
 | 
			
		||||
	case 64:
 | 
			
		||||
		return 38;
 | 
			
		||||
	case 77:
 | 
			
		||||
		return 51;
 | 
			
		||||
	case 90:
 | 
			
		||||
		return 64;
 | 
			
		||||
	case 103:
 | 
			
		||||
		return 77;
 | 
			
		||||
	case 12:
 | 
			
		||||
		return 90;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Invalid / not of interest */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* determine if a measurement period ends at the given frame number */
 | 
			
		||||
static int is_meas_complete(struct gsm_lchan *lchan, uint32_t fn)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int fn_mod = -1;
 | 
			
		||||
	const uint8_t *tbl;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	enum gsm_phys_chan_config pchan = ts_pchan(lchan->ts);
 | 
			
		||||
 | 
			
		||||
	if (lchan->ts->nr >= 8)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (pchan >= _GSM_PCHAN_MAX)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	switch (pchan) {
 | 
			
		||||
	case GSM_PCHAN_TCH_F:
 | 
			
		||||
		fn_mod = translate_tch_meas_rep_fn104(fn % 104);
 | 
			
		||||
		if (tchf_meas_rep_fn104[lchan->ts->nr] == fn_mod)
 | 
			
		||||
			rc = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_TCH_H:
 | 
			
		||||
		fn_mod = translate_tch_meas_rep_fn104(fn % 104);
 | 
			
		||||
		if (lchan->nr == 0)
 | 
			
		||||
			tbl = tchh0_meas_rep_fn104;
 | 
			
		||||
		else
 | 
			
		||||
			tbl = tchh1_meas_rep_fn104;
 | 
			
		||||
		if (tbl[lchan->ts->nr] == fn_mod)
 | 
			
		||||
			rc = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_SDCCH8_SACCH8C:
 | 
			
		||||
	case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
 | 
			
		||||
		fn_mod = fn % 102;
 | 
			
		||||
		if (sdcch8_meas_rep_fn102[lchan->nr] == fn_mod)
 | 
			
		||||
			rc = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	case GSM_PCHAN_CCCH_SDCCH4:
 | 
			
		||||
	case GSM_PCHAN_CCCH_SDCCH4_CBCH:
 | 
			
		||||
		fn_mod = fn % 102;
 | 
			
		||||
		if (sdcch4_meas_rep_fn102[lchan->nr] == fn_mod)
 | 
			
		||||
			rc = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		rc = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rc == 1) {
 | 
			
		||||
		DEBUGP(DMEAS,
 | 
			
		||||
		       "%s meas period end fn:%u, fn_mod:%i, status:%d, pchan:%s\n",
 | 
			
		||||
		       gsm_lchan_name(lchan), fn, fn_mod, rc, gsm_pchan_name(pchan));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* receive a L1 uplink measurement from L1 */
 | 
			
		||||
int lchan_new_ul_meas(struct gsm_lchan *lchan, struct bts_ul_meas *ulm, uint32_t fn)
 | 
			
		||||
{
 | 
			
		||||
	if (lchan->state != LCHAN_S_ACTIVE) {
 | 
			
		||||
		LOGPFN(DMEAS, LOGL_NOTICE, fn,
 | 
			
		||||
		     "%s measurement during state: %s, num_ul_meas=%d\n",
 | 
			
		||||
		     gsm_lchan_name(lchan), gsm_lchans_name(lchan->state),
 | 
			
		||||
		     lchan->meas.num_ul_meas);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lchan->meas.num_ul_meas >= ARRAY_SIZE(lchan->meas.uplink)) {
 | 
			
		||||
		LOGPFN(DMEAS, LOGL_NOTICE, fn,
 | 
			
		||||
		     "%s no space for uplink measurement, num_ul_meas=%d\n",
 | 
			
		||||
		     gsm_lchan_name(lchan), lchan->meas.num_ul_meas);
 | 
			
		||||
		return -ENOSPC;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* We expect the lower layers to mark AMR SID_UPDATE frames already as such.
 | 
			
		||||
	 * In this function, we only deal with the comon logic as per the TS 45.008 tables */
 | 
			
		||||
	if (!ulm->is_sub)
 | 
			
		||||
		ulm->is_sub = ts45008_83_is_sub(lchan, fn, false);
 | 
			
		||||
 | 
			
		||||
	DEBUGPFN(DMEAS, fn, "%s adding measurement (is_sub=%u), num_ul_meas=%d\n",
 | 
			
		||||
		gsm_lchan_name(lchan), ulm->is_sub, lchan->meas.num_ul_meas);
 | 
			
		||||
 | 
			
		||||
	memcpy(&lchan->meas.uplink[lchan->meas.num_ul_meas++], ulm,
 | 
			
		||||
		sizeof(*ulm));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* input: BER in steps of .01%, i.e. percent/100 */
 | 
			
		||||
static uint8_t ber10k_to_rxqual(uint32_t ber10k)
 | 
			
		||||
{
 | 
			
		||||
	/* Eight levels of Rx quality are defined and are mapped to the
 | 
			
		||||
	 * equivalent BER before channel decoding, as per in 3GPP TS 45.008,
 | 
			
		||||
	 * secton 8.2.4.
 | 
			
		||||
	 *
 | 
			
		||||
	 * RxQual:				BER Range:
 | 
			
		||||
	 * RXQUAL_0	     BER <  0,2 %       Assumed value = 0,14 %
 | 
			
		||||
	 * RXQUAL_1  0,2 % < BER <  0,4 %	Assumed value = 0,28 %
 | 
			
		||||
	 * RXQUAL_2  0,4 % < BER <  0,8 %	Assumed value = 0,57 %
 | 
			
		||||
	 * RXQUAL_3  0,8 % < BER <  1,6 %	Assumed value = 1,13 %
 | 
			
		||||
	 * RXQUAL_4  1,6 % < BER <  3,2 %	Assumed value = 2,26 %
 | 
			
		||||
	 * RXQUAL_5  3,2 % < BER <  6,4 %	Assumed value = 4,53 %
 | 
			
		||||
	 * RXQUAL_6  6,4 % < BER < 12,8 %	Assumed value = 9,05 %
 | 
			
		||||
	 * RXQUAL_7 12,8 % < BER		Assumed value = 18,10 % */
 | 
			
		||||
 | 
			
		||||
	if (ber10k < 20)
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (ber10k < 40)
 | 
			
		||||
		return 1;
 | 
			
		||||
	if (ber10k < 80)
 | 
			
		||||
		return 2;
 | 
			
		||||
	if (ber10k < 160)
 | 
			
		||||
		return 3;
 | 
			
		||||
	if (ber10k < 320)
 | 
			
		||||
		return 4;
 | 
			
		||||
	if (ber10k < 640)
 | 
			
		||||
		return 5;
 | 
			
		||||
	if (ber10k < 1280)
 | 
			
		||||
		return 6;
 | 
			
		||||
	return 7;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
 | 
			
		||||
{
 | 
			
		||||
	struct gsm_meas_rep_unidir *mru;
 | 
			
		||||
	uint32_t ber_full_sum = 0;
 | 
			
		||||
	uint32_t irssi_full_sum = 0;
 | 
			
		||||
	uint32_t ber_sub_sum = 0;
 | 
			
		||||
	uint32_t irssi_sub_sum = 0;
 | 
			
		||||
	int32_t ta256b_sum = 0;
 | 
			
		||||
	unsigned int num_meas_sub = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* if measurement period is not complete, abort */
 | 
			
		||||
	if (!is_meas_complete(lchan, fn))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* if there are no measurements, skip computation */
 | 
			
		||||
	if (lchan->meas.num_ul_meas == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* compute the actual measurements */
 | 
			
		||||
 | 
			
		||||
	/* step 1: add up */
 | 
			
		||||
	for (i = 0; i < lchan->meas.num_ul_meas; i++) {
 | 
			
		||||
		struct bts_ul_meas *m = &lchan->meas.uplink[i];
 | 
			
		||||
 | 
			
		||||
		ber_full_sum += m->ber10k;
 | 
			
		||||
		irssi_full_sum += m->inv_rssi;
 | 
			
		||||
		ta256b_sum += m->ta_offs_256bits;
 | 
			
		||||
 | 
			
		||||
		if (m->is_sub) {
 | 
			
		||||
			num_meas_sub++;
 | 
			
		||||
			ber_sub_sum += m->ber10k;
 | 
			
		||||
			irssi_sub_sum += m->inv_rssi;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* step 2: divide */
 | 
			
		||||
	ber_full_sum = ber_full_sum / lchan->meas.num_ul_meas;
 | 
			
		||||
	irssi_full_sum = irssi_full_sum / lchan->meas.num_ul_meas;
 | 
			
		||||
	ta256b_sum = ta256b_sum / lchan->meas.num_ul_meas;
 | 
			
		||||
 | 
			
		||||
	if (num_meas_sub) {
 | 
			
		||||
		ber_sub_sum = ber_sub_sum / num_meas_sub;
 | 
			
		||||
		irssi_sub_sum = irssi_sub_sum / num_meas_sub;
 | 
			
		||||
	} else {
 | 
			
		||||
		LOGP(DMEAS, LOGL_ERROR, "%s No measurements for SUB!!!\n", gsm_lchan_name(lchan));
 | 
			
		||||
		/* The only situation in which this can occur is if the related uplink burst/block was
 | 
			
		||||
		 * missing, so let's set BER to 100% and level to lowest possible. */
 | 
			
		||||
		ber_sub_sum = 10000; /* 100% */
 | 
			
		||||
		irssi_sub_sum = 120; /* -120 dBm */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOGP(DMEAS, LOGL_INFO, "%s Computed TA256(% 4d) BER-FULL(%2u.%02u%%), RSSI-FULL(-%3udBm), "
 | 
			
		||||
		"BER-SUB(%2u.%02u%%), RSSI-SUB(-%3udBm)\n", gsm_lchan_name(lchan),
 | 
			
		||||
		ta256b_sum, ber_full_sum/100,
 | 
			
		||||
		ber_full_sum%100, irssi_full_sum, ber_sub_sum/100, ber_sub_sum%100,
 | 
			
		||||
		irssi_sub_sum);
 | 
			
		||||
 | 
			
		||||
	/* store results */
 | 
			
		||||
	mru = &lchan->meas.ul_res;
 | 
			
		||||
	mru->full.rx_lev = dbm2rxlev((int)irssi_full_sum * -1);
 | 
			
		||||
	mru->sub.rx_lev = dbm2rxlev((int)irssi_sub_sum * -1);
 | 
			
		||||
	mru->full.rx_qual = ber10k_to_rxqual(ber_full_sum);
 | 
			
		||||
	mru->sub.rx_qual = ber10k_to_rxqual(ber_sub_sum);
 | 
			
		||||
	lchan->meas.ms_toa256 = ta256b_sum;
 | 
			
		||||
 | 
			
		||||
	LOGP(DMEAS, LOGL_INFO, "%s UL MEAS RXLEV_FULL(%u), RXLEV_SUB(%u),"
 | 
			
		||||
	       "RXQUAL_FULL(%u), RXQUAL_SUB(%u), num_meas_sub(%u), num_ul_meas(%u) \n",
 | 
			
		||||
	       gsm_lchan_name(lchan),
 | 
			
		||||
	       mru->full.rx_lev,
 | 
			
		||||
	       mru->sub.rx_lev,
 | 
			
		||||
	       mru->full.rx_qual,
 | 
			
		||||
	       mru->sub.rx_qual, num_meas_sub, lchan->meas.num_ul_meas);
 | 
			
		||||
 | 
			
		||||
	lchan->meas.flags |= LC_UL_M_F_RES_VALID;
 | 
			
		||||
	lchan->meas.num_ul_meas = 0;
 | 
			
		||||
 | 
			
		||||
	/* send a signal indicating computation is complete */
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,603 @@
 | 
			
		||||
/* (C) 2014 by 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 Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <osmo-bts/dtx_dl_amr_fsm.h>
 | 
			
		||||
#include <osmo-bts/msg_utils.h>
 | 
			
		||||
#include <osmo-bts/logging.h>
 | 
			
		||||
#include <osmo-bts/oml.h>
 | 
			
		||||
#include <osmo-bts/amr.h>
 | 
			
		||||
#include <osmo-bts/rsl.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/gsm/protocol/ipaccess.h>
 | 
			
		||||
#include <osmocom/gsm/protocol/gsm_12_21.h>
 | 
			
		||||
#include <osmocom/gsm/abis_nm.h>
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/core/fsm.h>
 | 
			
		||||
#include <osmocom/trau/osmo_ortp.h>
 | 
			
		||||
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#define STI_BIT_MASK 16
 | 
			
		||||
 | 
			
		||||
static int check_fom(struct abis_om_hdr *omh, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (omh->length != len) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR, "Incorrect OM hdr length value %d %zu\n",
 | 
			
		||||
		     omh->length, len);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (len < sizeof(struct abis_om_fom_hdr)) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR, "FOM header insufficient space %zu %zu\n",
 | 
			
		||||
		     len, sizeof(struct abis_om_fom_hdr));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int check_manuf(struct msgb *msg, struct abis_om_hdr *omh, size_t msg_size)
 | 
			
		||||
{
 | 
			
		||||
	int type;
 | 
			
		||||
	size_t size;
 | 
			
		||||
 | 
			
		||||
	if (msg_size < 1) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR, "No ManId Length Indicator %zu\n",
 | 
			
		||||
		     msg_size);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (omh->data[0] >= msg_size - 1) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR,
 | 
			
		||||
		     "Insufficient message space for this ManId Length %d %zu\n",
 | 
			
		||||
		     omh->data[0], msg_size - 1);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (omh->data[0] == sizeof(abis_nm_ipa_magic) &&
 | 
			
		||||
		strncmp(abis_nm_ipa_magic, (const char *)omh->data + 1,
 | 
			
		||||
			sizeof(abis_nm_ipa_magic)) == 0) {
 | 
			
		||||
		type = OML_MSG_TYPE_IPA;
 | 
			
		||||
		size = sizeof(abis_nm_ipa_magic) + 1;
 | 
			
		||||
	} else if (omh->data[0] == sizeof(abis_nm_osmo_magic) &&
 | 
			
		||||
		strncmp(abis_nm_osmo_magic, (const char *) omh->data + 1,
 | 
			
		||||
			sizeof(abis_nm_osmo_magic)) == 0) {
 | 
			
		||||
		type = OML_MSG_TYPE_OSMO;
 | 
			
		||||
		size = sizeof(abis_nm_osmo_magic) + 1;
 | 
			
		||||
	} else {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR, "Manuf Label Unknown\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* we have verified that the vendor string fits */
 | 
			
		||||
	msg->l3h = omh->data + size;
 | 
			
		||||
	if (check_fom(omh, msgb_l3len(msg)) != 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
	return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* check that DTX is in the middle of silence */
 | 
			
		||||
static inline bool dtx_is_update(const struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	if (!dtx_dl_amr_enabled(lchan))
 | 
			
		||||
		return false;
 | 
			
		||||
	if (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_U_NOINH)
 | 
			
		||||
		return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* check that DTX is in the beginning of silence for AMR HR */
 | 
			
		||||
bool dtx_is_first_p1(const struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	if (!dtx_dl_amr_enabled(lchan))
 | 
			
		||||
		return false;
 | 
			
		||||
	if ((lchan->type == GSM_LCHAN_TCH_H &&
 | 
			
		||||
	     lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1))
 | 
			
		||||
		return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* update lchan SID status */
 | 
			
		||||
void lchan_set_marker(bool t, struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	if (t)
 | 
			
		||||
		lchan->tch.dtx.ul_sid = true;
 | 
			
		||||
	else if (lchan->tch.dtx.ul_sid) {
 | 
			
		||||
		lchan->tch.dtx.ul_sid = false;
 | 
			
		||||
		lchan->rtp_tx_marker = true;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Store the last SID frame in lchan context
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 *  \param[in] l1_payload buffer with SID data
 | 
			
		||||
 *  \param[in] length length of l1_payload
 | 
			
		||||
 *  \param[in] fn Frame Number for which we check scheduling
 | 
			
		||||
 *  \param[in] update 0 if SID_FIRST, 1 if SID_UPDATE, -1 if not AMR SID
 | 
			
		||||
 */
 | 
			
		||||
void dtx_cache_payload(struct gsm_lchan *lchan, const uint8_t *l1_payload,
 | 
			
		||||
		       size_t length, uint32_t fn, int update)
 | 
			
		||||
{
 | 
			
		||||
	size_t amr = (update < 0) ? 0 : 2,
 | 
			
		||||
		copy_len = OSMO_MIN(length,
 | 
			
		||||
				ARRAY_SIZE(lchan->tch.dtx.cache) - amr);
 | 
			
		||||
 | 
			
		||||
	lchan->tch.dtx.len = copy_len + amr;
 | 
			
		||||
	/* SID FIRST is special because it's both sent and cached: */
 | 
			
		||||
	if (update == 0) {
 | 
			
		||||
		lchan->tch.dtx.is_update = false; /* Mark SID FIRST explicitly */
 | 
			
		||||
		/* for non-AMR case - always update FN for incoming SID FIRST */
 | 
			
		||||
		if (!amr || !dtx_is_update(lchan))
 | 
			
		||||
			lchan->tch.dtx.fn = fn;
 | 
			
		||||
		/* for AMR case - do not update FN if SID FIRST arrives in a
 | 
			
		||||
		   middle of silence: this should not be happening according to
 | 
			
		||||
		   the spec */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(lchan->tch.dtx.cache + amr, l1_payload, copy_len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Check current state of DTX DL AMR FSM and dispatch necessary events
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 *  \param[in] rtp_pl buffer with RTP data
 | 
			
		||||
 *  \param[in] rtp_pl_len length of rtp_pl
 | 
			
		||||
 *  \param[in] fn Frame Number for which we check scheduling
 | 
			
		||||
 *  \param[in] l1_payload buffer where CMR and CMI prefix should be added
 | 
			
		||||
 *  \param[in] marker RTP Marker bit
 | 
			
		||||
 *  \param[out] len Length of expected L1 payload
 | 
			
		||||
 *  \param[out] ft_out Frame Type to be populated after decoding
 | 
			
		||||
 *  \returns 0 in case of success; negative on error
 | 
			
		||||
 */
 | 
			
		||||
int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
 | 
			
		||||
			size_t rtp_pl_len, uint32_t fn, uint8_t *l1_payload,
 | 
			
		||||
			bool marker, uint8_t *len, uint8_t *ft_out)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t cmr;
 | 
			
		||||
	enum osmo_amr_type ft;
 | 
			
		||||
	enum osmo_amr_quality bfi;
 | 
			
		||||
	int8_t sti, cmi;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	if (dtx_dl_amr_enabled(lchan)) {
 | 
			
		||||
		if (lchan->type == GSM_LCHAN_TCH_H && !rtp_pl) {
 | 
			
		||||
			/* we're called by gen_empty_tch_msg() to handle states
 | 
			
		||||
			   specific to AMR HR DTX */
 | 
			
		||||
			switch (lchan->tch.dtx.dl_amr_fsm->state) {
 | 
			
		||||
			case ST_SID_F2:
 | 
			
		||||
				*len = 3; /* SID-FIRST P1 -> P2 completion */
 | 
			
		||||
				memcpy(l1_payload, lchan->tch.dtx.cache, 2);
 | 
			
		||||
				rc = 0;
 | 
			
		||||
				dtx_dispatch(lchan, E_COMPL);
 | 
			
		||||
				break;
 | 
			
		||||
			case ST_SID_U:
 | 
			
		||||
				rc = -EBADMSG;
 | 
			
		||||
				dtx_dispatch(lchan, E_SID_U);
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				rc = -EBADMSG;
 | 
			
		||||
			}
 | 
			
		||||
			return rc;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!rtp_pl_len)
 | 
			
		||||
		return -EBADMSG;
 | 
			
		||||
 | 
			
		||||
	rc = osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, &bfi, &sti);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DRTP, LOGL_ERROR, "failed to decode AMR RTP (length %zu, "
 | 
			
		||||
		     "%p)\n", rtp_pl_len, rtp_pl);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* only needed for old sysmo firmware: */
 | 
			
		||||
	*ft_out = ft;
 | 
			
		||||
 | 
			
		||||
	/* CMI in downlink tells the L1 encoder which encoding function
 | 
			
		||||
	 * it will use, so we have to use the frame type */
 | 
			
		||||
	if (osmo_amr_is_speech(ft))
 | 
			
		||||
		cmi = ft;
 | 
			
		||||
 | 
			
		||||
	/* populate L1 payload with CMR/CMI - might be ignored by caller: */
 | 
			
		||||
	amr_set_mode_pref(l1_payload, &lchan->tch.amr_mr, cmi, cmr);
 | 
			
		||||
 | 
			
		||||
	/* populate DTX cache with CMR/CMI - overwrite cache which will be
 | 
			
		||||
	   either updated or invalidated by caller anyway: */
 | 
			
		||||
	amr_set_mode_pref(lchan->tch.dtx.cache, &lchan->tch.amr_mr, cmi, cmr);
 | 
			
		||||
	*len = 3 + rtp_pl_len;
 | 
			
		||||
 | 
			
		||||
	/* DTX DL is not enabled, move along */
 | 
			
		||||
	if (!lchan->ts->trx->bts->dtxd)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (osmo_amr_is_speech(ft)) {
 | 
			
		||||
		/* AMR HR - SID-FIRST_P1 Inhibition */
 | 
			
		||||
		if (marker && lchan->tch.dtx.dl_amr_fsm->state == ST_VOICE)
 | 
			
		||||
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
						      E_INHIB, (void *)lchan);
 | 
			
		||||
 | 
			
		||||
		/* AMR HR - SID-UPDATE Inhibition */
 | 
			
		||||
		if (marker && lchan->type == GSM_LCHAN_TCH_H &&
 | 
			
		||||
		    lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U)
 | 
			
		||||
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
						      E_INHIB, (void *)lchan);
 | 
			
		||||
 | 
			
		||||
		/* AMR FR & HR - generic */
 | 
			
		||||
		if (marker && (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1 ||
 | 
			
		||||
			       lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 ||
 | 
			
		||||
			       lchan->tch.dtx.dl_amr_fsm->state == ST_U_NOINH))
 | 
			
		||||
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
						      E_ONSET, (void *)lchan);
 | 
			
		||||
 | 
			
		||||
		if (lchan->tch.dtx.dl_amr_fsm->state != ST_VOICE)
 | 
			
		||||
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
						      E_VOICE, (void *)lchan);
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ft == AMR_SID) {
 | 
			
		||||
		if (lchan->tch.dtx.dl_amr_fsm->state == ST_VOICE) {
 | 
			
		||||
			/* SID FIRST/UPDATE scheduling logic relies on SID FIRST
 | 
			
		||||
			   being sent first hence we have to force caching of SID
 | 
			
		||||
			   as FIRST regardless of actually decoded type */
 | 
			
		||||
			dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, false);
 | 
			
		||||
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
						      sti ? E_SID_U : E_SID_F,
 | 
			
		||||
						      (void *)lchan);
 | 
			
		||||
		} else if (lchan->tch.dtx.dl_amr_fsm->state != ST_FACCH)
 | 
			
		||||
			dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, sti);
 | 
			
		||||
		if (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2)
 | 
			
		||||
			return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
						      E_COMPL, (void *)lchan);
 | 
			
		||||
		return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
					      sti ? E_SID_U : E_SID_F,
 | 
			
		||||
					      (void *)lchan);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ft != AMR_NO_DATA) {
 | 
			
		||||
		LOGP(DRTP, LOGL_ERROR, "unsupported AMR FT 0x%02x\n", ft);
 | 
			
		||||
		return -ENOTSUP;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (marker)
 | 
			
		||||
		osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_VOICE,
 | 
			
		||||
				       (void *)lchan);
 | 
			
		||||
	*len = 0;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* STI is located in payload byte 6, cache contains 2 byte prefix (CMR/CMI)
 | 
			
		||||
 * STI set = SID UPDATE, STI unset = SID FIRST
 | 
			
		||||
 */
 | 
			
		||||
static inline void dtx_sti_set(struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	lchan->tch.dtx.cache[6 + 2] |= STI_BIT_MASK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dtx_sti_unset(struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	lchan->tch.dtx.cache[6 + 2] &= ~STI_BIT_MASK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Check if enough time has passed since last SID (if any) to repeat it
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 *  \param[in] fn Frame Number for which we check scheduling
 | 
			
		||||
 *  \returns true if transmission can be omitted, false otherwise
 | 
			
		||||
 */
 | 
			
		||||
static inline bool dtx_amr_sid_optional(struct gsm_lchan *lchan, uint32_t fn)
 | 
			
		||||
{
 | 
			
		||||
	if (!dtx_dl_amr_enabled(lchan))
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	/* Compute approx. time delta x26 based on Fn duration */
 | 
			
		||||
	uint32_t dx26 = 120 * (fn - lchan->tch.dtx.fn);
 | 
			
		||||
 | 
			
		||||
	/* We're resuming after FACCH interruption */
 | 
			
		||||
	if (lchan->tch.dtx.dl_amr_fsm->state == ST_FACCH) {
 | 
			
		||||
		/* force STI bit to 0 so cache is treated as SID FIRST */
 | 
			
		||||
		dtx_sti_unset(lchan);
 | 
			
		||||
		lchan->tch.dtx.is_update = false;
 | 
			
		||||
		/* check that this FN has not been used for FACCH message
 | 
			
		||||
		   already: we rely here on the order of RTS arrival from L1 - we
 | 
			
		||||
		   expect that PH-DATA.req ALWAYS comes before PH-TCH.req for the
 | 
			
		||||
		   same FN */
 | 
			
		||||
		if(lchan->type == GSM_LCHAN_TCH_H) {
 | 
			
		||||
			if (lchan->tch.dtx.fn != LCHAN_FN_DUMMY &&
 | 
			
		||||
			    lchan->tch.dtx.fn != LCHAN_FN_WAIT) {
 | 
			
		||||
				/* FACCH interruption is over */
 | 
			
		||||
				dtx_dispatch(lchan, E_COMPL);
 | 
			
		||||
				return false;
 | 
			
		||||
			} else if(lchan->tch.dtx.fn == LCHAN_FN_DUMMY) {
 | 
			
		||||
				lchan->tch.dtx.fn = LCHAN_FN_WAIT;
 | 
			
		||||
			} else
 | 
			
		||||
				lchan->tch.dtx.fn = fn;
 | 
			
		||||
		} else if(lchan->type == GSM_LCHAN_TCH_F) {
 | 
			
		||||
			if (lchan->tch.dtx.fn != LCHAN_FN_DUMMY) {
 | 
			
		||||
				/* FACCH interruption is over */
 | 
			
		||||
				dtx_dispatch(lchan, E_COMPL);
 | 
			
		||||
				return false;
 | 
			
		||||
			} else
 | 
			
		||||
				lchan->tch.dtx.fn = fn;
 | 
			
		||||
		}
 | 
			
		||||
		/* this FN was already used for FACCH or ONSET message so we just
 | 
			
		||||
		   prepare things for next one */
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lchan->tch.dtx.dl_amr_fsm->state == ST_VOICE)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	/* according to 3GPP TS 26.093 A.5.1.1:
 | 
			
		||||
	   (*26) to avoid float math, add 1 FN tolerance (-120) */
 | 
			
		||||
	if (lchan->tch.dtx.is_update) { /* SID UPDATE: every 8th RTP frame */
 | 
			
		||||
		if (dx26 < GSM_RTP_FRAME_DURATION_MS * 8 * 26 - 120)
 | 
			
		||||
			return true;
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	/* 3rd frame after SID FIRST should be SID UPDATE */
 | 
			
		||||
	if (dx26 < GSM_RTP_FRAME_DURATION_MS * 3 * 26 - 120)
 | 
			
		||||
		return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool fn_chk(const uint8_t *t, uint32_t fn, uint8_t len)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t i;
 | 
			
		||||
	for (i = 0; i < len; i++)
 | 
			
		||||
		if (fn % 104 == t[i])
 | 
			
		||||
			return false;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Check if TX scheduling is optional for a given FN in case of DTX
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 *  \param[in] fn Frame Number for which we check scheduling
 | 
			
		||||
 *  \returns true if transmission can be omitted, false otherwise
 | 
			
		||||
 */
 | 
			
		||||
static inline bool dtx_sched_optional(struct gsm_lchan *lchan, uint32_t fn)
 | 
			
		||||
{
 | 
			
		||||
	/* According to 3GPP TS 45.008 § 8.3: */
 | 
			
		||||
	static const uint8_t f[] = { 52, 53, 54, 55, 56, 57, 58, 59 },
 | 
			
		||||
				h0[] = { 0, 2, 4, 6, 52, 54, 56, 58 },
 | 
			
		||||
				h1[] = { 14, 16, 18, 20, 66, 68, 70, 72 };
 | 
			
		||||
	if (lchan->tch_mode == GSM48_CMODE_SPEECH_V1) {
 | 
			
		||||
		if (lchan->type == GSM_LCHAN_TCH_F)
 | 
			
		||||
			return fn_chk(f, fn, ARRAY_SIZE(f));
 | 
			
		||||
		else
 | 
			
		||||
			return fn_chk(lchan->nr ? h1 : h0, fn,
 | 
			
		||||
				      lchan->nr ? ARRAY_SIZE(h1) :
 | 
			
		||||
				      ARRAY_SIZE(h0));
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Check if DTX DL AMR is enabled for a given lchan (it have proper type,
 | 
			
		||||
 *         FSM is allocated etc.)
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 *  \returns true if DTX DL AMR is enabled, false otherwise
 | 
			
		||||
 */
 | 
			
		||||
bool dtx_dl_amr_enabled(const struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	if (lchan->ts->trx->bts->dtxd &&
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm &&
 | 
			
		||||
	    lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
 | 
			
		||||
		return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Check if DTX DL AMR FSM state is recursive: requires secondary
 | 
			
		||||
 *         response to a single RTS request from L1.
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 *  \returns true if DTX DL AMR FSM state is recursive, false otherwise
 | 
			
		||||
 */
 | 
			
		||||
bool dtx_recursion(const struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	if (!dtx_dl_amr_enabled(lchan))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_V ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_F ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_V_REC ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_F_REC ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH_V ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH_F ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH_V_REC ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH_F_REC ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_V ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F_REC ||
 | 
			
		||||
	    lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_V_REC)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Send signal to FSM: with proper check if DIX is enabled for this lchan
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 *  \param[in] e DTX DL AMR FSM Event
 | 
			
		||||
 */
 | 
			
		||||
void dtx_dispatch(struct gsm_lchan *lchan, enum dtx_dl_amr_fsm_events e)
 | 
			
		||||
{
 | 
			
		||||
	if (dtx_dl_amr_enabled(lchan))
 | 
			
		||||
		osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, e,
 | 
			
		||||
				       (void *)lchan);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Send internal signal to FSM: check that DTX is enabled for this chan,
 | 
			
		||||
 *         check that current FSM and lchan states are permitting such signal.
 | 
			
		||||
 *         Note: this should be the only way to dispatch E_COMPL to FSM from
 | 
			
		||||
 *               BTS code.
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 */
 | 
			
		||||
void dtx_int_signal(struct gsm_lchan *lchan)
 | 
			
		||||
{
 | 
			
		||||
	if (!dtx_dl_amr_enabled(lchan))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (dtx_is_first_p1(lchan) || dtx_recursion(lchan))
 | 
			
		||||
		dtx_dispatch(lchan, E_COMPL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! \brief Repeat last SID if possible in case of DTX
 | 
			
		||||
 *  \param[in] lchan Logical channel on which we check scheduling
 | 
			
		||||
 *  \param[in] dst Buffer to copy last SID into
 | 
			
		||||
 *  \returns Number of bytes copied + 1 (to accommodate for extra byte with
 | 
			
		||||
 *           payload type), 0 if there's nothing to copy
 | 
			
		||||
 */
 | 
			
		||||
uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn)
 | 
			
		||||
{
 | 
			
		||||
	/* FIXME: add EFR support */
 | 
			
		||||
	if (lchan->tch_mode == GSM48_CMODE_SPEECH_EFR)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) {
 | 
			
		||||
		if (dtx_sched_optional(lchan, fn))
 | 
			
		||||
			return 0;
 | 
			
		||||
	} else
 | 
			
		||||
		if (dtx_amr_sid_optional(lchan, fn))
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
	if (lchan->tch.dtx.len) {
 | 
			
		||||
		if (dtx_dl_amr_enabled(lchan)) {
 | 
			
		||||
			if ((lchan->type == GSM_LCHAN_TCH_H &&
 | 
			
		||||
			     lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2) ||
 | 
			
		||||
			    (lchan->type == GSM_LCHAN_TCH_F &&
 | 
			
		||||
			     lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1)) {
 | 
			
		||||
				/* advance FSM in case we've just sent SID FIRST
 | 
			
		||||
				   to restore silence after FACCH interruption */
 | 
			
		||||
				osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
						       E_SID_U, (void *)lchan);
 | 
			
		||||
				dtx_sti_unset(lchan);
 | 
			
		||||
			} else if (dtx_is_update(lchan)) {
 | 
			
		||||
				/* enforce SID UPDATE for next repetition: it
 | 
			
		||||
				   might have been altered by FACCH handling */
 | 
			
		||||
				dtx_sti_set(lchan);
 | 
			
		||||
				if (lchan->type == GSM_LCHAN_TCH_H &&
 | 
			
		||||
				    lchan->tch.dtx.dl_amr_fsm->state ==
 | 
			
		||||
				    ST_U_NOINH)
 | 
			
		||||
					osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
 | 
			
		||||
							       E_COMPL,
 | 
			
		||||
							       (void *)lchan);
 | 
			
		||||
				lchan->tch.dtx.is_update = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		memcpy(dst, lchan->tch.dtx.cache, lchan->tch.dtx.len);
 | 
			
		||||
		lchan->tch.dtx.fn = fn;
 | 
			
		||||
		return lchan->tch.dtx.len + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LOGP(DL1C, LOGL_DEBUG, "Have to send %s frame on TCH but SID buffer "
 | 
			
		||||
	     "is empty - sent nothing\n",
 | 
			
		||||
	     get_value_string(gsm48_chan_mode_names, lchan->tch_mode));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return 0 in case the IPA structure is okay and in this
 | 
			
		||||
 * case the l2h will be set to the beginning of the data.
 | 
			
		||||
 */
 | 
			
		||||
int msg_verify_ipa_structure(struct msgb *msg)
 | 
			
		||||
{
 | 
			
		||||
	struct ipaccess_head *hh;
 | 
			
		||||
 | 
			
		||||
	if (msgb_l1len(msg) < sizeof(struct ipaccess_head)) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR,
 | 
			
		||||
			"Ipa header insufficient space %d %zu\n",
 | 
			
		||||
			msgb_l1len(msg), sizeof(struct ipaccess_head));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hh = (struct ipaccess_head *) msg->l1h;
 | 
			
		||||
 | 
			
		||||
	if (ntohs(hh->len) != msgb_l1len(msg) - sizeof(struct ipaccess_head)) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR,
 | 
			
		||||
			"Incorrect ipa header msg size %d %zu\n",
 | 
			
		||||
			ntohs(hh->len), msgb_l1len(msg) - sizeof(struct ipaccess_head));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hh->proto == IPAC_PROTO_OSMO) {
 | 
			
		||||
		struct ipaccess_head_ext *hh_ext = (struct ipaccess_head_ext *) hh->data;
 | 
			
		||||
		if (ntohs(hh->len) < sizeof(*hh_ext)) {
 | 
			
		||||
			LOGP(DL1C, LOGL_ERROR, "IPA length shorter than OSMO header\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		msg->l2h = hh_ext->data;
 | 
			
		||||
	} else
 | 
			
		||||
		msg->l2h = hh->data;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief Verify the structure of the OML message and set l3h
 | 
			
		||||
 *
 | 
			
		||||
 * This function verifies that the data in \param in msg is a proper
 | 
			
		||||
 * OML message. This code assumes that msg->l2h points to the
 | 
			
		||||
 * beginning of the OML message. In the successful case the msg->l3h
 | 
			
		||||
 * will be set and will point to the FOM header. The value is undefined
 | 
			
		||||
 * in all other cases.
 | 
			
		||||
 *
 | 
			
		||||
 * \param msg The message to analyze starting from msg->l2h.
 | 
			
		||||
 * \return In case the structure is correct a positive number will be
 | 
			
		||||
 * returned and msg->l3h will point to the FOM. The number is a
 | 
			
		||||
 * classification of the vendor type of the message.
 | 
			
		||||
 */
 | 
			
		||||
int msg_verify_oml_structure(struct msgb *msg)
 | 
			
		||||
{
 | 
			
		||||
	struct abis_om_hdr *omh;
 | 
			
		||||
 | 
			
		||||
	if (msgb_l2len(msg) < sizeof(*omh)) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR, "Om header insufficient space %d %zu\n",
 | 
			
		||||
		     msgb_l2len(msg), sizeof(*omh));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	omh = (struct abis_om_hdr *) msg->l2h;
 | 
			
		||||
	if (omh->mdisc != ABIS_OM_MDISC_FOM &&
 | 
			
		||||
	    omh->mdisc != ABIS_OM_MDISC_MANUF) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR, "Incorrect om mdisc value %x\n",
 | 
			
		||||
		     omh->mdisc);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (omh->placement != ABIS_OM_PLACEMENT_ONLY) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR, "Incorrect om placement value %x %x\n",
 | 
			
		||||
		     omh->placement, ABIS_OM_PLACEMENT_ONLY);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (omh->sequence != 0) {
 | 
			
		||||
		LOGP(DL1C, LOGL_ERROR, "Incorrect om sequence value %d\n",
 | 
			
		||||
		     omh->sequence);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (omh->mdisc == ABIS_OM_MDISC_MANUF)
 | 
			
		||||
		return check_manuf(msg, omh, msgb_l2len(msg) - sizeof(*omh));
 | 
			
		||||
 | 
			
		||||
	msg->l3h = omh->data;
 | 
			
		||||
	if (check_fom(omh, msgb_l3len(msg)) != 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
	return OML_MSG_TYPE_ETSI;
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user