Compare commits

...

1712 Commits

Author SHA1 Message Date
Pau Espin Pedrol
11f72dfbcb Bump version: 0.9.0.280-56b7c-dirty → 1.0.0
Change-Id: I38b083755e71eac5158e68ef958e210eeced9038
2021-11-16 16:47:29 +01:00
Pau Espin Pedrol
56b7c64298 Move T3172 T_defs_bts->T_defs_pcu to have it configurable in VTY
The timers in T_defs_bts are actually set by BTS over PCUIF. That's not
the case for T3172, hence let's move it to T_defs_pcu so it can be
configured over VTY.

Change-Id: If24191b2305007aa5be5b551c913738a97597c77
2021-11-16 11:35:23 +01:00
Pau Espin Pedrol
683ce64039 T_defs_pcu: Set default val for X2000 to 0 ms
That timer is really only useful to free the tbf asynchronously after
generating the Pkt Access Reject message, since we have nothing to do
with it after the message is sent, and the dummt TBF doesn't really hold
any reserved resource such as USF or TFI.
The timer is useful to still do the freeing asyncrhonously, since the
scheduler is interacting with the TBF during the code path, but there's
no real need to keep the object alive for 2 ms afterwards. Having a
default value of 0 ms is enough, since it fullfills the requirement
of freeing asnchronously.

The value of 2 ms was set initially when the reject support was added
here (e9a138e111), with no specific
explanation on the 2 ms value. It was just probably picked as a
convinience one, but 0 is actually more convinient.

Change-Id: I60e34e643f5c9d9afaf85530c54ab3232dc8f0be
2021-11-15 17:10:55 +00:00
Pau Espin Pedrol
e30153ea10 tbf_dl_ass_fsm: Drop unsued X2000 timer callback
That timer is only relevant for transmission of Packet Access Reject,
which happens only for Uplink assignment, and hence is only set in the
timer of tbf_ul_ass_fsm, never in tbf_dl_ass_fsm. This is probably a
copy-paste artifact when implementing both FSMs.

Change-Id: I95900e211eddb280c72fb712ba1da4d2230cb77b
2021-11-15 17:10:55 +00:00
Pau Espin Pedrol
0dcbc07682 bts: Add counter availablePDCHAllocatedTime
We basically want to probe whether it's possible to allocate TBFs, or
whether we know it will fail due to all main resources being already in
use (TFI, USF).

Having bts_all_pdch_allocated() return false doesn't mean though that an
MS will be able to allocate a TBF for sure. That's because further
restrictions are applied based on MS: whether it was already attached to
a specific TRX, whether the ms_class allows for a certain multislot
combination, etc. However, it should provide a general idea on whether
for sure the PCU is unable to provide more allocations. More fine
grained state about failures can still be followed by looking at
tbf:alloc:failed:* rate counters.

Related: SYS#4878
Depends: Iabb17a08e6e1a86f168cdb008fba05ecd4776bdd (libosmocore)
Change-Id: Ie0f0c451558817bddc3fe1a0f0df531f14c9f1d3
2021-11-15 11:40:07 +01:00
Pau Espin Pedrol
5deac1404d Fix MS ending up with assigned imsi 000
The whole paging path and data structre is cleaned up.
New MS helpers ms_imsi_is_valid() and ms_paging_group() are introduced
to help in the process and keep implementation details inside GprsMs
class.

Related: OS#5303
Change-Id: I4c0838b26ede58e4b711410eee2a8e4f71e9414b
2021-11-12 18:38:43 +01:00
Pau Espin Pedrol
13866f02a2 vty: Introduce command 'gsmtap-remote-host' and 'gsmtap-category enable-all'
Related: OS#5306
Change-Id: Ibc6f78c46831b3c90ee3e97300fc13dc441df4c8
2021-11-12 17:01:28 +01:00
Pau Espin Pedrol
afd9393a2d pcu_main: Mark -r cmdline param as deprecated
We have VTY support for it enabled in osmo-pcu since a while ago. Let's
mark it as depcreated now so that we can drop this cmdline arg in the
future.

Change-Id: Ic39c94984cb311aac0464d69f564af6d5447bd0f
2021-11-12 17:00:34 +01:00
Pau Espin Pedrol
17bfbedbc7 tbf_{dl,ul}_ass_fsm.c: use proper macro to log tbf
TBF can be either UL or DL in that FSM.

Change-Id: Ief0cd5298e062f11b0f39716162a67b87c9ff35f
2021-11-12 13:14:19 +01:00
Pau Espin Pedrol
bd1b90f141 tbf_dl_ass_fsm: Fix missing transition to NONE if DL TBF is nonexistent
If by the time the PktDlAss is to be scheduled by the scheduler the DL
TBF is gone, the FSM will abort the assignment and go back to state
NONE.
However, the transition was missing, ending up in the scheduler trying
to schedule the message unsuccessfuly lots of times per second, clogging
the logs and disrupting normal operation.

Related: OS#5293
Change-Id: I6f421e5ddc9894fee72de1102df35a76cf2f2647
2021-11-12 12:03:00 +00:00
Pau Espin Pedrol
84f2b51a37 tbf_dl_ass_fsm: Log both TBFs if old TBF is handling assignment for new one
Change-Id: I4ec4eb2ca3f4fa576a4f9ada8c2462f59ca078b9
2021-11-12 12:03:00 +00:00
Pau Espin Pedrol
dbdf84eaff cosmetic: gprs_pcu.h: Fix typo in comment
Change-Id: I7140decb50e822bf412fa380dc8b6ef6486a5681
2021-11-11 14:11:40 +01:00
Pau Espin Pedrol
7eb9e69506 tbf_ul_ass_fsm: Log both TBFs if old TBF is handling assignment for new one
Change-Id: If475560aab16b0a89743139189ff7720389132a5
2021-11-10 17:54:38 +01:00
Pau Espin Pedrol
715aeb4ebc pdch: Increase log level of line informing about TS control change
This way it's the same log level as the one used in all other paths
using tbf_assign_control_ts() to assign tbf->control_ts =
tbf->first_common_ts, and this specific event is not lost from logs.

Change-Id: Ia32d835ee4c14d7d48391452b5e3d05ed88e0483
2021-11-10 17:21:43 +01:00
Pau Espin Pedrol
ace3b1bdc1 pdch: Drop previous UL TBF from MS who sent PktResReq through SBA
If the MS has a pending UL TBF but we just received a PktResReq on an
allocated SBA from it (same TLLI, hence same MS), then it means it
allocated the SBA through RACH req and hence it was on CCCH. That means
it was not active on any PDCH, hence for sure the previous UL TBF can be
dropped.

Related: OS#5293

Change-Id: I1f20dba56f46ea15cbb9b03bdc5b79d923491a3c
2021-11-10 16:11:19 +01:00
Pau Espin Pedrol
54a126f6d4 pdch: Update ms_reserved_slots in GprsMS when TS becomes disabled
Otherwise, after the TS is disabled, a new TBF created for that MS may
end up in alloc_algorithm assigning the disabled TS, since it will be in
the mask of reserved PDCH TS for that MS.

Related: OS#5265
Change-Id: Ifc59ac37fa6b0ad9ecc8f76326928611e748b11c
2021-11-10 11:36:55 +01:00
Pau Espin Pedrol
853cdf85eb ts_alloc: rename variable to clarify meaning
The variable counts reserved slots, not available one. It can easily be
seen by checking function count_slots() documentation "Number of
reserved TS".

The previous naming was used probably to indicate "available to reserve"
TS, but the naming is misleading.

Change-Id: Ib58e87d5a067d20d0b331fe32dff61b95ecc3e3f
2021-11-10 11:36:55 +01:00
Pau Espin Pedrol
978071bce9 ts_alloc: rename function to clraify what it does
The function updates nothing, so it's misleading. It simply counts
slots, so let's call it like that.

Change-Id: I55954321d6f2b5e755177a8829512da371e934aa
2021-11-10 11:36:55 +01:00
Pau Espin Pedrol
d9066272ec ts_alloc: Simplify tfi_find_free logic
Avoid passing an extra pram which is accessible by GprsMs object already
being passed. Once, the "trx = ms_current_trx(ms)" is moved inside the
tfi_find_free function, it becomes clear that all the logic can be
further simplified.

Change-Id: I733d9bee3fa1dfc647da9f150b30014fbdab7442
2021-11-10 11:36:14 +01:00
Pau Espin Pedrol
fb904fbbd9 pdch: Log DL TBF originating the new UL TBF
Change-Id: Ie4257a2468d589464d0d56882e4408e4bcfe340f
2021-11-09 14:01:40 +01:00
Pau Espin Pedrol
304b10a8b5 pdch: Log TS enable/disable transitions
Change-Id: I6780634de4791382ccd25bf7b74f5286420e2c52
2021-11-09 12:22:48 +01:00
Pau Espin Pedrol
20dfa54508 pdch: Log line detaching TBF at start of the function
Log before the action is done ("Detaching", not "Detached"). This way,
if something crashes we see that last line.

Change-Id: I6811d3772e2ac850741d3db5ec32be5c0812e81a
2021-11-09 12:15:23 +01:00
Pau Espin Pedrol
ef8a730f6d bts_pch_timer: Avoid resend Paging Request over PCUIF if T3113 is armed
Let's avoid flooding the BTS and taking CCCH resources for no good
reason. If user configures everything correctly, the SGSN should not
attempt a retry after similar timer >= T3113.

Related: OS#5297
Change-Id: I2a77714648d16ccff2a340ce775e83dcc5ffe707
2021-11-08 18:54:12 +00:00
Pau Espin Pedrol
19b3392166 tests/alloc: Extend test_bts_pch_timer() to validate MI type TMSI
Change-Id: I3673d387fa735b54fbc137ffaa18af581fa1b85a
2021-11-08 18:54:12 +00:00
Pau Espin Pedrol
13961c9b7a bts_pch_timer: Fix timer working only for MI type IMSI
This commit actually addresses 2 errors:

1- gprs_bssgp_pcu_rx_paging_ps() called gprs_rlcmac_paging_request()
with MI which can be either TMSI or IMSI, and the later always called
bts_pch_timer_start() passing mi->imsi regardless of the MI type. Hence,
trash was being accessed & stored into bts_pch_timer structures if MI
type used for paging was TMSI.

2- When the MS received the PS paging on CCCH and requests an UL TBF, it
will send some data. If one phase access is used for whatever reason,
the IMSI may not be yet available in the GprsMs object since we never
received it (and we'd only have it by means of PktResourceReq). Hence,
let's better first try to match the paging by TLLI/TMSI if set in both
places, and otherwise use the IMSI.

Related: OS#5297
Change-Id: Iedffb7c6978a3faf0fc26ce2181dde9791a8b6f4
2021-11-08 18:54:12 +00:00
Pau Espin Pedrol
f8a93cb882 doc: Update counters_generated.adoc using osmo_vty_interact.py
osmo_interact_vty.py -c 'enable;show asciidoc counters' -p 4240 -H 127.0.0.1 -O doc/manuals/chapters/counters_generated.adoc

Change-Id: I88e8e5548876fd6515e6bfcccec47bc48ba0ceb4
2021-11-08 18:33:04 +00:00
Pau Espin Pedrol
ba5683194a Add counter for successful contention resolution procedures
This counter is related to succPDTCHSeizures,
(3GPP TS 52.402 B.2.1.51 Successful PDTCH seizures).

The relevant event when the first RLC block on the PDCH from the MS is
received is the fact that contention resolution is considered as done in
the network side. Hence, name the counter that way to ease
interpretation.

Related: SYS#4878
Change-Id: I3d67e3e68907921b43f2ca4398ad9578c0b2618c
2021-11-08 18:33:04 +00:00
Pau Espin Pedrol
cc77eed9d9 tbf_ul: Improve documentation of tbf_alloc_ul_pacch()
Change-Id: I59493788b4a54610a70f3eb4c31fd05f6e39e63d
2021-11-08 18:33:04 +00:00
Pau Espin Pedrol
10b29153b7 pdch::rcv_resource_request(): Use local var to store bts pointer
Change-Id: Ica727c4b70cecc0ddb5d2a235bfc416735754b61
2021-11-08 18:33:04 +00:00
Pau Espin Pedrol
f61acd75c4 cosmetic: Add parenthesis around expression to clarify it
Change-Id: I621ef02868aff2bd23d82c8bc70e5cdbc391fbc2
2021-11-08 16:34:17 +01:00
Pau Espin Pedrol
dbd3b78a9b tbf_ul: Update FSM names for dummy reject TBFs
This allows easily identifying dummt TBFs created to send assignment
rejects.

Change-Id: I73a197795a9c8e9cd8dc06bf46ddb8f275d2c289
2021-11-08 16:33:51 +01:00
Pau Espin Pedrol
dff399fa42 bts: Add counters for successful 1,2 phase pkt access
These counters relate to succPDTCHAssProcsPerCause
(B.2.1.50 Successful Packet Channel Assignment Procedures, per cause).

Related: SYS#4878
Change-Id: I494afab337f2557ffa38e4c7ff2c15a1647a1e04
2021-11-08 15:26:49 +00:00
Pau Espin Pedrol
a02f945479 tbf: Set tfi to initial special value
This allows distinguishing when a TBF didn't set the TFI. Useful to
identify dummy reject TBFs, etc, and make sure a non-dummy TBF set its
TFI properly.

Change-Id: Iecf54a24041bd14f4ef5b86e57c3732e1b69d463
2021-11-08 13:24:20 +01:00
Pau Espin Pedrol
d3d46de278 tbf: Mark initial first_(common_)ts with special value
This way it's easier to distinguish when this value was not properly
filled when debugging or looking at logs.

Change-Id: I0c9c9fdcfca9eb15125ea49efcbb76711850052e
2021-11-08 13:24:20 +01:00
Pau Espin Pedrol
de0eeafd2e tbf: Set m_created_ts in constructor
This way the timestamp is also set for dummy reject TBFs. For other
TBFs, setup() is called immediatelly after calling the constructor, so
we are fine too.

Change-Id: I2966ec7f3f9161d528a173d94797b72d1398c747
2021-11-08 13:24:20 +01:00
Pau Espin Pedrol
063296883f tbf_ul: Set first_(common_)ts in handle_tbf_reject
Let's set them to match expectancies for this type of dummy TBFs, in
order to avoid acidental use/access of other timeslots to the one where
the reject was associated to.

Also use tbf_assign_control_ts() to log the TS used for the TBF, similar
to what's used in other places where control_ts is assigned.

Related: OS#5293
Change-Id: I32dcb29ad24519082b8665921efcce0b5a16d12e
2021-11-08 13:24:20 +01:00
Pau Espin Pedrol
92cbe4aee0 pdch: Improve log line and increase log level
Change-Id: Ie593331a69f6b8ec3b21e2b274a1aa060b2dc439
2021-11-08 13:24:19 +01:00
Pau Espin Pedrol
b6babc39dc tbf: Increase log level of line about unable to allocate poll for TBF
Change-Id: I0bd972d3b68017f12a0816a27162e3a409b1893a
2021-11-08 13:24:19 +01:00
Pau Espin Pedrol
48df600bfa bts: Count RACH Request with unexpected content
Change-Id: I86420b08a9a634ca2e1f5a1c7e66ec3d3c08ce0b
2021-11-08 12:23:31 +00:00
Pau Espin Pedrol
812a7d3fa3 bts: Improve logging to clarify RACH req is for 2 phase access
Change-Id: I047b688197a07e3592f19888f0ca71b9c3d2b3fd
2021-11-08 12:23:31 +00:00
Pau Espin Pedrol
769e28114f bts: Introduce new RACH req counters for one/two phase access
These new counters allow the user to find out which kind of access are
MS requesting.

Related: SYS#4878
Change-Id: Id87c3a53d3acee92499987c843130e358f54742c
2021-11-08 12:23:31 +00:00
Pau Espin Pedrol
bf129c1437 vty: show tbf: Drop unneeded check for non-null ms
Since a while a go, a TBF is guaranteed to always have a MS assigned.
Hence, there's no point in checking it.

Change-Id: I89e062432ac671c73731ce68c889aeb5e24277f5
2021-11-05 20:46:08 +01:00
Pau Espin Pedrol
14015124ed vty: Log tbf_state when showing a TBF
That's one of the most important information bits about a TBF when
debugging, and it's not shown currently, only when "show ms" is used.

Change-Id: I98e3c9cac4ca6fc29695768ecc6e0444e618b945
2021-11-05 20:44:49 +01:00
Pau Espin Pedrol
43fc4a8690 vty: Avoid crash in tbf_print_vty_info with null ptr ctrg
Previous code did use a ctrg based on MS being EGPRS capable or not.
However, an MS being EGPRS capable doesn't mean necessarily that all its
TBFs are EGPRS, since we may known about the capability after we already
created some previous TBF, so it was not ugpraded. Hence, we were
sometimes accessing the wrong NULL ctrg.
Let's simply check for non NULL ctrg when deciding what to print.

"""
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7561ea6 in vty_out_rate_ctr_group (vty=vty@entry=0x897850, prefix=prefix@entry=0x4482cd " ", ctrg=0x0) at utils.c:82
82    utils.c: No such file or directory.
(gdb) bt
 #0  0x00007ffff7561ea6 in vty_out_rate_ctr_group (vty=vty@entry=0x897850, prefix=prefix@entry=0x4482cd " ", ctrg=0x0) at utils.c:82
 #1  0x000000000041437b in tbf_print_vty_info (vty=vty@entry=0x897850, tbf=0x3fb61f0) at pcu_vty_functions.cpp:98
 #2  0x0000000000414acc in pcu_vty_show_tbf_all (vty=vty@entry=0x897850, bts=bts@entry=0x7be650, flags=4294967295) at pcu_vty_functions.cpp:127
 #3  0x000000000041206f in show_tbf (self=<optimized out>, vty=0x897850, argc=<optimized out>, argv=0x7fffffffe040) at pcu_vty.c:1150
 #4  0x00007ffff755d167 in cmd_execute_command_real (vline=vline@entry=0x7bc300, vty=vty@entry=0x897850, cmd=<optimized out>) at command.c:2604
"""

Related: SYS#5689
Change-Id: I3979bfc12dd3b9a53b34b284537f271c356a3024
2021-11-05 20:44:39 +01:00
Pau Espin Pedrol
7ce56d7c64 bts: Rename 11bit RACH request counter
This way it fits better the structure where the general one counts all
rachs, and 11bit only the 11 bits. More per-type splitting will be done
in follow-up commits where new types are added.

Change-Id: Ibdfb10dcc65d71e98e2fe8b05001cafea786f071
2021-11-02 16:47:08 +01:00
Pau Espin Pedrol
858f038c1c tbf_ul: Document context where tbf_alloc_ul_ccch() is used
It can be seen that this function properly passes single=true to
tbf_alloc_ul_tbf().

Change-Id: Id83bfd78c88fa9e4fa98268cc726298c276e6f20
2021-11-02 16:45:42 +01:00
Pau Espin Pedrol
7e8d5ab4c4 bts: Fix misleading log line in bts_rcv_rach()
If it's not single block packets access, then it's one phase packet
access. TS 44.018 Table 9.1.8.1:
"""
One phase packet access with request for single timeslot uplink transmission;
one PDCH is needed.
"""

Change-Id: Ic6beb6dcfebb77fd264b179b028f99a29c644fb1
2021-11-02 14:08:15 +01:00
Daniel Willmann
dd28f82747 gprs_bssgp_pcu: Fix crash when configuring an existing ns bind
ns_configure_nse() only sets bind when it doesn't exist yet. If it
already exists bind[i] stays NULL and causes a segfault in
gprs_ns2_is_ip_bind() later on.
This patch ensures bind[i] is either created of set to the existing
bind.

Change-Id: I103e82e6c64324c087a4ff325a83eeab0e5a4ee9
Related: SYS#4971
2021-10-29 17:34:24 +02:00
Pau Espin Pedrol
9ecdc11eb6 csn1_dec.c: Fix stored bit in CSN_NEXT_EXIST_LH
Fixup for previous patch, which forgot to update the pui using the new
variable, as done already in the same patch for M_NEXT_EXIST.

Change-Id: I92a04c708bcc6c15348324321e8890361bbc5c31
Fixes: 72cdb30ee2b1c0d71ff6d9583d51f46b2e5fdcea
2021-10-20 17:21:34 +02:00
Pau Espin Pedrol
1859ec38cc csn1: Avoid storing existence bit as true if content was actually NULL
If we decode Exist bit as "1" but we are at the end of the message, and
all the Next items we'd read are expected to be possibly NULL, then swap
the Exist bit in the decoded structure as "0" in order to tell the
decoder user that the related information structure is actually unset,
as if "0" was received.

Related: SYS#5552
Related: OS#4955
Related: OS#5020
Change-Id: I38602e4b680ed87297c7e440691a494c07cad446
2021-10-20 15:36:01 +02:00
Pau Espin Pedrol
ebdc0d8c17 csn1: Avoid failing if optional DownlinkDualCarrierCapability_r7 is missing
All additional release fields are considered optional, and the
CSN_DESCR for Content_t already marks almost all as such, except
DownlinkDualCarrierCapability_r7.

It has been found that some MS transmits a MS RA Capability with a Length=61 bits
where the last bit in the buffer is setting the Exist bit for
DownlinkDualCarrierCapability_r7 as 1. Hence, the CSN1 decoder failed to
decode the whole message because it expected to keep reading there
despite there's no more bytes to read.

While this is could actually be considered an MS bug, let's relax our
expectancies and simply consider the case { 1 <end> } as it was { 0 },
and mark skip decoding DownlinkDualCarrierCapability_r7. That waht
wireshark (packet-gsm_a_gsm.c) or pycrate do for instance.

This patch itself doesn't fix the problem where actually the Exist bit
is stored as 1 in the output decoded structure, but simply allows keep
ongoing with decoding until the end. This issue will be fixed in a
follow-up patch.

Related: SYS#5552
Related: OS#4955
Related: OS#5020
Change-Id: I9a2541bd3544802a646890f32725201836abb0da
2021-10-20 15:36:01 +02:00
Pau Espin Pedrol
089d734cd1 csn1: Add unit test showing RadioAccess Capability decoding failure
This RA Cap creaes a decoding error on our CSN1 decoder, but seems to be
handled properly by wireshark's own decoder as well as pycrate.

The ending bit of last byte in "MS RA capability 1" has a "1" which
according to spec should flag the existance of
DownlinkDualCarrierCapability_r7, but nothing else comes after it. This
matches the expectancies as per Length field of the first RA Cap.

Related: SYS#5552
Related: OS#4955
Related: OS#5020
Change-Id: I51235e8575f4b992b44078713ec67bbccfd13293
2021-10-20 15:36:01 +02:00
Pau Espin Pedrol
c90e6f8de1 Split csn1.c into common, enc and dec files
The CSN1 encoder/decoder code is already lengthy and complex enough,
there's no need to keep it in the same file, specially because when
debugging, only is interested in one of the 2 functions, and they both
look really similar (long spaghetti switches).

Change-Id: I7d1b1f7e6d7f89b052b3fd73a960419bb2673020
2021-10-20 13:35:44 +00:00
Pau Espin Pedrol
fef3da24ae pcuif: Submit data_req with len=0 as idle frames
This way PCU always answers DATA.ind and the BTS can still clearly
identify idle frames. It also simplifies testing and verification of
correct behavior.

Related: SYS#4919
Change-Id: Ife718eeed2af011479c03099ea109518f04567bc
2021-10-20 13:35:10 +00:00
Pau Espin Pedrol
9f43c65c99 cosmetic: Fix typo in comment
Change-Id: I9e6d0963533e15e73fb51bed11af563a62b92ecb
2021-10-19 14:20:11 +02:00
Pau Espin Pedrol
affd6a7f7a tbf: Drop unneeded braces in one line condition
Change-Id: Ief5e0ea0b7146d3330a17d5f0d171755b576fca3
2021-10-18 16:44:19 +02:00
Pau Espin Pedrol
e50b5f1e3f tbf: update(): return negative val on error
Let's follow usual convention where errors are returned as negative
values.

Change-Id: Ib4f4dc37ae82ba8efdc212ed85af7934e16a8a8d
2021-10-18 16:13:51 +02:00
Pau Espin Pedrol
8a9eec345e tbf: Assert if update() is called on UL TBF
This function is expected to be used only on DL TBF so far, so let's
really assert to avoid going through if something is wrong and ending up
later with other issues.

Change-Id: If398ee48364fce5b5e38830b2b278b3bad9a48a2
2021-10-18 16:11:34 +02:00
Pau Espin Pedrol
89a995a439 tbf_fsm: Add assert verifying X2002 only triggers for DL TBF
Code above setting the timer in same tbf_fsm already has this kind of
assert, but it helps understanding the code having this assert here.

Change-Id: I7588deef5073694eb5fecdb516c241a04594e2b0
2021-10-18 15:36:58 +02:00
Pau Espin Pedrol
a2ef802dba tbf: Update FSM names when TFI change during tbf_update()
In that function, previous PDCHs are unlinked and then alloc_algorithm
is expected to assign new TFIs.

Change-Id: I7bcbb223ca32400bede7ab638695ba3c015c9946
2021-10-18 15:36:58 +02:00
Pau Espin Pedrol
77e2ff32d9 ts_alloc: Rename s/tbf_/tbf/
Off the top of my head: The tbf_ was kept during a previous refactoring
a while ago to avoid changing lots of more lines in the same patch.

Change-Id: I8ae689a272b7c4d244576ff157f6019a87041abc
2021-10-18 15:36:45 +02:00
Pau Espin Pedrol
9c84c88259 Get rid of tbf tsc field
TSC is not really a property of a TBF, so let's drop it in order to avoid
confusing and possible misuse of that accessor.

Change-Id: I105eb65d507e45631faddb23420c42bc9560e580
2021-10-18 15:35:51 +02:00
Pau Espin Pedrol
f5cb4acb14 bts_rcv_rach(): Split code paths for Ass and Ass Rej
The function becomes a bit more long but it's a lot easier to follow.

Change-Id: I80e554315d36a515a7edc9ae51057ce31eb9110d
2021-10-18 13:33:15 +02:00
Pau Espin Pedrol
9b9f5efb09 bts_rcv_rach(): Gather pointers to data objects early and use them later
Change-Id: I476814d0f7be4b53f66211bb472700fee4f2caa9
2021-10-18 13:20:32 +02:00
Pau Espin Pedrol
196f36b75a pdch: Log reason of expected POLL when receiving unexpected UL data
Change-Id: I914e38154029f57cbf38120495220cd860877c45
2021-10-18 12:37:51 +02:00
Pau Espin Pedrol
592239630b pdch: Simplify code path allocating UL TBF
There's no real need to pass a tlli per separate, the information is
already contained in the MS. Furthermore, when doing so, it becomes
clear the TLLI was only passed to set it again on the MS, so actually
that ms_update() can be totally dropped since it will act as a no-op.

Change-Id: Ie761c3c7c222458ab0514117ae637ad3267139a0
2021-10-18 12:24:42 +02:00
Pau Espin Pedrol
b0aba59143 tbf: Drop pending polls during free also on states != ASSIGN
The situation holds true as long as the assignment is resolved. Hence,
it can also happen that the TBF is in RELEASE state, because it was
unable to do the assignment (and after retrying, MAX_N3105 moved it into
RELEASING).
Let's not explicitly check states, the other conditions should be
enough.

Related: SYS#5647
Change-Id: I05fb0ea44aeb3fbda9e8e1c449e9366efaa2c511
2021-10-14 19:31:18 +02:00
Pau Espin Pedrol
b3291bc0e3 Abort scheduling of pending Pkt Ul Ass if tbf goes into RELEASE step
Change-Id: I20bab79070274b1d8f6b4e1867b30de61983ab54
2021-10-14 19:31:18 +02:00
Pau Espin Pedrol
880cbd3a8f tbf_ul_ass_fsm: Avoid retrying Pkt Ul Ass if tbf is not in state ASSIGN
It doesn't make sense to keep asking the scheduler to retransmit Pkt Ul
Ass if the tbf_fsm already decided we are going to release the TBF.

It can be seen in following log extract:
"""
tbf_ul_ass_fsm.c:112 TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=ASSIGN EGPRS) start Packet Uplink Assignment (PACCH)
tbf_ul_ass_fsm.c:131 TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=ASSIGN EGPRS) Scheduled UL Assignment polling on PACCH (FN=612941, TS=7)
tbf_ul_ass_fsm.c:188 UL_ASS_TBF(UL-TFI_1)[849e50]{SEND_ASS}: state_chg to WAIT_ACK
pdch_ul_controller.c:330 PDCH(bts=0,trx=1,ts=7) Timeout for registered POLL (FN=612937, reason=DL_ASS): TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=ASSIGN EGPRS)
tbf.cpp:550 TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=ASSIGN EGPRS) poll timeout for FN=612937, TS=7 (curr FN 612937)
tbf.cpp:392 TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=ASSIGN EGPRS) N3105 exceeded MAX (8)
tbf.cpp:602 TBF(UL-TFI_1)[7bd530]{ASSIGN}: Received Event MAX_N3105
tbf_fsm.c:194 TBF(UL-TFI_1)[7bd530]{ASSIGN}: state_chg to RELEASING
pdch_ul_controller.c:330 PDCH(bts=0,trx=1,ts=7) Timeout for registered POLL (FN=612941, reason=UL_ASS): TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=RELEASING EGPRS)
tbf.cpp:550 TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=RELEASING EGPRS) poll timeout for FN=612941, TS=7 (curr FN 612941)
tbf.cpp:589 UL_ASS_TBF(UL-TFI_1)[849e50]{WAIT_ACK}: Received Event ASS_POLL_TIMEOUT
tbf_ul_ass_fsm.c:224 TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=RELEASING EGPRS) Timeout for polling PACKET CONTROL ACK for PACKET UPLINK ASSIGNMENT: |Assignment was on PACCH|No uplink data received yet|
tbf_ul_ass_fsm.c:226 UL_ASS_TBF(UL-TFI_1)[849e50]{WAIT_ACK}: state_chg to SEND_ASS
tbf_ul_ass_fsm.c:308 UL_ASS_TBF(UL-TFI_1)[849e50]{SEND_ASS}: Received Event CREATE_RLCMAC_MSG
tbf_ul_ass_fsm.c:112 TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=RELEASING EGPRS) start Packet Uplink Assignment (PACCH)
tbf_ul_ass_fsm.c:131 TBF(TFI=1 TLLI=0xe1c12303 DIR=UL STATE=RELEASING EGPRS) Scheduled UL Assignment polling on PACCH (FN=612976, TS=7)
tbf_ul_ass_fsm.c:188 UL_ASS_TBF(UL-TFI_1)[849e50]{SEND_ASS}: state_chg to WAIT_ACK
"""

Change-Id: I94243ff99dfaf3664a1a4b3c4c87b5104ba4f7d1
2021-10-14 19:31:12 +02:00
Pau Espin Pedrol
b9fede74ef tbf: Avoid keeping poll nodes in pdch_ulc of temporary control_ts used during PACCH assignment
When MS sends us the Packet Resource Request as RRBP from final UL ACK/NACK, we create a new TBF
with a different set of allocated TS. However, we must send the Pkt UL Assignment with information
of the new TBF using that same TS where we receive the Packet Resource Request, which happens to
be the control TS of the previous/old TBF. The original control TS of the new TBF is kept in
tbf->first_common_ts.

Hence the code does gprs_rlcmac_pdch::rcv_resource_request():
"""
ul_tbf->control_ts = ts_no;
"""

And later, when we receive a CTRL ACK answering the Pkt UL Assigment, we change the control TS of
the new TBF back to the new one, by calling tbf_assign_control_ts(), which basically does:
"""
tbf->control_ts = tbf->first_common_ts;
"""

So, for instance we have a TBF which was allocated with tbf->control_ts=4 and hence is only attached
to PDCH 4 (tbf->pdch[]), but for which is temporarily applied tbf->control_ts=7.  Hence, when a poll
is requested, it is done in control_ts, aka 7, which is not in the array of attached PDCH.

The problem is of course if we never reach the point where the final control_ts is set, due to never
receiving the CTRL ACK. If the TBF is freed (due to timer X2001) before receiving the CTRL ACK and
hence tbf_assign_control_ts() is called, a crash may occur, because potentially a poll for the TBF is
left in TS 7 because it's not a PDCH attached to the TBF and hence poll
entries on that TS are not released, hence keeping a pointer to the
freed TBF.

Related: SYS#5647
Change-Id: I0c49f2695e0d932d956c01976c9458eebee63cd4
2021-10-12 20:07:19 +02:00
Pau Espin Pedrol
ffa2918bc5 pdch: rcv_data_block: Avoid releasing ULC entry if expecting something else on UL
Let's only release PDCH ULC entry if it was indeed what we expected.
In other case, time it out.

Change-Id: I1537587f5ee801c633784691b576ebb1ed521e95
2021-10-12 20:07:19 +02:00
Pau Espin Pedrol
32744c8916 Return void in tbf_assign_control_ts()
This operation cannot fail, hence let's simplify code.

Change-Id: I5675df4b6309d680d1d5e2dbea87991468f30630
2021-10-12 19:36:49 +02:00
Pau Espin Pedrol
ffe998ce9d tbf: Document temporary change of control_ts and move code assigning it back to FSM
Change-Id: I1b7eb7802060778487e5729ee789b2323b6636f8
2021-10-12 19:32:28 +02:00
Pau Espin Pedrol
38a9c873bc tbf: Use define to flag control_ts unset special value
Change-Id: Idd3ccec509b40b6229544b45e54da1142805b6f9
2021-10-12 19:18:57 +02:00
Pau Espin Pedrol
85aa87b61f tbf_fsm: Handle MAX_N3105 in state ASSIGN
Seen on a runnig osmo-pcu against real MS:
"""
pdch_ul_controller.c:329 PDCH(bts=0,trx=1,ts=7) Timeout for registered POLL (FN=751140): TBF(TFI=0 TLLI=0xe8c12143 DIR=UL STATE=ASSIGN EGPRS)
tbf.cpp:542 TBF(TFI=0 TLLI=0xe8c12143 DIR=UL STATE=ASSIGN EGPRS) poll timeout for FN=751140, TS=7 (curr FN 751140)
tbf.cpp:384 TBF(TFI=0 TLLI=0xe8c12143 DIR=UL STATE=ASSIGN EGPRS) N3105 exceeded MAX (8)
tbf.cpp:594 TBF(UL-TFI_0)[9bc050]{ASSIGN}: Received Event MAX_N3105
tbf.cpp:594 TBF(UL-TFI_0)[9bc050]{ASSIGN}: Event MAX_N3105 not permitted
"""

It was first though when FSMs where introduced that an FSM in ASSIGN
state could not receive this kind of event because it was believed to be
sending no CTRL blocks at all until flow state. That's because the
believe was that Assignment over PACCH was done by another existing TBF.
It turns out this is usually the case, but not in all cases. In at least
one case, the tbf object (and tbf_fsm/tbf_{ul,dl}_ass_fsm) itself is
handling its own assignment (hence eg. sending the UL assignment and waiting
response through tbf_ul_ass_fsm. This happens if a UL TBF sends a Pkt
Resource Req as a response to RRBP of final UL ACK/NACK in order to
request a new TBF, where it temporarily uses the control_ts of the
previous TBF to get a new Pkt UL Assignment over PACCH.

If Pkt Ul Assignment doesn't receive a CTRL ACK, tbf_ul_ass_fsm will
retrnamist it, until MAX_N3015 is reached (the event we failed to
handle until now). At this point, we really want to transition to
RELEASING in order to avoid keeping the TBF allocating resources (until
X2001 times out).

Related: SYS#5647
Change-Id: I86d5c1bbccd06673d08451b812d149e727404733
2021-10-12 18:57:44 +02:00
Pau Espin Pedrol
27a4e7371c tbf_ul_ass_fsm: Fix use of incorrect log macro
Change-Id: I61e46199086a3e82985606cf81995e27663c91f5
2021-10-12 17:53:44 +02:00
Pau Espin Pedrol
78ddfbc413 tbf_dl_ass_fsm: Move block msg generation conditions to rts() function
Move the required conditions to generate a message to the rts()
function, this way the scheduler knows this TBF cannot yet attempt the
procedure and hence will not request it to create a message which will
fail.

This way the scheduler will schedule other itneresting messages instead
of failing and scheduling a dummy block as a result.

Change-Id: Idbe4f9bbd23005a43c586b737cf9adc2114287e2
2021-10-12 13:10:49 +02:00
Pau Espin Pedrol
4a1c561ce8 pdch_ulc: Log POLL reason upon timeout
Change-Id: I7cd59b60fe0af0bfdfcdf8a91e4cf8bd3f25b2f7
2021-10-12 11:01:07 +00:00
Pau Espin Pedrol
0043005afb tbf_fsm: rename state NULL -> NEW
This helps distinguishing the case where a TBF is in the initial state
and the unexpected case where osmo_fsm_inst_state_name reports "NULL"
due to fi pointer being NULL.

Change-Id: Ieaabfc9fa0dedb299bcf4541783cf80e366a88c3
2021-10-12 11:01:07 +00:00
Pau Espin Pedrol
7a2b65ed2c Handle Final UL ACK/NACK Confirmation in tbf_fsm
Pass the event over the FSM for better understading of the entire
lifecycle of the TBF.

Change-Id: If30d881037209d33b2b41ecf8bb8419caf36e367
2021-10-12 12:41:53 +02:00
Pau Espin Pedrol
201dbe04f7 pdch: PktResReq: Avoid releasing ULC entry if expecting something else on UL
Let's only release PDCH ULC entry if it was indeed what we expected.
In other case, time it out.

Move the case in the switch statement to the start to easy function
readibility (early return style).

Change-Id: I3d8749acca8e7859295d73cce556b2083169f726
2021-10-12 12:41:18 +02:00
Pau Espin Pedrol
8318d9c25d pdch: Validate poll reason matches in rcv_control_(egprs)_dl_ack_nack()
If we didn't expect this kind of UL messages according to pdch ULC, then
we shouldn't allow going forward and releasing the ULC entry: let it
time out instead so that TBF runs whatever appopiate action is needed in
this case, be it retransamission, releasing itself, etc.

Change-Id: I8ab3f5e4f2f802944269453db13a80c9ede67714
2021-10-11 18:22:01 +02:00
Pau Espin Pedrol
0dbf6f2a54 pdch: Only release ULC entry if rx ul block matches the expected one
If it doesn't match out expectancies, it means we early return and hence
don't push forward / update whatever state was requested upon receival
of the UL message for the expected TBF. Hence, we shall not remove the
allocated ULC entry: in this scenario we need to keep it so that timeout
procedure times out and the tbf applies whatever measures are required,
be it retransmission, releasing itself, etc.

Change-Id: Ia69a7d92c4b5c98ec71a75605c8dc3a755e63a35
2021-10-11 18:14:32 +02:00
Pau Espin Pedrol
e080808cfa sched: Rename function
Properly describe that function is aimed at selecting a DL data block.

Change-Id: Ic0680d15edf70449e66f40eab1ead97313631cbb
2021-10-11 17:42:35 +02:00
Pau Espin Pedrol
b5bad20731 tbf: Assert if FSM allocation fails
Change-Id: Ib3db7a554a4467814785df08e3772455bf00b7d5
2021-10-09 17:03:35 +02:00
Pau Espin Pedrol
abed2e326d rlcmac: Fix CSN1 definition for DownlinkDualCarrierCapability_r7_t in MS RA cap
Related spec: 3GPP TS 24.008 Table 10.5.146

Change-Id: I61b41e06b54024254c71242ffa2206e4eada8559
2021-10-07 20:27:50 +02:00
Pau Espin Pedrol
2282b50e5c tests: RLCMACTest: Add one more sample RA capabilities to suite
This one is larger than some of the other already available.
The decoder is wroking as expected here.

Change-Id: I5d986f68395326f894349446194090b1ddaecd69
2021-10-07 18:32:54 +02:00
Pau Espin Pedrol
cee6b122c2 tbf_fsm: Ignore event DL_ACKNACK_MISS in state RELEASING
Fixes following error log line:
"{RELEASING}: Event DL_ACKNACK_MISS not permitted"

Rationale: We may move to RELEASING state at some point, for instance
due to MAX_N3101/MAX_N3105 while still having some active poll
registered in some PDCH ulc. Upon that poll (most probably) timing out,
it will send a DL_ACKNACK_MISS event to us. Since we are already
determined to release the TBF (waiting for T3195 or T3169 to trigger),
simply ignore the event and avoid logging an error.

Fixes: OS#5240
Change-Id: Ibfb49356d2b3b5fccb6d59db8593b2256e5c51fb
2021-09-28 16:53:00 +02:00
Pau Espin Pedrol
e9db5c7387 assert if tbf pointer for POLL event is NULL
The tbf pointer should always point to a valid TBF.

Change-Id: Ib607a38459802f780826f46c20a1696ec98408fb
2021-09-28 16:38:30 +02:00
Pau Espin Pedrol
a27fb3fce3 cosmetic: Fix missing space
Change-Id: Ib64cbf1d95dd0a881f6ace0cf9a4f517eb58ae0f
2021-09-28 16:38:30 +02:00
Pau Espin Pedrol
c8d2166b86 pdch: refactor rcv_control_ack() with a switch statement
This clarifies the different paths and uniforms them. Makes code far
easier to read and debug.

New improved verification already found some misehavior in some tests.

Change-Id: I7e4a88d6e004bbb7974595320ed73742162c7ad7
2021-09-28 16:05:27 +02:00
Pau Espin Pedrol
422636d752 tests: TbfTest: Fix wrong behavior in test_tbf_dl_reuse()
The test uses get_poll_fn() to submit a UL ctrl block on the next
expected poll TS+FN.

During initial transmit_dl_data(), 2 POLLs for DL_ACK are set on
different TS, but the test only updates the clock for one of them in
send_ul_mac_block(). As a result, one POLL item is left in the rb_tree,
and later on, when send_control_ack() is called, get_poll_fn() will pick
that 2nd DL_ACK poll FN+TS which was left untouched (due to sending no
events to the PCU clock) instead of the FN+TS which was expected to be
allocated by PCU for DL_ASS.

Until now this was not an issue since rcv_control_ack() was not properly
veirfying what the poll scheduler was expecting and accepted it. This is
no longer the case after the follow up patch refactoring
rcv_control_ack() and improving its robustness.

Change-Id: I3a4b089fe66a99e73e07bd1c690cd4d67752fad9
2021-09-28 16:05:03 +02:00
Pau Espin Pedrol
d72f46f020 tbf: refactor poll_timeout() with a switch statement
This clarifies the different paths and uniforms them. Makes code far
easier to read and debug.

Change-Id: I4c56af70c79c20f1e600371e040bd48bcc908a75
2021-09-28 13:28:27 +02:00
Pau Espin Pedrol
c276e4996d nacc: Introduce helper function nacc_fsm_exp_ctrl_ack()
Move FSM internal state checks to its own file. Re-use the helper
function in the 2 places where same stuff is checked.

Change-Id: I9ded6e1c80e6cd7bcf6883bc2e853b6dafb33f7c
2021-09-28 12:53:37 +02:00
Pau Espin Pedrol
864a41496c tbf: poll_timeout(): Validate expected poll reason
Change-Id: I680b00fcb18a15a831ca13403c19162dadc67a2f
2021-09-28 12:41:02 +02:00
Pau Espin Pedrol
ea7cb48c9c tbf_ul_ass_fsm.c: Fix missing state transition in FSM description
As seen operating PCU after BTS restart, lots of following message
sequences due to FSM kept in same state (hence scheduler retyring every
time):
"""
DTBF tbf_ul_ass_fsm.c:306 UL_ASS_TBF(DL-TFI_0){SEND_ASS}: Received Event CREATE_RLCMAC_MSG
DTBF tbf_ul_ass_fsm.c:95 TBF(TFI=0 TLLI=0xf80bd801 DIR=DL STATE=RELEASING EGPRS) We have a schedule for uplink assignment, but there is no uplink TBF
DTBF tbf_ul_ass_fsm.c:97 UL_ASS_TBF(DL-TFI_0){SEND_ASS}: transition to state NONE not permitted!
DTBF tbf_ul_ass_fsm.c:306 UL_ASS_TBF(DL-TFI_0){SEND_ASS}: Received Event CREATE_RLCMAC_MSG
"""

Change-Id: I91d74f70a9106ccbf0c137b6e713877f9ea8f59d
2021-09-22 16:53:43 +02:00
Oliver Smith
fce67bc7fa pdch: has_gprs_only_tb_attached: use m_num_tbfs
Make use of the separate GPRS counters added in previous patch
I0c0a1121b4ae5f031782e7e63a0c28eb0b6c8b42 to shorten
has_gprs_only_tb_attached.

Related: SYS#4878
Change-Id: I1dd7df2c740ea604f07c65bebcb7c0051aebf9ae
2021-09-21 10:28:52 +00:00
Pau Espin Pedrol
eeae776345 PTCCH: skip Tx DL idle blocks when possible
Same was already done for PDTCH in previous commits. Let's now apply
same bits to PTCCH.

Related: SYS#4919
Change-Id: If6617964e67fc35eeee1791b06e13bf63ac88f73
2021-09-20 11:22:32 +02:00
Pau Espin Pedrol
0e3083daf5 scheduler: Skip Tx DL idle blocks in TRX0 when not in DIRECT_PHY mode
We also want to avoid sending idle blocs in TRX0 to the BTS, so that the
BTS can be aware of blocks being idle and then submitting dummy blokcs
by itself applying required BCCH Carrier power reduction.

Related: SYS#4919
Change-Id: Idd58d2a09c3947098b960cfcb5cd1b7b7bca3d84
2021-09-20 10:55:21 +02:00
Oliver Smith
402451b308 Add stats: pcu.bts.N.pdch.occupied.gprs/egprs
Add stats needed for performance measurements in
3GPP TS 52.402 § B.2.1.54-55.

Split m_num_tbfs to count GPRS and EGPRS TBFs separately. Move the code
that updates m_num_tbfs and sets the PDCH_OCCUPIED stats to a separate
function, as it's mostly the same in the TBF attach and detach.

Related: SYS#4878
Change-Id: I0c0a1121b4ae5f031782e7e63a0c28eb0b6c8b42
2021-09-17 17:28:03 +02:00
Pau Espin Pedrol
6c81adda45 nacc_fsm: Move logic checking if SI is being waited for to a func helper
We already have a similar function for Neighbor Address Resolution.
This way we keep as much as possible internal state related logic into
the nacc_fsm.c file.

Change-Id: I7378939825cc3ec3280f76bc51233c0a172d8a27
2021-09-13 13:31:09 +02:00
Pau Espin Pedrol
5557c0af80 Support Neighbor Address Resolution over PCUIF IPA multiplex
While NACC was initially developed, it became clear there was need for
a way to interact PCU<->BSC in order resolve ARFCN+BSIC into CGI-PS
for later RIM usage.
Hence, this resolution was first (until today) implemented using an out
of bands RPC system using the CTRL interface, which required specific
config to be written and matches in osmo-pcu and osmo-bsc VTY (ip+port
of the CTRL interface to use).
However, this has several shortcomings:
* As explained above, specific configuration is required
* Since recently, we do support BSC redundancy in osmo-bts. Hence the BTS
  may switch to a BSC other than first one. If that happened, that'd mean
  the CTRL interface would still point to the initially configured one,
  which may not be the same currently serving the PCU.

During recent development of ANR related features, a similar need for
PCU<->BSC was required, but this time it was decided to extend the IPA
multiplex of the Abis OML connection to pass PCUIF messages,
transparently forwarded to each side by the BTS.
This has the advantage that connection PCU<->BTS is handled by BTS and
both sides send messages transparently.

Let's switch by default to using this new interface, while still
maintaing the old way for a while (announcing them as deprecated) to
avoid breaking existing deployments until they are upgraded to new
versions of osmo-pcu and osmo-bsc.

Related: SYS#4971
Change-Id: I6ad33c7ab10202840cf804dea9ba595978d0e920
2021-09-13 13:31:06 +02:00
Oliver Smith
35d51ca4e3 Add stats: pcu.bts.N.pdch.available/occupied
Count available PDCHs (3GPP TS 52.402 § B.2.1.38) as well as occupied
PDCHs (§ B.2.1.42-44).

Related: SYS#4878
Change-Id: I74760a68ee055510a79e80854ec7bf1521669119
2021-09-06 09:11:47 +00:00
Pau Espin Pedrol
1d663d9277 pdch: Make sure pending ImmAssRej scheduled for disabled pdch are dropped
When a PDCH TS becomes disabled (eg due to dyn TS being used for a
call), we are currently freeing all attached PDCHs in order to avoid
further use of it. However, pdch_free_all_tbf() was only freeing TBFs
attached to the PDCH, that is, TBFs having a valid TFI assigned.
There are some cases where temporary dummy TBFs are created which have
no TFI assigned, such as when creating an ImmAssReject. Let's take those
into account too, and make sure they are freed.

Related: OS#5226
Change-Id: Ibfe78448ebdedc8b049c80664711e166d910f9b7
2021-09-03 16:01:37 +00:00
Oliver Smith
bf7bde1cbb debian/control: remove dh-systemd build-depend
Related: OS#5223
Change-Id: Ieb8669a9a43ea1acc6b2d8d2e363f2466c51697a
2021-09-01 16:07:06 +02:00
Pau Espin Pedrol
25d60cafc4 sched: Lower log level of RTS on disabled pdch
These messages are expected under some circumstances, such as when
direct phy is used and a chan is disabled (eg. dyn TS). This happens
because PCU asks for chan de-activation through PCUIF while at the same
time marking the PDCH locally as disabled. Hence, in the time the BTS
manages to disable it on the lower layers, the phy still sends us
RTS indications.

Let's keep it under NOTICE to avoid clogging the logs in production
setups which are usually using global level of NOTICE or ERROR.

Related: OS#5222
Change-Id: Iab9e1590b504bf05dc693e27550b30db0dffcbc7
2021-08-31 16:50:35 +02:00
Pau Espin Pedrol
0f88bcdebf bts: Use public getter instead of class member
Change-Id: Ia7b37a4c721d7d02c516d8d3a5417d166f1d3bec
2021-08-31 14:56:17 +02:00
Pau Espin Pedrol
767144f7b7 cosmetic: sysmo: Drop unneded comment line
Change-Id: I66685fa69af5ad18e45d97a25e7150815beef805
2021-08-31 14:53:10 +02:00
Pau Espin Pedrol
e376fd57cf Use LOGPDCH macro to standarize log line
Change-Id: If815779b2e2e56707f36c72dbdbfd4c5b07165ed
2021-08-31 14:38:21 +02:00
Pau Espin Pedrol
3bbb3cc1f2 Fix crash with dyn TS when using direct pcu
It seems there may be a race conditon where lower layers (direct PCU)
send UL blocks to us while the PDCH was already disabled (due to a call
entering on a dynamic TS).
As the PDCH is disabled, the ULC is NULL and shouldn't be used before
being enabled again.

Related: OS#5222
Change-Id: I4b8931f0cc7cfc787a1cc35196295402524b15c3
2021-08-31 14:36:02 +02:00
Pau Espin Pedrol
a89a23881f sched: energy saving: Avoid Tx dummy blocks on empty PDCH TS
Related: SYS#4919
Related: OS#4772
Change-Id: I8d66dd5e838748611e7b77b504fc86295f02c019
2021-08-26 12:51:15 +02:00
Pau Espin Pedrol
c4fe1f97b4 cosmetic: Fix typo in comment
Change-Id: I423410416e572141fc2b44c81215b8f41c13f2c6
2021-08-25 14:35:27 +02:00
Pau Espin Pedrol
d06ec27856 fix typo 's/dowlink/downlink/g'
Change-Id: Iae66aff9eed3856f09e58116ee26ec061733b076
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
f48de627f4 tbf: Move T3193 to tbf_state FSM
Related: OS#2709
Change-Id: Icf8249651e34132eb7ba99188a23662dec6f8653
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
a161bf48bd Simplify tbf::set_polling()
When setting a POLL, it will always happen on PACCH, so all the CCCH
part makes no sense there. Let's drop it and move the logging of each
case to the caller, where logging file+line is more useful.

Change-Id: I242f97fd6f927131ac64c1a7c9c3812b6389de04
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
ea8dbddab1 Move tbf ul_ack_state to osmocom FSM
Related: OS#2709
Change-Id: Icf23bf5a4b85fbcbf1542cebceb76b9ba7185d30
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
3e48cfd9f3 tbf.h: Improve documentation on several flags
Change-Id: Ice2c164ced039fb4ab621d8f7c2fb85f8348788a
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
405d2d10ec tbf_dl: Clarify requirements for DL ACK/NACK
Method is renamed since it clearly relates to getting DL ACK/NACK, no
CTRL ACK.

use same methods in both scheduler and internal use since they are
expectd to be run in the same code path by the scheduler. This way we
make sure the same conditions apply and it's clearer when looking at
the code.

Change-Id: Ib0e9b9547f5292b95064bab2dc182fdf659f0518
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
3225290d77 Move timer X2002 to tbf_fsm
Related: OS#2709
Change-Id: I94b71c60ed49d51ebdf6d6b428056b4b94354676
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
907f037339 tbf: Use type bool for upgrade_to_multislot
Change-Id: I644d91b6230a90cc72e83443c11d24b8d0a2dcac
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
628d881247 Fix typos in comments documenting fsm st chg macro
Change-Id: I8f1cef5810c84441f7d6d2fbe5b3106e0ae71b69
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
fbc1baa139 tbf: Merge handle_ack_nack() into rcvd_dl_ack()
There's no real use in having those 2 methods separately, and only adds
complexity. Let's merge it to have 1 TBF code path handling DL ACK/NACK.

Change-Id: I546d2e46bda96a2f551b28673464e57831c71828
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
afe189e802 Get rid of lots of code only used by tests
There are 2 methods "rcvd_dl_ack()" in osmo-pcu code. One is used by
osmo-pcu itself, and the other is only used in tests.
Changing the tests to use the same method as osmo-pcu allows removing
the second one, and with it, a lot of code and complexity out of
osmo-pcu.

Change-Id: I14d9312cb61534dc97fca83141b9c0cd933c9206
2021-08-23 17:14:23 +02:00
Pau Espin Pedrol
9d67e72e85 Move timer X2001 to tbf_fsm
The side effect is that the timer is enabled for other scenarios where a
PACCH assignment happens, like an Assignment Reject or Ul Assignment
(that's why there's more lines showing up now in TbfTest.err).

Change-Id: Ib8ab2f7397ad05c6fcd5dd74af55a1e2c56e1463
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
c65c9e56e1 tbf: Drop unuseful flag GPRS_RLCMAC_FLAG_UL_DATA
Same information is available under ul_tbf->m_rx_counter.

Change-Id: I1d993117c7daa2609b132c2d0fd748e0338ef559
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
5bc6560efc tbf: Drop unuseful flag GPRS_RLCMAC_FLAG_TO_DL_ASS
The flag is only used to print some non interesting stuff, let's drop it
in order to simplify code. We can add later whatever we want in the new
shiny FSM.

Change-Id: I13f92f058c219f230d57b3c00b8ae1d187603813
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
49a2f404e8 replace dl_ass_state with osmocom FSM
Related: OS#2709
Change-Id: Ia33418478e17986a316ffda48b091030f53fa371
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
432d4f3b89 tbf: Drop unuseful flag GPRS_RLCMAC_FLAG_TO_UL_ASS
The flag is only used to print some uninteresting stuff, let's drop it
in order to simplify code. We can add later whatever we want in the new
shiny FSM.

Change-Id: I20aa7f83cc4f32de129e64c74a91745b983a7b16
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
ab8fba3a20 tbf: Reimplement rlcmac_diag() and make it available from C
We never use the std:string anyway, we always call .c_str() to log using
osmocom logging system.
Furthermore, we'll need to use it from C code soon (next commit).

Change-Id: I3ad66f9f3f4d55d11da3a3b8b38656ae2dd50603
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
6ad11a6990 Replace ul_ass_state with osmocom FSM
Related: OS#2709
Change-Id: Id414eafe9c04a9a8759c6fb1a483bf2ee093a4d2
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
b0ead922a1 tbf_free: Get rid of uneeded tbf_state transition
We are freeing the object immediately afterwards anyway, so no need to
pretend it went through the normal state release.
Leaving current state as it is actually provides more information on
what was the status/state at the time the TBF had to be freed.

Change-Id: I3016caaccc2c43e1e300f3c6042d69f8adcd9d69
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
284711d627 Get rid of tbf_dl:abort()
Having that code in a separate function is confusing and adds code
complexity since it looks like an entry point to start feeing a TBF, but
it simply some (not yet really useful) set of instructions to be called
one 1 code path in tbf_free.
Let's move it there, this way it becomes clear tbf_free() is THE place
to be (if you want to get rid of a TBF).

Change-Id: I30febf4d21a0bfab37524c07598bbb0dd32f7f65
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
131deb059f Move rate_ctr free to tbf subclass destructor
This way we clean up tbf_free entry point, and leave memory freeing for
later on at the end when talloc_free is called.

Change-Id: I1c45e3296e565725bcbbca391d9518772fffa89d
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
9dacf0b35b Remove duplicate call to gprs_rlcmac_lost_rep
Function is already called by gprs_rlcmac_received_lost(), so next call
following it will be sum=0 and return EINVAL.

Change-Id: I015ba16d18fdd6e2441ec3c256b5ac88771d7a8b
2021-08-23 17:14:22 +02:00
Pau Espin Pedrol
8c4f978483 Drop logging last mas report before freeing TBF
There's no much use in logging it since anyway we are immediately
getting rid of it.

Change-Id: I9b712f720b5874886cc19d998fb8fcd0e618d590
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
62e06f92e9 Put dl_tbf::cleanup into destructor
It's fine to always attemt dropping the timer since it's set up in the
constructor.
This also drps the double function call abort()+cleanup() which is
confusing.

Change-Id: Ia2aaa43bd8faacf09fe4b36b11b38022bea7a59c
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
f45ede640b Drop duplicate log line
Same line (or similar if run_diag) is logged immediately below, showing
up twice in log which is confusing:

"""
20210726171543005 DTBF tbf.cpp:455 TBF(TFI=2 TLLI=0xfe563576 DIR=DL STATE=WAIT_RELEASE EGPRS) T3193 timeout expired, freeing TBF
20210726171543005 DTBF tbf.cpp:462 TBF(TFI=2 TLLI=0xfe563576 DIR=DL STATE=WAIT_RELEASE EGPRS) T3193 timeout expired, freeing TBF
"""

Change-Id: Ie171c458e670f8471ac93f78520a05926114c974
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
cfb61d9536 Move T3169 and T3195 to tbf_fsm
Change-Id: I599f4e7e82b0a8c0f5cf633c2d8b1975435f0b60
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
55f600b702 Move RELEASING tbf_state transition to tbf_fsm
PdchUlcTest output changes because the original state NULL is not
expected when transactioning to RELEASING upon MAX N310* being hit. In
any case, none of those events should happen in NULL state, but we
don't really care about TBF states there so we are fine with whatever
the state is.

Related: OS#2709
Change-Id: I516b8d989a0d705e5664f8aeaf7d108e0105aa16
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
efcb046ce1 Move WAIT_RELEASE tbf_state transition to tbf_fsm
While at it, method maybe_start_new_window is renamed to
rcvd_dl_final_ack to make more sense out of the code.

Related: OS#2709
Change-Id: Iebd650c1036ef2d5132789778be7117ce3391c01
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
c32c4a3648 Move FINISHED tbf_state transition to tbf_fsm
Related: OS#2709
Change-Id: I81f507e3a2821254f03364a58ead02333e63099f
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
65bba93afa tests: tbf: Fix dl_tbf polled for data without being in FLOW state
Prior code was wrong, as in it did stuff diferent to what is expected
and actually done in osmo-pcu. In osmo-pcu code, the function is guarded
and only called in FLOW or FINISHED state by the scheduler.

Change-Id: If8029bee90adceee128ebb20c033756efd50e90e
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
720e19e7f3 Move FLOW tbf_state transition to tbf_fsm.
Related: OS#2709
Change-Id: Ia8c7de759c195d09263fb1f083fbf6cfa3087f8d
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
33e8007100 Move NULL and ASSIGN tbf_state transition to tbf_fsm
At some point later in time the state_flags will most probably be split
into different variables, one ending up in a different FSM. It is moved
so far to the exsiting FSM from the C++ class since it's easier to
access it from C and C++ code, and anyway that kind of information
belongs to the FSM.

Related: OS#2709
Change-Id: I3c62e9e83965cb28065338733f182863e54d7474
2021-08-23 17:14:21 +02:00
Pau Espin Pedrol
88f34812df Revert "Revert "Stop abusing T3169""
This reverts commit 112c63e9b4.

Change-Id: Ic18674ccd38f81ddd46e1ec733159df350991899
2021-08-23 17:14:19 +02:00
Pau Espin Pedrol
b5fece959f Revert "fix: handle NULL return of as_dl_tbf() and as_ul_tbf()"
This reverts commit d8e8ea9c8f.

Change-Id: I8000e78515b25b9be5c28a249bde330dac915dcb
2021-08-23 17:14:17 +02:00
Pau Espin Pedrol
bc139a4af4 Revert "coverity: fix null deref from recent UL TBF leak fix"
This reverts commit 3bd6488889.

Change-Id: I59c4ae726286216850ad9b53fee34ab4bda5630f
2021-08-23 17:14:15 +02:00
Oliver Smith
e54f148ce9 tests: make update_exp: build check_PROGRAMS first
Make test development a bit more convenient.

Change-Id: Ic053aa3ab7485176b58eab6ebb4835cfbe6b8260
2021-08-23 14:56:27 +02:00
Oliver Smith
3f79470453 bts: delete pch_timer list in destructor
Run bts_pch_timer_remove() on each entry of the BTS specific pch_timer
list, so we don't have a memory leak and so the timer doesn't
potentially fire for a deallocated BTS.

Fixes: d3c7591 ("Add counters: pcu.bts.N.pch.requests.timeout")
Change-Id: Ia5e33d1894408e93a51c452002ef2f5758808269
2021-08-23 14:51:18 +02:00
Neels Hofmeyr
3bd6488889 coverity: fix null deref from recent UL TBF leak fix
Fix a possible NULL deref, introduced in recent patch
I8ce21be6836549b47a606c00b793d6f005964c5c /
d8e8ea9c8f

Related: OS#5205 SYS#5561 CID#239246
Change-Id: I603d4a5bc0fe5bd2e9f0dba171604c459e38aeaf
2021-08-18 18:23:44 +02:00
Neels Hofmeyr
d8e8ea9c8f fix: handle NULL return of as_dl_tbf() and as_ul_tbf()
Go through all callers of as_dl_tbf() and as_ul_tbf(), and make sure
they can handle the possible NULL return value.

OS#5205 reports a NULL deref crash of osmo-pcu at pdch.cpp:525. The
immediate cause is that as_dl_tbf() may well return NULL, which this
caller does not handle and instead dereferences immediately.
This is a code path that apparently assumes that a DL-TBF should always
be present. The higher level cause for the NULL DL-TBF has not been
identified.

Related: OS#5205 SYS#5561
Change-Id: I8ce21be6836549b47a606c00b793d6f005964c5c
2021-08-17 12:17:13 +00:00
Neels Hofmeyr
112c63e9b4 Revert "Stop abusing T3169"
This reverts commit 846fd248dc.

The commit introduced a leak of UL-TBF, which do not time out and
accumulate indefinitely, leading to out-of-memory for the running
osmo-pcu process.

A proper fix for the leak is pending on a development branch pespin/fsm,
but that branch is not yet ready for merging. Hence let's re-introduce
timer T3169 to avoid the OOM due to lingering UL-TBF.

Related: OS#5209
Change-Id: I99a7d2ddf68a76739ce2db1d6a44967dd97667b0
2021-08-15 17:46:53 +00:00
Neels Hofmeyr
4163361906 T_defs_bts: remove unit from doc strings
The main reason to change this is that the unit for T3172 is wrong. It
is defined as ms but the doc string says "(s)".

The tdef implementation already includes the unit as defined for each T
in the doc string implicitly, so instead of fixing that string, just
remove the unit strings from all the doc strings.

Now it will show:

 OsmoPCU# show bts-timer
 BTS0:
  T3142 = 20 s	Wait Indication used in Imm Ass Reject during TBF Establishment (CCCH) (default: 20 s, range: [0 .. 255])
  T3169 = 5 s	Reuse of USF and TFI(s) after the MS uplink TBF assignment is invalid (default: 5 s)
  T3172 = 5000 ms	Wait Indication used in Imm Ass Reject during TBF Establishment (PACCH) (default: 5000 ms, range: [0 .. 255000])
  T3191 = 5 s	Reuse of TFI(s) after sending (1) last RLC Data Block on TBF(s), or (2) PACKET TBF RELEASE for an MBMS radio bearer (default: 5 s)
  T3193 = 1600 ms	Reuse of TFI(s) after reception of final PACKET DOWNLINK ACK/NACK from MS for TBF (default: 100 ms)
  T3195 = 5 s	Reuse of TFI(s) upon no response from the MS (radio failure or cell change) for TBF/MBMS radio bearer (default: 5 s)

Related: OS#5209
Change-Id: I140122bb10f750bf996272cc7f9c5b541c9bd364
2021-08-12 15:08:16 +02:00
Oliver Smith
d3c7591304 Add counters: pcu.bts.N.pch.requests.timeout
Implement T3113 for paging over PCH with default value of 7s (same as
T3113 in OsmoBSC). Increase the new counter on timeout.

Related: SYS#4878
Change-Id: I97475c3dbe2cf00b9cbfec39e93a3c65cb7f749f
2021-08-11 13:42:30 +02:00
Oliver Smith
4df959d305 Add counters: pcu.bts.N.pch.requests
Count attempted paging requests over PCH.

Related: SYS#4878
Change-Id: I1026780ef8542f40060b961df2f37213e15c29d7
2021-08-10 10:35:18 +00:00
Oliver Smith
978396732b Add counters: pcu.sgsn.N.rx_paging_{cs,ps}
Related: SYS#4878
Change-Id: Iefba6f3d29c69fd4865c084bd9cf1a3a78f5c202
2021-08-10 10:35:18 +00:00
Oliver Smith
3f561bfbfe test: add 'make update_exp' target
Add convenience target to update the test output.

Change-Id: I225dd3746200cad748ea09b2c3e1c7f9d006d32f
2021-08-06 22:21:14 +02:00
Pau Espin Pedrol
945be91032 tests/tbf: Fix null pointer access if slowly stepping with gdb
When slowly debugging test_tbf_dl_llc_loss, bssgp_tx_llc_discarded() may
trigger, submitting events to the libosmogb code. Since it didn't
properly set up the callback, it would end up in a null pointer
dereference when lib code tried to use backward-compatible API (which
was neither set up properly).

"""
TBF(TFI=0 TLLI=0xc0123456 DIR=DL STATE=ASSIGN) Discarding LLC PDU because lifetime limit reached, count=3 new_queue_size=0
BSSGP (BVCI=2234) Tx LLC-DISCARDED TLLI=0xc0123456, FRAMES=3, OCTETS=57
/git/libosmocore/src/gb/gprs_ns.c:271:2: runtime error: member access within null pointer of type 'struct gprs_ns_inst'
"""

"""
(gdb) bt
 #0  0x00007ffff729cac0 in gprs_active_nsvc_by_nsei (nsi=nsi@entry=0x0, nsei=2234, bvci=bvci@entry=0)
    at /git/libosmocore/src/gb/gprs_ns.c:271
 #1  0x00007ffff72b1fec in gprs_ns_sendmsg (nsi=0x0, msg=0x621000000160) at /git/libosmocore/src/gb/gprs_ns.c:1087
 #2  0x00007ffff72d1803 in _gprs_ns_sendmsg (ctx=<optimized out>, msg=<optimized out>) at /git/libosmocore/src/gb/gprs_bssgp.c:80
 #3  0x00007ffff730226f in bssgp_tx_llc_discarded (bctx=<optimized out>, tlli=<optimized out>, num_frames=<optimized out>, num_octets=<optimized out>)
    at /git/libosmocore/src/gb/gprs_bssgp_bss.c:249
 #4  0x000055555588243e in gprs_rlcmac_dl_tbf::llc_dequeue (this=0x7ffff1622860, bctx=<optimized out>)
    at /git/osmo-pcu/src/tbf_dl.cpp:413
"""

Change-Id: Iee5bcf21afc8980a14f90f5b1ead6d2460a244ea
2021-07-26 16:05:55 +02:00
Pau Espin Pedrol
81db7334da tbf: Drop impossible paths in create_dl_ass()
create_dl_ass() is only called in gprs_rlcmac_sched.cpp on
tbf_cand->dl_ass pointer, which is always assigned under the guard
"!tbf->is_control_ts(pdch->ts_no)", since we only send CTRL messages for
a TBF on its control TS.
Hence, condition "!is_control_ts(ts)" in create_dl_ass will always be
false, and as a result poll_ass_dl will always be 1.
So we can drop different code paths.

Change-Id: Ibea4100a5dc8bd49303cb6a3d02417038c3d3887
2021-07-22 20:06:18 +02:00
Pau Espin Pedrol
890de986ce Make gcc 11.1.0 false positivies happy
After my system's gcc was upgraded, I get false positivies like the one
below:
"""
/git/osmo-pcu/src/gprs_bssgp_pcu.c: In function ‘ns_configure_nse’:
/git/osmo-pcu/src/gprs_bssgp_pcu.c:1103:58: error: ‘%d’ directive output may be truncated writing between 1 and 11 bytes into a region of size 2 [-Werror=format-truncation=]
 1103 |                         snprintf(name, sizeof(name), "pcu%d", i);
      |                                                          ^~
/git/osmo-pcu/src/gprs_bssgp_pcu.c:1103:54: note: directive argument in the range [-2147483648, 1]
 1103 |                         snprintf(name, sizeof(name), "pcu%d", i);
      |                                                      ^~~~~~~
/git/osmo-pcu/src/gprs_bssgp_pcu.c:1103:25: note: ‘snprintf’ output between 5 and 15 bytes into a destination of size 5
 1103 |                         snprintf(name, sizeof(name), "pcu%d", i);
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
In this case, i can't never take a value with more than 1 digit, but gcc
seems to be unable to see that.

Let's increase the buffer size a few bytes to make gcc happy, and make
the variable unsigned since it never will get negative values.

Next change is also a false positive, since variables are always
initialized beforehand in the cod epaths where they are used:
"""
/git/osmo-pcu/src/bts.cpp: In function ‘int bts_rcv_rach(gprs_rlcmac_bts*, const rach_ind_params*)’:
/git/osmo-pcu/src/bts.cpp:859:25: error: ‘ts_no’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
  859 |         uint8_t trx_no, ts_no;
      |                         ^~~~~
/git/osmo-pcu/src/bts.cpp:859:17: error: ‘trx_no’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
  859 |         uint8_t trx_no, ts_no;
      |                 ^~~~~~
"""

Change-Id: I1362a335a0c761bde367dbc779de4afa88f13584
2021-07-15 14:39:39 +02:00
Pau Espin Pedrol
4f67a9bf46 pdch: Fix heap-use-after-free in pdch->ulc
In existing previous code, pdch->ulc would be freed in
gprs_rlcmac_pdch::free_resources() when  it became disabled as per PCUIF
info_ind (for instance, when a DYN TS is switched PDCH->SDCCH8).
However, pdch->ulc was so far only allocated during pdch_init, which is
only called during bts_alloc() time.
Hence, after first info_ind disabling it, if it became again enabled
(again by info_ind re-enabling it after SDCCH8 was not longer in use),
the pdch->ulc would be used again but it would point to freed memory.

Let's rearrange how/when resources are freed to make it more logical.
With this patch, pdch internal resources are freed upon ->disable(), and
re-allocated upon ->enable().

Change-Id: Id51f5f6a54ac9f24b784c17bc360ac38f5726fc7
2021-07-01 13:09:10 +02:00
Pau Espin Pedrol
1989a19066 Support proto IPAC_PROTO_EXT_PCU BSC<->PCU
Related: SYS#5303
Change-Id: I633db291107883c2e370a9b56606d562a990b714
2021-06-25 17:20:50 +02:00
Pau Espin Pedrol
8c29236d35 pcuif_proto.h: Add new container message
Related: SYS#5303
Change-Id: Ib6c7bf5ca5a06186a71ec50cfc1a91a5c9b01d9c
2021-06-25 17:20:46 +02:00
Pau Espin Pedrol
ab178903d4 pdch: Fix null MS access gprs_rlcmac_pdch::rcv_control_ack
If bts_ms_by_tlli() at the start of the function fails, ms could be
NULL. As a result "ms->nacc" access at the end of the function would
crash.
Solution:
In the function, we get the related expected TBF from pdch_ulc, and we only
continue if a TBF is found. Since tbf objects are always expected to
have a GprsMs, simply gather it from there.

Change-Id: I666ed5d157f42e74956fa49fc9eea85d27e63d44
2021-06-23 13:50:35 +02:00
Vadim Yanitskiy
b657213773 pcu_l1_if: ignore PDCH interference reports, do not log errors
Change-Id: I88e5c53131ee94bc3f3ff3f095077feb4ff272a7
Related: SYS#5313, OS#1569
2021-06-22 05:58:23 +00:00
Vadim Yanitskiy
94dc6a8b6c PCUIF protocol: add message definition for interference report
Change-Id: I4b5a4c25e984f9262f0afd30f9671f150edee20f
Related: SYS#5313, OS#1569
2021-06-22 05:58:23 +00:00
Vadim Yanitskiy
826576287e gprs_rlcmac_sched: fix incorrect length for CTR_RLC_DL_BYTES
msg->data_len is the total number of bytes available in the buffer,
while for CTR_RLC_DL_BYTES we need to count size of the actual
payload within the buffer.  A consequence of this bug: osmo-pcu
was counting more Downlink bytes than it's actually transmitted.

Change-Id: I6884d220f3d06a79b16c18ccc2d2a6cd047b8251
2021-06-21 02:33:07 +02:00
Pau Espin Pedrol
86f4c093d1 pcuif: Support receiving System Information 2
OsmoPCU will need this SI2 in order to gain knowledge of the BCCH
Frequency List being broadcasted, in order to build a per-MS specific
Neighbour List using NC_FREQUENCY_LIST bits in Packet Measurement Order.

Related: SYS#5303
Change-Id: I4a9c4f70beac6805322a19835a0d30f7247780b4
2021-06-15 19:11:07 +02:00
Pau Espin Pedrol
c6e911cf22 pdch: Log pdch_ulc reason upon rx of pkt ctrl ack
Change-Id: I7c7a421b1e9189e2814e9a28698d66655fc9ba60
2021-06-07 18:16:55 +02:00
Pau Espin Pedrol
9c1db1738f Use new stat item/ctr getter APIs
Patch mostly done with the help of several small spatch snippets.

Change-Id: I600c7a8725f5b229b1a2feb879da7c3b2dce4505
2021-06-04 17:14:32 +02:00
Pau Espin Pedrol
d65bd9d7b2 bts: Fix typo in field name
Change-Id: I5426ff4ccbc45464888e2246cceb8e861d1e477e
2021-06-01 16:43:41 +02:00
Pau Espin Pedrol
c9880b97cf csn1: Implement CSN_CALLBACK type in encoder
Picked code from the Decoder function. I gave it a try
callback_init_Cell_Selection_Params_FREQUENCY_DIFF and looks
like working fine.

Change-Id: Iac962ae3e9f52f417f394060b64fc4d0ebf3d0bf
2021-05-28 18:42:42 +02:00
Pau Espin Pedrol
4c2387026a gsm_rlcmac.c: Fix arg list of 2 callbacks
Other callback functions are properly specified as per what's in
"typedef CSN_CallBackStatus_t". However, these two were wrong.

Change-Id: I280b51d4c8c38c76cc1ccd49656b6b7bbe769760
2021-05-28 18:42:42 +02:00
Pau Espin Pedrol
2761e574de cosmetic: Fix typo s/TIMSI/TMSI/
Change-Id: I64231311633b64d898625c49fdbf3f816dfbb97a
2021-05-21 13:44:18 +02:00
Pau Espin Pedrol
dc2aaac29f tbf: Move existing tbf_state implementation to osmo_fsm
This is only an initial implementation, where all state changes are
still done outside the FSM itself.
The idea is to do the move in several commits so that they can be
digested better in logical steps and avoid major break up.

Related: OS#2709
Change-Id: I6bb4baea2dee191ba5bbcbec2ea9dcf681aa1237
2021-05-19 12:50:25 +02:00
Pau Espin Pedrol
38f80be73b MsTest: Set up tbf talloc destructor
This is right now not an issue, but it will be whenever talloc
destructor contains extra steps like freeing an FSM.

Change-Id: I096ff56321c8ae5e66634537aae8b95804282c65
2021-05-19 12:50:25 +02:00
Pau Espin Pedrol
1a1557a60a Move TBF list from BTS to the TRX structure
The TBFs are managed per TRX. Move the global list from BTS to TRX.

Related: OS#1541
Change-Id: Id3c59c11d57d765fe68aaebaac94290c0d84feb2
2021-05-19 12:50:25 +02:00
Pau Espin Pedrol
f62b0ec37d tbf: Log error path in setup() failing to assign control TS
Change-Id: I047209dfe139e37a80878318cca75cb50905536e
2021-05-19 12:50:25 +02:00
Pau Espin Pedrol
9d2fd018ff bts: Use ms_store when calculating set of target PDCHs for Pkt Paging Request
The ul_tbfs/dl_tbfs lists will become per-trx. Since in this case we
want to operate on the BTS globally, let's iterate over MS objects
instead. This makes more sense too since here we really aim at reaching
a MS (subscriber) instead of specific TBFs. Later on the code can be
optimized easily to schedule a Pkt Paging Request for only 1 of the TBFs
of each MS instad of scheduling it for each TBFs in the MS.

Change-Id: I671e531921bbea2f5cc0f2bfcb8a39ea5c6673b8
2021-05-19 12:50:21 +02:00
Pau Espin Pedrol
bd54205475 Optimize PAGING-CS PDCH set selection when target MS is known
Before this patch, when a PAGING-GS was received in PCU from SGSN, it
would always forward the paging request to all PDCHs in all TRXs of all
BTS (well, it did some heuristics to avoid sending it in some PDCHs
where onyl repeated TBFs would be listening).

The previous behavior, didn't make much sense in the case where the PCU
is asked to page an MS which it knows (ie in which PDCHs is listening
to). Hence, in that case it makes sense to simply send the paging
request on 1 PDCH where the MS is listening, instead of sending it in a
big set of different PDCHs.

This commit also splits the old get_paging_mi() helper which was
erroneously created to parseboth CS/PS-PAGING requesst, since they
actually use a different set of target subscriber information (for
instance, CS-PAGING provides optionally a TLLI, and one provides P-TMSI
while the other provides TMSI).

In this patch, the handling of CS paging request is split into 2 parts:
1- A new helper "struct paging_req_cs" is introduced, where incoming
CS-PAGING requests (from both SGSN over BSSGP and BTS/BSC over PCUIF)
are parsed and information stored. Then, from available information, it
tries to find a target MS if avaialable
2- bts_add_paging() is called from both BSSGP and PCUIF paths with the
helper struct and the target MS (NULL if not found). If MS exists,
paging is forwarding only on 1 PDCH that MS is attached to. If no MS
exists, then the old heursitics are used to forward the request to all
MS.

Change-Id: Iea46d5321a29d800813b1aa2bf4ce175ce45e2cf
2021-05-19 12:46:00 +02:00
Pau Espin Pedrol
4c51eaf05b Use LOGPDCH macro in bts_add_paging()
Change-Id: I58daab719924d70de121f7a5f2cc1f122f8840af
2021-05-19 12:02:34 +02:00
Pau Espin Pedrol
6e25119c18 Clean false positive in newer GCC version checking guard of else clause
Got this today with newer gcc (11.1.0) after system upgrade:
egprs_rlc_compression.cpp:693:9: error: this ‘else’ clause does not guard... [-Werror=misleading-indentation]

The indentation was indeed wrong, provoking a warning in GCC. From code
flow point of view, however, the previous state was fine too, so no
logical change is involved in this commit.

Change-Id: I37bfc8e85daaabbbf10dfd907b305e3e0ec31863
2021-05-19 11:58:57 +02:00
Pau Espin Pedrol
c43570c351 RIM: Refactor Rx path to decode stack in proper order
Previous implementation of the Rx path was first checking the APP ID
before checking the lower layer (container type), which was confusing
because the information is then not verified in ascending order in the
protocol stack.

Let's instead, first, pass the pdu to the correct container type
handler, and only once there, let each container type handler verify the
available applications.

Change-Id: Ibe017c1a6e789f45d74c4a5f5f4608298c8c9f91
2021-05-17 14:21:21 +02:00
Pau Espin Pedrol
c48d27b57b pdch: Use llist_first_entry() API
Change-Id: I96e7188ecf7d2cfc54598975f8d538e7aa94401a
2021-05-13 15:58:55 +02:00
Pau Espin Pedrol
48517620b9 sched: Clean up param passing and improve logging
Change-Id: If137a2aaac7744e60564ca833a1b5564ed7d93bb
2021-05-12 14:24:02 +02:00
Pau Espin Pedrol
9b63cd04e4 ul_tbf: Fix accessing zeroed block when checking if transfer is complete
The logic checking whether the UL TBF had already been sent all the data
(and hence was marked as finished and requesting UL ACK to be sent) was
not taking into account the case where there was still no valid block
stored, ie. when the first received UL data block was discarded for some
reason (ex: because TLLI was not set during content resolution).

Related: OS#1940
Change-Id: I739e67ae1bb40555a362170f26fb98ac69caabb2
2021-05-12 14:24:02 +02:00
Pau Espin Pedrol
58916318ef ul_tbf: Simplify function rcv_data_block_acknowledged
Let's avoid different code paths in the loop based on is_tlli_invalid.
Instead, always do the proper storing of the block, and if later on the
corner case is found (no TLLI received while in Content Resolution
process) when checking tlli related stuff, then simply invalidate the
block.

Related: OS#1940
Change-Id: I77afaa617d7ce045c0f6d994fc0d8e03fe69de53
2021-05-12 14:24:02 +02:00
Pau Espin Pedrol
f53815f2fc Drop existing tbf->ms() check condition
Since a while ago, tbf should always have an MS attached since its
creation, so there's no sense to check for it here.

Change-Id: If056a3fb83b43a48c2a6382fc30c6c81fe2b2651
2021-05-12 14:24:02 +02:00
Pau Espin Pedrol
632542348a sched: Clean up helper function and improve logging
Change-Id: I8c19d0924e73c324a36ea038cab7cc4e096b866b
2021-05-12 14:23:59 +02:00
Pau Espin Pedrol
c432e062ea encoding: Encode TA in UL ACK/NACK if available
Change-Id: I3b060ee16aeac5f5d9b314b6bc46383f5e9c44c3
2021-05-11 13:24:13 +02:00
Pau Espin Pedrol
6bab522e90 encoding: Use gsm48_ta_is_valid() API
Change-Id: Ieaa4c2f926611576e22eaac8a7ac595135809e2c
2021-05-11 13:01:53 +02:00
Pau Espin Pedrol
eb13c79cc0 Tx ul ack/nack: Avoid sending invalid/unknown TLLI
It could happen that if MS sends first UL blocks without TLLI (wrongly,
due to being in contention resolution), the submitted UL ACK/NACK would
contain an invalid TLLI.

Related: OS#1940
Change-Id: Ibae5df6cfbb56f8f8007cb9fec9c29006d673b72
2021-05-11 12:55:44 +02:00
Pau Espin Pedrol
faf0ccb241 tbf_ul: Use is_tlli_valid() API
Change-Id: I4abb46913b05d1e89ebe9e361b0a774880dee998
2021-05-11 12:55:44 +02:00
Pau Espin Pedrol
4b6f0bfe69 Implement T3141
Related: OS#1940
Change-Id: I154984b835b2b436b1ebe4631a8afcebb7338c65
2021-05-11 11:32:44 +02:00
Pau Espin Pedrol
20271c421c Split ul_tbf alloc on CCCH into new function
This allows more easily finding when this specific scenario happens, and
can easily be compared against the PACCH one.

Change-Id: I609792a40fda2a798ca71a0e9f5639d0a0f011d7
2021-05-11 11:32:44 +02:00
Pau Espin Pedrol
c6571b5581 Rename function s/tbf_alloc_ul/tbf_alloc_ul_pacch/
Change-Id: I70ca0b5be0a29a05c6e65b9c92cc6d3b5c43d3dc
2021-05-11 11:32:38 +02:00
Pau Espin Pedrol
50272a4776 alloc_algorithm_b: Rearrange variable initialization
Untangle variable assignment at the start of the function. Changes end
up in same kind of assignment, but are far easier to understand based on
the variable use later on.
* reserved_{dl,ul}_slots contain mask of TS either "previously-reserved" or
  "intended to be reserved now" based on MS's ms_class.
* {dl,ul}_slots contain a derived mask from the one above, filtered
  further based on more factors like type of allocation requested (multi
  vs single), available USFs (UL), etc.

Change-Id: If3cfa82f8b793a87e97145ee8a6fc0fe1a61add6
2021-05-10 12:25:24 +02:00
Pau Espin Pedrol
393484a5d0 Simplify helper function tbf_select_slot_set()
Store direction check to simplify the code.
Get rid of 2-step LOGP to avoid multi-row logs in gsmtap log.

Change-Id: Ia2e061da82ddce564b2d768d8ade1672c22934e2
2021-05-10 11:21:52 +02:00
Pau Espin Pedrol
0e35aee194 rim: Constify param in func
Change-Id: I47c471929a62d6a5340ae4a4ca88bd0b758c208d
2021-05-06 19:47:15 +02:00
Pau Espin Pedrol
c6dcfe32f3 sched: Rename func to describe its used only for RLCMAC CTRL blocks
Change-Id: I20e15047af2aac4d51e1dae263ab16e479bb0c46
2021-04-30 17:42:25 +00:00
Pau Espin Pedrol
4b7a71f93f bts: constify arg in func bts_ms_store()
Change-Id: I4cc8c4fc075cdd07e689511df8f1c267e5360014
2021-04-30 17:42:25 +00:00
Harald Welte
292d04d19d manual: Include QoS chapter and add osmo-pcu specific example
Change-Id: I4d409b55861f05ba229dc5cb97f99370356e3dbd
Requires: osmo-gsm-manuals.git Id344c29eda2a9b3e36376302b425e9db1f6c0f28
2021-04-29 22:16:49 +02:00
Harald Welte
d9367e34db vty: Add configuration for Gb DSCP and socket priority
While libosmogb / ns2 supports that natively in the VTY, the PCU
doesn't want to use the complexities of the full NS2 vty.

Change-Id: I7bfbad46582e65e5ad2ac0cc66545538bc632df8
Related: SYS#5427
2021-04-29 22:13:05 +02:00
Harald Welte
4e453b41f3 manual: Update copyright years
Change-Id: Ia0dde7100dd90c6ad6279efbaf02b9bd3f868635
2021-04-29 22:07:10 +02:00
Harald Welte
fa48b4b720 manual: remove revhistory, as we don't maintain it manually anyyway
Change-Id: Ibbe08cac143f4bff6192125940ef190cc943d307
2021-04-29 22:07:10 +02:00
Pau Espin Pedrol
f593fc5cbb doc/tbf.txt: Update and improve some information
Change-Id: I3cd643ef462637708c69895c62c488554a428571
2021-04-27 12:01:52 +02:00
Pau Espin Pedrol
039ee8200a Clarify, document Assignment related timers
Related: OS#3928
Change-Id: Iad31a5c6f83cd78793adf05a6af782ceacae8b11
2021-04-26 18:49:58 +02:00
Pau Espin Pedrol
34f61af3d0 sched: Simplify else-if condition
The code path running into first call of "create_packet_access_reject()"
is a superset condition of the second one, so the second one will never
be hit.

As a result first, this block:
"""
else if (tbf == tbfs->ul_ass && tbf->direction == GPRS_RLCMAC_DL_TBF)
    if (tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ))
        msg = tbfs->ul_ass->create_packet_access_reject();
    else
        msg = tbfs->ul_ass->create_ul_ass(fn, ts);
"""

Can be simplified into:
"""
else if (tbf == tbfs->ul_ass && tbf->direction == GPRS_RLCMAC_DL_TBF &&
	     !tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ))
        msg = tbfs->ul_ass->create_ul_ass(fn, ts);
"""

Next, one can see that previous condition still forces
!tbf->ul_ass_state_is(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ) to be always true
if we ever reach that code, so it can be dropped.

Change-Id: I62e2255e28fc4f43fe0a31259ebf18ad00e7e357
2021-04-26 18:02:54 +02:00
Pau Espin Pedrol
2ab840a1fa Make WaitIndication T3172 configurable
Tbftest expectatins need to change because 5000/20 = 250 < 255, hence
the message is now sent as units of 20ms instead of seconds.

Related: OS#3928
Change-Id: I48b34b94b1a5dfb046a3a6cf8a0d944a7c9b6754
2021-04-26 17:53:09 +02:00
Pau Espin Pedrol
54742f287c ul_tbf: Clean up handle_tbf_reject()
Document the function, make it look similar to usual TBF creation path
tbf_alloc_ul()->tbf_alloc_ul_tbf->tbf::setup(), which it mimics with
some differences.
Get rid of unneeded stuff like creating MS and settings its TLLI (that's
already done in only caller of the function). There's no need for
calling update_ms() either.

Change-Id: I61df2e4f0f0df1f8db941741a2d35a2319252c5e
2021-04-26 17:19:07 +02:00
Pau Espin Pedrol
14339f6fac Use negative numbers for non-spec osmo-specific timers
(values -1 and -2 cannot be used because they are already taken).

Related: OS#3928
Change-Id: Ibcdb05ff5bb8efe6cb95cf94e2c8e418dc8deced
2021-04-26 14:15:08 +02:00
Pau Espin Pedrol
25ebf3c8f9 Make use of T3142 received from BTS
Related: OS#3928
Change-Id: I4e26f181db9693d3a267a879e2aebda12eab2a8c
2021-04-26 14:10:11 +02:00
Pau Espin Pedrol
846fd248dc Stop abusing T3169
Now that we finally handle N3101 and N3103 correctly, we can fix abuse
of T3169 we were doing to make sure TBFs were freed.

According to 3GPP TS 44.060, T3169 should be armed:
* N3101_MAX reached
* N3103_MAX reached

Furthermore, when T3169 is enabled, the tbf should be in state
RELEASING so that its USF is not used.

See full description: https://osmocom.org/issues/5033#note-2

Related: OS#5033
Change-Id: I2cec531e2633281b88f69ba065c0105580c81076
2021-04-26 11:20:19 +02:00
Pau Espin Pedrol
710e0e9ad8 pdch: tbf_by_tfi(): Allow returning TBFs in state RELEASING
During RELEASING state the TFI, USFs, etc. are still reserved and
assigned to the TBF, and hence the TBF may still use it.
If callers of this function rely on not taking TBFs under RELEASING
state, they should check that explicitly.

It still makes sense being to operate on RELEASING TBFs, since under
some circumstances the TBF may go under a previous state. See for
instance 3GPP TS 44.060 sec 8.1.1.3a.2:

"""
If N3101 reaches the value N3101max, the network shall stop sending
PACKET UPLINK ACK/NACK messages to the mobile station for that TBF
and shall start timer T3169 for the TBF. If an RLC/MAC block is received
from the TBF when timer T3169 is running, the network shall stop timer
T3169 and resume sending PACKET UPLINK ACK/NACK messages to the TBF.
When T3169 expires, the network may consider the TBF as released and
reuse the TFI value.
"""

Change-Id: Ibb471e727388512d42794d3faa26597e2545b852
2021-04-22 21:07:06 +02:00
Pau Espin Pedrol
434799720c pdch: rcv_resource_request: Improve robustness
Use recently added PDCH UL Controller to verify expectancies.

Test test_packet_access_rej_prr is rewritten since it didn't make sense
as it was before, since it relied on osmo-pcu not checking stuff
properly to trigger the reject. The RACH requests are changed to
allocate 8 SBAs (maximum of 7 concurrent USFs). Allocating the SBA
doesn't reserve a USF, that happens at PKT RESOURCE REQUEST, hence we
end up exhausting resources there and triggering the REJECT at that
point.
Previous version of the patch allocated TBFs directly through RACH req,
and then submitted an extra PKT RESOURCE REQUEST which PCU didn't expect
to trigger the reject.

Change-Id: I157e72160317340ee7742c78c62a25d3d98fc01e
2021-04-22 20:28:40 +02:00
Pau Espin Pedrol
ffc533b1af sba: Drop unused function find_sba_rts
This function is not longer used since commit below, let's drop it.

Change-Id: I633676fc3a573acd0dccdd035ffe557c9c71a56e
Fixes: fd1fbdb8db
2021-04-22 19:46:54 +02:00
Pau Espin Pedrol
ab3aca65c5 RIM: Improve logging
Change-Id: I0adbb8ea4480912463dc1dded6c06a1b8f7ed807
2021-04-19 17:47:26 +02:00
Pau Espin Pedrol
16e1678bfc tbf: Get rid of attribute poll_ts
That field is not needed anymore, and it works only under the assumption
that only 1 poll request can be active at a time per TBF, which is not
true.

Change-Id: I9b8bed7741d385bab4cd8c64b841a78a02a05fe1
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
58046e45d1 tbf: Get rid of attribute poll_fn
That field is not needed anymore, and it works only under the assumption
that only 1 poll request can be active at a time per TBF, which is not
true.

Change-Id: I63a34a702f028b871530fb7caeb13e8ea1cc78ac
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
2c0931cedc Get rid of param 'poll' with constant value
Value 'false' is always passed by all callers of the function, so
there's no need to pass it. Furthermore, since it's false, there's no
need to access poll_fn since RRBP will always be invalid.

Change-Id: Ia48ce2a021865e76e813dedb22aca9c2522c5693
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
127e7392f6 tbf: get rid of poll_state completely
The poll_state logic was part of previous implementation (prior to pdch
ul controller) where the ssumption was that TBF could only had 1 POLL
request in transit, which is really not true. With current
infrastructure we don't need this state tracking at all.

Change-Id: Ie5b807ccd38aa736ae11b3310ca61ad0156ca4d4
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
feee2b9b83 Remove unneeded poll_state check
The related ul_ass_state already implies polling is ongoing since we are
waiting for an ACK to be received from MS. Hence there's no need to
check poll_state there.

Change-Id: I5e12280a6835407fa452bd4d5df799d2672790ec
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
42445ea944 tbf: Allow multiple concurrent polls
There's no good reason to allow only for 1 concurrent POLL requested to
a TBF, it was onyl done this was as an implementation limitation factor.
It can well happen that several multiple POLLs may be in transit at the
same time, eg to get DL ACK/NACK as well as to get a CTRL ACK for a Pkt
Cell Change Continue (NACC).

Change-Id: Ic4080db684a4626cae90dd574d123081981284ca
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
ed066b5328 tbf: Get rid of unneeded poll_scheduled()
This API is not really needed anymore, since anyway it works under the
assumption there can only be 1 POLL in transit per TBF, which isn't
necessarily true.

Change-Id: I875f51cade95faeb2d79dcebfead4c83e23a731b
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
86580e1966 pdch_ulc: Store TBF poll reason
This allows easily checking the initial reason to trigger the poll when
either it is received or times out.

Later on this reason can be transformed into an FSM event and sent to
the related FSM.

Related: OS#5020
Change-Id: Ie8fefd1f47ad674ce597a8065b15284088956bde
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
b5ae0811d1 Drop unused function tbf_check()
Change-Id: I90d75a75ae5b528c6ca7b409e60bd158d6043b35
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
50a1ede693 pdch_ulc: Support picking RRBP other than N+13
Current algo always tries to sched RRBP the soonest possible.

Related: OS#5020
Change-Id: Ic6ddeea70e1f914cf423d0daab8fc492d0c992e2
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
ce3bd2522a Pick unreserved UL FN when allocating an SBA
Make sure an unreserved FN is picked and reserved when allocating and
scheduling an SBA.
In practice this has no change in behavior right now, since anyway using
an offset of 52 FNs ensure no USF or POLL has alredy been scheduled that
far in the future. Since it's also impossible to allocate more than 1
SBA per PDCH and RTS FN, we are also safe about multiple SBAs being
allocated, because we use a hardcoded offset of 52.
However, that could change in the future, when we dynamically tweak the
current offset of 52 FN based on information from BTS about its AGCH
queue load:
* If load is high, we may need to increase the offset since it
will take more time for the BTS to transmit the TBF and hence we must
reserve a TBF starting time further in the future (higher FN).
* If load turns low, we may schedule next SBA a bit more nearby in time
  than the previously allocated SBA, hence here there could be a
  collision.

Related: OS#5020
Change-Id: I2d4e21e2307de6c17748e8da5c7e149c947a7eb9
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
222f674116 pdch_ulc: Optimize rbtree FN search
Use logarithmic lookup algo to find if FN is available instead of
iterating over the whole tree.

Change-Id: I2843aedb5ce74c909bde82d29269d0f956e9a093
2021-03-31 17:39:50 +02:00
Pau Espin Pedrol
54e6450293 sba: Document AGCH_START_OFFSET after some experimental tests
Related: OS#5020
Change-Id: Id1460207be25750aeb5c1d7af2fac6591cf5e424
2021-03-31 17:39:46 +02:00
Pau Espin Pedrol
0b998b15da Properly implement N3101
N3101 is incremented by unanswered USF requests, not from unanswered
POLLs.

Related: OS#5033
Change-Id: I1a55bdd39db8843976915b9f74fadb0942298413
2021-03-24 17:16:29 +01:00
Pau Espin Pedrol
c1f38c7f0b Track scheduled UL blocks through USF
This way PCU can now detect whether scheduled UL blocks through USF
were never received. This allows in a follow-up patch to start
increasing N3101 properly.

Related: OS#5033
Change-Id: Ia99c9edad6e5bd837e9baeb4fb2683b227887957
2021-03-24 17:14:19 +01:00
Pau Espin Pedrol
ade9c2f553 pdch_ulc: Create helper API pdch_ulc_release_node
Change-Id: I6362ad7382c2b73e6fedb11182964be96e5c8d35
2021-03-24 17:12:01 +01:00
Pau Espin Pedrol
9a6f0b191a pdch: Add mising pdch_ulc_release_node in Rx Cell Change Notif
All other RX CTRL block paths have it, this one was missing.

Change-Id: Ief315d7b6d4fea946d43e5bd87cf8a0394adc855
2021-03-24 17:12:01 +01:00
Pau Espin Pedrol
7bd92a3e1d Set matching USF if available when polling a UL TBF
When the scheduler detects it's time to receive a UL block due to a
scheduled poll, if that polling is done on a UL TBF, then use its USF if
available instead of using USF_UNUSED (=7) when sending a DL block on
that same FN.

This is not really needed for correct work, since MS take care
themselves of scheduling a UL block when they receive the poll (RRBP)
some time before, and don't check the USF at the time of transmitting.
In any case, it helps understand better when looking at pcap traces that
indeed it a UL block from that MS was requested, instead of setting USF
to 7.

Related: OS#5033
Change-Id: I2ad9d8ea6afc8f83192033470bd27010a7474430
2021-03-24 17:12:01 +01:00
Pau Espin Pedrol
4bab867d9f sched: Simplify usf selection code
Simply use the UL TBF pointer all along until the end, instead of setting
both the UL TBF pointer plus the usf var.

This commit is also a preparation for next commit which also selects UL
TBF when a poll is available, to set its USF in the DL message instead
of "USF_UNUSED".

Change-Id: I3aa3886932ef87db18ed7ff6991ea315f481990b
2021-03-24 17:12:01 +01:00
Pau Espin Pedrol
107e94c9f8 sched: Fix scheduling UL TBF not matching conditions
With previous code, a skipped TBF could be returned despite not matching
the conditions, since at the end of the loop the tbf pointer was
returned.

Related: OS#5020
Change-Id: If6dccec86c7a655bf1c62f333cfbc8d2c507c94f
2021-03-24 17:12:01 +01:00
Pau Espin Pedrol
56f223d8d1 Fix: left shift cannot be repesented in type int
Caught by ASan:
runtime error: left shift of 1 by 31 places cannot be represented in type 'int'

Change-Id: I30aed795d027dc063f06e08c8455bad2dd92cf24
2021-03-24 14:27:19 +01:00
Alexander Couzens
5d376845bb gprs_bssgp_pcu: add comments to the pcu states
Related: OS#3879
Change-Id: Iccf6508ce46162e6dfd6b00abd44e24cb425b346
2021-03-23 17:47:22 +00:00
Alexander Couzens
82519264ca gprs_bssgp_pcu: ensure only known BVCI can be resetted by the SGSN
Related: OS#3879
Change-Id: I04e36ce4a29e51d85e67a0d3a81aa0e1eb9e9c08
2021-03-23 17:47:22 +00:00
Harald Welte
d7f0558b5c pdch_ul_controller: Fix compiler warning on gcc-10.2
pdch_ul_controller.c: In function ‘pdch_ulc_release_tbf’:
pdch_ul_controller.c:217:7: error: ‘item_tbf’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
  217 |    if (item_tbf != tbf)
      |       ^

Change-Id: I42120fdf23753945ebc16bb5469d9fd253c3da37
2021-03-20 16:17:30 +01:00
Pau Espin Pedrol
755a8d61bb direct_phy: Fix condition dropping rx DATA.ind payload in in
Related: OS#5020
Fixes: 81c549d5be
Change-Id: Iad8e50b856009439d78c596c5b54dc3e9836e1d4
2021-03-18 14:03:35 +01:00
Pau Espin Pedrol
fecab50066 sysmo: fix wrong FN jumps in rx RA.ind
There's no need for setting the FN in RA.ind since we anyway already
receive a DATA.ind beforehand.
Furthermore, the applied delay of 5 in the call is not really used at
all.

Change-Id: I437f4f95d054aea96bec3b9343e495451020ff3c
2021-03-17 15:58:16 +01:00
Pau Espin Pedrol
c7cc4162e1 ulc: Fix FN store order upon wrap around
Related: OS#5020
Change-Id: I0a742f7fa1541b1837739207b9383772f981fb25
2021-03-15 19:36:56 +01:00
Pau Espin Pedrol
95f8fa1f7c tests: ulc: Show current bug with FN wrap around
Issue will be fixed in next commit. Leaving ASSERTs disabled so that
test passes in jenkins.

Related: OS#5020
Change-Id: I657db6b300363f8f3a9e4cfaf7a7f49e361a0512
2021-03-15 19:36:27 +01:00
Pau Espin Pedrol
582a15e413 tests: Introduce unit tests for PDCH UL Controller
Related: OS#5020
Change-Id: Ie1ff0ca3d7fc8a9824d6fe4dceb746e301082bda
2021-03-15 19:35:43 +01:00
Pau Espin Pedrol
5bc9612c02 cosmetic: tests/Makefile.am: Split content into several lines
Change-Id: I67361862b992d761b314d9565165ece7e380606d
2021-03-15 19:34:35 +01:00
Pau Espin Pedrol
3a42d17b14 bts: Detect FN jumps
Change-Id: I29fb27981597edc69abb976049ba41aa840488cb
2021-03-15 19:34:35 +01:00
Pau Espin Pedrol
fd1fbdb8db sched: Use new PDCH UL Controller
Take the time to also do small refactorings to clarify and simplify the
function, by using rts_next_fn() already available in pcu_utils.h and
getting rid of poll_tbf from tbf_candidates, which clearly follows
another objective.

Using PDCH UL Controller has the advantage that we don't need to check
poll_scheduled() on each TBF, but only do the query once.

Related: OS#5020
Change-Id: Ia60bb5249a9837dec1f42180e44d9848334d86d6
2021-03-15 19:34:20 +01:00
Pau Espin Pedrol
99360a304f Replace PollController with newly added PDCH UL Controller
TbfTest is updated to submit empty blocks to have somehow meaningful
output (at least as meaningful test results as before, not much). That's
because we must update bts->curr_fn to have polls expire.

Related: OS#5020
Change-Id: I683ca738ce5a133c49c36a1d94439a942d64a831
2021-03-15 19:32:36 +01:00
Pau Espin Pedrol
15c58ace75 Add new PDCH UL Controller, drop SBAllocator class
Right now we handle different types of UL allocations in different
classes like PollAllocator and SBAllocator, and they usually don't take
into account the other one in most cases. Furthermore, those objects are
usually per-BTS object, instead of per PDCH object.

This is a first step towards having a unified per-PDCH controller which
takes care of controlling what is scheduled and hence expected on the
uplink. Each PDCH has a UL Controller which keeps track of all reserved
uplink frame, be it SB, RRBP poll or USF assigned, all under the same
API.

As a first step, only the SBA part is fully implemented and used (being
it the easiest part to replace); TBF poll+usf will come in follow-up
patches later on. As a result, the SBAllocator per-BTS class dissappears
but some of its code is refactored/reused to provide more features to the
gprs_rlcmac_sba object, which is also further integrated into the new UL
Controller.

Related: OS#5020
Change-Id: I84b24beea4a1aa2c1528f41435f77bd16df2b947
2021-03-15 19:32:26 +01:00
Pau Espin Pedrol
68bfdff3f0 pdch: Log FN when decoding UL Ctrl block
Change-Id: I5a44ebf49f7489211a77607052db6d9731f38704
2021-03-12 07:40:11 +00:00
Pau Espin Pedrol
4f2c8cd96a tbf: Fix wrong variable printed in log
Change-Id: Iad99e48fcb7488daed40a5095c5dcdc02def00c5
2021-03-12 07:40:11 +00:00
Pau Espin Pedrol
df58ddf6d8 Improve logging in DATA.req and ACT.req
Change-Id: Id57d50d8bf528adfef3713c594102d31ab49c149
2021-03-12 07:40:11 +00:00
Pau Espin Pedrol
c1f31c46ac Improve DATA.ind logging
pdch object is obtained prior in the stack so it is available for
logging.

Change-Id: If51f7bdbd626a44c7b8e182a3460dad49fda6ec3
2021-03-12 07:40:11 +00:00
Pau Espin Pedrol
91cc780b40 pdch.h: Drop uneeded include bts.h
This header is not needed and creates include loop issues in follow-up
patches.

Change-Id: Ic12ab293f27b5e13d1401c6f17d4d549bf5115f9
2021-03-12 07:40:11 +00:00
Pau Espin Pedrol
1e97951582 tests: rlcmac: Fix C vs C++ linkage of extern symbol
RLCMACTest.cpp:31:30: error: conflicting declaration of ‘const log_info gprs_log_info’ with ‘C’ linkage
   31 | extern const struct log_info gprs_log_info;
gprs_debug.h:54:30: note: previous declaration with ‘C++’ linkag

Change-Id: I5922950dd0057bf7eb8578e2144f127082323fc6
2021-03-12 07:40:11 +00:00
Pau Espin Pedrol
702ebee751 Introduce init() APIs for PDCH and TRX objects
This will make it easier to keep object specific initializations in
expected place.

Change-Id: Idf1dbdf8bc0b1e16d86eeeffb1193fdf3a57d6ef
2021-03-12 07:40:11 +00:00
Pau Espin Pedrol
30617115ba Track TDMA clock with DATA.ind instead of TIME.ind
Since recently (see Depends below), BTS side submits DATA.ind with len=0
to announce nothing was received on that UL block FN. This will allow
osmo-pcu track time more accurately, and use this information to quickly
find out if a UL block was expected as requested by RRBP or USF poll and
increment counters such as N3101 (finally being able to properly
implement timers such as T3619).

Depends: osmo-bts.git Change-Id I343c7a721dab72411edbca816c8864926bc329fb
Related: OS#5020

Change-Id: Ibc495173119465e74f726ddc36e312334e6dc0fd
2021-03-12 07:40:11 +00:00
Pau Espin Pedrol
5447f3acf6 pcu_utils.h: Fix trailing whitespace
Change-Id: I113766e342a00f61f9894dee1bb89b8ae8354007
2021-03-11 17:01:25 +01:00
Pau Espin Pedrol
81c549d5be direct_phy: Support submitting DATA.ind with len=0 to upper layers
Since recently (see Depends below), BTS side submits DATA.ind with len=0
to announce nothing was received on that UL block FN. This will allow
osmo-pcu track time more accurately, and use this information to quickly
find out if a UL block was expected as requested by RRBP or USF poll and
increment counters such as N3101 (finally being able to properly
implement timers such as T3619).

This patch does the same for direct phy feature, where the osmo-pcu
process receives the DATA.ind directly from the DSP.

Depends: osmo-bts.git Change-Id I343c7a721dab72411edbca816c8864926bc329fb

Related: OS#5033
Change-Id: I9a835e16ef0e5a68c003a93d1a33233aa43464ae
2021-03-08 13:11:03 +01:00
Pau Espin Pedrol
3cba94d70e pdch: Silently ignore DATA.ind with len=0
Since recently (see Depends below), BTS side submits DATA.ind with len=0
to announce nothing was received on that UL block FN. This will allow
osmo-pcu track time more accurately, and use this information to quickly
find out if a UL block was expected as requested by RRBP or USF poll and
increment counters such as N3101 (finally being able to properly
implement timers such as T3619).

Depends: osmo-bts.git Change-Id I343c7a721dab72411edbca816c8864926bc329fb
Related: OS#5020
Change-Id: I17c28abf63b153448b533971ac5cf2e48daadea8
2021-03-08 10:39:31 +01:00
Pau Espin Pedrol
58fdc54a7f tbf: Log N310* counter increments
Change-Id: Iacd2fb894b4f2a9aade7e66aa40969fea031c3b2
2021-03-04 14:11:23 +01:00
Pau Espin Pedrol
0057bd76fd TODO-RELEASE: document requirement of master libosmocore
Recent commit started using ->is_sgsn field which is only available as
of current libosmocore master (> 1.5.1)

Fixes: 423bf8c408
Change-Id: I3d579bd253363efc3cf183a922d6affca1a499e0
2021-03-04 11:24:50 +00:00
Pau Espin Pedrol
2ad15d51fa sched: sched_select_downlink(): Clean up param list and improve logging
Passing TRX and TS is redundant since the info is contained in pdch
object.

Change-Id: I1b154d82c4a3e09f7fe7ef771de2abca0160cc7b
2021-03-03 20:52:26 +01:00
Pau Espin Pedrol
3973eb5fe8 sched: sched_select_ctrl_msg(): Clean up param list and improve logging
Passing TRX and TS is redundant since the info is contained in pdch
object.

Change-Id: Ic3ec7547cae2ddd0f9c33b82e15ec83cd941e6c8
2021-03-03 20:47:09 +01:00
Pau Espin Pedrol
11f01105a0 gprs_ms: Use standarized logging on more messages
Change-Id: If7f471f4932c2347cd857cd59f761a36d9e735d1
2021-03-03 20:37:38 +01:00
Pau Espin Pedrol
4fe090146f ms: clarify delayed MS release process related code and logging
Change-Id: Ieaea6ab07b4b2822bcf394f2d0e9298b9f3c5854
2021-03-03 20:28:51 +01:00
Alexander Couzens
423bf8c408 gprs_bssgp_pcu: rework BSSGP Reset messages to support SGSN originated BSSGP-RESET
Use primitives instead of parsing the message a second time.
Set bctx->is_sgsn to false to allow the BSSGP layer to send back a
RESET_ACK with cell information.

Related: OS#3879
Depends: Ibcbaffa94cbdc4296a8a7c372304ac11d50d9559 (libosmocore)
Change-Id: I3afaf826798e362270ffa622c24bfd124ef25cd1
2021-03-03 15:37:19 +00:00
Pau Espin Pedrol
cf6c71263f tbf_dl: fix FBI not set upon X2031 = 0
If Idle TBF timer (X2031) is set to 0, it means the TBF release is
immediately started once all queued data has been scheduled. In that
case, we must set FBI=1 (by setting cv=0) and move to FINISH state.

This used to work over the usual path where X2031 != 0, because release
start will alays happen at a later sched poll time where a dummy LLC
frame is sent and FBI set accordingly.

Change-Id: Ib20602936ae084c413f6bfe14eea33b602020be0
2021-03-02 18:25:33 +01:00
Pau Espin Pedrol
8afc6bad80 tbf_dl: Fix m_last_dl_drained_fn not set under some conditions
Old commit getting rid of LLC UI dummy and updating create_new_bsn()
function introduced a bug by not moving update of value m_last_dl_drained_fn
prior to a new break introduced.
As a result, the value is not updated in the case LLC queue becomes
drained but last few bytes are drained at exactly that moment.
Furthermore, then the IDLE tbf timer (X2031, keep_open())) returns always
true since according to it the drain never happened.

The impact of the bug is basically delaying a bit more than expected the
time the TBF stays in IDLE state with the TBF release process yet
to be started.

Related: OS#4849
Fixes: 7d0f9a0ec3
Change-Id: I7420aeffda3500bcdc990291e4a56511af433ff9
2021-03-02 18:24:46 +01:00
Pau Espin Pedrol
5b9d0bb8e5 tbf: log keep_open condition status
Change-Id: I069e84926aaa8f13b23c3ea4083b4c68dbc6cff2
2021-03-02 13:13:52 +01:00
Pau Espin Pedrol
a89008b724 tbd_dl: Don't re-initialize class field twice
Change-Id: Ia92c24032dc1f8965008ff03a3a0a94bbb93893a
2021-03-02 13:09:32 +01:00
Pau Espin Pedrol
a70bf72ce5 llc: use memset to fill llc dummy frame padding
Change-Id: Iaa55549f979ca23dad0bddd308c1144aa4b17255
2021-03-02 12:28:32 +01:00
Pau Espin Pedrol
9688dc9aca bts: Add new stats to detect TBF allocation failure reasons
This is specially useful to detect for instance if a cell is handling
too many users, ending up in TFI or USF exhaustions. This information
can be later in the future used to tune TBF allocation algorithm behavior
(either manually/statially through config file, or
automatically/dynamically in code based on some thresholds).

Related: OS#5042
Change-Id: I5402e937ff8d800684655e500ef8e5c867141dc3
2021-03-01 13:18:36 +01:00
Pau Espin Pedrol
c85e093969 Remove uneeded ms param from alloc_algorithm_func_t func
Since a while ago, the data architecture was changed so that TBF is
guaranteed to always have a MS object associated. Hence, it makes no
sense to pass the MS object as a separate param as we can take it from
tbf object and makes code less confusing.

Change-Id: Idc0c76cf6f007afa4236480cdad0d8e99dabec5f
2021-02-26 11:50:21 +01:00
Pau Espin Pedrol
36177c6b58 tbf: Improve logging when TBF being allocated or no TBF avail
Change-Id: I68491fe2c643262e35b4d4f1ecac34afcf61848f
2021-02-26 11:50:15 +01:00
Pau Espin Pedrol
95e2266832 pdch: Standarize and improve logging
Change-Id: I1686a72eb9f9014ed3365376bc43d59d60bee8a5
2021-02-26 11:36:55 +01:00
Pau Espin Pedrol
4e1c9adb67 bts: Count TBF TS allocation failure
Related: OS#2282
Change-Id: I0696bf77364bd31b96c00614a58ce66809683d1c
2021-02-25 17:49:59 +01:00
Pau Espin Pedrol
7c9a4a41bc tbf: Log timeslot allocation failure
Change-Id: I48fc1eac37eeb74649bfc0888e06afc0079a58f8
2021-02-25 17:21:10 +01:00
Pau Espin Pedrol
ed2afa3bed Support uplink multi-slot allocations
Before this patch, allocate_usf() was implemented to only allocate 1 USF
per TBF, regardless of the available ul_slot mask.

As a result, only 1 slot at max was allocated to any TBF. That's a pity
because usual multislot classes like 12 support up to 2 UL slots per TBF
(in common TS with DL).

This patch reworks allocate_usf() to allocate as many UL multislots as
possible (given mslot class, current USF availability, TFI availability,
related DL TBF slots for the same MS, etc.).

As a result, it can be seen that AllocTest results change substantially
and maximum concurrent TBF allocation drops under some conditions.
That happens due to more USFs being reserved (because each TBF has now
more UL slots reserved). Hence now USF exhaustion becomes the usual
limitation factor as per the number of concurrent TBFs than can be
handled per TRX (as opposed to TFIs previously).

Some of the biggest limitations in test appear though because really
high end multislot classes are used, which can consume high volumes of
UL slots (USFs), and which are probably not the most extended devices in
the field.

Moreover, in general the curren timeslot allocator for a given
multislot class will in general try to optimize the DL side gathering
most of the possible timeslots there. That means, for instance on ms
class 12 (4 Tx, 4Rx, 5 Sum), 4 DL slots and 1 UL slot will still be
selected. But in the case where only 3 PDCHs are available, then with
this new multi-slot UL support a TBF will reserve 3 DL slots and 2 UL
slots, while before this patch it would only taken 1 UL slot instead of
2.

This USF exhaustion situation can be improved in the future by
parametrizing (VTY command?) the maximum amount of UL slots that a TBF
can reserve, making for instance a default value of 2, meaning usual
classes can gather up 2 UL timelosts at a time while forbidding high-end
hungry classes to gather up to 8 UL timeslots.

Another approach would be to dynamically limit the amount of allowed
reservable UL timeslots based on current USF reservation load.

Related: OS#2282
Change-Id: Id97cc6e3b769511b591b1694549e0dac55227c43
2021-02-24 13:48:01 +00:00
Pau Espin Pedrol
50aa492b85 Bump version: 0.8.0.396-fe8d-dirty → 0.9.0
Change-Id: I4b9405df5f40e8f2724ba8aa8f88e2602c1e8374
2021-02-23 14:41:01 +01:00
Pau Espin Pedrol
fe8de457ac Use ALPHA value received in SI13 from PCUIF
The old VTY command is marked as deprecated and still overrides the use
in case it's used.

Related: SYS#5358
Depends: libosmocore.git Change-Id I74fb0a3afc1ac4aadbfc609b882d929401f790eb
Depends: osmo-bsc.git Change-Id I8b97ea11bad5fe05f2f634945b5703ee9abde81d
Change-Id: I46f2a955b157a409055fca7fb917dc4f75482426
2021-02-22 12:29:12 +00:00
Pau Espin Pedrol
4df2658884 find_multi_slots: Avoid multiple calls to mslot_class_get_type()
Change-Id: I9cda52befe32a7727ab479bc151d10106fb94688
2021-02-19 17:35:11 +01:00
Pau Espin Pedrol
10475f5832 find_multi_slots: Mark mslot_class properties const
This way it's clear for reader that those variables are never touched
during the function.

Change-Id: Ief038c75bc02d0e987135f29599014eab88447dd
2021-02-19 17:33:23 +01:00
Pau Espin Pedrol
dfbf3d2c09 find_multi_slots: Avoid multiple calls to mslot_class_get_rx()
Change-Id: I06c97d81636e251f81c26f3aa042c70717be083a
2021-02-19 17:32:14 +01:00
Pau Espin Pedrol
47a3b780db find_multi_slots: Avoid calling mslot_class_get_tx() on each iteration
Change-Id: I397495c158bce1c2715991371368b0d84cf69261
2021-02-19 16:56:36 +01:00
Pau Espin Pedrol
1f8e229221 Use NULL as default value for pointer type
Using zero there is confusing since it's a pointer to an integer.

Change-Id: Ief2368954c71005c529e3eea3fee5df2630e44c1
2021-02-19 16:49:24 +01:00
Pau Espin Pedrol
00f52cc3d6 tests: Replace deprecated API log_set_print_filename
Change-Id: Idcc4875592c81f17ac98c4f6098492b3d9dd33d2
2021-02-19 16:24:11 +01:00
Pau Espin Pedrol
b18d2a5fd9 tests: Explicitly drop category from log
Let's disable category here since we don't care about its formatting here.

In any case, every test relying on logging output validation should
always explicitly state the config to avoid issues in the future if
default values change.

Change-Id: I7f9c56313cfaa74ebe666f44763a83d8102f5484
Related: OS#5034
2021-02-19 16:24:11 +01:00
Alexander Couzens
151bc5b0d3 gprs_bssgp: use gprs_ns2_sns_add_bind() to allow the NSE to use the binds for IP-SNS configuration
The gprs_ns2 now requires to specify every bind which should be used by the NSE for IP-SNS

Related: SYS#5354
Depends: I9ab8092bf286e7d90e92f5702a5404425e959c84 (libosmocore)
Change-Id: I35c987224ce098f7ee9f189ce0fce9e68ad3feac
2021-02-19 12:00:47 +00:00
Pau Espin Pedrol
9345eb34d3 sched: Avoid selecting TBF to tx NACC Dl msg if no TFI is assigned
The DL NACC related message (PKT Cell Neighbor Data/Change Continue)
are filled with the TFI of the target TBF. Hence, only select the tbf
for NACC transmission if the related TBF already has a TFI assigned.

Otherwise, "OSMO_ASSERT(tbf_is_tfi_assigned(tbf));" in nacc_fsm.c when
generating messages may be hit.

Related: SYS#4909
Change-Id: I72b2dff28aacdb04909c098c94834ff79f55b31d
2021-02-18 15:50:47 +01:00
Pau Espin Pedrol
cf6b3bc08f cosmetic: fix line indentation
Change-Id: Ia8335ce5c005885e4db1864faf775c4bff509c53
2021-02-18 14:02:50 +01:00
Pau Espin Pedrol
66e8a49734 vty: Write 'neighbor resolution' config to file
Fixes: c0a250d17d
Related: SYS#4909
Change-Id: I44eef3826939e05ba88e0c5a67e1fef535582ba7
2021-02-17 20:25:03 +01:00
Alexander Couzens
94a367f224 gprs_bssgp: rename gprs_ns_config -> gprs_ns_update_config
Improve the naming of the function to match it's purpose.

Related: SYS#5354
Change-Id: Ib8e4ae734503fd6f6695d9d6767d809e1bf79d22
2021-02-16 21:32:47 +00:00
Alexander Couzens
13a12e2e3b gprs_bssgp: rework and rename ns_create_nsvc -> ns_configure_nse
Add support for multiple SNS endpoints.
Move the NSE allocation to the top in preparation of IP-SNS binds.
The future gprs_ns2 library will require to manual add every bind to the NSE for IP-SNS.
Rename the function to match more it's purpose.

Related: SYS#5354
Change-Id: I69cf48ab168a6dca4f649157bf6556d7cd27d4fb
2021-02-16 21:32:47 +00:00
Pau Espin Pedrol
9313da517d nacc_fsm: Improve log when sending RIM RAN-INFO to gather SI from remote cell
Change-Id: I6972f46f0f3223ce00672178e5610bd3a012fb19
2021-02-15 12:12:51 +01:00
Pau Espin Pedrol
a78f0d5bfe nacc_fsm: Support receiving Pkt Cell Chg Notif while in some advanced states
Related: SYS#4909
Change-Id: Iee9cb67bf2c0c6f36b788498f4ef2672e33204b7
2021-02-11 18:49:03 +01:00
Pau Espin Pedrol
8e69fc0c3a nacc_fsm: nacc_fsm: Support receiving Pkt Cell Change Notify in state WAIT_REQUEST_SI
Similar to what's done in the previous commit, but this time when we are
further forward in the resolution process.
This can be triggered for instance because we are taking too much time
to resolve and MS has timer to retransmit the Pkt cell Change Notify in
case no response was received in time.

This commit fixes osmo-pcu exiting due to ASSERT(0) since the event was
already accepted but not being handled in the state function.

Related: SYS#4909
Change-Id: I0c29e5979fec6eebe9dfb151907a4cd2f5e4a737
2021-02-11 13:23:52 +01:00
Pau Espin Pedrol
069a637be8 nacc_fsm: Support receiving Pkt Cell Change Notify in state WAIT_RESOLVE_RAC_CI
If the message is a duplicate (same tgt cell), simply ignore it.
If the message contains a different tgt cell, restart the resolution:
* Avoid re-creating the socket in that case
* Avoid potentially picking a CTRL response for an older request

Related: SYS#4909
Change-Id: Ia2ed2580bbbdd6d3464833257b0dcb8ec6f8d699
2021-02-11 13:17:16 +01:00
Pau Espin Pedrol
41ff273226 nacc_fsm: Remove NACC_EV_RX_SI from in_event_mask of some states
We don't care about those messages anymore if we already transitioned
further than NACC_ST_WAIT_REQUEST_SI. Furthermore, RIM code dispatching
the event to the FSM is only doing it in the mentioned state above.

Related: SYS#4909
Change-Id: If420b49e437ff02073669522408763e5e84fe477
2021-02-11 13:17:16 +01:00
Pau Espin Pedrol
0c10b3cdc1 nacc_fsm: Move code filling struct to helper function
Same filler will be needed in different places since that message can
arrive at different points of time (different states).
It also helps supporting newer key types in the future.

Change-Id: Idfd4db8408f767b1847b04c88047a1c4996e543e
2021-02-11 12:26:24 +01:00
Pau Espin Pedrol
abba102d7b cosmetic: fix typo in comment
Change-Id: I5a384985ef54234e915bf6334125f8d087988d1d
2021-02-08 18:35:13 +01:00
Vadim Yanitskiy
830ca26034 vty: register libosmocore's FSM introspection commands
Change-Id: Id268e44de6eb873138f38720a61cabe589a5d2c8
2021-02-05 23:22:37 +01:00
Pau Espin Pedrol
55aca83098 rlc.h: Fix struct bit fields on big endian systems
Related: OS#5003
Change-Id: I534539cdf197ce5c038752a177aff7efeefc9883
2021-02-04 12:59:40 +01:00
Pau Espin Pedrol
44768f2127 nacc: Avoid RIM procedures targeting cells under same PCU
Now that we have the required System Information in osmo-pcu to craft
the Packet Neigbour Cell Change packet for cells it controls, let's
avoid starting a RIM procedure to gather the SI info, since the SGSN
would end up routing the RIM request back at us and we'd answer back to
ourselves.

This same optimization cannot be done on the first step (CTRL Neighbor
Resolution against BSC), because the PCU cannot know if the target
ARFCN+BSIC requested by the MS is actually managed by a cell under the
PCU or it's another cell managed by another external PCU, because
ARFCN+BSIC keys can be resued among non-neighbor cells. Hence, it shall
always ask the BSC since only it holds the information about neighboring
cells.

Related: OS#4909
Change-Id: I928875b6b66dff55fc12f51b6b1ad919fef7d03b
2021-02-03 08:34:12 +00:00
Pau Espin Pedrol
952cb3d5d7 nacc: Implement Pkt Cell Change Continue retransmission
Use the fact that the MS must answer the RRBP of the Pkt Cell Change
Continue with a CTRL ACK to find out whether the message was received
successfuly or a retransmission is potentially required.

3GPP TS 44.060:
"""
When the mobile station receives the PACKET CELL CHANGE ORDER or
the PACKET CELL CHANGE CONTINUE message the mobile station shall
transmit a PACKET CONTROL ACKNOWLEDGMENT message in the specified
uplink radio block if a valid RRBP field is received as part of the
message; the mobile station may then switch to a new cell.
"""

Related: SYS#4909
Change-Id: I7cc28922e71699598da0ef6eb90136a47d3c002f
2021-02-03 08:34:04 +00:00
Philipp Maier
a58ec61514 gprs_bssgp_rim: add serving BSS NACC application
Answer an incoming RAN INFORMATION REQUEST RIM PDU with RAN INFORMATION
PDU that contains system information type 1, 3 and 13

Depends: osmo-bts I5138ab183793e7eee4dc494318d984e9f1f56932
Change-Id: Id72118120c14984d2fb1b918b41fac4868150d41
Related: SYS#5103
2021-02-02 21:57:09 +01:00
Pau Espin Pedrol
1aef113bb7 nacc: Fix typo in function name
Change-Id: I74857eacf4664508dce70eb0c6dd2acd7bfb72e4
2021-02-01 19:34:53 +01:00
Pau Espin Pedrol
57dcde4242 tbf: Constify some methods
Change-Id: I2681a98583f4fb26a274c75d0279084239f76a68
2021-02-01 18:14:37 +01:00
Pau Espin Pedrol
b71aab5646 tbf: Reuse stored result in variable in check_polling()
Change-Id: Ie6fbe3699bcb4f63f7b617243c769e60881d8aac
2021-02-01 16:37:46 +01:00
Pau Espin Pedrol
4668dc6f07 encoding: Fix comment description of S/P field
Those fields were ment to be 0 (non-valid), just the comments were
copied over from somewhere else, and they are misleading.

Change-Id: Ic95853e115f60c65f7f11187d49d6e870d08c7bb
2021-02-01 16:37:46 +01:00
Pau Espin Pedrol
79784d0249 Move src/tbf.txt to doc/
At least there it will pass less unnoticed, I just discovered this file
by chance.

Change-Id: I65a443ae498ae4c5e837e5a069fd87863f259152
2021-02-01 14:28:35 +01:00
Pau Espin Pedrol
fdbcea3532 Drop comment about an already implemented TODO
The comment target is already implemented just above it.

Change-Id: I05534bbbad24ad8ba602244b834cdbadcabcc7ec
2021-02-01 14:02:15 +01:00
Pau Espin Pedrol
05be90367a Update TS 04.60 references to new TS 44.060
Change-Id: Ib7c3a74b502b2251da2f7b9d6d711f3e32133bc3
2021-02-01 13:06:45 +01:00
Vadim Yanitskiy
3877848e22 contrib/osmo-pcu.spec.in: add missing libosmoctrl dependency
Change-Id: I37c478f3f430f72620af17f1c3329f6ee8515402
Fixes: Id35f40d05f3e081f32fddbf1fa34cb338db452ca
2021-01-30 19:14:55 +00:00
Vadim Yanitskiy
e0fb465678 contrib/osmo-pcu.spec.in: require libosmo* version 1.4.0
Keep this file in sync with the requirements in configure.ac.

Change-Id: I8fec52d0d77778775df0022da6cd53a213c057bc
2021-01-30 19:14:55 +00:00
Vadim Yanitskiy
809dc8b046 tests/rlcmac: add more test vectors for Packet Resource Request
All vectors should be valid, since they were generated by an MS.
As can be seen, osmo-pcu fails to decode one of the vectors.

Change-Id: I37a2ddd394eeffa1cae0f3e419eeee0200a57fcf
OS#4955

Change-Id: Ib5677048f5668185ffe752f97c97d5612eee4d72
2021-01-30 14:14:24 +00:00
Pau Espin Pedrol
f7e1df0da2 nacc: Improve log line failing to establish CTRL neigh conn
Change-Id: Ic92158f9fe986ff427ee2ed2cfbf95549e348746
2021-01-29 16:48:54 +01:00
Pau Espin Pedrol
ced5c1f5c8 doc: Introduce section documenting NACC support
Change-Id: I74e4828ed1b99a7f4d28ea4797c93ee85c0068cb
2021-01-29 15:52:44 +01:00
Pau Espin Pedrol
7b7fb225ce doc: Mark PCU node red in network node diagram
Change-Id: I81ab7bf144eacbfab94d3cee3d75af5a05e1c71a
2021-01-29 13:04:36 +01:00
Pau Espin Pedrol
a06ac18d22 NACC: Send only Pkt Cell Chg Continue if SI retrieve fails
If fore some reason we fail to fetch SI of target cell, we move
directly to NACC_ST_TX_CELL_CHG_CONTINUE in order to submit a Cell
Change Continue against the MS without providing any Packet Neighbor
Cell Data beforehand, as per spec that's probably the best we can do
in this scenario (TS 44.060):
"""
1)  The network responds with a PACKET CELL CHANGE CONTINUE message.
If a mobile station as response to a PACKET CELL CHANGE NOTIFICATION
message receives a PACKET CELL CHANGE CONTINUE message without receiving
any neighbour cell system information, the mobile station shall stop timer
T3208, stop timer T3210 if still running, leave CCN mode and continue cell
reselection in NC0/NC1 mode.
"""

This commit also fixes a use-after-free triggered by TTCN3 test
TC_nacc_outbound_rac_ci-resolve_fail_parse_response, where the "cmd"
pointer passed to nacc_fsm_ctrl_reply_cb() was freed during FSM
termination (its talloc ctx was under ctx->neigh_ctrl_conn) and the
libosmocore code calling that callback was later on accessing
cmd->defer.
Since due to this change the FSM is no longer syncrhonously freed, the
issue is gone.

Related: SYS#4909
Change-Id: Ie3f12a08ad611b1086d3f4ab7c3d34af43c07961
2021-01-29 12:59:30 +01:00
Pau Espin Pedrol
41a22a7ab8 NACC: Configure neighbor and SI resolution timeout values
Upon timeout, we move directly to NACC_ST_TX_CELL_CHG_CONTINUE in order
to submit a Cell Change Continue against the MS without providing any
Packet Neighbor Cell Data beforehand, as per spec that's probably the
best we can do in this scenario (TS 44.060):
"""
1)  The network responds with a PACKET CELL CHANGE CONTINUE message.
If a mobile station as response to a PACKET CELL CHANGE NOTIFICATION
message receives a PACKET CELL CHANGE CONTINUE message without receiving
any neighbour cell system information, the mobile station shall stop timer
T3208, stop timer T3210 if still running, leave CCN mode and continue cell
reselection in NC0/NC1 mode.
"""

Related: SYS#4909
Change-Id: Ia9932ab082ec095294e85dc4d532046970e17986
2021-01-29 12:59:30 +01:00
Pau Espin Pedrol
ab7159f6ec NACC: allow setting keep time for entries in neigh and si cache
Related: SYS#4909
Change-Id: Ifa336aa27dd88ff5b78dbc5a2799740f542bb369
2021-01-29 12:59:30 +01:00
Pau Espin Pedrol
c0805e6389 NACC: delay CTRL conn socket init until it's needed
This way, we don't open a socket and do the IPA handshake in the event
the request is already cached.

Related: SYS#4909
Change-Id: Ib1ea85e1196c8b9dc40c8837ab5d4a54f2a1f2d4
2021-01-29 12:59:30 +01:00
Pau Espin Pedrol
202a47886c NACC: Fix crash freeing struct if CTRL conn was refused during alloc
Older versions of osmo_ctrl_conn_alloc() may not properly initialize
write_queue.bfd.fd to -1, which means if osmo_sock_init2_ofd() failed
during nacc_fsm_alloc(), the destructor would wrongly enter the conditon
where the whole structure is set and unregister the unregistered fd.

Related: libosmocore Change-Id I98f744d2880fbb883719cdf1d3eb31f2b22a13b6
Related: SYS#4909
Change-Id: I253bd9087b1f7ab039aa1127e9dc586f5106905a
2021-01-29 12:59:30 +01:00
Pau Espin Pedrol
c0a250d17d Introduce NACC support
A new nacc_fsm is introduced per MS object, with its partner priv
structure struct nacc_fsm_ctx, which exists and is available in the MS
object only during the duration of the NACC procedure.

The NACC context is created on an MS whenever a Pkt Cell Change
Notification is received on Uplink RLCMAC, which asks for neighbor
information of a given ARFCN+BSIC.

First, the target ARFCN+BSIC needs to be translated into a CGI-PS
(RAC+CI) address. That's done by asking the BSC through the Neighbour
Resolution Service available in osmo-bsc using the CTRL interface.

Once the CGI-PS of the target cell is known, PCU starts a RIM RAN-INFO
request against the SGSN (which will route the request as needed), and
wait for a response containing the SI bits from the target cell.

After the SI are received, the scheduler is instructed to eventually
poll a TBF for the MS originating the CCN, so that we can send the SI
encapsulated into multiple Packet Neighbor Cell Data messages on the
downlink.

One all the SI bits are sent, the scheduler is instructed to send a
Packet Cell Change Continue message.

Once the message above has been sent, the FSM autodestroys itself.

Caches are also introduced in this patch which allows for re-using
recently known translations ARFCN+BSIC -> CGI-PS and CGI-PS -> SI_INFO
respectively.

Change-Id: Id35f40d05f3e081f32fddbf1fa34cb338db452ca
2021-01-29 12:59:30 +01:00
Pau Espin Pedrol
1e77ca88af tbf: Make tbf_ms() param const
Change-Id: I041c564b15d17d05ce97ea0085fcd9192a346578
2021-01-29 11:54:18 +00:00
Alexander Couzens
54211b1e1b gprs_ns2: migrate to the new vty syntax
This also changes the vty configuration. If only timeout has been
configured for ns the new configuration is compatible.

For further information see:
https://osmocom.org/projects/libosmocore/wiki/Network_service_(NS)

Depends-on: I8c3f2afecc74b78f7f914f7dce166cbcb63444eb (libosmocore)
Change-Id: I14af821a8d1fda670643c3d5f81299a3abf3c583
2021-01-28 19:55:14 +01:00
Alexander Couzens
f7ec52560f follow gprs_ns2 API enum changes
All gprs_ns2 enums have now GPRS_NS2 as prefix.

Depends-on: I548ff12f7277cbb7e1a630a3dc02b738ce89be72 (libosmocore)
Change-Id: Ifdc7956318c07d680feab33c22bc2c6f20927bf9
2021-01-28 12:55:41 +00:00
Oliver Smith
91e3567a15 configure.ac: set -std=gnu11
Change-Id: Iac2c0b14252c46aec2b00d46800fcc9f87a5a586
2021-01-28 09:28:34 +00:00
Pau Espin Pedrol
1a5439b739 sched: Avoid picking TBF with nacked dl blocks when GMSK is required
Sine we don't yet implement properly all resegmentation of blocks from
same MCS family type, when requiring a GMSK DL block (due to GPRS+EGPRS
multiplexing limitations) we need to skip retransmitions, otherwise we'd
be incorrectly picking a DL block which was already built with a
potentially higher MCS value.

The "DL_PRIO_NEW_DATA" prio serves two purposes:
* There's new data to send
* There's some nacked data to be retransmitted

The 2nd purpose has, later on, more priority over the 1st one when the tbf
is selected (see gprs_rlcmac_dl_tbf::take_next_bsn()).

Until now we were handling correctly the case where the tbf was skipped
in case the prio was to resend unacked data (DL_PRIO_SENT_DATA), but
was incorrectly selected when it'd send nacked data. Let's fix it by
specifically checking w->resend_needed() < 0.

Change-Id: I253de8e1a190a9adb56160f38892c9e43e2c0272
2021-01-26 16:26:34 +01:00
Pau Espin Pedrol
fc464935a4 Fix Dl EGPRS data blocks being generated occasionally on GPRS TBFs
Under some circumstances, it could happen that a DL TBF is created as a
GPRS TBF due to not yet having enough information of the MS, and only
after the TBF is created the PCU gains that information and upgrades the
MS mode to "EGPRS". Hence, there's the possibility to run into a
situation where a GPRS TBF is attached to a EGPRS MS.

It may also happen sometimes that despite the TBF and the MS be EGPRS,
there's need to further limit the DL MCS to use, eg. MCS1-4 (GMSK).

As a result, when asking for the current DL (M)CS to use, we must tell
the MS which kind of limitations we want to apply. The later reasoning
was already implemented when GPRS+EGPRS multiplexing was added, but the
former was not being checked. Hence, by further spreading through the
call stack the "req_kind_mode" we match both cases.

Related: OS#4973
Change-Id: Ic0276ce045660713129f0c72f1158a3321c5977f
2021-01-25 16:56:59 +01:00
Pau Espin Pedrol
201da4e5b2 ms: Properly handle EGPRS_GMSK mode in ms_max_cs_dl/ul()
Change-Id: Ied3e02a12145112fafa12282ed7aefa5b0fa6eb6
2021-01-25 16:19:37 +01:00
Pau Espin Pedrol
7bb8cd683c ms: Set proper initial MCS values setting mode EGPRS_GMSK
Before this patch, shared logic with EGPRS case would allow keeping
MCS>4.

Change-Id: I94cbf0c120fd37deb2dfd077d35b3811c7da0675
2021-01-25 16:19:37 +01:00
Pau Espin Pedrol
7963edba09 encoding: fix typos in comment
Change-Id: I0867935ad08d6e49c62e061742d3d76eeac35844
2021-01-25 16:19:37 +01:00
Pau Espin Pedrol
2238228e3c tbf: Drop always-true condition checking for MS
The TBF can sometimes be detached from an MS, for eg. when switching
from one MS object to another due to them being merged after we found
duplicate objects upon receiving new information from it, but that
change is instantaneous so it shouldn't be a problem. The only other way
where an MS can be detached from an MS is during the end of its (or the
MS) life, where it is not sending data anymore.

Hence, it is safe to drop those checks for MS not being null. Those
being trigger, it should be considered a bug.

Change-Id: If292a53a09a64664031e756bff4735b9c6ee8651
2021-01-25 16:18:19 +01:00
Pau Espin Pedrol
8f1701fe24 sched: Check if egprs is enabled in TBF rather than MS being egprs capable
It could happen as of current implementation that a TBF was created as
GPRS due to the MS being non-egprs, and later on the MS was upgraded to
EGPRS due to newly received information from the MS.
Hence, in order to infer if the data block is EGPRS or GPRS, let's
better check for the TBF info, which is the one really mandating the
kind of dl block to generate.

Change-Id: I49720fb3a69ca972cd1973de937ac8ee77615431
2021-01-25 11:31:59 +01:00
Pau Espin Pedrol
0298c0b6a0 ms: Drop always-false check
MS is always assigned to a BTS, since it's set during MS constructor.
Hence, the check removed in this patch would never hold true (and if it
did, it'd be a bug).

Change-Id: I86a71c64623f7bec031226938a54306148370ffb
2021-01-25 11:20:46 +01:00
Pau Espin Pedrol
a100a6bc56 gprs_pcu: Use libosmocore osmo_cgi_ps_cmp API
it was noticed that gprs_pcu_get_bts_by_cgi_ps() sometimes failed to
return the BTS even if the CGI-PS fields matched, probably due to memcmp
checking too padding bytes which may not be zero-initialized in one of
the two memory regions being checked. Let's be on the safe side and use
libosmocore APIs to check them.

Depends: libosmocore.git Change-Id I00e329bc5be8674b30267dec238e7656ddfc21db
Change-Id: I7c8ee2c447634e45b367bb8f84adf0140ae48591
2021-01-22 20:40:08 +01:00
Pau Espin Pedrol
3a27102e59 Initial handling support for RIM messages
This code doesn't do anything yet app-related with the received RIM
messages, but already provides the initial infrastructure to handle them
in the future, and does first checkings.

Related: SYS#5103
Change-Id: Ia0ade0e97ea781ec655439c008b6cefaf3e90dec
2021-01-22 16:37:12 +01:00
Pau Espin Pedrol
db5e339da4 Get rid of singleton gprs_bssgp_pcu_current_bctx()
Access it from existing pointers instead.

Change-Id: I77455da5221090ebea142ecd49d5dba0065bfc5c
2021-01-21 18:02:57 +01:00
Pau Espin Pedrol
2e6b60df45 bts: Store RAC+CI from info_ind
Having those values at hand will be needed later for RIM / NACC related
purposes.

Change-Id: Ia3596e9e81cd71443be2cc6f2450bb7f91d2667d
2021-01-20 15:00:38 +01:00
Pau Espin Pedrol
d1049dc8cc Allow multiple bts objects in PCU
This patch doesn't really tests whether osmo-pcu can work on a multi-bts
environment, but it prepares the data structures to be able to do so at
any later point in time.

Change-Id: I6b10913f46c19d438c4e250a436a7446694b725a
2021-01-20 12:36:21 +01:00
Pau Espin Pedrol
e91c4c72b1 Convert osmo_bts_sock.cpp to C
There's no real point in using C++ there, and using C++ makes the
compiler fail to use llist_head in multi-bts patches added later due to:
"""
'offsetof' within non-standard-layout type is conditionally-supported
"""

Change-Id: I8965b5cc5a713e64788b5b6aa183d3035341ddbb
2021-01-19 16:28:13 +01:00
Pau Espin Pedrol
906aafc9e2 Move tbf::free_all static methods to proper object files
Move each method to the object on which they operate, be it a trx or a
pdch ts.

Change-Id: Ida715cbf384431d37b2b192fbd7882957c93a4d1
2021-01-19 16:28:13 +01:00
Pau Espin Pedrol
8a35e640a3 Convert gprs_bssgp_pcu.cpp to C
There's no real use of C++ in that file, and it causes problems when
using llist_head entry macros in future patches adding initial support
for multiple BTS in PCU object, so let's move it to plain C.

Change-Id: Ic771a89fd78b5e66151a5384f0ff6a8895589466
2021-01-19 16:28:13 +01:00
Pau Espin Pedrol
4a5209d8bc Get rid of unused gsm_timer.{cpp,h}
Those files are not really being used other than for calling
get_current_fn() which is just a placeholder to call
bts_current_frame_number on the global bts object.

Change-Id: I6d50a8c15c1de5e2a308a24b313a7776f94ae54f
2021-01-19 16:28:13 +01:00
Pau Espin Pedrol
289f90048b bts: combine bts_{init,cleanup} into consturctor/destructor methods
The bts_init/cleanup functions were kept during the C and C++ structure
merge process to make the patch simpler. It's not needed anymore,
let's move all the destructor logic into one function and keep that
together.

Change-Id: I73a9457d5c92f62261561ef6afe392953576aec4
2021-01-19 16:28:13 +01:00
Pau Espin Pedrol
0ece97d718 Rename 'bts_data' leftovers to 'bts'
Before, we used tho have a BTs object split into 2 parts, a C
gprs_rlcmac_bts struct and a C++ BTS struct, and "bts_data" naming was
used to distinguish them in variable names. Nowadays the struct is
finally combined into one, so there's no point in using this "bts_data"
terminology, we use always "bts".

Change-Id: I9852bf439292d1abc70711bea65698b21bde0ee8
2021-01-19 16:28:13 +01:00
Pau Espin Pedrol
a45aafd39c Get rid of bts singletons
There's no BTS single global object anymore, get rid of those APIs. Move
users to use "pcu->bts", which will evolve to a linked list in the
future.

Change-Id: I9cf762b0d3cb9e2cc3582727e07fa82c8e183ec5
2021-01-19 16:28:13 +01:00
Pau Espin Pedrol
2182e627cd Unify BTS into a C usable structure
Previous work on BTS class started to get stuff out of the C++ struct
 into a C struct (BTS -> struct gprs_glcmac_bts) so that some parts of
it were accessible from C code. Doing so, however, ended up being messy
too, since all code needs to be switching from one object to another,
which actually refer to the same logical component.

Let's instead rejoin the structures and make sure the struct is
accessible and usable from both C and C++ code by rewriting all methods
to be C compatible and converting 3 allocated suboject as pointers.
This way BTS can internally still use those C++ objects while providing
a clean APi to both C and C++ code.

Change-Id: I7d12c896c5ded659ca9d3bff4cf3a3fc857db9dd
2021-01-19 16:28:10 +01:00
Pau Espin Pedrol
793583ea21 Fix configuration mess of initial_cs/mcs between PCUIF and VTY
Both values (optionally) set (forced) by VTY and the values received
from PCUIF were stored in the same variable, meaning that for instance
the PCUIF values wouldn't really be used if someone applied eg "no cs"
during runtime.

This commit does something similar to what was already done for the
max_(m)cs fields. We store PCUIF values in one place and VTY ones in
another place, and then trigger a bts object internal process to find
out exactly which initial CS should it be using.

Change-Id: I80a6ba401f9c0c85bdf6e0cc99a9d2008d31e1b0
2021-01-18 11:57:14 +01:00
Pau Espin Pedrol
f473ec9d7a Move llc_* fields from BTS to PCU
Change-Id: Iffb916e53fdf99164ad07cd19e4b35a64136307e
2021-01-18 11:54:57 +01:00
Pau Espin Pedrol
519d071131 Move ws_* fields from BTS to PCU
Change-Id: I997bc52f0d924c8f2a0b1d6cf23af98828ad4258
2021-01-18 11:54:57 +01:00
Pau Espin Pedrol
47f15fb6fd tests/tbf: Allocate PCU per test instead of globally
Otherwise some state may be left from one test to another.

Change-Id: I18e2fe7dd1cc5940570252a2a6a106de49d8a7dd
2021-01-18 11:54:57 +01:00
Pau Espin Pedrol
e891222920 Move fc_* fields from BTS to PCU
Change-Id: I816d49e732d0fc7a3c9aa1f0e9a83b83d25e6a32
2021-01-18 11:54:57 +01:00
Pau Espin Pedrol
113fb419ec Move ns_dialect field from BTS to PCU
Change-Id: Iffb22b776b91f93d6d2a7ccfa47deeecc22c33f0
2021-01-18 11:54:57 +01:00
Pau Espin Pedrol
54b159aab9 Move (m)cs_lqual_ranges fields from BTS to PCU
Change-Id: I39e2fc7e229851610d797c594d84902af6079411
2021-01-18 11:54:57 +01:00
Pau Espin Pedrol
ad79b857cd Move cs_downgrade_threshold field from BTS to PCU
Change-Id: I3e1c65eb3cccff565d5d84588bdce93a47909a0f
2021-01-18 11:54:57 +01:00
Pau Espin Pedrol
e8dcf64881 Move cs_adj* fields from BTS to PCU
Change-Id: I2b00a83279dccd4feeeeb95e34878c4405e7972c
2021-01-18 11:54:57 +01:00
Pau Espin Pedrol
97296b299c Move dl_arq_type field from BTS to PCU
Change-Id: I0b82ab59edd58d60e5581c707dc49f58de0ba203
2021-01-18 11:54:53 +01:00
Pau Espin Pedrol
05f9f59a67 Move dl_tbf_preemptive_retransmission field from BTS to PCU
Change-Id: I3ab32fcafe83f3ecb116a5b8a05f58f3fddc5451
2021-01-18 11:38:38 +01:00
Pau Espin Pedrol
a281495008 Move alpha,gamma fields from BTS to PCU
Change-Id: I2fdd9c8a7393157183fff64084bb10e2a3b1dc63
2021-01-18 11:38:38 +01:00
Pau Espin Pedrol
03de898d19 Move force_two_phase field from BTS to PCU
Change-Id: I68a6e032f725cde87992b99f039c5280e912faf7
2021-01-18 10:37:05 +00:00
Pau Espin Pedrol
924aaad4bc Move T_defs_pcu from BTS to PCU object
Change-Id: I0cac5c12dff2e90b52d00383a00b4b94a9603a0a
2021-01-18 10:37:05 +00:00
Pau Espin Pedrol
ac3fd12026 Split PCU global PCU object from BTS object
Currently the BTS object (and gprs_rlcmac_bts struct) are used to hold
both PCU global fields and BTS specific fields, all mangled together.
The BTS is even accessed in lots of places by means of a singleton.

This patch introduces a new struct gprs_pcu object aimed at holding all
global state, and several fields are already moved from BTS to it. The
new object can be accessed as global variable "the_pcu", reusing and
including an already exisitng "the_pcu" global variable only used for
bssgp related purposes so far.

This is only a first step towards having a complete split global pcu and
BTS, some fields are still kept in BTS and will be moved over follow-up
smaller patches in the future (since this patch is already quite big).
So far, the code still only supports one BTS, which can be accessed
using the_pcu->bts. In the future that field will be replaced with a
list, and the BTS singletons will be removed.

The cur_fn output changes in TbfTest are actually a side effect fix,
since the singleton main_bts() now points internally to the_pcu->bts,
hence the same we allocate and assign in the test. Beforehand, "the_bts"
was allocated in the stack while main_bts() still returned an unrelated
singleton BTS object instance.

Related: OS#4935
Change-Id: I88e3c6471b80245ce3798223f1a61190f14aa840
2021-01-18 10:37:05 +00:00
Alexander Couzens
695ce77167 gprs_rlc_ts_alloc: ensure no rolling slots are allocated
When allocating multiple slots for a UE the following example
is not allowed 'UU----UU' for a UE class 12.
The time slot number can not roll over 7 and move to 0.
44.060 or 45.002 only specifies contigous however it was unclear
it this is an allowed pattern.

Only the example 45.002 B.3 in release 12 cleared this up.
It gives an example for a multi slot class 5 UE which has 7 possible
configuration this means the rolled over is not allowed.

Multislot class type 2 UE doesn't have this limitation.
Further if a UE supports 8 time slots this is not a limitation because
the window size (45.002 B.1) can include all time slots.

Releated: SYS#5073
Change-Id: I16019bdbe741b37b83b62749b840a3b7f4ddc6c7
2021-01-15 15:50:41 +00:00
Pau Espin Pedrol
54faf023be Workaround ASan false positive runtime errors under some platforms
Under some platforms (RPI4, ARM) container older ASan, it will log false
positive log errors which will make unit test fail because then output
changes:
"""
pcu_l1_if.cpp:847:2: runtime error: member access within misaligned address 0xb3f0b78c for type 'struct GprsMs', which requires 8 byte alignment
"""

The pointer is indeed misaligned, but it's not actually a bug, because
the pointer is never derreferenced. That happens during
llist_for_each_entry operation where it does cast the pointer but it
only checks if the list has actually reached the end.

To workaround the issue, simply defer casting it by using llist_for_each
instead, where the pointer is assigned only in the case it really points
to a GprsMS struct.

Change-Id: I149fb42706501eb33f9c6fe48f76a03ddee5954a
2021-01-14 12:12:45 +01:00
Oliver Smith
f842e06c88 contrib/jenkins: don't build osmo-gsm-manuals
Related: OS#4912
Change-Id: If45bb7d4958b200ca6b5d1c5b8a52eba06944909
2021-01-13 17:30:56 +00:00
Vadim Yanitskiy
eb70a4098f bts: fix uninitialized memaccess in BTS::send_gsmtap()
Change-Id: I7c5105c9e8a2c680dc8b24cc5e3bda6f7405a3ee
Fixes: CID#216511
2021-01-13 13:58:16 +01:00
Vadim Yanitskiy
55022ea1b1 bts: fix uninitialized memaccess in BTS::send_gsmtap_rach()
Unfortunately, RACH.ind on the PCU interface contains no Uplink
measurements: neiter RSSI nor C/I.  In order to avoid sending
garbage, let's zero-initialize 'struct pcu_l1_meas'.

Change-Id: I8c3210c428da17d23d798f3ef9df941ded6e162a
Fixes: CID#216512
2021-01-13 13:57:13 +01:00
Pau Espin Pedrol
f5a251bcee gprs_ms: Mark ms_ctrg_desc static
Change-Id: I3b1f0d0ee932a97414375a679962356c9178c2eb
2021-01-12 20:57:56 +01:00
Pau Espin Pedrol
1e00947c29 AllocTest: Avoid queuing tons of to-be-freed ms
When both TBFs (Dl, Ul), are detached, ms_detach_tbf() will call
ms_start_timer() which will hold a reference of the MS (ms_ref()) and
wait for X seconds (VTY config, T=-2030, 60 seconds by default) before
unrefing the MS, which will trigger ms_update_status() finally (ref==0)
and will in turn call cb.ms_idle(), which will tell the ms_storage to
free the MS.

This mechanism is used to keep MS objects around for a certain time so
that when new TBFs are established, we have cached interesting
information about the MS, ready to use.

However, in AllocTest, tons of MS are allocated in a loop calling a
function (such as test_alloc_b_ul_dl()). In that function, a BTS is
allocated in the stack and at the end of the function BTS::cleanup() is
called due to implicit destructor, which ends up calling
ms_storage::cleanup() which removes all MS from its list and frees them
*if they are not idle*. The problem here, is that due to T=-2030, an
extra reference is hold and hence the ms is not considered idle
(ms_is_idle() checks ms->ref==0). As a result, the MS is never freed,
because we don't use libosmocore mainloop here (and in any case, it
would take 60 seconds to free it).

By setting the timeout of T=-2030 to 0, ms_start_timer will avoid using
the timer and will also avoid holding the extra reference, hence
allowing ms_storage to free the object during cleanup().

This fix really helps in improving performance for AllocTest specially
after MS object contains a rate_ctr. As tons of MS objects were left
alive, they stood in the rate_ctr single per-process queue, making the
test last crazy amount of time and spending 50% of the time or more
iterating the list full of MS related rate counters.

Change-Id: I6b6ebe8903e4fe76da5e09b02b6ef28542007b6c
2021-01-12 18:01:53 +00:00
Pau Espin Pedrol
bed48cc14f ms: Replace struct var with rate_ctr
Let's use usual osmocom rate_ctr instead of having one variable +
setter/getter functions, so we can easily add new counters and also
because it makes code more clear (no need to look at what the "update"
function is doing).

Using rate counter also provides info about how recently the MS has been
interacting with the network.

Related: OS#4907
Change-Id: I744507fde4291955c1dbbb9739b18a12a80145b1
2021-01-12 18:01:53 +00:00
Pau Espin Pedrol
c2d3625bf6 tbf: remove 'software error' logs from tbf_free
It is expected that the tbf object is freed at any moment in time, for
instance if osmo-pcu drops PCUIF connection with osmo-bts. I couldn't
find any reason why it would e dangerous to free the tbf, so let's
remove this message.

related: OS#4779
Change-Id: I4ab5ccaa5bf6257b18d8fd5ba06baab083821817
2021-01-11 19:17:05 +01:00
Eric
1188167a92 tbf: add virtual destructor
This ensures spec compliance, because currently the base class
destructor would be called through a base class pointer to derived
class instead of the most derived one, which ist unexpected and actually
undefined behavior in c++11 and beyond.

Change-Id: Ic4abde1658a983bb0ccf9a526177dce50ff6dc23
2021-01-11 17:55:07 +00:00
Vadim Yanitskiy
480c8acc8b gprs_rlcmac_sched: fix incorrect SBA frame number assignment
There is a big difference between:

  if ((a = foo() != 0xffffffff)) { ... }

and

  if ((a = foo()) != 0xffffffff) { ... }

In the first case, 'a' is the result of '!=' operation, i.e. either
0 (false) or 1 (true).  In the second case, 'a' will hold the value
returned by foo(), and this is exactly what must have been used in
gprs_rlcmac_rcv_rts_block().

The bug was there since SBA allocation feature was added in 2012.

Change-Id: Ifd607ae8a33382e48f9d9e50a28a4bdf4eaf73a2
Fixes: 07e97cf8a5
Related: CID#215835
2021-01-06 12:34:07 +00:00
Pau Espin Pedrol
d3123ea0f5 doc: Improve CS/MCS GPRS/EGPRS considerations in User Manual
Related: OS#4544
Related: SYS#4869
Change-Id: I7b205f5cab5862058a408f628925beb9f0f60a92
2021-01-05 15:48:58 +00:00
Pau Espin Pedrol
a5b9fb5304 .gitignore: ignore files ending with ~
I'm lately getting this kind of files in git after building:
config.guess~
config.sub~
configure~
install-sh~

Let's ignore them.

Change-Id: I976e3a33f638f4cd19650b9c799e61713d73bf8a
2021-01-05 11:34:45 +01:00
Pau Espin Pedrol
8b4b19a012 tbf: Fix wrong verb used in log message
Change-Id: Id9f8df9a5c0e0f88a811c5d7f06821cb4f30ab93
2021-01-05 10:34:25 +00:00
Pau Espin Pedrol
da971ee502 Convert GprsMS and helpers classes to C
As we integrate osmo-pcu more and more with libosmocore features, it
becomes really hard to use them since libosmocore relies heavily on C
specific compilation features, which are not available in old C++
compilers (such as designated initializers for complex types in FSMs).

GprsMs is right now a quite simple object since initial design of
osmo-pcu made it optional and most of the logic was placed and stored
duplicated in TBF objects. However, that's changing as we introduce more
features, with the GprsMS class getting more weight. Hence, let's move
it now to be a C struct in order to be able to easily use libosmocore
features there, such as FSMs.

Some helper classes which GprsMs uses are also mostly move to C since
they are mostly structs with methods, so there's no point in having
duplicated APIs for C++ and C for such simple cases.

For some more complex classes, like (ul_,dl_)tbf, C API bindings are
added where needed so that GprsMs can use functionalitites from that
class. Most of those APIs can be kept afterwards and drop the C++ ones
since they provide no benefit in general.

Change-Id: I0b50e3367aaad9dcada76da97b438e452c8b230c
2021-01-05 10:34:25 +00:00
Alexander Couzens
86fad1ec4e gprs_rlcmac_sched: don't leak a sched_dummy()
Change-Id: Iea0fc51809c78514c85e45e7f499a531c4ea1bcf
2020-12-30 23:30:16 +01:00
Pau Espin Pedrol
d6b913fc39 sched: Convert code handling next_list array to be size independant
Change-Id: Id209fe66f85501437a79f7ca0c8e3cf816177611
2020-12-17 15:27:41 +00:00
Pau Espin Pedrol
b77a2c992e gprs_rlcmac_sched: Use helper structure to store several tbf pointer params
The resulting code is cleaner since it becomes clear the relation
between all those pointers, which are set in one function and used in
another one, passed through the caller of the former two.

Moreover, if more tbf candidates are to be added for other type of
actions, having them in a struct is much easier since only one pointer
is passed.

Change-Id: I55482aa5af7be5a176a7b4879a672ad37e618020
2020-12-17 15:27:41 +00:00
Alexander Couzens
3db4789be8 gprs_ns2: set default dialect to ipaccess
The default pcu dialect is ipaccess. Keep it that way.

Fixes ttcn3 pcu testcases.

Change-Id: I426f507fb8863abd8995bc615dc6a6fa7ae69217
2020-12-16 21:39:07 +01:00
Alexander Couzens
1e6c350a9f ns2: follow ns2 sns api changes
Related: OS#4472, OS#4890
Depends: libosmocore.git I71cdbfb53e361e6112fed5e2712236d797ef3ab2
Change-Id: Id530e5497c17885817493f8a8a9436bc187c88aa
2020-12-16 12:51:08 +01:00
Alexander Couzens
b644fd1f09 ns2: follow changes to add a unique name to all binds
Related: OS#4472, OS#4890
Depends: libosmocore.git I8f1d66b7b3b12da12db8b5e6bd08c1beff085b3e
Change-Id: I3638c7204db576116ba2e20dae27539ce6143bd7
2020-12-16 12:51:04 +01:00
Alexander Couzens
5012e07685 ns2: follow ns2 dialect changes
NS2 introduce a ns dialect to differentiate
between the 4 possible dialects.

Related: OS#4472, OS#4890
Depends: libosmocore.git Ia118bb6f994845d84db09de7a94856f5ca573404
Change-Id: I16dc82c38eb75c2b9d1197640a955fec7df84efc
2020-12-16 12:50:50 +01:00
Harald Welte
398f60e11c migrate to DLBSSGP as log sub-system for BSSGP
Change-Id: I94864c5fa2688fc91b8b6077a14ad098851afdc7
Depends: libosmocore.git Change-Id I506190aae9217c0956e4b5764d1a0c0772268e93
2020-12-12 20:05:51 +01:00
Harald Welte
b645365546 manuals/gb/ns.adoc: Update documentation regarding SNS capability
The SNS capability was added to our Gb stack quite some time ago,
but it seems the manual was not updated.  Let's update the document
accordingly.

The individual sub-sections about the SNS-* messages are empty as
I think lynxis is currently most qualified to fill them in, I'll
ask him to submit a follow-up patch.

Related: SYS#5212
Change-Id: I21e891fc7662b582681cd9bd7568e4b65d357751
2020-12-12 20:05:43 +01:00
Pau Espin Pedrol
95e4a2b3ae rlcmac: Fix typo in MT_PACKET_CELL_CHANGE_NOTIFICATION value_string
Change-Id: I1b327bf955069ab10b2c6aa643ecf975fa23c1b5
2020-12-11 19:57:29 +00:00
Harald Welte
ea2147af90 gb manual: NS is implemented in libosmogb, not libosmocore
Change-Id: Ie833370d9839017cbc508912992fb084ee879fe3
2020-12-10 13:50:11 +00:00
Harald Welte
8938431fdc gb manual: 08.16 -> 48.016 / 08.18 -> 48.018
Change-Id: I10505d9aebe65e1f0952df75b13951e2b40d6997
2020-12-10 13:50:07 +00:00
Pau Espin Pedrol
7d0f9a0ec3 Dl TBF: Get rid of LLC UI dummy blocks following other data
According to:
* 3GPP TS 44.060 version 16.0.0 "9.3.1a Delayed release of downlink Temporary Block Flow"
* 3GPP TS 44.064 version 16.0.0 "6.4.2.2 Unconfirmed Information (UI) Dummy command"

LLC UI Dummy frames are to be used when there no more data to send, only
in order to delay the release of a TBF. Hence, while not incorrect per
se, makes no sense to send those LLC UI Dummy frames inserted into
rlcmac blocks which already contain other LLC frames, since the MS in
that case is already being kept active.
It only makes sense to send those LLC UI Dummy frames when we have
nothing else to send, that is, alone inside a RLCMAC block without other
LLC frames.

Related: OS#4849
Change-Id: Ifae1a7b2b3dfad8df19585063088ba0df2749c8f
2020-12-01 15:57:37 +01:00
Alexander Couzens
30d9a5989e NS2: rework handling of unknown primitive
Use prim_str() method to get the human readable string.
Define unhandled events with a nop in the switch()

Depends-on: Ibf610fbd929dddc4a4e235152447caff522d4eb2 (libosmocore)
Change-Id: I50188afb83ac142e22d4bda4e8050eb4de962e70
2020-12-01 12:07:18 +00:00
Pau Espin Pedrol
022f9e56e5 Implement downgrade to DL MCS1-4 when USF for GPRS_only MS
In previous status, if USF for GPRS-only MS was selected, then EGPRS
TBFs were skipped and either a GPRS TBF was selected or a Dummy Block
was sent. That means the behavior was unfair towards EGPRS TBFs, because
sometimes they were skipped in favor of GPRS ones.
This patch imporves the situation in the above mentioned USF scenario, by
first, under specific conditions, allowing selection of an EGPRS TBF and
then forcing it to transmit in EGPRS-GMSK (MCS1-4) so that the
USF-targeted MS can still decode the USF, while at the same time
providing more fairness by allowing the EGPRS TBF to transmit data.

The specific conditions mentioned above are, mainly, related to the fact
that once a DL data block has been sent, and hence a BSN was assigned to
it, it cannot be retransmitted later using another MCS, since lower
MCS1-4 wouldn't be able to contain higher MCS RLC payload.

The set of conditions could be expanded in the future by also selecting
the EGPRS TBF if retransmition is required and the block to be
retransmitted was originally transmitted as MCS1-4.

Related: OS#4544
Change-Id: I9af23e175435fe9ae7b0e4119ad52fcd4707b9ca
2020-12-01 11:56:01 +00:00
Pau Espin Pedrol
7fd9a29eba tbf: Log previous TS when changing Control TS
Change-Id: I5f37f3512dde60e4eb1ccebbb2d96de24604d241
2020-12-01 11:53:39 +00:00
Pau Espin Pedrol
58cd1d2f8a main: generate coredump and exit upon SIGABRT received
Previous code relied on abort() switching sigaction to SIG_FDL +
retriggering SIGABRT in case the signal handler returns, which would
then generate the coredump + terminate the process.
However, if a SIGABRT is received from somewhere else (kill -SIGABRT),
then the process would print the talloc report and continue running,
which is not desired.

Change-Id: I8f02925eedd8855bb58555df20b443f79d5c6da8
Fixes: OS#4865
2020-11-26 13:40:57 +01:00
Alexander Couzens
4e8f2c310f gprs_bssgp_pcu: follow ns2 library changes
Depends-on: I18dfd40a2429cd61b7c4a3dad5f226c64296f7d8 (libosmocore)
Change-Id: I056fe624160f2fe01d405690eba5cc0032780837
2020-11-25 20:53:37 +00:00
Pau Espin Pedrol
74aa3523f3 csn1: Log CSN_VARIABLE_ARRAY values as hex
Change-Id: If84c4b3cb870068a85405116f1d505ffcff9c26e
2020-11-24 11:24:11 +01:00
Pau Espin Pedrol
259a694ba7 csn1: Fix readIndex pointer change in CSN_VARIABLE_ARRAY
There's actually 3 errors:
* Its value should be updated, not the pointer itself
* Value should be increased, not decreased
* bitvec_read_field() API is already advancing it, no need to do it

Fixes: OS#4838
Change-Id: I009abc373794e148091e637ffee80c6461960945
2020-11-24 11:22:06 +01:00
Pau Espin Pedrol
9c4f9ffec1 pdch: Log hexdump of decde failure for dl rlcmac block
Change-Id: I591212a43bf92984348d1992df8c9b4fdddeba3b
2020-11-23 16:36:42 +01:00
Pau Espin Pedrol
7d3ee9ed8d pdch: packet_paging_request: Put back non-fitting paging entry where where it was
dequeue_paging() dequeues the first paging (at the start of the list).
If a paging request is dequeued but later it cannot be added to the
message being sent, it has to be re-added to the list for later
processing on next message. However, existing code was enqueueing it at
the end, which meant that paging request was delayed for no reason.

Change-Id: Iad8e7045267d56e32f42db0fbb8448b1b1185f05
2020-11-23 16:04:11 +01:00
Pau Espin Pedrol
228628860f Support multiplexing of GPRS and EGPRS TBFs in one PDCH
There are some restrictions to have both GPRS-only and EGPRS MS attached
to the same MS:
* Any MS needs to be able to successfully decode a DL block at least
  every 18 DL blocks (360 ms). That means a Dl block with CS1-4 must be
  sent at least once during that time.
* Any MS needs to be able to decode USF targeting it. GPRS-only MS can
  successfully decode USF from DL blocks using GMSK: CS1-4 and MCS1-4.

In this patch, if USF of a GPRS-only MS is selected, then all DL EGPRS
TBFs are discarded from data block selection. However, this logic can be
further improved later by still allowing selection of DL EGPRS TBFs and
then forcing construction of a DL EGPRS data block using MCS1-4.

Sources:
* 3GPP TS 03.64 version 8.12.0 "6.6.4.1.1.2 Multiplexing of GPRS and EGPRS MSs"
* 3GPP TS 05.08 version 8.23.0 "10.2.2 BTS output power"

Related: OS#4544
Change-Id: Ib4991c864eda6864533363443f76ae5d999532ae
2020-11-17 16:42:15 +01:00
Pau Espin Pedrol
daa6c1c645 sched: Use correct GMSTAP category for EGPRS DL data blocks
Change-Id: I3bd8b6a2328e13543b7d4c4a945e86f14ff35bda
2020-11-17 15:05:10 +01:00
Pau Espin Pedrol
4c5a7d315c sched: Fix sending GSMTAP DL data blocks with unset USF
Change-Id: Ib5ceb83a85b517ee9bf2c59cf27fe818373abe60
2020-11-17 15:05:10 +01:00
Pau Espin Pedrol
49efd9b606 encoding: Fix duplicate word in log str
Change-Id: Ifb0b359c43e79bab5599625fae20750ae5a6ae54
2020-11-17 09:52:29 +00:00
Pau Espin Pedrol
e309d80dd4 Fix ctr reports: Remove ctr description from already removed counter
Recent commit removed the counter enum but forgot to remove the
description, so the descriptions were all shifted by 1 counter.

Fixes: 133fe4a852
Change-Id: I82ee9f36d60a1fd129ae3a864508fcd886e4bfef
2020-11-13 16:19:25 +01:00
Harald Welte
2bbdf2e3d7 Use osmo_fd_*_{disable,enable}
Change-Id: I16563a1033ad12a32104bfee974045ac4302bc74
Depends: libosmocore.git Idb89ba7bc7c129a6304a76900d17f47daf54d17d
2020-11-11 20:15:37 +00:00
Vadim Yanitskiy
cb98894eb1 TLLI 0x00000000 is a valid TLLI, use 0xffffffff instead
The assumption that TLLI 0x00000000 is invalid and can be used
as the initializer is wrong.  Similar to TMSI, 0x00000000 is a
perfectly valid value, while 0xffffffff is reserved - use it.

According to 3GPP TS 23.003, section 2.4, a TMSI/P-TMSI with
all 32 bits equal to 1 is special and shall not be allocated by
the network.  The reason is that it must be stored on the SIM,
where 'ff'O represents the erased state.  According to section
2.6 of the same document, a local/foreign TLLI is derived from
P-TMSI, so the same rule applies to TLLI.

I manually checked and corrected all occurances of 'tlli' in the
code.  The test expectations have been adjusted with this command:

  $ find tests/ -name "*.err" | xargs sed -i "s/0x00000000/0xffffffff/g"

so there should be no behavior change.  The only exception is
the 'TypesTest', where TLLI 0xffffffff is being encoded and
expected in the hexdump, so I regenerated the test output.

Change-Id: Ie89fab75ecc1d8b5e238d3ff214ea7ac830b68b5
Related: OS#4844
2020-11-10 17:06:39 +00:00
Pau Espin Pedrol
305763dc6f tbf_ul: Log mismatching TLLI on log message
Change-Id: Ia2ac7062c1f3308a1485da6d769cb8a869fa8100
2020-11-06 20:03:24 +01:00
Pau Espin Pedrol
9897b26e3e gprs_ms: Avoid enabling EGPRS if no MCS are supported
This patch avoids enabling EGPRS on MS objects if BTS/VTY assigned no
MCS supported/available for use.
As a result, if NO MCS is enabled/supported EGPRS won't be used despite
the MS announcing through EGPRS MS class that it supports EGPRS.

Change-Id: Ib19e9e006d851c2147de15f4aec36ab65250bdd3
2020-11-05 15:48:11 +01:00
Pau Espin Pedrol
f1159c559b Fix mcs_is_valid(): UNKNOWN value is not a valid (M)CS
Also add a few more asserts to make sure a valid CS/MCS is passed in
some placed where we expect (M)CS to be set.

Change-Id: I0a973e10cd9477f72d8bd47a06048414b33ae96a
2020-11-05 15:48:04 +01:00
Pau Espin Pedrol
b47b137c66 Fix configuration of initial_(m)cs
Properly clip initial_(m)cs values to be lower-equal than maximum
configured.

Regarding initial_mcs, use values provided by BTS, which were not used
before.

Change-Id: Ifc6bc7c2734d1ae404adc2497afec5366e4f9e50
2020-11-04 21:39:43 +01:00
Pau Espin Pedrol
87eec1fd74 Get rid of bts->egprs_enabled
BTS simply notifies the PCU about the supported MCS, and PCU is
responsible for providing correct data formatting supported for the BTS
and the target MS.

Related: OS#4544
Change-Id: Ifcf23771bd23afc64ca6fea38948f98f2d134ecb
2020-11-04 21:39:43 +01:00
Pau Espin Pedrol
133fe4a852 tbf_ul: Allow non-egprs phones if EGPRS is enabled
We'll be able to still serve GPRS-only phones if EGPRS is enabled.

Related: OS#4544
Change-Id: I2e01b9d0de7506e0c0960342d73dba29187fe61f
2020-11-04 21:39:43 +01:00
Pau Espin Pedrol
569f0d27c7 tbf_dl: Don't fake EGPRS MS class when no related info is available
For instance if PCU received DL data to be sent to an MS from an SGSN,
and the MS is not currently cached in the PCU (because there's no TBF
active for it), it will page it and transmit the DL data to it.
The SGSN is capable of sending (EGPRS) MS Class information in that same
DL data message, so it's the one responsible for providing that
information if not available at the PCU.
In the PCU if we don't have information about that MS and SGSN didn't
provide us information about it, we cannot assume the MS is going to be
EGPRS capable and even less expecting a specific EGPRS MS class.
So let's drop this code.

Related: OS#4544
Change-Id: Icce66cadb51af25ae0c3b3719940eccb548fe33b
2020-11-04 21:39:42 +01:00
Pau Espin Pedrol
4808d1ceb8 pdch: Process received CS1-4 data blocks regardless of egprs_enabled
EGPRS "enabled" or "not enabled" is a bit of confusing idea, since there
are different levels of EGPRS support. For instance we may have been
instructed by config to not transmit using MCS5-9 (8PSK), or not use
MCS1-9 at all (GMSK+8PSK). However, we cannot control what is sent to us
or what we receive on lower layers, so if the BTS PHY/receiver was able
to decode+receive, let's try to process it anyway...

Related: OS#4544
Change-Id: Ie70ec8e4a2d688762d7d320d6ad58d5a0cc52ea1
2020-11-04 21:39:42 +01:00
Pau Espin Pedrol
270c9ea5d9 Enable egprs support through PCUIF from BTS/BSC
This VTY command was added due to EGPRS being introduced later as an
experimental feature. It's no longer needed and causes more problems
than goodness (since people sometimes forgets to enable it).

Let's rather simply enable EGPRS support based on what BTS/BSC requests
over PCUIF.

Related: OS#4544
Change-Id: Ic80970a136361584da9c912252a07e7c3c9d85d0
2020-11-04 21:39:42 +01:00
Pau Espin Pedrol
343ec9b9fd Take into account BTS supported (M)CS values when retrieving the maximum
Change-Id: I2d3a8bbae2f9887400ce56d2f8303ea30abaecfa
2020-11-04 21:39:42 +01:00
Pau Espin Pedrol
8072e354cc Move EGPRS MS mode set to gprs_ms.cpp
Some tests were wrong (TypesTest) and required modification, since they
were setting a EGPRS MS but then expecting a GPRS assignment.

Change-Id: I9d3ee21c765054a36bd22352e48bde5ffca9225a
2020-11-04 21:39:42 +01:00
Pau Espin Pedrol
d87722d03c pcuif: Improve BTS-supported CS/MCS handling
Take into account the MCS values supported by the BTS. In osmo-bts,
in general all MCS are enabled if "mode egprs" is selected in BSC,
and none otherwise.

Change-Id: Ie8f0215ba17da1e545e98bec9325c02f1e8efaea
2020-11-04 21:39:42 +01:00
Pau Espin Pedrol
46fd7a0316 Move BTS initial values inside bts.cpp
This way everytime any program or test initiates a BTS object, the
bts_data structure has the same values.

Change-Id: Iffd6eecb1f08bda0091f45e2ef7c9c63b42e10b3
2020-11-04 19:32:12 +00:00
Alexander Couzens
a2848546d2 NS2: follow the change of ownership
When receiving a primitive from the NS2 layer
the PCU must free the msg buffer if given.

Change-Id: I180433735bfbb3375c41318d7a7709d5845199ba
2020-11-03 22:37:49 +00:00
Vadim Yanitskiy
2c1fed20ab BSSGP: constify argument 'tp' of gprs_bssgp_pcu_rx_paging_{cs,ps}
Change-Id: I24e48964a0ff86c2ca962ab3928d07b1c9200390
2020-11-02 09:10:00 +00:00
Vadim Yanitskiy
e9bddabc01 BSSGP: use tlvp_val8() in gprs_bssgp_pcu_rx_paging_cs()
Change-Id: Ic1e37cb9938323c9b9f0466be5cf7251a6db1008
2020-11-02 09:10:00 +00:00
Pau Espin Pedrol
b6450840dc gprs_ms: Use proper function to get CS
Change-Id: I161e733991ac4fa7bd25a0f12b20e5701c76fc52
2020-10-30 19:44:43 +01:00
Pau Espin Pedrol
b1bbcae71c cosmetic: tests: pcu_emu: fix trailing whitespace
Change-Id: I889498c75a78fd8aa406cff5600e4773785782de
2020-10-30 17:10:55 +01:00
Pau Espin Pedrol
758ace867b tbf_dl: Update (egprs_)ms_class for already known MS
If SGSN provides us with MS class information upon DL data, let's use it
and set it in an already existing MS object if not yet known.

Also remove all unneeded code passing ms_class to append_data() which
would simply try to (again) set the ms_class.

Change-Id: I4979c9344bffd3ba7657bbab94981d233eab801f
2020-10-29 12:38:17 +01:00
Pau Espin Pedrol
16705a4db1 cosmetic: Fix ws between if keyword and parenthesis
Change-Id: I5932f21c58e76552f7187a175b8e281c5846536c
2020-10-29 11:34:17 +00:00
Pau Espin Pedrol
4d1663594b bts: define egprs_enabled as bool
Change-Id: I66a8254ee392ad75226c58b7df5746f409463f0f
2020-10-29 11:34:17 +00:00
Pau Espin Pedrol
983bb7eb31 alloc_algo_b: Select TRX with least assigned TFIs during TBF alloc
Before this patch, it would always allocate all TBFs on the first TRX
until all TFIs were filled, then second, and so on. But it would
actually fail around 8th MS requesting an UL TBF because despite a TFI
was successfuly assigned, because all USFs were already exhausted for
that PDCH.

Related: OS#1775
Change-Id: Iccfc8acfbfdc258ed16cc5af01f12b376fe73b72
2020-10-29 11:34:17 +00:00
Pau Espin Pedrol
528820dbe1 tbf: Clean up gprs_rlcmac_dl_tbf::handle()
Avoid passing tons of params to internal helper function
tbf_nel_dl_assignment() in order to either fetch again the ms object or
create a new one. Let's instead create the ms function earlier if needed
and fill it with all the discovered information prior to calling the
helper function. This provides cleaner code and also better log output.

This way we also avoid trying to fill the MS twice and unneeded
getter+setter for TA.

tbf::imsi(): There' always an ms, so simply forward call to
ms()->imsi().

We can also get rid of assign_imsi, since the modified code is the only
place where it's used and there's already some code in place there to
update the MS. We instead merge it with set_imsi and keep the
duplication code to catch possible bugs from callers.

Move merge_and_clear_ms from tbf class to GprsMS, where it really
belongs.

Change-Id: Id18098bac3cff26fc4a8d2f419e21641a1f4c83b
2020-10-29 11:34:17 +00:00
Alexander Couzens
87c6dd3c26 pcu_l1_if: fix misaligned assignment of remote address
Found-by: asan
Change-Id: I9c87d3fc1b6f03d79b53f1da3a146630061c3459
2020-10-27 15:29:05 +00:00
Pau Espin Pedrol
38de84cdc4 tests: ms: Pass correct pointer in constructor instead of NULL
The BTS field will be used in code paths after next patch changes,
otherwise the test fails accessing the NULL pointer.

Change-Id: I5098292bdafa9f4f70fef1a053b80a33deca722c
2020-10-26 13:46:33 +01:00
Pau Espin Pedrol
9f6d1a85e1 tbf: Drop unused function disable_egprs()
Change-Id: I8e3e1d9e70d46c7ca65ce67c408830f8bd20ce3b
2020-10-25 23:29:20 +01:00
Pau Espin Pedrol
b385969039 Move dl_tbf allocation code to correct file
Change-Id: I50d41b1c6f244edcfb78646d0fac4e47c2e3e561
2020-10-24 22:14:42 +02:00
Pau Espin Pedrol
442198cd41 Move ul_tbf allocation code to correct file
Change-Id: Ifd98abbcce49e4605c764267965903fbf9f35867
2020-10-24 22:14:42 +02:00
Pau Espin Pedrol
e9f77d377b tbf: Set MS during constructor time
This is another step forward towards a more clear data model where a TBF
always has a MS object (which may be lacking some information, and at a
later point when more information is found, it may actually be a
duplicated MS object and hence one duplicate removed and the TBF moved
to the object being kept).

This helps for instance in removing duplicated information stored in
the TBF which is really per MS, like ms_class, ta, etc. Since there's
always a MS object there's no need to keep a duplicate in both classes
in case there's no MS object.

It can already be seen looking at unit test logging that this kind of
data model already provides better information.
Some unit test parts were needed to adapt to the new model too.

Change-Id: I3cdf4d53e222777d5a2bf4c5aad3a7414105f14c
2020-10-24 22:14:42 +02:00
Pau Espin Pedrol
7bde60f260 tbf: Implement enable_egprs() once
There's no real need for having different copies of this method in each
children. Furthermore, having the method implemented in the base class
made me shoot my foot while trying to move this to the tbf constructor
(see next commit), so let's simplify this and avoid other people
following into the same issue.

enable_egprs() in tbf.h is moved to be public since it needed (as it was
for the duplicated children mehtods with same name), but anyway it will
be moved to private in next commit.

Change-Id: Id7de060318201a42e51f277f898463f4b9a84eba
2020-10-24 22:14:42 +02:00
Pau Espin Pedrol
b3f239785c tbf: Make window() available to tbf base class
Return an interface to the window base class so that the tbf base class
can access the common window methods, such as set_ws(). It will be used
in next commit to get rid of duplicated function enable_egprs in both
dl_tbf and ul_tbf subclasses.

The user of the function can then decide to access more specific
functionaltiites of the window class by static casting it to the
specific direction (which is known by the caller since it operates on a
ul_tbf or a dl_tbf).

Change-Id: Ia2e1decf91be1184668e28297c2126affb9c7ae4
2020-10-24 22:14:42 +02:00
Pau Espin Pedrol
834cbab97d Move constructor gprs_rlcmac_dl_tbf::BandWidth to correct file
Change-Id: I7587fd2ee97424020a099a8513f95544d6635f3d
2020-10-24 19:49:43 +00:00
Pau Espin Pedrol
9767e44fd4 Move gprs_rlcmac_ul_tbf::window to correct file
It wasn't move when all the UL specific code was moved to a separate
file.

Change-Id: I6f8c2d568ffdea3826ec1e11358d24eea6c9335b
2020-10-24 19:49:43 +00:00
Vadim Yanitskiy
1136fdb563 main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
Change-Id: If82208ecb931a6024f1a83c8648c5855b15dcc96
Depends: Ie2022a7f9e167e5ceacf15350c037dd43768ff40
Related: SYS#4910
2020-10-24 05:15:20 +07:00
Vadim Yanitskiy
35668a2e06 main: remove line breaks in print_help(), increase spacing
Change-Id: I07010afec3bb85d875926813772a6504f3bdb7b5
Related: SYS#4910
2020-10-24 05:14:39 +07:00
Pau Espin Pedrol
a611b4f6a0 Fix several calls to LOGPAL
In those cases since a string pointer was passed, it always printed
"single" instead of whatever really was being used, since the string
pointer was not NULL.

Change-Id: Idab7d18e8f519e10fc3df4007634661c46f9256d
2020-10-23 17:13:04 +02:00
Pau Espin Pedrol
8353d97904 Improve debug logging for alloc algos
In general we want to see explicitly the kind of requested allocation at
the start. The MS class is not needed since it's printed in the previous
log line in any case.

Change-Id: I9eb0a592c15be96da9d140ff373c1afead76b18c
2020-10-23 17:08:43 +02:00
Harald Welte
8347359cb0 Use osmo_fd_setup() whenever applicable
Change-Id: I8abd4c50b172f6b312bb4ba3c29e74396f6e6b93
2020-10-19 11:36:33 +00:00
Vadim Yanitskiy
a6c5db954f fix tbf_select_slot_set(): use LOGP() instead of LOGPC()
Change-Id: I8e9ae854d147735357921f71d9a02862376a50b2
2020-10-16 22:33:54 +07:00
Vadim Yanitskiy
1ab35d100b doc/manuals: (re-)generate XML VTY reference automatically
Change-Id: I0818be314e36d5fb848c9248be6b8cd7fe20fb39
Related: SYS#4937
2020-10-16 15:29:19 +00:00
Alexander Couzens
5bece2a0ed Rework NS configuration over the info indication
Add support of the second NSVC in the info indication.
Add support to update a previous NS configuration.
Allow to update of a NS-VC while the NSE is still available over the
second.

Depends-on: I917f25ebd1239eae5855d973ced15b93731e33a0 (libosmocore)
Depends-on: I3a0cd305fd73b3cb9ec70246ec15ac70b83e57f2 (libosmocore)
Depends-on: I5a2bb95d05d06d909347e2fb084a446ead888cb3 (libosmocore)
Depends-on: I54f110acc3acccb362f6e554324d08cc42b7c328 (libosmocore)
Depends-on: Ia00753a64b7622a0864341f51ea49b6963543755 (libosmocore)
Depends-on: Ic8f6f8aca10da23a18fab8870be7806065a34b47 (libosmocore)
Depends-on: I5f67e6a9bf4cb322bd169061fee0a528012ed54d (libosmocore)
Change-Id: I589ebaa2a2b7de55b7e4e975d8fd6412dd5f214b
2020-10-13 08:45:30 +00:00
Pau Espin Pedrol
3839605ec9 contrib/jenkins: Enable parallel make in make distcheck
Change-Id: Ie3f5b6063167875ecb2f25e194806a2476aec984
Related: OS#4421
2020-10-13 08:21:00 +00:00
Vadim Yanitskiy
974cc7b324 gprs_bssgp_pcu: fix: do not crash on receipt of subsequent INFO.ind
It's expected to receive subsequent INFO.ind messages at run-time,
e.g. when a dynamic TCH/F_TCH/H_PDCH timeslot is switched from
PDCH to TCH/F or TCH/H, osmo-bts would send us INFO.ind with the
updated PDCH slot-mask indicating that this timeslot is disabled.

In gprs_nsvc_create_and_connect(), do not bind() on the received
NSVC address unconditionally - we may already be bound to it.
Instead, return early and keep everything unchanged.

I don't know how the PCU is supposed to handle NSVC address change,
at least the new NS2 library does not handle this internally, nor
it provides any API for that.  Let's leave it for later.

Change-Id: I159138e41e147cd30212da548b0ccd3f81d61b4e
Related: I4c3bc883d795e5d1ee5ab175ac03684924692a7c
Fixes: Ib389925cf5c9f18951af6242c31ea70476218e9a
Related: SYS#5108
2020-10-10 06:16:11 +07:00
Vadim Yanitskiy
d038361e95 struct gprs_rlcmac_bts: remove unused 'nsei' field
The code in gprs_nsvc_create_and_connect() stores NSEI there for
no reason, despite it's already stored in struct gprs_ns2_nse.

Change-Id: Ib30152a12384cf0448104a1ee1cfb949f4a27553
2020-10-10 05:05:33 +07:00
Vadim Yanitskiy
0d0ac1b949 gprs_bssgp_pcu: fix possible memleak in gprs_nsvc_create_and_connect()
Change-Id: I9f44cd22b1353ded6eeb2fe9f8dd4818de758003
2020-10-10 05:05:33 +07:00
Vadim Yanitskiy
194b6f06a0 gprs_bssgp_pcu: make osmo_sockaddr local/sgsn arguments const
Change-Id: I40e51de300533cfcbb3c9f90a0858a489a3c2b6b
Depends: I0df6a00ac1830bd64a10b9336b827e113fa772bb
2020-10-09 21:43:09 +00:00
Philipp Maier
08c5037d60 pcu_main: add commandline option --vty-ref-xml
The commandline option --vty-ref-xml is needed to enable automatic
generation of the VTY reference manual.

Change-Id: Ie1829a06b83f69f4cd8256adbf9437388ca3d7e0
Related: SYS#4937, OS#1601
2020-10-09 20:42:16 +02:00
Vadim Yanitskiy
781f04a8f8 pcu_l1_if: print NSVC address in more common format
Change-Id: I5aac1b0624d127ef92a7b9c791f6b409e9e6055a
2020-10-09 20:54:03 +07:00
Vadim Yanitskiy
24c643e143 pcu_l1_if: use proper format string specifiers: %d -> %u
Change-Id: Ieb81dcb4096acbc7a308d003c9e653800071e149
2020-10-09 20:34:21 +07:00
Vadim Yanitskiy
19622aee5b pcu_l1_if: cosmetic: make {local,remote}_sockaddr scoped variables
Change-Id: Ib5ddf3622226ac9c612a03ca32d373bcc9b208cf
2020-10-09 20:03:16 +07:00
Vadim Yanitskiy
c1a726c573 pcu_l1_if: correct logging level in pcu_rx_info_ind()
Change-Id: Ib4bb9b907fc2bf279cf22a3bb9b95ea1a0fb3db6
2020-10-08 23:03:39 +07:00
Vadim Yanitskiy
5d5b50aaf3 pcu_l1_if: cosmetic: use ARRAY_SIZE() in pcu_rx_info_ind()
Change-Id: Iff11c854b1687f75c1125a5bcd616da95ade69ee
2020-10-08 23:03:36 +07:00
Philipp Maier
9459ebde32 vty: add attributes to VTY commands indicating when they apply
Change-Id: I63978ce3ea87593c9a41e503ed3b761c64e1e80f
Related: SYS#4937, OS#1601
2020-10-08 07:16:31 +00:00
Alexander Couzens
290d9030e9 Use the new NS2 lib
Depends: Id7edb8feb96436ba170383fc62d43ceb16955d53 (libosmocore)
Depends: I2a9dcd14f4ad16211c0f6d98812ad4a13e910c2a (libosmocore)
Change-Id: Ib389925cf5c9f18951af6242c31ea70476218e9a
2020-10-06 16:38:38 +02:00
Harald Welte
0a369e560c bts.cpp: Increase constructor priority
It seems that some gcc versions do not consider the priority of
"C" __attribute__((constructor)) definitions in the same order as
they do C++ static initializers, which are called in the order in which
they appear in the compile unit (source file).

The problem has been observed at least in a
environment based on T2 SDE with GCC 6.3.0 and binutils 2.28.

Let's work around this by making sure the __attribute__((constructor))
function always gets the highest priority value permitted by gcc (101).

Closes: SYS#5093
Change-Id: I65de69a32ac929e6ddd4e58980027f9e76813153
2020-10-01 19:39:58 +02:00
Pau Espin Pedrol
84abd2f65e Fix crash accessing NULL tbf->pdch[first_ts]
Fixes consistent crash under some specific scenarios explained in
OS#4756.

The crash was caused due to a bug in channel allocator algorithm
incorrectly populating tbf->pdch[] array as a result of mismatching
first_ts and resulting pdch selected slot bitmask.

The issue happens because when allocating a UL TBF in allocator B, the
subset is always further forced into allocating one single TS. As a
result, on that branch several variables are updated, but first_ts was
not.

The field used to be updated in older versions, but a bug was introduced
during code refactoring in commit listed below (31 Jan 2018).

Fixes: 0cc7212cfd
Related: OS#4756
Change-Id: I79596803f7dab6f21b58bfe39c2af65d9c5b39d5
2020-09-22 20:57:06 +02:00
Pau Espin Pedrol
01aef5ed8b cosmetic: Fix typo in comment
Change-Id: I6567065b8ec0082b21c371bbd0c2e85fecc96c90
2020-09-22 20:57:05 +02:00
Pau Espin Pedrol
5d2d2ec466 cosmetic: Fix indentation of for loops
Change-Id: Id7087bd00d9003235688ff34f2b039d525caa777
2020-09-22 20:57:05 +02:00
Pau Espin Pedrol
a1ac2f017f vty: Add 'show bts pdch' command
This allows to see which channels have been enabled according to PCU.

Change-Id: If72e67ba80aab4e0c68408e6996d74d2ff70c322
2020-09-22 20:56:53 +02:00
Pau Espin Pedrol
5fc95771bb cosmetic: fix indentation alignment
Change-Id: I105cf184a478cf178d69e16cd35fa36c51133a18
2020-09-22 20:46:20 +02:00
Pau Espin Pedrol
bd9973a64f Free all MS TBFs when receiving GPRS Suspension Request
Otherwise the TBFs are kept, and hence PCU will continue reserving resources and
DL data queued will still be sent over the air, despite the MS not
listening anymore on the PDCH.

Change-Id: I4ae1c3706b2ed6e4d271cd16f7cd7f8937b84836
2020-09-22 20:46:15 +02:00
Pau Espin Pedrol
e3ef51ec06 gprs_ms_storage.h: Set pointer to NULL instead of 0
Change-Id: If8acd012909c9f452b609e4a804c9a059379f07d
2020-09-22 13:56:57 +02:00
Pau Espin Pedrol
cd6c466922 tbf: Don't log rlcmac_diag() output in separate lines
Output of all diag in different lines is really confusing, since the
user reads a timeout ocurred and then later in another line something
like "Downlink ACK was received" while no GSMTAP message shows any ACK.

Change-Id: I6a7d79c16c930f0712bc73b308409ececb1946ba
2020-09-22 13:44:15 +02:00
Pau Espin Pedrol
6ce1299567 gitignore: Add __pychache__ dir
That's created by VTY tests running python.

Change-Id: Idb67909ddd5027dbdcbf5a3882d1bb0d4ff9d29e
2020-09-22 13:44:15 +02:00
Alexander Couzens
9b5c960f55 pcuif_proto: version 10: add support for IPv6 NSVCs
Introduce a address_type in the NSVC configuration pass the given
protocol.  The remote_ip is network byte order, the default
encoding for in_addr and in6_addr.

Change-Id: Ia0852f9f4395f1248b39363ef90f6f5673b24e2f
Related: SYS#4915
2020-09-22 00:49:28 +07:00
Vadim Yanitskiy
8e2bd1e79d pcuif_proto: version 10: add frequency hopping parameters
Change-Id: I6863830883d90954006a7126c22d348aa2a83271
Related: SYS#4868, OS#4547
2020-09-22 00:49:11 +07:00
Alexander Couzens
40a9e603b9 Revert "pcuif_proto: version 0xa: add support for IPv6 NSVCs"
This reverts commit 38aaa10ed4.
It was to early because the frequency hopping wasn't ready to be merged.

Change-Id: Ibf055d5adfd9bffaaf51cb8468c79be597467e0f
2020-09-16 03:24:55 +02:00
Alexander Couzens
38aaa10ed4 pcuif_proto: version 0xa: add support for IPv6 NSVCs
Introduce a address_type in the NSVC configuration pass the given
protocol.
The remote_ip is network byte order, the default encoding for in_addr and in6_addr.

Change-Id: If26958d5b584973dca79159cf9e7f3f266519ce9
2020-09-15 22:21:43 +02:00
Vadim Yanitskiy
2597cf1494 encoding: fix gen_freq_params(): do not check pdch twice
This is a left-over from an earlier version of [1] that makes
Coverity think that there can be NULL pointer dereference,
even despite we assert(pdch != NULL).

[1] I8adc0cdb1b05a87b4df5d4bc196f6d381283a06f

Change-Id: I3490c38e0c1186dfd2fae63526a05c694547cebb
Fixes: CID#214230
2020-09-10 18:23:03 +07:00
Vadim Yanitskiy
542e388e4f encoding: implement handing of hopping parameters
The following test cases verify coding of the hopping parameters:

  + (RR) Immediate Assignment
    - TC_pcuif_fh_imm_ass_ul_egprs,
    - TC_pcuif_fh_imm_ass_ul,
    - TC_pcuif_fh_imm_ass_dl,

  + (RLC/MAC) Packet Uplink/Downlink Assignment:
    - TC_pcuif_fh_pkt_ass_ul,
    - TC_pcuif_fh_pkt_ass_dl,

all of them pass with this (and the upcoming) change applied.

Change-Id: I8adc0cdb1b05a87b4df5d4bc196f6d381283a06f
Related: SYS#4868, OS#4547
2020-09-08 02:47:02 +07:00
Vadim Yanitskiy
db56a3563e encoding: use CSN.1 codec to generate Packet Uplink Assignment
It's quite odd to see that in write_packet_downlink_assignment()
we initialize an 'RlcMacDownlink_t', so then the caller can use
the power of CSN.1 codec to generate the final sequence of bytes
to be transmitted, while in write_packet_uplink_assignment() we
already compose the final RLC/MAC message straight away using
the low-level bitvec API (like bitvec_write_field()).

I guess the reason is that at the time of writing this code, the
CSN.1 codec was not stable enough, so it was safer to generate
the message 'by hand'.  This would also explain why we *decode*
the final RLC/MAC message in create_ul_ass() right after encoding.

Rewrite write_packet_uplink_assignment(), so now it initializes
a caller-provided 'RlcMacDownlink_t' structure.  Given that it's
allocated on heap using talloc_zero(), do not initialize presence
indicators of fields that are not present in the message.

This would facilitate handling of frequency hopping parameters
in the upcoming changes, in particular we can now introduce a
function that would compose Frequency Parameters IE for both
write_packet_{downlink,uplink}_assignment().

Tested manually by running a GPRS-enabled network, as well as by
running test cases from ttcn3-pcu-test => no regressions observed.

Change-Id: I2850b91e0043cdca8ae7498a5fc727eeedd029b6
Related: SYS#4868, OS#4547
2020-09-08 02:47:02 +07:00
Vadim Yanitskiy
962d717f41 encoding: clarify docstring for write_packet_downlink_assignment()
Change-Id: I7c4458c2e7767b6cf03462ba79acdd9c9904ee83
2020-09-08 02:47:02 +07:00
Pau Espin Pedrol
1d68cdff92 Fix recent typo preventing MS from registering
Fixes: 0052051c07
Change-Id: Icbbf7340d78ef709ea00d527036533a14e9c21f9
2020-08-26 13:43:39 +02:00
Vadim Yanitskiy
1156776572 encoding: pass pdch slot directly to encoding functions
In order to be able to encode frequency hopping parameters, let's
pass a const pointer to 'gprs_rlcmac_pdch' (PDCH slot) directly,
instead of passing all related parameters separately.

Change-Id: I6bccad508f0fdccc4a763211008dd847a9111a8d
Related: SYS#4868, OS#4547
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
a76cdaceb2 encoding: use bool for use_egprs in write_packet_uplink_assignment()
Change-Id: Iab4fb44c666a0d4fe8c98f5ff9221e23a6f1f2fa
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
59d64fb234 encoding: fix RRBP field in write_packet_uplink_assignment()
Do not hard-code 0x00, write what was passed as a parameter.

Change-Id: I9eb362292e9f4c16d4b8f8d4253df0422062eeb4
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
7a1fdfde8a encoding: do not encode out of range Timing Advance values
According to 3GPP TS 44.060, section 12.12 "Packet Timing Advance",
the 'TIMING_ADVANCE_VALUE' field is optional, and takes 6 bits
if present.  This means that a value that fits in range 0..63
(inclusive) can be encoded (0b111111 == 63).

It's possible that tbf->ta() returns GSM48_TA_INVALID == 220,
so the bitvec API would encode only 6 LSBs of it:

  220 & 0b111111 == 28

Let's ensure that the 'TIMING_ADVANCE_VALUE' is present iff
tbf->ta() returns a correct (0 <= x <= 63), and absent otherwise.

Change-Id: I342288ea4ef1e218e5744e9be6a8e528d4e697fa
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
c0ddaa94e6 encoding: constify 'tbf' in UL/DL assignment functions
Change-Id: I9b80ce22914a355592502c936046b233c3ba216d
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
e4bcd2103c tbf: allocate the bitvec on stack in create_{dl,ul}_ass()
Initialize the bit vector to use already allocated memory,
so we would not need to allocate additional 23 bytes and
copy them from the bit vector to a msgb.

Change-Id: I4190707d7fa5b1c4c3db745635f88d5afb9e21ca
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
c82c1f5efc tbf: cosmetic: use GSM_MACBLOCK_LEN where possible
Change-Id: Ib42770cb009e8d559f733ebedd058e2f0a18820a
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
48587d5475 gsm_rlcmac: use consistent naming for [Extended] Packet Timing Advance
Change-Id: I6382c81f7569b4c5a68521c04f6b03a34bfc39dd
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
1d52c1e02e pcu_l1_if: cosmetic: correct error message in pcu_rx_info_ind()
Change-Id: I26ad0e990f6bf049a14f63b1255722d60c7ff868
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
0f41b710b7 pcu_l1_if: cosmetic: move struct 'gprs_rlcmac_pdch' into the for loop
Change-Id: I5bc270ddb6064e5086a801061c2eff074c293e77
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
11b0f00c00 pcu_l1_if: cosmetic: rename both 'trx'/'ts' to 'trx_nr'/'ts_nr'
Change-Id: Id481eba9bd462e411b2ba047ee5b849ddba8ac6b
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
ce0dae9fda pcu_l1_if: constify the argument of pcu_rx_info_ind()
Change-Id: I0b146c9f8c1e566c3aff4bd7869ca9699f888d4f
2020-08-24 10:53:08 +00:00
Vadim Yanitskiy
fad2128d17 pcu_l1_if: use proper format specifier for PCUIF version
Change-Id: Ibd15a678a7a8fc840422e2280b0d358138a67e0c
2020-08-24 10:53:08 +00:00
Pau Espin Pedrol
b69928cfaf pdch: rcv pkt meas rep: Allocate MS object early in path and use it
Let's create the MS object early if doesn't exist and fill in the
information, so that we can operate on it in an early way (for instance,
logging macros), this way it's easier to trace the lifecycle of
subscribers.

Change-Id: I3ec7eb970310698dd228ae6ad65ec5ca833bab3f
2020-08-24 07:50:49 +00:00
Neels Hofmeyr
59fc0bda6e paging: pass struct osmo_mobile_identity, not encoded IE bytes
In get_paging_mi(), before this, an encoded buffer of Mobile Identity bytes is
returned. Code paths following this repeatedly decode the Mobile Identity
bytes, e.g. for logging. Also, in get_paging_mi(), since the TMSI is read in
from a different encoding than a typical Mobile Identity IE, the TMSI was
manually encoded into a typical Mobile Identity IE. This is essentially a code
dup of osmo_mobile_identity_encode(). Stop this madness.

Instead, in get_paging_mi(), return a decoded struct osmo_mobile_identity. Code
paths after this use the struct osmo_mobile_identity directly without repeated
decoding.

At the point of finally needing an encoded Mobile Identity IE (in
Encoding::write_paging_request()), do a proper osmo_mobile_identity_encode().

Since this may return errors, add an rc check for the caller of
write_paging_request(), gprs_rlcmac_paging_request().

A side effect is stricter validation of the Mobile Identity passing through the
Paging code path. Before, invalid MI might have passed through unnoticed.

Change-Id: Iad845acb0096b75dc453105c9c16b2252879b4ca
2020-08-24 01:12:16 +00:00
Neels Hofmeyr
0052051c07 use new osmo_mobile_identity api (avoid deprecation)
Note: subsequent patch Iad845acb0096b75dc453105c9c16b2252879b4ca will change to
passing a struct osmo_mobile_identity in the Paging code path, instead of
passing the encoded IE data.

Change-Id: Ibb03b8e601160427944f434761ca59811d1fc12f
2020-08-21 16:40:14 +02:00
Pau Espin Pedrol
b75c27febd Support setting rt-prio and cpu-affinity mask through VTY
Change-Id: I92bfabd57fab28b23bd4494a577373106be1daec
Depends: libosmocore.git Change-Id If76a4bd2cc7b3c7adf5d84790a944d78be70e10a
Depends: osmo-gsm-masnuals.git Change-Id Icd75769ef630c3fa985fc5e2154d5521689cdd3c
Related: SYS#4986
2020-08-20 08:44:54 +00:00
Pau Espin Pedrol
183b01eb4c doc: Update VTY reference xml file
Change-Id: I5800f1607878ab764323dc12c537a8e28d387cc9
2020-08-20 08:44:54 +00:00
Pau Espin Pedrol
fad557ec0f configure.ac: Fix trailing whitespace
Change-Id: I54b360c537e04ab3a9cb30ac3e3f9730bcad1c91
2020-08-20 08:44:54 +00:00
Pau Espin Pedrol
f2dad593ae Introduce log macro helper LOGPMS
Change-Id: Ib304ced06531a5154b7ec8bf87f9717dfd7d1397
2020-08-18 20:26:25 +02:00
Pau Espin Pedrol
5f10fbb166 pdch: Drop unneeded notice log message in rcv pkt meas report
It's totally fine to receive Packet Measurement Report messages with no
SBA present, since the MS also sends measurements on PACCH while
transmitting data.

Related: OS#4719
Change-Id: I8f642d9cdeb342df7d5f2fa30516ea69554a6270
2020-08-18 19:39:26 +02:00
Pau Espin Pedrol
a2c574ede1 Fix typo in log message
Change-Id: Ifd65542eca9180a2fcaaca290861396569e453ec
2020-08-17 18:15:46 +02:00
Vadim Yanitskiy
74b750df81 debian/control: change maintainer to the Osmocom team / mailing list
Change-Id: Ic114f2552ceadfeaaa00f8e719a5c7bd5d6b4917
2020-08-13 16:09:03 +07:00
Vadim Yanitskiy
811c90c5fd direct-phy: fix handle_ph_ra_ind(): handle PH-RA.ind on PRACH SAPI
In [1] I restricted L1 SAPI of PH-RA.ind to PDTCH and PTCCH, and
this seems to have caused a regression reported in [2]:

  DL1IF ERROR sysmo_l1_if.c:251 Rx PH-RA.ind for unknown L1 SAPI PRACH

I assumed that PH-RA.ind belonging to a Control Acknowledgement
message (in format of 4 Access Bursts) would have PDTCH SAPI,
while apparently it's actually arriving on PRACH.

[1] I482d60a46b9d253dfe0b16140eac9fea6420b30c
[2] https://osmocom.org/issues/1526#note-39

Change-Id: Ib0a6da37de7a1db4cad2b96293b31b9f32e7d9eb
Related: OS#1526
2020-08-12 18:20:33 +00:00
Vadim Yanitskiy
9d5a115ee2 encoding: assert() presence of Downlink TBF
This is not something that should normally happen.  If it happens,
then it's definitely a bug, and we should not tolerate it.

Change-Id: I6e46ba42650f0db2399649b536a1d2b3f0fcbf04
2020-07-18 20:54:24 +07:00
Vadim Yanitskiy
8f628ab77f encoding: drop log_alert_exit(), use OSMO_ASSERT() instead
Change-Id: Id5ef1c3c08dc7f264ad801e519d727d86f5ae5b8
2020-07-18 20:47:47 +07:00
Vadim Yanitskiy
eb1e0fa859 bts: cosmetic: use DUMMY_VEC for padding where possible
Change-Id: I725a7bd1b0c4d2b0d73f1b6d1f16543bf3d9d9fe
2020-07-18 20:33:49 +07:00
Pau Espin Pedrol
5935707489 pdch.cpp: Store TLLI promptly on newly created TLLI in rcv_resource_request
The TLLI is tried to be updated later anyway during tbf_alloc_ul(), but
this way it's clear that information is stored where it belongs as soon
as possible. The change already shows clearer log lines in TbfTest.err.

Change-Id: I20ce4eb94ecf85ce2835275d0056d9ecd1b558c3
2020-07-09 13:40:55 +02:00
Pau Espin Pedrol
9e7361a8ba pdch.cpp: Fix wrong annoying log line about non-scheduled ResourceReq received
It's perfectly fine receiving a Resource Request message under some
circumstances (as stated in the comment added in the commit).

To print issues only under non-expected circumstances, the function
rcv_resource_request need to be refactored:
* Destroying older UL_TBF is delayed because it is needed further
  down.
* When the old UL_TBF is FINISHED, it's an acceptable time to receive a
  Resource request, so we check if that's the case and don't print a
  warning in that case.

Change-Id: I4b4367126d6a16055cd2f45afc4a6b9c15a7c980
2020-07-09 13:37:15 +02:00
Pau Espin Pedrol
bcb226d607 pdch.cpp: Avoid resetting (egprs_)ms_class to unknown if not found in MS RadioAccCap
If the information is not found in the message, 0 (unknown MS class)
will be returned. If the MS already had some previous information on the
MS class, let's not lose it by setting it back to 0.

Take the opportunity to drop related log lines which are no needed,
since set_(egprs_)ms_class() functions already log the value changes.

Change-Id: Icd52209fd4395d78dc770e7869d1b1fe45a18ca0
2020-07-09 13:37:15 +02:00
Pau Espin Pedrol
85faa762c3 pdch.cpp: Avoid dropping existing DL TBF during rcv_resource_request
There's no real good explanation on why the DL TBF is dropped there,
since PKT RESOUCE REQUEST is used basically during UL TBF establishment.
Also, as decribed by TS 44.060 11.2.16 "Packet Resource Request":
"""
This message is sent on the PACCH by the mobile station to the network
to request a change in the uplink resources assigned.
"""

Change-Id: Iab4afb66f0d671f7ad54909d2685a1613e12ab4d
2020-07-09 13:37:15 +02:00
Pau Espin Pedrol
f2c6c83816 encoding.cpp: Fix missing spacing in function param
Change-Id: I4f30a0cea615d57cd7783a92ae782790c8075a6c
2020-07-09 13:37:15 +02:00
Pau Espin Pedrol
732373d7b4 encoding: Encode TA as unsigned and check validty against GSM48_TA_INVALID
According to 3GPP TS 44.018 sec 10.5.2.40, Timing Advance value is 8 bit
and range is 0-63 (0-219 on GSM400). Unsigned value (uint8_t) is used
everywhere else, so avoid using a signed one here, and simply check for
GSM48_TA_INVALID here, which we use everywhere else to initialize when the
value is not known. Ideally we should check for value based on band, but
it makes more sense to check that when receiving the data and storing in
in set_ta().

Change-Id: I82b13561d0fe5ebafb5c3a8b9a501045c29809bc
2020-07-09 13:36:47 +02:00
Pau Espin Pedrol
26743ac4f9 tbf_dl: uint8_t is enough to store a TA value
According to 3GPP TS 44.018 sec 10.5.2.40, Timing Advance value is 8 bit
and range is 0-63 (0-219 on GSM400). So there's no need for 16 bits to
store it. uint8_t is used in all other places in the code.

Change-Id: I38aa063ae30ca5680fef6252d2cef22cea98c123
2020-07-07 17:18:14 +02:00
Pau Espin Pedrol
f861d312fe decoding.cpp: Improve logging in malformed UL data parsing
Change-Id: Ic4ad14b88fddde8d9e62e0a2587b501d36821f01
2020-06-30 21:33:49 +02:00
Pau Espin Pedrol
72e395656d Set correct GSMTAP channel type for PDTCH messages returning error
For instance, that may happen because the len of the message is not
filling the expect size (because padding is missing for example). Still,
in this case we know the channel type, so we set it so that wireshark
tries to decode the message as a data one.

Change-Id: Ifea94095d669b528874e64ca823a776cd6e22b4b
2020-06-30 18:34:58 +02:00
Pau Espin Pedrol
259532fcf9 pdch.cpp: Fix logging line format in rcv_block wrong length
Change-Id: I2f818021cef41ab6f4569cd87026072811853352
2020-06-30 17:48:45 +02:00
Pau Espin Pedrol
d21e961a8b tbf: Drop unneeded method set_tlli_from_ul
Since commit 322456ed47 (and previous
one), it is expected that a tbf object ALWAYS has a MS object referend
to it, even if it's a temporary copy which will later be merged when
TLLI/IMSI is retrieved and it is found that several MS objects relate to
the same MS.

The purpose of set_tlli_from_ul was mainly to update TBF's ms() to
old_ms before going through usual tbf->update_ms() path. That's not
really needed since ms() is already always set and TBFs for old_ms are
already freed in update_ms() and children function.

Change-Id: Ie8795e7a02032336e53febb65c11f9150c36d2a0
2020-06-26 14:35:01 +02:00
Pau Espin Pedrol
cbf05f5146 gprs_ms: Transfer known EGPRS MS class when mergling old MS
Since not all the the information about the MS is known during TBF
creation in all scenrios, it may happen that when TBF is created it
creates a MS which later will end up being found a duplicate of an
already previously existing MS.
At that point, the old object is dropped and information retrieved from
both is merged into the new one.

The GPRS MS class was being transferred, but the EGPRS MS class was missing.

Change-Id: Ieb9929b60254b12f79392d6acb8b456d71cccb9e
2020-06-26 14:16:50 +02:00
Pau Espin Pedrol
43f0bce253 gprs_ms: Small clean ups in IMSI storage related code
Change-Id: I987af0d33b79302c037d062c9d1c828a0e027147
2020-06-26 13:09:44 +02:00
Vadim Yanitskiy
81b610ea2c bts: fix send_gsmtap_rach(): properly pack 11 bit RA
According to 3GPP TS 44.004, section 7.4a, two alternative RACH
block formats are specified: 8 bit (1 octet) and 11 bit. The
bit order is LSB (right to left), byte order is MSB.

In PCUIF RACH.ind structure (see gsm_pcu_if_rach_ind) we use
a field of type uint16_t to store RA values regardles of the
block format. Thus when packing it to bytes, we cannot just
cast uint16_t* to uint8_t*, we need to do some bit shifting.

Change-Id: I08a0a908f855b0d8a002df732e02781126d27dfb
2020-06-11 01:29:40 +07:00
Vadim Yanitskiy
07b6487c5a bts: add send_gsmtap_rach(), also send PTCCH/U over GSMTAP
Change-Id: I5cc4c3d2522215a31924121f83fcc2ac9ac6fe9c
2020-06-11 01:29:12 +07:00
Vadim Yanitskiy
b90d34b3d1 BTS::parse_rach_ind(): properly handle EGPRS Packet Channel Request
Let's finally use the API we introduced in [1].

[1] I96df3352856933c9140177b2801a2c71f4134183

Change-Id: Ia15761c33c8048d35c7f7bc93dbea781dd0894b7
Related: OS#1548
2020-06-03 12:49:40 +00:00
Vadim Yanitskiy
a0a0b7fb0e bts: refactor handling and parsing of RACH.ind
This patch is a set of tightly related changes:

  - group all RACH.ind parameters into struct 'rach_ind_params';
  - group Channel Request parameters into struct 'chan_req_params';
  - get rid of egprs_mslot_class_from_ra(), priority_from_ra(),
    and is_single_block(), introduce unified parse_rach_ind();
  - improve logging, get rid of redundant information.

This is needed for proper EGPRS Packet Channel Request handling.

Change-Id: I5fe7e0f51bf5c9eac073935cc4f4edd667c67c6e
Related: OS#1548
2020-06-03 12:49:40 +00:00
Vadim Yanitskiy
088dcbc016 doc/manuals: fix typo in overview.adoc: s/Omsocom/Osmocom/g
Change-Id: I7730e65728a3917dc4923728738253155e1e0428
2020-05-31 03:54:54 +07:00
Vadim Yanitskiy
4c593c8c8a encoding: fix write_ia_rest_egprs_uplink_sba(): add missing CHECK(rc)
Change-Id: I8e41c2912aaff689b0e311c8e2d3e961d2f1ac2c
2020-05-25 09:15:09 +00:00
Vadim Yanitskiy
a2d972a38a RLC/MAC: implement decoding of EGPRS Packet Channel Request
According to 3GPP TS 44.004, section 7.4a, two alternative RACH block
formats are specified: 8 bit (1 octet) and 11 bit. This change adds
CSN.1 definitions for 11 bit EGPRS Packet Channel Request as per
3GPP TS 44.060, table 11.2.5a.2.

Change-Id: I96df3352856933c9140177b2801a2c71f4134183
Related: OS#1548
2020-05-23 19:38:35 +07:00
Vadim Yanitskiy
3f2022e2cb encoding: cosmetic: use RLC_MODE_ACKNOWLEDGED where possible
Change-Id: Ic69d120f622f512f05016596bfdd4a89b96e3e3b
2020-05-23 19:28:03 +07:00
Vadim Yanitskiy
93ad3fd9b9 csn1: fix: never use enumerated types in codec structures
I faced a problem while working on EGPRS Packet Channel Request
coding support: the unit test I wrote for it was passing when
compiled with AddressSanitizer, but failing when compiled
without it o_O. Somehow this was observed only with GCC 10.

Here is a part the standard output diff for that unit test:

   *** testEGPRSPktChReq ***
   decode_egprs_pkt_ch_req(0x2b5) returns 0
  - ==> One Phase Access
  + ==> unknown 0xdd5f4e00
   decode_egprs_pkt_ch_req(0x14a) returns 0
  - ==> One Phase Access
  + ==> unknown 0xdd5f4e00
   decode_egprs_pkt_ch_req(0x428) returns 0
  - ==> Short Access
  + ==> unknown 0xdd5f4e01

At the same time, debug output of the CSN.1 decoder looked fine.
So WYSINWYG (What You See Is *NOT* What You Get)! As it turned
out, this was happening because I used an enumerated type to
represent the sub-type of EGPRS Packet Channel Request.

  typedef struct
  {
    EGPRS_PacketChannelRequestType_t      Type; // <-- enum
    EGPRS_PacketChannelRequestContent_t	  Content;
  } EGPRS_PacketChannelRequest_t;

The problem is that length of an enumerated field, more precisely
the amount of bytes it takes in the memory, is compiler/machine
dependent. While the CSN.1 decoder assumes that the field holding
sequential number of the chosen element is one octet long, so its
address is getting casted to (guint8 *) and the value is written
to the first MSB.

  // csnStreamDecoder(), case CSN_CHOICE:
  pui8  = pui8DATA(data, pDescr->offset);
  *pui8 = i; // [ --> xx .. .. .. ]

Let's make sure that none of the existing RLC/MAC definitions is
using enumerated types, and add a warning comment to CSN_CHOICE.

Affected CSN.1 definitions (unit test output adjusted):

  - Additional_access_technologies_struct_t,
  - Channel_Request_Description_t.

Change-Id: I917a40647480c6f6f3b0e68674ce9894379a9e7f
2020-05-23 19:26:58 +07:00
Vadim Yanitskiy
0614e9333f csn1: fix csnStreamEncoder(): always check the choice index
It's so easy to pick an out of bounds value otherwise...

Change-Id: I12f5ab739b97f1f3b5d4bed1b5a4a661c879e89f
2020-05-23 18:00:53 +07:00
Vadim Yanitskiy
fac8332649 csn1: fix csnStreamEncoder(): also check length of the choice list
Similar checks are done in csnStreamDecoder(), so better check than sorry.

Change-Id: I441c716975905a37264efc8a76df92194f39c1fb
2020-05-23 18:00:53 +07:00
Vadim Yanitskiy
c9915660ff csn1: fix M_CHOICE: restirct maximum length of the choice list
The current implementation is not capable of handling more than
256 (UCHAR_MAX) selectors in the choice list. Let's document
this and add a guard check to the M_CHOICE handler.

Change-Id: I40c3c5b9be892804c6cd71cbb907af469ce5d769
2020-05-23 18:00:53 +07:00
Vadim Yanitskiy
6fd4733041 l1if: fix: s/pcu_rx_rach_ind_pdtch/pcu_rx_rach_ind_ptcch/g
This is not a functional change, just fixing misleading function
name. Access Bursts on PTCCH/U have nothing to do with PDTCH.

Change-Id: I4ab710ba026315301cc6970263967616401a9fc8
2020-05-22 21:09:22 +07:00
Oliver Smith
0d7bc876c0 Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
Change-Id: If17e82c5fe1fc49877a5a3d9ba250e86091e253c
2020-05-22 13:43:32 +02:00
Pau Espin Pedrol
0b0391ff66 gsmtap: Set signal level and SNR fields
lqual (containing C/I value) is passed instead of SNR, but let's have
that better than nothing.

Change-Id: Ibe9502d42c8bd1b984069e7fd805dde87ecbab0c
2020-05-20 14:20:56 +02:00
Pau Espin Pedrol
2ae8337669 Get rid of class GprsCodingScheme
We have same kind of object splitted into two layers, in coding_scheme
and gprs_coding_scheme. Let's merge them together and get rid of the
class, which is not really useful because it's only a set of functions
operating on one enum value.

This change also fixes gcc 10.1.0 error about memseting a complex type
in rlc.h init().

Change-Id: Ie9ce2144ba9e8dbba9704d4e0000a2929e3e41df
2020-05-20 11:07:07 +00:00
Oliver Smith
c10cb81593 contrib: integrate RPM spec
Remove OpenSUSE bug report link, set version to @VERSION@, make it build
with CentOS 8 etc.

Related: OS#4550
Change-Id: Idfe04c2e2609763387d1309f059c390b8e7ae938
2020-05-19 17:08:33 +02:00
Oliver Smith
d0156fd6a8 contrib: import RPM spec
Copy the RPM spec file from:
https://build.opensuse.org/project/show/home:mnhauke:osmocom:nightly

Related: OS#4550
Change-Id: I4da70814357a326842de52b33934819d3ea133d8
2020-05-19 17:08:33 +02:00
Pau Espin Pedrol
c33a024d4a tbf_ul: Fix UL ACK not sent to MS if intermediate UL block is lost
In normal conditions ACKing of UL blocks is only sent every
SEND_ACK_AFTER_FRAMES (20) frames. Which means if CV=0 is received (and
hence no more packets are received) less than 20 frames before a lost,
the PCU won't ask for a retransmission and wait there until some timer
destroys the TBF.

This issue is shown by TTCN3 test PCU_Tests.ttcn
TC_ul_intermediate_retrans.

Unit tests triggering this condition are adapted. Some similar tests are
not triggering it because BSN/CV relation being used is totally wrong
(like CV=0 being sent on a BSN with previous value than others).

Change-Id: I9b4ef7b7277efa645bdb5becf2e9f6b32c99a9b1
2020-05-19 09:30:23 +00:00
Pau Espin Pedrol
5bb87b83d1 rlc: Move prepare() function out of gprs_rlc_data struct
Newer gcc 10.1.0 is erroring due to memset being applied on a complex
type, so let's start by removing this only function outside of the
struct.

Change-Id: I20426557d9b3049ab275fadb92e10ea8a860a119
2020-05-18 11:07:03 +02:00
Pau Espin Pedrol
c68e97012c rlc: Drop unused function gprs_rlc_data::put_data
Change-Id: I10eb93a1aa6ac1eac15c8e64da300caf2e6ccc44
2020-05-18 11:07:03 +02:00
Pau Espin Pedrol
7b9e56a500 sysmo: femtobts.h: Avoid redefining global variables
Change-Id: I0f04726ae608f499c557cedffb4d86625bccbd5a
2020-05-18 11:07:03 +02:00
Pau Espin Pedrol
09afd6f230 pcu: tbf_ul: Clean up maybe_schedule_uplink_acknack()
Get rid of checking all conditions twice, and update one log message.

Change-Id: I95831991b01961e4b7faddb08d27133acb0ab4d4
2020-05-15 17:03:46 +02:00
Pau Espin Pedrol
97e88fd35f bts: Drop specific functions to add values to stats
Change-Id: I877a9c9a35b6c94c3dd6b1ab3019bc57f6c8568a
2020-05-14 11:19:05 +00:00
Pau Espin Pedrol
a107f8f496 bts: Drop specific functions to add values to counters
It's super annoying seeing lots of functions being called everywhere
only to find out they are only incrementing a counter. Let's drop all
those functions and increment the counter so people looking at code
doesn't see dozens of code paths evyerwhere.

Most of the commit was generated by following sh snippet:
"""
 #!/bin/bash
define_pattern="^CREATE_COUNT_ADD_INLINE"
generic_func="do_rate_ctr_add"
grep -r -l "${define_pattern}" . | xargs cat | grep "${define_pattern}("| tr -d ",;" | tr "()" " " | awk '{ print $2 " " $3 }' >/tmp/hello

while read -r func_name ctr_name
do
 #echo "$func_name -> $ctr_name";
files="$(grep -r -l "${func_name}(" .)"
for f in $files; do
echo "$f: $func_name -> $ctr_name";
sed -i "s#${func_name}(#${generic_func}(${ctr_name}, #g" $f
done;
done < /tmp/hello

grep -r -l "void ${generic_func}" | xargs sed -i "/void ${generic_func}(CTR/d"
grep -r -l "$define_pattern" | xargs sed -i "/$define_pattern/d"
"""

Change-Id: I966221d6f9fb9bb4f6068bf45ca2978008a0efed
2020-05-14 11:19:05 +00:00
Pau Espin Pedrol
2338e5318e bts: Drop specific functions to increase counters
It's super annoying seeing lots of functions being called everywhere
only to find out they are only incrementing a counter. Let's drop all
those functions and increment the counter so people looking at code
doesn't see dozens of code paths evyerwhere.

Most of the commit was generated by following sh snippet:
"""
 #!/bin/bash
grep -r -l ^CREATE_COUNT_INLINE . | xargs cat | grep "^CREATE_COUNT_INLINE("| tr -d ",;" | tr "()" " " | awk '{ print $2 " " $3 }' >/tmp/hello

while read -r func_name ctr_name
do
 #echo "$func_name -> $ctr_name"
files="$(grep -r -l "${func_name}()" .)"
for f in $files; do
echo "$f: $func_name -> $ctr_name";
sed -i "s#${func_name}()#do_rate_ctr_inc(${ctr_name})#g" $f
done;
done < /tmp/hello

grep -r -l "void do_rate_ctr_inc" | xargs sed -i "/void do_rate_ctr_inc(CTR/d"
grep -r -l "CREATE_COUNT_INLINE" | xargs sed -i "/^CREATE_COUNT_INLINE/d"
"""

Change-Id: I360e322a30edf639aefb3c0f0e4354d98c9035a3
2020-05-14 11:19:05 +00:00
Pau Espin Pedrol
5dc6e465cb Drop unneeded arg 'ta' in tbf_alloc_ul()
The function is simply setting the ta on the ms, so simply make sure ta
is set on callers before passing the ms object.

Change-Id: Iebb9c57f458690e045ddc45c800209ad8cf621e0
2020-05-14 11:19:05 +00:00
Pau Espin Pedrol
ce60011e77 pdch: rcv_resource_request(): Clarify tbf_free only needed if MS used to exist beforehand
Variable found is used to always call Guard() on MS to avoid possible
unexpected freeing regressions.

Change-Id: I62f24fe04ca10fca19bedda288fe3ed3ce75413f
2020-05-14 11:19:05 +00:00
Philipp Maier
de0e558baf gprs_debug: Use only LOGL_NOTICE as default loglevel
The default loglevels of some log categories are configured to
LOGL_INFO. This is still to verbose, lets use LOGL_NOTICE here.

Change-Id: Ibb1cd1a94fb4fdd0147e073f8c1c82562c2c14ef
Related: OS#2577
2020-05-13 16:41:55 +00:00
Pau Espin Pedrol
322456ed47 Expect ms object to exist before calling tbf_alloc_dl_tbf()
Same as previous commit, this time for the DL counterpart.

Change-Id: I87f6cdf8288a688466020bda0874e68b57aa71c4
2020-05-12 17:09:20 +00:00
Pau Espin Pedrol
17402a5902 Expect ms object to exist before calling tbf_alloc_ul_tbf()
It's really non-sense from architectural point of view to pass an
optional pointer to the MS holding the TBF and creating it otherwise.
TBFs shouldn't be creating MS they belong too.

This simple change requiring so many code line changes really exhibits
how badly entangled the object relationship is.

Another commit will follow doing the same for dl tbf.

Change-Id: I010aa5877902816ae246e09ad5ad87946f96855c
2020-05-12 17:09:20 +00:00
Vadim Yanitskiy
f094b46d1c fix egprs_mslot_class_from_ra(): multislot class may not be present
For more details, see 3GPP TS 44.060, table 11.2.5a.2.

Change-Id: Iba0466b29afd26cff317ed4fb6749f8a3079f16a
Signed-off-by: Vadim Yanitskiy <axilirator@gmail.com>
Related: OS#1548
2020-05-11 20:06:39 +00:00
Pau Espin Pedrol
db9ea55c6e Use OSMO_FD_* instead of deprecated BSC_FD_*
New define is available since libosmocore 1.1.0, and we already require
1.3.0, so no need to update dependenices.
Let's change it to avoid people re-using old BSC_FD_* symbols when
copy-pasting somewhere else.

Change-Id: Ida8fd3bd7347163567acde34ad67aefee913b0ea
2020-05-09 19:18:06 +02:00
Pau Espin Pedrol
e6bca376aa bts: Return uint8_t in egprs_mslot_class_from_ra()
MultislotClass is 5 bit long, so an uint8_t is enough.
In most places we are already storing multislot class as uint8_t.

Change-Id: I1dcaff9d69379453a0b794e5f36b820f5f78531f
2020-05-08 16:37:25 +02:00
Pau Espin Pedrol
98eb03c391 bts: Fix Decoding EGPRS MultislotClass from 11-bit EGPRS PACKET CHANNEL REQUEST
In osmo-pcu datatructures, the variables holding multislot classes
simply contain an integer referring to the multislot class number,
instead of coding from 3GPP TS 44.060 Table 11.2.5.3 and Table
11.2.5a.3.

So coding Multislot class 3 is stored as 0x03 in osmo-pcu variables,
while in 3GPP TS 44.060 coding it's coded as 0x02 (N-1).
This allows us using value 0x00 to designate a "yet unknown (EGPRS) Multislot
class".
Hence, we need to add 1 to the decoded value to match our data
structures.

Change-Id: Id3b121272bb7e84c0542ae9b4ce09598c6054edd
2020-05-08 16:35:51 +02:00
Pau Espin Pedrol
9ee90d2323 bts: Rename mslot_class_from_ra
This function is actually returning an EGPRS multislot class, so let's
update naming. The variable using the return value was already being
passed as egprs_ms_class to tbf_alloc_ul_tbf().

Change-Id: Idb51836c8c9dd4e865bf2cb0b0c24155662f2ae8
2020-05-08 16:34:50 +02:00
Pau Espin Pedrol
acd67cbdf1 tbf: Avoid crash: don't set TBF window size if setup failed
Should fix assertion triggered due to the tbf not set up properly
beforehand.

Fixes: OS#4524
Change-Id: I267b147520ef5a50f40ad4bc19e7b5fb3e708127
2020-05-08 13:50:54 +02:00
Pau Espin Pedrol
20331ae5f6 pdch: Avoid sending GSMTAP_CHANNEL_UNKOWN for rejected UL EGPRS data block
Even if we don't accept it, let's submit GSMTAP with correct channel.
We don't return error like in code below, because otherwise the generic
UNKNOWN gsmtap message will be sent.

Change-Id: I853679ce8907d46fcb84ae4127335c10623f09c9
2020-04-29 21:02:12 +02:00
Pau Espin Pedrol
3301cc900e pcu_l1_if: Don't use GSMTAP_CHANNEL_PACCH when sending unknown gsmtap blocks
It's actually counter-productive when analyzing wireshark traces, since
one may not spot a decoding issue and assume PACCH is sent on the wrong
TS.

Change-Id: I7a96148f1ca1ebfa88a3ff714ea3bb8798866046
2020-04-29 20:56:31 +02:00
Vadim Yanitskiy
3f27fb56e4 TBF/UL: fix rcv_data_block_acknowledged(): print the actual TLLI
Change-Id: I71b5c656d4b318d11bd5fe2b5d163c3a06e09a6a
2020-04-20 13:18:49 +07:00
Vadim Yanitskiy
72ec18ce5a sba: fix possible memleak in SBAController::alloc()
Change-Id: I417eda155cd5b1e46dd0b05db3f507abd79121d1
2020-04-20 11:25:05 +07:00
Harald Welte
a4e8c10a38 TODO: remove those that have obviously been implemented 5+ years ago
The TODO file hasn't seen any updates sicne 2014, while the code has
evolved.  I'm not sure about some of the topics, but at least several
can for sure be removed by now

Change-Id: I56581c9b2a08edb1b6d4dc53ad9eb6fdd1800a0d
2020-04-17 16:02:26 +00:00
Eric
2e90a1f015 configure.ac: fix libtool issue with clang and sanitizer
As pointed out at https://github.com/libexpat/libexpat/issues/312
libtool does not play nice with clang sanitizer builds at all.
For those builds LD shoud be set to clang too (and LDFLAGS needs the
sanitizer flags as well), because the clang compiler driver knows how
linking to the sanitizer libs works, but then at a later stage libtool
fails to actually produce the shared libraries and the build fails. This
is fixed by this patch.

Addtionally LD_LIBRARY_PATH has no effect on conftest runs during
configure time, so the rpath needs to be set to the asan library path to
ensure the configure run does not fail due to a missing asan library,
i.e.:

SANS='-fsanitize=memory -fsanitize-recover=all -shared-libsan'
export CC=clang-10
ASANPATH=$(dirname `$CC -print-file-name=libclang_rt.asan-x86_64.so`)
export LDFLAGS="-Wl,-rpath,$ASANPATH $SANS $LDFLAGS"

Change-Id: I999adf84a34c03765ce6c32ece0e61d0ac6e1c13
2020-04-11 01:19:46 +02:00
Vadim Yanitskiy
b30f28f38d l1if: fix pcu_rx_rach_ind(): use proper format string specifiers
Change-Id: If95362ef4cc203a60856d6b47d95d441813a5c19
2020-04-02 05:42:57 +07:00
Pau Espin Pedrol
c374ab00ac csn1: Remove code block from CSN_NEXT_EXIST_LH
It was removed in wireshark.git e8407dd6c1378427daee77e8de540d0b5f7a0b73
and it's not there anymore in current master.

Change-Id: I73f4eeca3fd4f00a5bc4f06ef7a9bb9b8a70e37b
2020-03-30 10:08:02 +00:00
Pau Espin Pedrol
c8280a538a csn1: Properly verify CSN_BITMAP length
Change-Id: I9f7672b534f9345caff99095504749eebad25adb
2020-03-30 10:08:02 +00:00
Pau Espin Pedrol
f5e275aec0 csn1: verify enough bits present to decode whole CSN_UINT_ARRAY
Change-Id: I4a762a8fec4153b53e10df1ec8ba3708c1f47649
2020-03-30 10:08:02 +00:00
Pau Espin Pedrol
70a211747b csn1: Fix Several typos & whitespace
Change-Id: Ibe31d52d4a5a4015196d73681082f68b99a80c77
2020-03-30 10:08:02 +00:00
Pau Espin Pedrol
99eb353337 rlcmac: add dissection of 2G->3G/4G PS handover
Port from wireshark.git 428ee66ae1c524b49f9043729b1f1e9b4f52f409, from
Pascal Quantin.

The original commit is also changing the RRC_Container field to
M_CALLBACK, but we leave them as M_VAR_ARRAY since the callback is
basically used to add more dissection information in wireshark.

Change-Id: I0f374e78300efddff00c4df26a401adcdee18a12
2020-03-30 10:08:02 +00:00
Pau Espin Pedrol
f3ac06bbaf rlcmac: support decode FDD_CELL_INFORMATION of "UTRAN FDD Description
Port of patch (+ later fixes squashed) of wireshark.git commit
dea5452b95dfaf18e38670a8e2b3b38f9175fdfd, from Lei Chen:
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6856

Squashed wireshark.git fix commits:
774be29de0b4d93d01aecb1518c41d7d551071a9
51c31cd7bd3d8fc196a9f90a8af466ad84e9e6a8
6aca10831f86c562970b13efa811f46e25ee3091
c1ceac58cdb77051e9bd14c1f6f7669cf5779a86

Change-Id: I08523bc1bbdffde479ef974b4c7b56cfa5639591
2020-03-30 10:08:02 +00:00
Pau Espin Pedrol
b2653fe619 Move gsm_rlcmac.cpp -> .c
Original file from wireshark.git (packet-gsm_csn1.c) is being built and
maintained as a C file. There's no real need for us to maintain it as a
C++, and doing so will make both files derive over time (as already
happened). Let's keep it as a C compiler (which btw seems to be more
strict) to make it easier to port patches back and forth wireshark.git.

Take the chance to move some declarations we added to csn1.h to be able
to build it out of wireshark. Let's keep those in a separate header file
to ease looking for differences.

Change-Id: I818a8ae947f002d35142f9f5473454cfd80e1830
2020-03-30 10:08:02 +00:00
Pau Espin Pedrol
799cf8221a gsm_rlcmac: Disable unused CSN1 descriptors
When switching to C compiler, it will warn/error. Use #if 0 as in the
original wireshark.git epan/dissectors/packet-gsm_rlcmac.c code.

Change-Id: If1be50947c02208f15892d99edeb394fb4f52b75
2020-03-30 10:08:02 +00:00
Vadim Yanitskiy
d2e50e7f21 fix: properly include pure C headers from C++ code
Header files included from libosmocore may potentially contain
some language constructions allowed in C but not in C++, such
as type casting. Let's add 'extern "C" { ... }' and be safe.

Change-Id: I7197f7b34f30b49d5397506ce9d67cbf0e2cc196
2020-03-29 01:46:36 +07:00
Pau Espin Pedrol
a0cbde700a tbf.cpp: Include c++ <new> header required for new operator's replacement type
Including the <new> header is required as explained by the c++ specs [1]

osmo-pcu/src/tbf.cpp: In function ‘gprs_rlcmac_ul_tbf* tbf_alloc_ul_tbf(gprs_rlcmac_bts*, GprsMs*, int8_t, uint8_t, uint8_t, bool)’:
osmo-pcu/src/tbf.cpp:1002:39: error: no matching function for call to ‘operator new(sizetype, gprs_rlcmac_ul_tbf*&)’
 1002 |  new (tbf) gprs_rlcmac_ul_tbf(bts->bts);
      |                                       ^

Most of the times this issue is not detected because other STL headers
are already including <new>.

[1] http://www.cplusplus.com/reference/new/operator%20new/

Change-Id: Ie5fb536ae29dcf40e2a0dbe67432bebd61b8c7aa
2020-03-27 15:06:41 +00:00
Vadim Yanitskiy
ce160147f4 pdch: cosmetic: use GSM_MI_TYPE_* constants from libosmocore
Change-Id: I1d85c8eded68bc8aa8e90c33b36d335fa775ded2
2020-03-27 14:55:22 +00:00
Vadim Yanitskiy
d71c566ee6 pdch: fix packet_paging_request(): properly print paging MI
This problem problem was discovered by the Undefined Behavior Sanitizer:

  pdch.cpp:210:4: runtime error: load of misaligned address
                  0x60c00002abf2 for type 'uint32_t',
                  which requires 4 byte alignment

Do not convert TMSI to number, use osmo_mi_name() from libosmocore.
Also use this function to print other MI types (IMSI or IMEISV).

Change-Id: Icf8836f216793e342b239c8e6645aac1e82bf324
2020-03-27 14:55:22 +00:00
Vadim Yanitskiy
0b25f693b3 BSSGP: fix: properly encode P-TMSI in RR Paging Request
The TMSI/P-TMSI IE in BSSGP PAGING-PS/CS comes without the MI type
header, that must be present in RR Paging Request. Prepend it.

TTCN-3 test case: I7fbec5b2c5c3943a7413417b623f55c135c152d7

Change-Id: I97fd5ffc15a4a58112d7c37c69b7ac42b0741a0e
2020-03-27 14:55:22 +00:00
Vadim Yanitskiy
f497412f20 BSSGP: cosmetic use OSMO_IMSI_BUF_SIZE from libosmocore
Change-Id: I2079118100a3422e9c2ee63a5ac74e3ee81080b3
2020-03-27 14:55:22 +00:00
Keith
2b6acd8873 Don't check ul_control_block before decoding into it.
This patch corrects an error introduced in
6fd8ffb6fe
That commit allowed us to send the data over GSMTAP even
if the Uplink Control Block had invalid content,
that is to say, if decode_gsm_rlcmac_uplink() returned error.

However the check for ul_control_block->u.MESSAGE_TYPE
was place before decode_gsm_rlcmac_uplink()

Change-Id: Ic47602e5c6a13571b92c0a939fc3514110b82444
2020-03-26 23:32:49 +00:00
Pau Espin Pedrol
e5e2f747c3 csn1.h: Fix trailing whitespace
Change-Id: If17d36378fabeb7d22a513b93b0ecfde899df520
2020-03-26 16:03:56 +01:00
Pau Espin Pedrol
24fa27453f gsm_rlcmac.cpp: Avoid declaring variable in for loop
That's only allowed under C++.

Change-Id: I0da8849a0fb7f9a7ee5e726edea87e91dc411ea8
2020-03-26 16:03:56 +01:00
Pau Espin Pedrol
980ef1e38b cosmetic: Do not indent header includes inside extern C block
Change-Id: I3091d917a13e45b3aef8e52a53dcafa308581652
2020-03-26 16:03:56 +01:00
Pau Espin Pedrol
007056e4ad gsm_rlcmac: Use 'struct bitvec' instead of 'bitvec'
The later is only accepted when compiling as c++.

Change-Id: Ib5004643d4eff3bc9d11b66ddaf262f1c0d2aef6
2020-03-26 16:03:27 +01:00
Pau Espin Pedrol
754b093d16 pcu_l1_if.cpp: Add missing header ctype.h
The file uses the isdigit() function.

Change-Id: Id06ea25969ad9b964b3207479604132d25160f24
2020-03-26 14:49:04 +01:00
Pau Espin Pedrol
de63548f04 rlcmac: Rename field to MS RA Cap2 in Additional_MS_Rad_Access_Cap_t
This fix was spotted by wireshark.git developers while reviewing port of
osmo-pcu commit e50ce6e45c.

Related: https://code.wireshark.org/review/c/36574/
Fixes: e50ce6e45c

Change-Id: Ic5fc3252f61b6a042d9c3def7a6a32b311dd9d9e
2020-03-25 20:26:07 +01:00
Pau Espin Pedrol
10ec506cc9 cosmetic: rlcmac: Fix comment typo and whitespace introduced recently
Change-Id: Ie56898e11e2c9426393af0f6558d340c454fe6c4
2020-03-25 14:32:30 +01:00
Pau Espin Pedrol
e50ce6e45c rlcmac: Introduce MS Radio Access Capabilities 2 to fix related spare bits
There's two variants for the Ms Radio Access Capabilities.
* The usual encoding with spare bits (usually to fill up to octet boundary)
as defined in TS 24.008 Table 10.5.146
And there's too:
* MS Radio Access Capabilities 2 IE from TS44.060 section 12.30, which is
the same but removing all spare bits, and which is used in messages like
Packet Resource Request and Additional MS RAC messages.

The later is used basically for messages having extra IEs after the MS
Radio Access capabilities IE, since they are encoded immediatelly
afterwards.

So this patch does:
* Adds the expected spare bits (M_PADDING) to MS_Radio_Access_capability_t
* Creates a new MS_Radio_Access_capability2_t without padding
* Updates code to use the new "2" version where needed.

Note RLCMACTest long de/encoding line logs change only because the name
of the struct changes (the "2" is added).

Change-Id: Ibd756f80a03452a651e2771dbc628d701e55ac4b
2020-03-23 19:02:01 +01:00
Pau Espin Pedrol
20848c3ae5 rlcmac: Log names of de/encoded rlcmac packet types
Change-Id: I6a6e79d7e12cd5e8e969bf0eaa30ddac6b0aa7d3
2020-03-23 19:02:01 +01:00
Pau Espin Pedrol
7faa5da209 rlcmac: Fix bug receiving RA cap
It seems the assumptions regarding maximum number of RA capabilitites
in one message were wrong. Doing some rough calculations, each RA
capabilitiy value (without extensions) can take around 20ish bits, which
means for a message containing up to 52 bytes that quite a lot of
different values could be theoretically fed in. Let's be safe and
increase the array size to be able to handle all different access
technologies listed in See TS 24.008 table 10.5.146 following
restrictions:
* "The MS Radio Access capability is a type 4 information element, with a maximum length of 52 octets."
* "Among the three Access Type Technologies GSM 900-P, GSM 900-E and GSM 900-R only one shall be present."
* "the mobile station should provide the relevant radio access
  capability for either GSM 1800 band OR GSM 1900 band, not both".

Wireshark requires similar fix (it's not important though because it
currently uses another ad-hoc decoder for RAcap).

Related: OS#4463
Change-Id: I5334eaacfbc238fae8bea50c9e9667c2117f81ff
2020-03-23 19:01:58 +01:00
Pau Espin Pedrol
efad80bfbf csn1: Validate recursive array max size during decoding
This way if CSN1 encoded bitstream contains more elements than what the
defintion expects it will fail instead of overflowing the decoded
buffer.

RA cap struct placed in unit test is taken from a real android phone
sending the value when attaching to the network. Then SGSN sends it back
and osmo-pcu would crash similar to unit test:
*** stack smashing detected ***: terminated
 Process terminating with default action of signal 6 (SIGABRT): dumping core
at 0x4C62CE5: raise (in /usr/lib/libc-2.31.so)
by 0x4C4C856: abort (in /usr/lib/libc-2.31.so)
by 0x4CA62AF: __libc_message (in /usr/lib/libc-2.31.so)
by 0x4D36069: __fortify_fail (in /usr/lib/libc-2.31.so)
by 0x4D36033: __stack_chk_fail (in /usr/lib/libc-2.31.so)
by 0x124706: testRAcap2(void*) (RLCMACTest.cpp:468)

Related: OS#4463
Change-Id: I9fe0e55e0a6a41ae2cc885fba490c1d4a186231e
2020-03-23 15:34:11 +01:00
Pau Espin Pedrol
81b40cbaf3 rlcmac: Don't pass array element to CSN1 descriptors
This way the macros can be used to access the arrays themselves and
calculate its static size to enable validation later.

In the case of Packet_Access_Reject_t, modify the description to use a
M_REC_TARRAY_1 object to get rid of access to 2nd element. The new
description is the correct one, since the first element is mandatory
according to TS 44.060 Table 11.2.1.

Change-Id: I6f10350d4734360c7a15a702c72b59efd84987ee
2020-03-23 15:29:48 +01:00
Pau Espin Pedrol
866becefff tests/RLCMACTest: Several fixes and improvements to RAcap tests
It was recently discovered that the Racap value used for testRAcap was
actually malformed (it was taken from a TTCN3 test). It had the presence
bit for "EGPRS multislot class" set but no struct was put after it.

So let's move that malformed value to a new test named
testMalformedRAcap(). Since it doesn't make sense trying to re-encode or
do similar things with an initially malformed value, let's drop all
those parts in this new test.

For the old testRAcap() test, use a new bitstream this time with the
"EGPRS multoslot class" struct set inside (class 3).

Change-Id: I1e7f8d8866695732ee24a79d8b54d660fd4f22d5
2020-03-21 01:24:28 +01:00
Pau Espin Pedrol
2f16924959 tests/RLCMACTest: free allocated bitvectors
Change-Id: I6d1e93cb1a07a7bf05483dbc877105a86a17829b
2020-03-20 23:59:44 +01:00
Harald Welte
570f9135cd csn1.c: Almost all of the logging is DEBUG, not NOTICE
low-level text decodes of CSN.1 messages certainly are not NOTICEable
events, but rather something used for debugging.

Right now we get various text CSN.1 log output of osmo-pcu in it's
default configuration.  Despite all log levels being relatively high
(NOTICE), we still see those messages as they simply are logged
at the wrong level.

Related: OS#2577
Change-Id: I7b42c9e21ad8d8a5b54e7a3b68490934ce3d3198
2020-03-19 15:09:45 +01:00
Pau Espin Pedrol
de7bb75ccf Use downlink BSSGP RA Cap IE
This commit is basically a revert of
f4bb42459c, which disabled the code. That
commit claimed the SGSN may have providen inacurate or wrong data at the
time, but then it should be fixed in the SGSN.

Related: OS#1525, OS#3499
Change-Id: Ie36ae23203110018d4b5ae47591e0a64989e23a0
2020-03-18 14:01:24 +01:00
Pau Espin Pedrol
1de6873810 Use clock_gettime(CLOCK_MONOTONIC) and timespec everywhere
We should really be using monotonic clock in all places that
gettimeofday is used right now. Since clock_gettime() uses timespec,
let's move all code to use timespecs instead to avoid having to convert
in several places between timespec and timeval.
Actually use osmo_clock_gettime() shim everywhere to be able to control
the time everywhere from unit tests.

Change-Id: Ie265d70f8ffa7dbf7efbef6030505d9fcb5dc338
2020-03-16 10:31:56 +00:00
Vadim Yanitskiy
29aeb901e4 csn1: fix: do not return 0 if no bits left in the buffer
Both csnStreamDecoder() and csnStreamEncoder() shall not return 0
prematurely if no more bits left in the input / output bit-vector.

Returning CSN_ERROR_NEED_MORE_BITS_TO_UNPACK might make more sense,
however we don't know in advance (i.e. without entering the loop)
whether it's an error or not. Some CSN.1 definitions have names
like 'M_*_OR_NULL', what basically means that they're optional
and can be ignored or omitted.

Most of the case statements do check whether the number of remaining
bits is enough to unpack / pack a value, so let's leave it up to
the current CSN_* handler (pointed by pDescr) if no bits left.

Return CSN_ERROR_NEED_MORE_BITS_TO_UNPACK only if the number of
remaining bits is negative as this is an error in any case.

Change-Id: Ie3a15e210624599e39b1e70c8d34efc10c552f6c
2020-03-11 19:55:55 +00:00
Vadim Yanitskiy
773cb74ec8 rlcmac: fix encode_gsm_*(): do not suppress encoding errors
Change-Id: Ieec8e6e0823c6f6985f9d343af6d503b8fe9e6ab
2020-03-11 19:55:55 +00:00
Pau Espin Pedrol
40d4e35fb3 tests/llc: Change unrealistic time jump to avoid runtime error under ARM
When running the test under a RaspberryPI4:
+../../../src/llc.cpp:216:29: runtime error: signed integer overflow: 864197544 * 1000 cannot be represented in type 'long int'

864197544 comes from comparing initial insertion time and dequeue time
	  (test does a big jump in time): 987654321 - 123456777

let's use more realistic time changes, since the current one account for
about 37 years.

Change-Id: I28abc9192e0e7c590bc1c3c88950627cf669ffaf
2020-03-11 13:06:15 +01:00
Vadim Yanitskiy
bbafcc1602 tests/rlcmac: also enable logging for DRLCMACDATA category
Change-Id: Idf0808461f7e7a1bce58d11a54238c215126451a
2020-03-07 16:13:26 +07:00
Vincent Helfre
1145fd263c gsm_rlcmac: improve dissection of MS RA Capability IE
Port from wireshark.git de028e81c53f9c45ccc5adb3bffd2f16ae2017bf

This commit breaks transcoding of the test vectors containing
the MS RA Capability IE due to the reasons explained in [1].

The more fields we add, the longer gets the output of the CSN.1
encoder. This is not critical, since we never need to encode
messages containing the MS RA Capability IE on practice.

[1] Ibb4cbd3f5865415fd547e95fc24ff31df1aed4c0

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: Ibb4cbd3f5865415fd547e95fc24ff31df1aed4c0
2020-03-07 05:04:40 +07:00
Vadim Yanitskiy
2679ec0a9f csn1: fix csnStreamDecoder(): skip bits unhandled by serialize()
This change fixes a bug that was reported by Keith Whyte and
confirmed in [1]. The problem is that a user-defined handler
in case of CSN_SERIALIZE may parse only a part of the given
bit-stream, leaving some bits unhandled. This is expected
because the sender (i.e. the MS) may use more recent RLC/MAC
message definitions containing new fields at the end.

Those bits that were left unhandled by serialize() shall not be
interpreted as continuation of the message, they shall be skipped.

Note that the encoded vector in the RLCMAC unit test still does
not match the original one. That's a known bug explained in [2].

[1] If5873355d52d7ddb06c2716154a88d34100f6ab5
[2] Ic46d6e56768f516203d27d8e7a5adb77afdf32b7

Change-Id: Id4cc042fed68fc54aca0355dcb986cab3f6b49ea
Related: OS#4338
2020-03-06 21:49:04 +00:00
Vadim Yanitskiy
f22163b1df tests/rlcmac: add a new test vector for Packet Resource Request
This test vector (from HTC Desire 628) demonstrates a bug in the
CSN.1 decoder. For some reason, OsmoPCU fails to decode it:

  DCSN1 ERROR csnStreamDecoder: error NEED_MORE BITS TO UNPACK (-5)
              at EGPRS_TimeslotLinkQualityMeasurements (idx 164)

while Wireshark dissects it without any errors.

Change-Id: If5873355d52d7ddb06c2716154a88d34100f6ab5
Reported: https://osmocom.org/issues/4338#note-15
Related: OS#4338
2020-03-06 21:49:04 +00:00
Keith
6fd8ffb6fe Send UL-CTRL Packet to GSMTAP even if we fail to decode.
Move the call to send_gsmtap() before the call to decode_gsm_rlcmac_uplink() as if
the latter returns error we return and never get to see the packet on the GSMTAP.

Change-Id: Ia6af9f40590f28fcae3fef50d9c601d8435412cd
2020-03-05 19:51:06 -06:00
Pau Espin Pedrol
0daf913e0c gsm_rlcmac: fix Packet_Resource_Request_t: s/Slot/I_LEVEL_TN/
This is how this field is named in Wireshark.

Change-Id: I140443c48af8e4bb1b6279e6de986879b7d9c276
2020-03-02 13:33:23 +00:00
Vadim Yanitskiy
b47e53b5fa tests/rlcmac: also verify encoding of MS RA Capability
The main idea of this change is to demonstrate a weakness of the
CSN.1 codec that most likely causes a unit test breakage in [1].

The problem seems to be that the transitional structures, where
the CSN.1 decoder stores the results, do not contain any details
about presence of the optional fields (such as M_UINT_OR_NULL).

In other words, it's impossible to know whether some optional
field is omitted in the encoded message (NULL), or is it just
set to 0. This means that the encoder will always include all
optional fields, even if they're not present in the original
message.

[1] Ibb4cbd3f5865415fd547e95fc24ff31df1aed4c0

Change-Id: Ic46d6e56768f516203d27d8e7a5adb77afdf32b7
2020-03-02 13:33:23 +00:00
Pau Espin Pedrol
5fc6e010a5 llc_queue::{dequeue,enqueue}() refactor
As seen in OS#4420, setting the MetaInfo.recv_time outside of
llc_queue before calling llc_queue::enqueue() and later on using that
value in llc_queue itself at dequeue time is not a good idea, since it
can provoke errors if the recv_time was not set correctly.
For instance, LlcTest was not setting the value for recv_time on some
test, which ended up with a huge millisec value when substracting now()
from it:
"""
llc.cpp:215:29: runtime error: signed integer overflow: 1582738663 * 1000 cannot be represented in type 'long int'
"""
This issue only appeared when started building on a raspberrypi4.

Let's better set/store the MetaInfo.recv_time internally during
llc_queue::enqueue(). Then, enqueue() only needs the
MetaInfo.expire_time, so let's change its arg list to only receive that
to avoid confusions.

Take the chance to move the llc_queue APIs to use osmo_gettimeofday,
since we need to fake the time now that the API itself sets that time.

Also take the chance during this refactor to disallow passing null
pointer by default since no user needs that.

Finally, update the LlcTest accordingly with all API/behavior changes.

Related: OS#4420
Change-Id: Ief6b1464dc779ff22adc2b02da7a006cd772ebce
2020-03-02 12:05:06 +01:00
Vadim Yanitskiy
55f06c3d77 tests/rlcmac: fix malformed MS RA capability in testRAcap()
Long story short: as it turns out the test vector '12a5146200'O
has been generated by TITAN, and it's malformed. The length
indicator it contains must be at least 29 bits, not 21. This
field is calculated by TITAN automatically, so I guess there
is a bug somewhere in its RAW encoder implementation.

It's funny that Wireshark decodes the old malformed vector without
any problems if it's encapsulated into the BSSGP DL-UNITDATA. The
reason for that is because BSSGP dissector does not actually use
the CSN.1 codec and relies on its own hand-written parser [1],
which does not respect the length constraints.

Furthermore, table 10.5.146/3GPP TS 24.008, describing the format
of MS Radio Access Capability IE, has the following comment:

  < Multislot capability struct > ::=
    { 0 | 1 < HSCSD multislot class : bit (5) > }
    ...
  -- error: struct too short, assume features do not exist

so ideally our CSN.1 decoder should be more tolerant to the old
malformed vector, but unfortunately error handling is not implemented.

[1] See de_gmm_ms_radio_acc_cap() in epan/dissectors/packet-gsm_a_gm.c.

Change-Id: I5f810397b8d09c18e069168023429f6a4d899c86
2020-02-19 00:07:56 +07:00
Vadim Yanitskiy
e60d9c7e9d gsm_rlcmac: fix misleading LOGP statement in decode_gsm_ra_cap()
Change-Id: I48fd701566e1364ce7fccaa3e3a1a0296b932988
2020-02-18 05:30:57 +07:00
Vadim Yanitskiy
1553049226 csn1: use proper format specifier for unsigned integers
Change-Id: I33f86b79e72394bdb7d99762f8ec21d80e06dc30
2020-02-17 19:40:15 +07:00
Vadim Yanitskiy
4b57b6da54 csn1: bitvec_get_uint() may return a negative, use %d
Change-Id: I3cfd66643ec140150a4089b0e1c493d911d3d7d4
2020-02-17 19:40:15 +07:00
Vadim Yanitskiy
d8e5e8bb3b csn1: fix csnStreamDecoder(): update bit_offset in CSN_EXIST{_LH}
Found while doing differential analysis (comparison against the
original implementation from Wireshark).

Change-Id: Ibd0b7400d78f7873c2a8d45267332f511b5c6fbb
2020-02-17 18:35:37 +07:00
Vadim Yanitskiy
e87066d01e csn1: fix csnStreamDecoder(): always keep remaining_bits_len updated
Found while doing differential analysis (comparison against the
original implementation from Wireshark).

Change-Id: I9f7fa9c3f2f4ff5213dded930cee7ec509b9d799
2020-02-17 18:35:37 +07:00
Vadim Yanitskiy
584daba8e9 csn1: fix csnStreamDecoder(): do not subtract no_of_bits twice
Found while doing differential analysis (comparison against the
original implementation from Wireshark).

Change-Id: Id2a4f03035cd8354d3fba0ad37571453d3986d21
2020-02-17 18:35:37 +07:00
Vadim Yanitskiy
39a65056da csn1: get rid of C++ specific code, compile with GCC
The implementation of CSN.1 codec was taken from Wireshark, where
it's implemented in pure C. For some reason it was mixed with C++
specific features, mostly using references in parameter
declaration. Not sure what are the benefits.

Change-Id: I56d8b7fbd2f9f4e0bdd6b09d0366fe7eb7aa327a
2020-02-17 02:31:15 +07:00
Vadim Yanitskiy
8a87f913bd tests/rlcmac: additionally match debug output of the CSN.1 codec
This would allow us to catch more bugs. Note that I had to remove
printing of pointer address to make the output deterministic.

Change-Id: I1a77441eb957353c919bc73f8e3a2e38f4a383a9
2020-02-17 02:30:58 +07:00
Vadim Yanitskiy
74bc150ab2 csn1: fix existNextElement(): use bitvec_get_bit_pos()
As was discovered recently (see OS#4388), bitvec_read_field()
would never return a negative value because its return type
is unsigned (uint64_t).

We don't really need to get more than one bit, so let's just
use the bitvec_get_bit_pos() instead.

Change-Id: I763a295cd955cd33f542292c85d97ff82f6b49bc
Related: OS#4388
2020-02-16 23:41:26 +07:00
Pascal Quantin
fa5f91c05f gsm_rlcmac.cpp: fix global-buffer-overflow error reported by ASAN
Port from wireshark.git f751918476bdde65f2289b86245a3c30dace6730.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I70d4ff3e137b5fd13d367bd4ea6ab501e81e7a87
2020-02-15 09:28:27 +00:00
Pascal Quantin
fb65682d34 gsm_rlcmac.cpp: fix another global-buffer-overflow error reported by ASAN
Port from wireshark.git aa3bbe5aebdc180172e7956719b26199e4784fcc.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I808ec66011cdfe8e1193298f7fb7e92d25b45be4
2020-02-14 19:42:33 +00:00
AndersBroman
2d075be3b8 gsm_rlcmac: Update : PACKET RESOURCE REQUEST to Release 14.0.0
Port from wireshark.git 07fc801684ebff7aff02505cdb2c120caea846e0.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: Iceb59c58406180bc57fe6eb27127b4d11a0a3df7
2020-02-14 19:38:48 +00:00
Vadim Yanitskiy
9b2f7c420e tests/rlcmac: mark Packet Polling Request as malformed
It contails no valid identity, and thus violates the specs.
Let's keep it 'as-is' to check that decoder actually fails.

Change-Id: I663edfdaac0c065e08ab7b6dc50d2f18e433433c
Related: OS#4392
2020-02-11 21:47:15 +07:00
Vadim Yanitskiy
5574a58cd6 csn1: fix csnStreamDecoder(): catch unknown CSN_CHOICE values
After the recent changes [1], it was noticed that one of the unit
tests fails. In particular, a decode-encode cycle of Packet
Polling Request produces a different vector:

  vector1 = 49 13 e0 08 50 88 40 13 a8 04 8b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
  vector2 = 49 13 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
  vector1 == vector2 : FALSE

As it turns out, the original (input) vector itself is malformed
because it contails no valid identity, and thus violates the
specs. The CSN.1 decoder from Pycrate [2] throws an exception
while trying to decode it. I believe we should do the same.

Let's stop decoding the bit stream and return an error in case
if neither of a given list of the choice items matched.

[1] Ia0f8cc224a4c38e80699f834fd83d4c0d99322ea
[2] https://github.com/P1sec/pycrate

Change-Id: I420144773ed5e80372534e0f18db5e74cdb2999d
Fixes: OS#4392
2020-02-11 05:58:44 +07:00
Vadim Yanitskiy
fee767f21c csn1: fix some mistaken CSN.1 error names
Change-Id: I3bd9954ee36212c94f0c4d91581da300c56fce60
2020-02-11 05:28:02 +07:00
Vadim Yanitskiy
9a530a2430 encoding: assert return value of bitvec_set_u64()
Change-Id: Ic0de3ae34f06e41aacacb917f5a0214623259bdc
Fixes: OS#182120
2020-02-10 14:52:33 +07:00
Vadim Yanitskiy
9cbfe11ee2 tbf: fix NULL pointer dereference in create_[ul|dl]_ass()
The problem is that bitvec_free() is not NULL-safe. Ideally we
need to fix it in libosmocore [1], but let's also fix it here,
so OsmoPCU can be safely used with older libosmocore versions.

[1] https://gerrit.osmocom.org/c/libosmocore/+/17114

Change-Id: I7647d17b3d03f8e193ef6e793a2d3c1967744eef
Fixes: CID#208181, CID#208179
2020-02-10 14:12:24 +07:00
Vadim Yanitskiy
c74e217799 tbf: cosmetic: fix spacing in gprs_rlcmac_tbf::create_ul_ass()
Change-Id: Ice4c4db20551753fa4219e7a216309229f7a2ab5
2020-02-09 05:40:51 +07:00
Pau Espin Pedrol
ac2b866426 Fix trailing newline mess with LOGP(C) in rlcmac/csn1
Output was incorrect before this patch. LOPC was being called without
having any initial LOGP, and trailing newline was usually missing at the
end.

Since csnDecoder/encoder functions are recursive, it's difficult to
handle logging state in a coherent way inside them. Let's better simply
control start/end of logging related topics in the callers of those
functions, and simply use LOGPC everywhere in csn1.cpp.

Change-Id: I50da7560939fac360b7545e2a6bfaf45ed0c4832
2020-02-08 11:03:13 +00:00
Vadim Yanitskiy
3ff1a3c6d5 pcu_sock: cosmetic: fix typo in a comment message
Change-Id: Ia7e91d803152ac3f2af88f4552fced27f59d8270
2020-02-08 14:36:01 +07:00
Vadim Yanitskiy
8832c2e5d4 pcu_sock: fix memleak, allocate pcu_sock_state on stack
It was noticed that OsmoPCU leaks memory when trying to reconnect
to the BTS. It could be easily fixed, but we don't really need to
allocate the PCU socket state on heap as we never have more than
one connection.

Change-Id: Iea8930f443caa16f522f7c5375e0004e4e2315cb
2020-02-08 14:36:01 +07:00
Vadim Yanitskiy
d83c8ffb6b VTY: install talloc context introspection commands
Change-Id: I2e1e26be1162b0fb695969e5ac265704adaf9d5c
2020-02-08 14:36:01 +07:00
Vadim Yanitskiy
1ec29c7324 VTY: get rid of pcu_vty_go_parent() / pcu_vty_is_config_node()
Since I2b32b4fe20732728db6e9cdac7e484d96ab86dc5, go_parent_cb()
is completely optional. It no longer has the task to determine
the correct parent node. The is_config_node() callback is no
longer needed too. Get rid of them.

Since Ic5e69a396df659933fd4d50298b9925e837a6861 we depend on 1.3.0.

Change-Id: Id7ce8c4e1ac43747ad40a06d01433c366da07b42
2020-02-08 14:36:01 +07:00
Vadim Yanitskiy
28b4d27209 csn1: fix csnStreamDecoder(): avoid conditional calls to bitvec_read_field()
As was discovered by pespin, changing logging level of DCSN1 makes
the CSN.1 decoder behave differently (see OS#4375). In particular,
this makes RLCMACTest (encode / decode test) fail.

I did a quick investigation and noticed that some of the logging
statements call bitvec_read_field(). By definition this function
moves the internal pointer (current bit position) of a given
vector and increments readIndex by a given amount of bits.

The problem is that LOGPC would not evaluate its format string if
the logging message is not going to be printed, e.g. if a given
logging level is lower than the current one, or in case if
logging is not enabled at all.

The first two conditional calls to bitvec_read_field() are related
to CSN_PADDING_BITS, so that's not critical because padding is
always in the end of messages. The later two are related to
CSN_RECURSIVE_ARRAY and CSN_RECURSIVE_TARRAY respectively.

Let's use bitvec_get_uint() instead to keep readIndex unchanged.

Change-Id: Ia331048db9f790ca407fd341ced01df12d10a233
Fixes: OS#4375
2020-02-06 16:19:47 +00:00
Pau Espin Pedrol
ea9de4ae25 rlcmac: Transform a few LOGPC messages to LOGP
Those messages are self contained and don't need LOGPC.

Change-Id: Iea79e030563cd29bfc9750ff5c3e398c590a7307
2020-02-05 17:27:48 +01:00
Pau Espin Pedrol
5e300ce565 Check return code of rlcmac decode/encode functions
Change-Id: Iabcb768bd714680aa768b35c786dea2015d1e451
2020-02-05 17:26:02 +01:00
Pau Espin Pedrol
47de23266d rlcmac: Return error code from csn1 encoder/decoder
Change-Id: I0c5e1b870608b0622b239791effd5c5878e230bc
2020-02-05 17:25:59 +01:00
Pau Espin Pedrol
d636f74923 csn1.cpp: Rework ProcessError() function to print errors
Same API is kept to more easily keep code compatibility with wireshark's
packet-csn1.c implementation.

Change-Id: I1ce2c52e2357841aa1f31babfdce9011435f866b
2020-02-05 11:44:46 +01:00
Pau Espin Pedrol
f960d5bcf4 cosmetic: csn1.cpp: Fix whitespace
Change-Id: I663c5c20a878b3643db6a8ddd58e29bc9fe93d80
2020-02-03 14:39:38 +00:00
Vadim Yanitskiy
3568fcfa7d gprs_bssgp_pcu: fixup: fix length check in gprs_bssgp_pcu_rx_dl_ud()
Change-Id: I7d49b27a615350a7707154aa3cc903db7c1df374
Fixes: I7f84bd776cc780a45880f136107f6e0bc56241d1
2020-02-03 16:39:12 +07:00
Vadim Yanitskiy
3898cd6843 gprs_bssgp_pcu: fix invalid use of non-static data member 'frame'
The 'gprs_llc' is defined as a pure C structure with C++ specific
extensions (methods), so it's rather a class. Accessing its field
'frame' statically causes Clang to throw a compilation error:

  gprs_bssgp_pcu.cpp:111:29: error: invalid use of non-static data member 'frame'
      if (len > sizeof(gprs_llc::frame))

Let's avoid this and use LLC_MAX_LEN as the size limitation.
God knows what to expect from such a mix of C++ and C...

Change-Id: I7f84bd776cc780a45880f136107f6e0bc56241d1
2020-01-29 06:17:50 +07:00
Vadim Yanitskiy
9f62b92258 tests/alloc: fix implicit conversion from 'double' to 'int8_t'
Looks pretty much like a typo. Both '-1' and '.' symbols are
neighbours in QWERTZ keyboard layout, so it must be -1.

Found by Clang [-Wliteral-conversion].

Change-Id: Id4eb2dcc3b44e18096c7b94efb7260e2400c596b
2020-01-29 06:17:50 +07:00
Vadim Yanitskiy
f6b83a24a3 encoding: fix log_alert_exit(): do not treat error as format string
This is rather a cosmetic change aimed to make ASAN / Coverity happy.
In general, we never pass any input from an untrusted source.

Change-Id: I26d654da4c3bf5fd86a298c3027fd9820c932308
2020-01-29 06:17:49 +07:00
Vadim Yanitskiy
4590b91728 gsm_timer: fix comparison of constant LONG_MAX with an integer
It does not make sense since INT_MAX is always less than LONG_MAX.
Found by Clang [-Wtautological-constant-out-of-range-compare].

Change-Id: I9934e05aa050bf93b3c795376f5dca3a848a7e11
2020-01-29 06:14:54 +07:00
Vincent Helfre
e525bf94ba gsm_rlcmac: add dissection of NAS container
Port from wireshark.git 575e4df4aa3392ffd09ca372859573f09f0a5c57

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I2a05a057b6f441364502a96f9f34872c7e251a36
2020-01-28 18:16:24 +01:00
Pascal Quantin
e4a243c02b gsm_rlcmac.cpp: fix an out of bounds access
Port from wireshark.git a4a5adb68b898f770e2addf9168d796979ebe237.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I23fb2199fc8f9cc3e5bd475e2558ee8d482df1e1
2020-01-28 18:08:29 +01:00
Pascal Quantin
463746917f gsm_rlcmac.cpp: Do not skip too many lines of the CSN_DESCR when the field is missing
Port from wireshark.git c4ead251da7199cfd746d378c51eb8c30d09a6ba.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: Ib9b8eafd69d3b45b0d631ba9635689807b472b73
2020-01-28 18:03:59 +01:00
Anders Broman
8ea3cbe6b2 gsm_rlcmac.cpp: hanged all M_BIT macros to M_UINT, as M_BIT does not use the referenced hf.
Port from wireshark.git e97273a35d101516decbc7d98fcc6c6b3f193962.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: Id20d31e9ebd851b45d5f3280f3e229d8d7ae2cea
2020-01-28 17:42:34 +01:00
Pau Espin Pedrol
034e32f0eb gsm_rlcmac.cpp: Fix trailing whitespace
Change-Id: I3b50cf386d417ba73b97f48b3000f69d9a54c8c9
2020-01-28 17:14:26 +01:00
Pascal Quantin
29248d6941 gsm_rlcmac: Enhance dissection of PSI1
Port of wireshark.git 7e9411fee3a101b53693210f7a38789fd4c70ba2.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I89d488c1f349c556e40a9d13895b1309d5140212
2020-01-28 17:13:39 +01:00
Pascal Quantin
cc76d412fd gsm_rlcmac.h: Remove Uplink messages from the RlcMacDownlink_t structure
(as they are part of the RlcMacUplink_t structure that is also used to call csnStreamDissector function).

Port from wireshark.git commit 9f8b638cfa8a660fb64c54dcadb83e6747db0a15.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: If46f8cc3f21f527f911dcac6ff1b78f182104a00
2020-01-28 16:46:51 +01:00
Gerald Combs
bc4f3930a9 gsm_rlcmac.h: Make sure we have a corresponding 'u' member to RlcMacDownlink_t for every call
Port from wireshark.git commit 6c32ba5ff1a5f5ec2426d1d2c4f4f37fd136bab0.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I989befc56fa37b8f982301f4f9aa4f4533e3e87a
2020-01-28 16:38:39 +01:00
Bill Meier
bcc6408cd1 gsm_rlcmac.h: #if 0 unused stuff
Port of wireshark.git 2ef0c615946cd290aa9463c637169da0a1ca7972.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: Ia2e80664d293a2a95372213b4164c3e72259e0bb
2020-01-28 16:17:41 +01:00
Alexis La Goutte
e36fb5b802 csn1: fix this statement may fall through [-Werror=implicit-fallthrough=] found by gcc7
Port of wireshark.git commit fd68c7dfc7d06ce7babe914f2575d9e4f35988ad.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: Ibaf47d7c4fdff326ac1dccf6fff77e2357e6a2bd
2020-01-28 13:45:03 +01:00
Pau Espin Pedrol
900c2e277a csn1: Drop format_p union from CSN_DESCR
Port of wireshark.git 8626bb4cbb4d9926f7b56663585d9ef66252f93f.
We don't really need the other fields added there, let's keep only the
value out of the union.

Change-Id: Ia8889252ee7518a919a15d749815c2803b4b23cd
2020-01-28 13:43:45 +01:00
Anders Broman
771da85a11 csn1: Try to fix cast discards '__attribute__((const))' qualifier from pointer target type
Port of wireshark.git 1ff6213c949b373bcb7de5c48a5a4f805093066f.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: Ie14c335a904a17333e98ef58bf5e40245444e956
2020-01-28 13:43:24 +01:00
Guy Harris
e26467c4ed csn1: Don't cast away constness
Port of wireshark.git commit 8e22ded7f8537e37e89ba558c83702d127443ae8.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I100d5c43d8878e660035bf4a64718771f41a38a8
2020-01-28 13:42:29 +01:00
Anders Broman
60bf845f25 csn1: Fix warning with -Wmissing-prototypes
Port of wireshark.git 2e52e2ac997ca58caabee3270b5a6c3f96159ff0.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: Ic69a75ce3f01cea326139f678b963110e895c356
2020-01-28 13:41:21 +01:00
Pascal Quantin
c515551625 csn1: Fix an infinite loop in CSN.1 dissector when having more than 255 padding bits
Port of wireshark.git 8b5aa913711b32b1e1bc707919d2a98c1875d443.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I7f6aecc2c0f300c1a77cd683652969d3f1aa5794
2020-01-28 13:40:14 +01:00
Pau Espin Pedrol
5b71697618 csn1: Fix pedantic compiler warnings in csn.1 dissectors
Port of wireshark.git commit 6aca10831f86c562970b13efa811f46e25ee3091.

    From Mike Morrin:
    Fix pedantic compiler warnings in csn.1 dissectors.

    There is some tricky casting going on in csn.1 structures.  To eliminate all
    the warnings, the function pointers needed to be moved out of the object
    pointer unions.  Fortunately macros (mostly) hide these changes from the
    protocol dissector tables.

    https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7686

    svn path=/trunk/; revision=44899

Change-Id: Ia1a8c50c4b024ca6df4e3fbbf891cd33591ccc9b
2020-01-28 13:38:42 +01:00
Pau Espin Pedrol
7cce825fa4 csn1: Allow CHOICE elements to re-process the bits used for the choice
This is a port of wireshark.git commit
2f024256bf337400ef3a82fa75e6d48d5707e059.

From 78516187d821b8d19d16987b1d6bc855ee7cbe10 Mon Sep 17 00:00:00 2001
From: Sylvain Munaut <tnt@246tNt.com>
Date: Sat, 4 Feb 2012 10:00:22 +0100
Subject: [PATCH 4/6] packet-csn1: Allow CHOICE elements to re-process the bits used for the choice

We may want to display more detail, or the sub-element should be
displayed with its headers or whatever ...

Change-Id: I3a5a95d5f918b8f17a2400a6d0c4d855ecacea7e
2020-01-28 13:38:42 +01:00
Pau Espin Pedrol
98e4c53cad csn1: Extend CSN_SERIALIZE to allow 0 bit of length
Port of wireshark.git 2f024256bf337400ef3a82fa75e6d48d5707e059.

From c6ee558d3bb00bfd25cca7c534448bf60df3c7cf Mon Sep 17 00:00:00 2001
From: Sylvain Munaut <tnt@246tNt.com>
Date: Sat, 4 Feb 2012 10:24:01 +0100
Subject: [PATCH 6/6] packet-csn: Extend CSN_SERIALIZE to allow 0 bit of length

In some coding there is no 'length' field at the top of a serialized
block, or it's more complex than a single field, in which case we
have to rely on the serialize decoder to consume the correct number
of bits.

We extend the CSN_SERIALIZE processing so that if a '0 bit' length
field is specified, then the length is not displayed and the
consumed bits by the serialize function is taken as the length
at posteriori.

The processing keeps the same behavior for any length > 0.

Change-Id: I9fadc99218594447001f7bb9943f4514b9877799
2020-01-28 13:38:42 +01:00
Jeff Morriss
c0b4f4a633 csn1: shuffle decrements of remaining_bits_len
So that they always occur next to an increment of bit_offset.

Port from wireshark.git 1c81971d4292438ffdf83e9f9b9ab96c133c785b.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I7474e9d632e068d6e33b0a502b81d4fff1f48802
2020-01-28 13:37:50 +01:00
Anders Broman
c0190c8a5a csn1: packet-csn1.c:179: warning: 'pui8' may be used uninitialized in this function
Port from wireshark.git commit fd9f182f4b13a3d81b1b5c797a6e4b9d6d327fdd.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I37f5f3732f92cd7340af8ac1e04383f3e45e7636
2020-01-28 13:34:36 +01:00
Anders Broman
72c102acf8 csn1: Update M_NULL CSN_DESCR to match wireshark
Port from iwireshark.git commit cc6d4341e65ef2e8d8488fe0ac0f236ece0dd844.
It looks like it makes no difference to us now, but other EGPRS messages
may use it in the future.

Ported-by: Pau Espin Pedrol <pespin@sysmocom.de>
Change-Id: I34039370c292e62790a38abb59f55c69fffa88e8
2020-01-28 13:34:08 +01:00
Pau Espin Pedrol
cdbc5dbd1c tests/rlcmac: Add test to showcase that decode_gsm_ra_cap() fails
Currently code using that function in osmo-pcu is disabled, allegadly
because SGSN was sending incorrect values, but it looks more like a CSN1
issue.

Related: OS#1525, OS#3499
Change-Id: I92c86397f988afaa791871d823a45fa85054f3bb
2020-01-28 13:29:42 +01:00
Pau Espin Pedrol
ea39fade07 tests/rlcmac: Don't check stderr output
Current stderr output is empty anyway, and not checking it allows
enavling different log levels to easily debug issues.

Change-Id: I5b12e919e08a6eeaad31a459e5a15fdee4d76a61
2020-01-24 13:01:23 +01:00
Pau Espin Pedrol
87bfbe4fe2 tests/rlcmac: Use osmo_hexdump to print buffers
Old method takes lots of lines of codes and prints inn unconfortable way
because left-trailing zeros are dropped, making it difficult to split in
bytes.

Change-Id: I56c24f934824e4e52a91a7273aec384b2e15aa67
2020-01-24 12:42:03 +01:00
Pau Espin Pedrol
5cb002f0ef tests/rlcmac: Fix missing commas with unexpected results
Change-Id: Ia0f8cc224a4c38e80699f834fd83d4c0d99322ea
2020-01-24 12:42:00 +01:00
Pau Espin Pedrol
99c437b7c7 tests/rlcmac: Memzero decoded struct
Otherwise final output is undefined.

Change-Id: I9b501b8a99473b4d79279f8a3a9854e0b2eb3284
2020-01-24 12:34:50 +01:00
Pau Espin Pedrol
54681c3ffe tests/rlcmac: print test name at the start
Change-Id: Ib8f0fcbd6bb68d77727c021f0d90d5248e895772
2020-01-23 21:59:23 +01:00
Vadim Yanitskiy
bd0b0b3242 pcu_l1_if.cpp: fix NULL-pointer dereference in imsi2paging_group()
Passing NULL to strlen() would lead to a segmentation fault.

Change-Id: I838e3a21a3b25c2bc8260f67d156c6cc284f4456
Fixes: CID#207484
2020-01-16 00:25:54 +07:00
Pau Espin Pedrol
771de1f439 Support PAGING-CS and PAGING-PS on on PTP-BVCI
Related: OS#2403
Change-Id: I5c52b5af740460c48bb3ba858243b1d20e624268
2020-01-06 10:26:46 +00:00
Pau Espin Pedrol
65a0d1d19b Support Gb PAGING-CS
The paging is sent over PACCH towards MS with an active TBF.

Related: OS#2406
Change-Id: I9501e02e1d7f6944497e724dbccb9a19c3f5221f
2020-01-06 10:26:46 +00:00
Pau Espin Pedrol
5530f12f71 Allow Gb PAGING-PS without P-TMSI
P-TMSI is optional IE, but IE is mandatory and hence always available.
Since the encoding is actually a Mobile Identity, the IMSI is used in
case P-TMSI is not available.

Change-Id: I4dbf8db04e81f98352a42ce34a5d91326be9bfd1
2020-01-06 10:26:46 +00:00
Pau Espin Pedrol
d7c3265223 Pass paging group instead of imsi where later is not needed
Change-Id: Id0663a81f439f2d0b893b0d34f85a6db1927ef8e
2020-01-06 10:26:46 +00:00
Pau Espin Pedrol
b507e428e8 Bump version: 0.7.0.62-fbfa-dirty → 0.8.0
Change-Id: Ic5e69a396df659933fd4d50298b9925e837a6861
2020-01-03 19:40:02 +01:00
Pau Espin Pedrol
fbfab297ee Split identity_lv param into mi+mi_len
It's not really needed to have those together in some function calls,
and makes it more difficult to follow the code. Furthermore, new callers
not having content already aligned (len+value) will be using these
functions in forthcoming commits.

Change-Id: Ifb9d3997bfb74b35366c3d1bc51ce458f19abf16
2020-01-01 16:10:15 +00:00
Pau Espin Pedrol
db12f254ce Log BVCI PTP value upon msg recv
Change-Id: I47c5902112d568cd5a48e003010d8085b02d64e8
2020-01-01 16:10:05 +00:00
Pau Espin Pedrol
506eb23dc5 fix typo in log message
Change-Id: Ib6fc4625242d855193b62b561624b23b265648b9
2019-12-31 17:01:34 +00:00
Pau Espin Pedrol
585cfb28b8 Fix trailing whitespace
Change-Id: I0515b5c8f6744fa501de88fa7808b7fc91981f0e
2019-12-10 20:02:21 +01:00
Pau Espin Pedrol
3f064f516d prs_bssgp_pcu.cpp: Mark priv funcs as static and remove trailing whitespace
Change-Id: I93b7ee33cc33c773675c85ace7b8f1afa86fbf06
2019-12-10 17:09:51 +01:00
Pau Espin Pedrol
32499b614b pcu_l1_if: Check pag_req id_lv len fits buffer
Related: OS#4316
Change-Id: I803e1d2577a0d210e74feb5ca4c216375a5024ea
2019-12-09 13:55:14 +01:00
Pau Espin Pedrol
30f6617c79 tbf_dl.cpp: Fix typo in log line
Change-Id: I9fdea4246c95897f3e72604981597db828a219a3
2019-12-04 18:11:52 +01:00
Pau Espin Pedrol
d0fc9e80fe Remove dash from name used in VTY cmd prompt
Others projects don't contain a dash in there, and it seems to cause
problems with TTCN3 VTY expectations.

Change-Id: I3430abb5fc622dec293457466e760de95fa3a05c
2019-12-02 11:14:26 +00:00
Harald Welte
3a61b920f2 manual: Add missing documentation for '-i' command line option
Change-Id: Iec0f2ecd610e63baba46a63d3e1a0979a9d8c5a8
2019-12-01 14:32:54 +00:00
Harald Welte
f6d282822e manual: Fix documentation missing "-D" command line option
Change-Id: I2fd0b6f52ddc6931f413921b45d9756cb1fe456d
2019-12-01 14:32:54 +00:00
Harald Welte
c925ccccfc manual: Fix copy+paste error
Change-Id: I27744628edeca6895f50f84c6f2f04c2e6e2de0b
2019-12-01 14:32:54 +00:00
Vadim Yanitskiy
657a4c0ccd VTY: cosmetic: use osmo_talloc_replace_string()
Change-Id: Id09c7d24b48ddecfa96404c3e75330465a11f830
2019-11-30 20:17:25 +07:00
Vadim Yanitskiy
fc75cc0ecf VTY: add warning about changing PCU socket path at run-time
Change-Id: I7cee2d782bd3dfc2cc8d2febc16dca905dcc294e
2019-11-30 20:17:21 +07:00
Pau Espin Pedrol
1e6eb30f51 Clarify (M)CS related VTY attributes
Some are used to control (M)CS values for downlink while some do it for
uplink. Let's make clear which one is used for what. Take the chance to
document the fields a bit better than they were.

Some more information about the origin of cs_downgrade_threshold can be
found in the commit introducing it: 70b96aa232.

Related: OS#4286
Change-Id: I4e890e924b094a1937fbd3794de96704cf0421a8
2019-11-28 17:11:56 +01:00
Pau Espin Pedrol
1d8497ba6a doc: vty: Update osmo-pcu_vty_reference.xml
Change-Id: I287893cabf0468f0c110eb751eb887f58ff238c0
2019-11-28 17:09:09 +01:00
Vadim Yanitskiy
ffebd24456 PTCCH: properly handle RACH.ind for PCU_IF_SAPI_PTCCH
Change-Id: I482d60a46b9d253dfe0b16140eac9fea6420b30c
Related: OS#1545
2019-11-23 17:42:45 +07:00
Vadim Yanitskiy
17954da56c pcuif_proto.h: extend RACH.ind with TRX / TS numbers
Since there can be multiple PDCH channels configured on different
timeslots, different TRXes, and BTSes, the PTCCH/U handling code
in OsmoPCU needs to know the exact origin of a given RACH.ind.

Otherwise, it is not known which subscriber originated a given
PTCCH/U indication, and hence it is impossible to send PTCCH/D
Timing Advance notification properly.

Fortunately, we can extend the RACH.ind message without even
bumping the protocol version, because every single PDU has a
fixed size defined by the largest message - INFO.ind. In case
if the actual message payload is smaller, the rest is filled
with a constant padding byte (0x00).

Older versions of OsmoPCU will consider the new fields as padding,
while the messages from older OsmoBTS versions will always have
both fields set to 0x00. Since C0/TS0 cannot be configured to
PDCH, this can be easily detected on the other end.

Change-Id: If209001885ffb14b64a8e808df3700d85a4b2ef9
Related: OS#1545
2019-11-17 02:58:35 +07:00
Vadim Yanitskiy
78f58618f3 PTCCH: properly handle RTS.req for PCU_IF_SAPI_PTCCH
Change-Id: Ib204acce1a7e33f6651b9da2a7b4a9b9ae461093
Related: OS#1545
2019-11-17 02:58:31 +07:00
Vadim Yanitskiy
bd0dac3783 PTCCH: implement basic message codec and API
Change-Id: Id79e95aafdde4a71977c64385fce48b729a51ca9
Related: OS#1545
2019-11-17 02:35:18 +07:00
Vadim Yanitskiy
0bf622e057 gprs_bssgp_destroy(): fix memleak and NULL-pointer dereference
So far there was a memory leak, because free()ing 'the_pcu.bctx'
would cause ASAN to complain. And that's reasonable, because it
needs to be freed properly. Moreover, 'the_pcu.bctx' may simply
be uninitialized in some cases, e.g. when OsmoPCU is terminated
before connecting to the SGSN.

Let's use the new bssgp_bvc_ctx_free() from libosmogb.

Change-Id: I274e79e1746c7678b81720ec11e8a564befe38ba
Depends: Ia78979379dbdccd6e4628c16f00d0c06d9212172
2019-11-10 09:04:21 +00:00
Vadim Yanitskiy
fd734de4d1 GprsMs::update_cs_ul(): clarify the meaning of old_link_qual
Change-Id: Iad703a573621c64613b9b8c229079dc63fcaeb9e
2019-11-08 06:20:55 +07:00
Vadim Yanitskiy
87b6e7dbed tests/tbf: suspend warnings about the link quality measurements
Share a single instance of 'pcu_l1_meas' between all unit tests,
set initial measurement values in main(). This way we can get
rid of the following warnings:

  Unable to update UL (M)CS CS-X because we don't have link quality measurements.

Change-Id: I1c82076df6cd0833d243e1e6afb140bae3bd2ec9
Fixes: OS#3828
2019-11-08 04:44:07 +07:00
Vadim Yanitskiy
ce27d1e126 BSSGP: properly print BVCI for signalling messages (BVCI=0)
Change-Id: I4ac0f48d2e62cd0545e8a1e1b26c9e43ef5e8dde
2019-11-08 04:18:46 +07:00
Vadim Yanitskiy
ef444142c8 BSSGP: do not reject SUSPEND ACK / NACK messages
Both BSSGP SUSPEND ACK and NACK messages use BVCI=0 (signaling),
which always exists. Claiming that BVCI=0 is unknown is wrong.

Instead of adding both BSSGP_PDUT_SUSPEND_{ACK,NACK} to the 'if'
statement, let's rather avoid rejection for all BVCI=0 messages,
as there may be other unlisted message types.

Change-Id: I780657c1e8f67e0bef0e92a31db7ba61b57d7ec4
Related: OS#4111
2019-11-08 04:11:20 +07:00
Pau Espin Pedrol
05bca3524a Fix assertion hit upon CCCH Paging Request
Recent commit added an assertion to check for buffer boundaries and it
actually gets hit.
One of the 2 code paths calling pcu_l1if_tx_pch() was passing a buffer
of 23 bytes while one of maximum 22 is expected (because plen is not set
in the buffer but set inside pcu_l1if_tx_pch()).
So it seems before the assert, that code path was actually writing 1
byte outside the boundaries of data buffer, since bitvec_pack() uses
data_len field of bitvec.

Related: OS#4228
Fixes: 8dc09e73d0
Change-Id: I84c5dfd4d5580e9d4c00ed21887cb51bd9abbd2e
2019-10-16 14:36:28 +02:00
Alexander Couzens
b3b0c49d1c encoding: fix space, tabs
Change-Id: I80ac88f50bfedfd2b86d548883313b5a187b1e8f
2019-10-09 17:14:17 +00:00
Vadim Yanitskiy
cef2f843b4 VTY: fix command 'show tbf all': properly filter TBFs
For a long time the VTY command to show all active TBFs was broken.
The TBF filtering (by allocation origin) logic allows one to show
TBFs allocated on CCCH, PACCH, or on both of them. In the latter
case we have been checking whether a TBF was allocated on both
logical channels at the same time.

Let's fix this by passing a flag-mask instead of boolean arguments.
To be able to use GPRS_RLCMAC_FLAG_* definitions from "tbf.h", let's
exclude them from "#ifdef __cplusplus ... #endif" block.

Change-Id: I1c9f401368af880a97d32905c4cce0da481ffc21
2019-10-09 22:00:54 +07:00
Vadim Yanitskiy
afbf189ef2 VTY: refactor pcu_vty_show_ms_all(): use show_ms()
Change-Id: I72aa1a1de22602a3ad2a4d19604ae0935c88c750
2019-10-09 20:26:47 +07:00
Pau Espin Pedrol
d752d7cebe pcu_l1_if.cpp: Replace value 23 with libosmocore's GSM_MACBLOCK_LEN
Change-Id: Ieec3dd028fffa1a735afaaf3f93da0a1202d122a
2019-10-07 21:04:19 +02:00
Pau Espin Pedrol
8dc09e73d0 pcu_l1_if.cpp: Imm Assign PCH: clarify size of different items
Change-Id: I32876858e3e93951e965b0fc7875c95c1f36f3ac
2019-10-07 21:04:19 +02:00
Pau Espin Pedrol
f681f07cd0 pcu_l1_if.cpp: Drop unneeded byte in Imm Ass PCH buffer
paging group is 3 bytes and imm assign with plen prepended is 23 bytes,
so there's 1 extra byte not needed and makes code confusing.

Change-Id: Id7835e5aa1506505ff54e019b38f30111f79b5dc
2019-10-07 21:04:19 +02:00
Pau Espin Pedrol
2ccb6aef89 pcu_l1_if.cpp: Fix GSMTAP Imm Assign PCH wrong encoding
Wireshark expects to receive the plen in order to decode it.

Fixes: 58543709e4
Change-Id: I91d1354689300b949760cdbaee03294eab958e12
2019-10-07 18:26:10 +02:00
Pau Espin Pedrol
58543709e4 Log AGCH and PCH blocks using GSMTAP
Change-Id: I4d62f98801af1b0a290d3dd35bd213ccf3151035
2019-10-01 10:38:55 +02:00
Pau Espin Pedrol
1ec211f57f Log RACH Requests using GSMTAP
Change-Id: Ib686a49e8c630808c30bede5810cd65fc045954a
2019-09-30 20:15:54 +02:00
Pau Espin Pedrol
1879442443 vty: Fix osmo_tdef timers not listed in write config
Change-Id: I5c7ae18919e4b016505aa01eea6694d8a3f5df5f
2019-09-26 18:25:35 +02:00
Pau Espin Pedrol
f4c77e686a tbf_dl.cpp: Remove dup call to tbf_update_ms_class() in state GPRS_RLCMAC_WAIT_RELEASE
tbf_update_ms_class() is already called two lines above in the common
path.

Fixes: 409efa1ec8
Change-Id: Icbe3805c72a5c77366215be55128b586e5a00fb7
2019-09-26 14:43:22 +02:00
Pau Espin Pedrol
ad586a9fe4 tbf_dl: Setup m_llc_timer in constructor using osmocom API
Change-Id: I3e761b319326e33ab1d56c4fb30cafe3b0f96c29
2019-09-26 14:43:22 +02:00
Pau Espin Pedrol
bddf1ad7f6 Move tbf_{dl,ul} child constructors to respective .cpp files
Fixes: 9d1cdb1f69
Change-Id: Id258589d46de42ad4e27889bc396f930b7f94b79
2019-09-26 14:43:22 +02:00
Pau Espin Pedrol
9d1cdb1f69 Move out tbf subclasses from tbf.h to their own headers
It's a good start towards clearing current mess between parent and the 2
children classes.

Change-Id: Ibc22ea2e02609af7ee058b8bc15df2115d4c6f60
2019-09-25 17:50:06 +02:00
Pau Espin Pedrol
488aa29083 cosmetic: fix whitespace
Change-Id: I45bbe4d3c69d573aaff010d16f338c7ec3eaf08a
2019-09-25 17:50:06 +02:00
Pau Espin Pedrol
e13cdc503e pdch.cpp: Use pcu_l1_meas previously filled by lower layers
Otherwise, a new meas object is allocated in the stack in upper layers
which doesn't contain the link_qual information (have_link_qual=0),
outputting following error:

osmo-pcu/src/gprs_ms.cpp:644 Unable to update UL (M)CS CS-2 because we don't have link quality measurements.

Change-Id: I1980ca325c8d65f3f6310fa697dd810eec7ab077
2019-09-25 13:52:31 +02:00
Pau Espin Pedrol
812d466bbd pdch.cpp: Refactor bitvec param passing in rcv_control_block
Move code in rcv_block_gprs() only needed for rcv_control_block() into
the later. This way rcv_block_gprs() is simplified and shows similar
code paths with regards to rcv_data_block().
It can now be seen that the main difference between both is the meas
param no being passed in the control case.

Change-Id: I2a0133463edced93c72ccc743a0cf00d1d6922cf
2019-09-25 13:35:13 +02:00
Oliver Smith
04797b1e35 configure.ac: set C and C++ dialects
Make sure that the compiler always assumes the same C dialect, to
prevent unexpected compiler errors when building with older compilers
(on other Linux distrubtions like in OBS, or in docker).

Use gnu89 and gnu++03, because that is what the code currently compiles
with.

Related: https://lists.osmocom.org/pipermail/openbsc/2019-September/013030.html
Related: OS#3598
Change-Id: Ia57ba101627e3cc0babeca82631e207a3e2e0960
2019-09-18 14:28:43 +02:00
Oliver Smith
2beb1b85e0 tests/app_info: fix compiling with older g++
Do not use C++11 extended initializers to prevent the following error.

AppInfoTest.cpp:109:54: error: extended initializer lists only available with -std=c++11 or -std=gnu++11
  pcu_prim.u.app_info_req = {0, 15, {0xff, 0x00, 0xff}};

I ran into this when modifying the gerrit build verification job to
build with docker (which still uses GCC-4.9).

Related: OS#4204
Change-Id: I307cd87af88e86804a90d6466e9cc3909bfe701f
2019-09-18 13:58:42 +02:00
Pau Espin Pedrol
2b5c629055 Use osmo_tdef to implement dl-tbf-idle-time
Change-Id: I5e4f0d2f90e643600b7752525d6c2830856c9d3b
2019-09-17 11:11:04 +02:00
Pau Espin Pedrol
63700ead34 Use osmo_tdef to implement ms-idle-time
This commit would also remove the option from config_write_pcu() since
it's automatically filled in by osmo_tdef, but there was actually a bug
because that param was never printed when saving the config...

Change-Id: Id8e70b0f44ef2f7e20ecdb3fd8ca93ae2a05b9a3
2019-09-17 11:05:45 +02:00
Pau Espin Pedrol
474dc77894 tests: TbfTest: Unify stderr and stdout to ease debugging
osmo-pcu code is really verbose, and since log lines printing start and
end of tests are sent to a different file, it's really difficult to
understand which test outputs what.

Change-Id: I3e887158e2c9585c360d44f12f995f55861170f2
2019-09-16 14:21:21 +00:00
Pau Espin Pedrol
38cfa734f4 Use osmo_tdef to implement T3190
Change-Id: I0c767c526398d98ca47ef98fdaccfc23af11fb0d
2019-09-16 14:21:21 +00:00
Pau Espin Pedrol
5211d9deca Use osmo_tdef for BSSGP T1 and T2
Change-Id: I477e5b702c8b956136d93fc1cee01991233e381f
2019-09-16 14:21:21 +00:00
Oliver Smith
cfb6321b88 Forward ETWS Primary Notification to MS
Receive an Application Information Request from the BTS via PCU
interface. Construct a Packet Application Information message from it
(3GPP TS 44.060 11.2.47) and send it to all MS with active TBF.

The TTCN-3 test infrastructure to test this feature is not quite ready
yet, so I've added C unit tests instead.

Related: OS#4048
Change-Id: Ie35959f833f46bde5f2126314b6f96763f863b36
2019-09-14 15:28:43 +00:00
Pau Espin Pedrol
5360ef5447 bts.cpp: Fix osmo_tdef initialization on older g++ compilers
Fixing errrors spotted:
bts.cpp:78:1: error: uninitialized const member 'osmo_tdef::T'
 };
 ^
bts.cpp:78:1: error: uninitialized const member 'osmo_tdef::default_val'
bts.cpp:78:1: error: uninitialized const member 'osmo_tdef::unit'
bts.cpp:84:1: error: uninitialized const member 'osmo_tdef::T'
 };
 ^
bts.cpp:84:1: error: uninitialized const member 'osmo_tdef::default_val'
bts.cpp:84:1: error: uninitialized const member 'osmo_tdef::unit'

Change-Id: I2dfecf22516f52cc19e0a0442e70dbc4dbc61336
2019-09-13 12:42:38 +02:00
Alexander Couzens
e46d8dcaab tbf_dl: add comments to the scheduler
Change-Id: Ib037f9fda30472313c7a82effb1e925c6abebbe5
2019-09-12 16:49:21 +00:00
Pau Espin Pedrol
28f160e76c Introduce osmo_tdef infra and timer VTY commands
This will allow for configuration of some of the timers by the user,
and allow him to inspect current values being used.
It will be also useful for TTCN3 tests which may want to test some of
the timers without having to wait for lots of time.

Timers are splitted into 2 groups: BTS controlled ones and PCU controlled
ones. The BTS controlled ones are read-only by the user (hence no
"timer" VTY command is provided to change them).

TbfTest.err output changes due to timers being set up correctly as a
consequence of changes. Other application such as pcu_emu.cpp and
pcu_main.cpp had to previosuly set the initial values by hand (and did
so), but apparently TbfTest.c was missing that part, which is now fixed
for free.

Depends: libosmocore.git Id56a1226d724a374f04231df85fe5b49ffd2c43c
Change-Id: I5cfb9ef01706124be262d4536617b9edb4601dd5
2019-09-12 14:17:07 +02:00
Oliver Smith
45fdc44d68 tbf_dl: make preemptive retransmission optional
Since [1], OsmoPCU already starts to retransmit downlink blocks before
the MS has had a chance to receive them and/or send the related
acknowledgement in uplink. Make this optional with the new VTY option
"no dl-tbf-preemptive-retransmission".

[1] e25b5b91f6 ("tbf: Only create dummy frames if necessary")
Related: OS#2408
Change-Id: Id08aed513d4033aa0d4324c6ce07cbb2852f2f92
2019-09-11 06:16:29 +00:00
Oliver Smith
37ae22ab13 doc: update generated VTY reference
Change-Id: I6243a2856df9db0f06e704e51e87113f9b57bb36
2019-09-11 06:16:29 +00:00
Pau Espin Pedrol
a8892a69b3 Use proper API osmo_timer_setup() to set up timer struct
Change-Id: Idd2b0c5247870bee3b3c3e460a6731ee50a47404
2019-09-05 16:21:49 +02:00
Pau Espin Pedrol
ef1fe58e19 cosmetic: tbf: Rename T and N arrays
Those namings my collide with usual osmocom "T" variable name associated
to a timer number, which will be added in following patches.

Change-Id: Ic2b5068a4882e4a043bf81496be30a378fdb9a09
2019-09-05 14:40:26 +02:00
Vadim Yanitskiy
df0fd8ba27 osmobts_sock.cpp: do not print the same debug message twice
The following message is printed by the pcu_tx_txt_ind():

  DL1IF INFO pcu_l1_if.cpp:113 Sending XXX TXT as PCU_VERSION to BTS

There is no need to print it twice:

  DL1IF INFO osmobts_sock.cpp:74 Sending version XXX to BTS.
  DL1IF INFO pcu_l1_if.cpp:113 Sending XXX TXT as PCU_VERSION to BTS

Change-Id: Ic2793f20cf9df2fa08c45070a8f81ef1c08b925a
2019-08-27 11:06:11 +02:00
Vadim Yanitskiy
9e5ef54594 osmobts_sock.cpp: pcu_sock_read(): further simplify the code
Change-Id: Ie7c0ca8baf0ae5beadda60bda0bc76a44664d439
2019-08-27 11:06:00 +02:00
Vadim Yanitskiy
c7849c2dfe osmobts_sock.cpp: pcu_sock_read(): use stack buffer, not heap
We don't really need to use the message buffer (on heap), because
it's never getting passed to pcu_rx(). Let's use a buffer on stack.

Change-Id: I4cb8ca80513df7b71e1438da2e82799be6be1fa0
2019-08-23 18:03:37 +02:00
Vadim Yanitskiy
aef6bf43e5 osmobts_sock.cpp: pcu_sock_cb(): use libosmocore's socket API
Change-Id: I7f5c7f5744ab14f36f46cf7941e91352eca8d2b9
2019-08-23 18:03:37 +02:00
Alexander Couzens
2585451408 tests: test encoding of egprs ul ack/nacks
Test the encoding with uncompressed and compressed acknowledgements.

Change-Id: I35d6b5e312faeb116ddda6b33c550840da1496fe
2019-08-12 08:40:04 +00:00
Pau Espin Pedrol
19b15a5b93 Bump version: 0.6.0.88-3bcc → 0.7.0
Change-Id: I98719f38c490b70983f2dca24ef743abc00b7d28
2019-08-07 21:09:53 +02:00
Pau Espin Pedrol
3bcc7ab418 Require newer libosmocore to avoid compile failures
Older commit started using OSMO_IMSI_BUF_SIZE, only available in
libosmocore 1.1.0 onwards, but forgot to increase the values in
configure.ac.

Fixes: 2c076bcb4d
Change-Id: Iaf5f276a092c695a5f077551d9784652c2289424
2019-08-07 21:07:49 +02:00
Pau Espin Pedrol
cd2ac56bd4 Remove undefined param passed to {logging,osmo_stats}_vty_add_cmds
Since March 15th 2017, libosmocore API logging_vty_add_cmds() had its
parameter removed (c65c5b4ea075ef6cef11fff9442ae0b15c1d6af7). However,
definition in C file doesn't contain "(void)", which means number of
parameters is undefined and thus compiler doesn't complain. Let's remove
parameters from all callers before enforcing "(void)" on it.
API osmo_stats_vty_add_cmds never had a param list but has seem problem
(no "void"), so some users decided to pass a parameter to it.

Related: OS#4138
Change-Id: Ic1ac815eafab49577ff883a5d700ecca5936d216
2019-08-05 14:30:47 +02:00
Vadim Yanitskiy
2c076bcb4d gprs_bssgp_pcu_rx_dl_ud(): use OSMO_IMSI_BUF_SIZE
Change-Id: Ia1da9f005b7f801872c542d31cc8eabd859d997a
2019-07-24 20:39:57 +00:00
Vadim Yanitskiy
6170ac041f gprs_bssgp_pcu.cpp: check return code of gsm48_mi_to_string()
Change-Id: Id1ad279ce9bef38eb3d11ac62337276207e8d8bd
2019-07-24 20:39:57 +00:00
Vadim Yanitskiy
aad87b66e8 gprs_bssgp_pcu_rx_dl_ud(): fix: BSSGP_IE_IMSI is optional
Change-Id: I940d220a399166122f33e67a222dd572085e1401
2019-07-24 20:39:57 +00:00
Eric Wild
ab8b01effd ubsan: fix shift
Ubsan complains about shifts into the sign bit due to automatic int
promotion, so cast explicitly.

Change-Id: I6387c7313832f6c7c920e1016b74562b66d6b68e
Related: OS#4029
2019-07-24 19:28:38 +00:00
Harald Welte
7b7f2048b8 bssgp: Fix dead code: PDUT_STATUS can never reach this part
Change-Id: Iae4332cd3b87f37164655d3df16554de4876159d
Closes: CID#188855
2019-07-21 09:26:56 +02:00
Thorsten Alteholz
8bb7904458 fix spelling errors detected by lintian
Change-Id: I381618eb55cc513cfa9c2e384c27cead0935c8bf
2019-07-17 10:56:19 +00:00
Max
f3038e7b2a Use libosmocore for IMSI parsing
Change-Id: Iec5c65776fc54b2f9e5dd55c711ace2471662db1
2019-07-16 04:19:21 +00:00
Vadim Yanitskiy
f17dfc062a src/pcu_l1_if.cpp: fix: properly pass measurements from PCUIF
The recent versions of OsmoBTS do provide the following measurements:

  - RSSI (Received Signal Strength Indication),
  - ToA (Timing of Arrival),
  - BER (Bit Error Rate),

as well as C/I (Carrier-to-Interference ratio) since [1] (OS#4006).

[1] https://gerrit.osmocom.org/r/Ia58043bd2381a4d34d604522e02899ae64ee0d26

Change-Id: I0fd6c35e8cf0b1314f4e3c336b233b5f7e42dfc6
Related: OS#1855
2019-07-16 04:11:20 +00:00
Alexander Couzens
210ccf4a1d Encoding: ACK/NACK: always encode with length field present
In most cases the length field was present and this field takes 7
bits of the maximum available 110 rest bits.
The length field was only removed when encoding huge bitmaps usually
only happen on lossy connections with packet lost.
However the cases without length field were encoded incorrect,
because all remaining bits must be used by the uncompressed bitmaps,
but the PCU violates this by encoding always the "release 5" bit.
Rather than fixing the encoding without length field, simply remove it
and always encode with length field. This also reduces the code
complexity.

Change-Id: I7bc2e18d647b72b8f17ba7a5c9c5e421d88275fb
2019-07-11 18:38:45 +02:00
Oliver Smith
5c3a9880ca contrib/jenkins.sh: run "make maintainer-clean"
Related: OS#3047
Change-Id: I733df8f8bfaf448a6507c9c9d75d2f076fedb342
2019-07-11 03:38:37 +00:00
Alexander Couzens
e4e70d052e Encoding: use uint16_t when interacting with the window object
The ESN, SSN and uncompress bitmap len are uint16_t. The Window is using uint16_t in
function arguments and return values. Don't do so many integer conversions.

Change-Id: If62fa09d7bfa8e91ce707824f7019edb1b83da9e
2019-07-11 03:23:52 +00:00
Alexander Couzens
fba931bab6 bts.cpp: ensure left-shift operation does not exceed uint32_t
Found by Asan
Relates: OS#4029
Change-Id: I21640e40e689016d6fb80a8db4257b22e85b303b
2019-07-11 03:22:15 +00:00
Alexander Couzens
243a204021 Encoding: write_packet_ack_nack_desc_egprs: don't use a reference for rest_bits
The rest_bits are never read after calling this function nor are rest_bits
updated properly.

Change-Id: Ic350b0365b125638a6c752f692bef981ad6b9d89
2019-07-11 00:27:15 +02:00
Alexander Couzens
2d24eba903 decompress_crbb: add length argument for search_runlen
search_runlen() must know the exact size in bits when parsing
the bits otherwise it read over the buffer.
Fixes testcase #7 which was wrongly decoded.

Change-Id: Ie34a0651e7e7efea4e9ecff1e3a467588113cf47
2019-06-24 13:51:06 +00:00
Alexander Couzens
3a499f3cb2 Encoding: drop struct gprs_rlcmac_bts* from all functions
The bts is not used at all.

Change-Id: Ia07755e825913a16352ab13f6cf55f2918de8681
2019-06-24 13:48:43 +00:00
Alexander Couzens
0d482c5c97 rlc: replace int with uint16_t
The i value will only count forward and is limited to 11 bit. The integer is also
converted when returning to uint16_t

Change-Id: Ib8a9081bbcb8b4344498254c58941002d17f9381
2019-06-24 13:48:09 +00:00
Keith
1f0ca54bba Cosmetic: Osmcoom -> Osmocom
Change-Id: I02c6b2655df54ca40717ce7609013d0bc54eabdf
2019-06-24 10:59:24 +02:00
Alexander Couzens
7fe3895b46 tests/BitcompTest: fix wording in log message
The testcase is showing the compressed rbb.

Change-Id: Ie7a2b31e305dffb2776698d1bc8e80d6a435c135
2019-06-22 15:52:09 +02:00
Daniel Willmann
79c6c4db3b manuals: Update VTY documentation
Related: OS#1700
Change-Id: I4a5da9b2b1caa625754383b0f9a180e7503bc60e
2019-06-19 12:43:02 +00:00
Daniel Willmann
76791d20f5 manuals: Add script to regenerate vty/counter documentation
Change-Id: Iff570e85828c87d69a7a49a00d9459094077ca30
Related: OS#1700
2019-06-19 12:43:02 +00:00
Alexander Couzens
6d73205280 egprs_rlc_compression: fix white spaces
Change-Id: I43a5acc2dda4ba567ada9846880e31c85bc98394
2019-06-17 02:04:09 +02:00
Alexander Couzens
b7439f28a1 encoding: use /* */ for comments instead of #if 0 #endif
Change-Id: Ifff9526b15bfda7a0f85c92bcb0d3fabab61ca32
2019-06-17 02:03:18 +02:00
Alexander Couzens
3f640773f3 encoding: correct encoding of CRBB in ACK/NACK when not byte aligned
The last bits of the CRBB (compressed receive block bitmap) was incorrect
encoded when the CRBB is not byte aligned.

Related: OS#3728
Change-Id: I7261aa71b37d7ead52992f8db462f72a3804988e
2019-06-13 21:26:12 +00:00
Alexander Couzens
5c3783b7e8 gprs_bssgp_pcu: explicit allocate & initialize bssgp_nsi instance
The instance bssgp_nsi is a global instance to be used by all
NS related functions. Previous the PCU allocated and initialized
the bssgp_nsi instance when (re-)connecting and freeing on disconnect.
The problem of the implicit initialisation is gprs_ns_vty_init(bssgp_nsi).
All vty init functions must be called before the configuration is read,
otherwise a previous vty written configuration is invalid.
Furthermore the vty modifications to the `ns` object were lost when the PCU has to
reconnect to the SGSN.

Fixes: OS#4024
Change-Id: I2aa53ea54e9352577f6280ad7b9d1d9da9f57eaf
2019-06-07 01:17:53 +02:00
Oliver Smith
a558ad4269 debian: create -doc subpackage with pdf manuals
I have verified, that the resulting debian packages build in my own OBS
namespace (see the -doc packages):
https://download.opensuse.org/repositories/home:/osmith42/Debian_9.0/all/
https://build.opensuse.org/project/show/home:osmith42

Depends: Ib7251cca9116151e473798879375cd5eb48ff3ad (osmo-ci)
Related: OS#3899
Change-Id: I9f2e7cfd93ee0b13d064c606a20378c1ea01400e
2019-05-29 12:14:18 +02:00
Alexander Couzens
eb64d43922 gprs_bssgp_pcu: make gprs_bssgp_ns_cb public
rename the function sgsn_ns_cb -> gprs_bssgp_ns_cb.
To allow writing and reading the same configuration, the pcu needs to register
all vty commands before reading the configuration. This callback
is required to register NS based vty commands

Related: OS#4024
Change-Id: I440c0df2e32fe22bf43288c00bb4aa3a0c6a3a51
2019-05-25 05:56:32 +02:00
Max
41d6b35670 Add test for MS mode and (M)CS settings
Right now set_mode() on GprsMs behaves in pretty counter-intuitive way:
* it's possible to set current DL MCS higher than max value
* EGPRS and EGPRS_GMSK have the same max DL MCS
* setting EGPRS* mode drops current/max MCS values to unknown

Let's capture this in a unit-test before attempting any further
modifications.

Change-Id: Ibf917f4b49d927a21cbd467775806fa6ea06a6a6
2019-04-11 07:29:53 +00:00
Rafael Diniz
0e6e45a65f Fix help message formatting of osmo-pcu.
Change-Id: If4ecf9be5a0739bb54aedb077eda51ad091b4c3f
2019-04-08 19:28:02 +00:00
Max
34513feff9 cosmetic: use const pointer for bts_data
It's used several time for logging so let's call it once to make code
easier to follow.

Change-Id: Icfd9e5603a5d8701f487f17e9c0335d458e9e80b
2019-04-08 07:36:11 +00:00
Max
902e3e58db Update MCS selection for retransmission
In 3GPP TS 44.060 the selection of MCS for retransmissions is defined as
separate tables (8.1.1.1 and 8.1.1.2) depending on the value of
resegmentation bit (which is opposite to the way EGPRS_ARQ are defined
in the source code). Let's follow the same idea and explicitly check for
resegmentation bit value and use separate tables. This also makes it
easier to add proper support for special cases (MCS-6-9 and MCS-5-7) and
padding in future independently for different ARQ types. The code is
also moved to c to avoid unnecessary conversions to and from cpp class.

Change-Id: Ia73baeefee7a58834f0fc50e3b8bf8d5e3eb7815
2019-04-08 07:35:19 +00:00
Max
12a0987b36 vty: add commands to show TBF of a certain kind
Add vty commands to show only TBFs allocated via PACCH or CCCH.

Change-Id: I80f8df4fe663a0346f4289a4220b761e39726312
Related: OS#1759
2019-04-08 07:35:00 +00:00
Max
0e6ac799f7 TS alloc: expand tests log
* restructure code for easier reading
* use consistent formatting for output
* log essential allocation parameters on failure

Change-Id: I4b78951a79ddbc0745b39d091080a4e0e247d3c5
Related: OS#2282
2019-03-28 08:58:41 +00:00
Daniel Willmann
8ab35b14e9 jenkins.sh: Add oc2g build support
Related: OS#3749, SYS#4524
Change-Id: I014e5e59bc5e904a616ddf50ebfb8247f0d428cf
2019-03-27 14:26:22 +01:00
Daniel Willmann
32518cce5a oc2g: Change log type (Litecell15->Oc2g)
Change-Id: I95ced5da1c89dae5a16963b10b005747277f320b
2019-03-27 14:23:17 +01:00
Daniel Willmann
f57dccbbfb oc2g: Remove custom alarms
Don't try to send custom alarms that weren't included in upstream.

Change-Id: I51de826aa732a3875d75396b46b7d2821ef7417c
2019-03-27 14:21:15 +01:00
Minh-Quang Nguyen
ba66ea4406 OC-2G: Always use positive TA information provided in PH-RA-IND
From-Commit: 960aa3d1b0b1
From-Remote: https://gitlab.com/nrw_noa/osmo-pcu
Change-Id: Ia526f712b95eb7bba99252f2a348d9fb5d2f3838
2019-03-27 14:20:21 +01:00
Minh-Quang Nguyen
2ba608415b OC-2G: Fix TA adjustment
Problem:
 TA provided from L1 PH-DATA-IND is a relative amount of TA adjustment to actual TA
 being used for given TBF. The current TA update algorithm in PCU simply applies the relative
 amount of TA to given TBF but does not take into account of current TA.
 As a result, the PCU will request wrong TA jump for given TBF if the MS is moving away from
 BTS more than 2 km.

 Related issue: http://osmocom.org/issues/2611

Fixes:
- The PCU needs increase or decrease current TA of given TBF on receiving of relative
  amount of TA adjustment provided by PH-DATA-IND from L1.
- The PCU needs to set absolute TA of given TBF on receiving absolute TA provided by
  PH-RA-IND from L1.

From-Commit: 139ad3f42193
From-Remote: https://gitlab.com/nrw_noa/osmo-pcu
Change-Id: I7665586dd5722bbe04632ee5673d3033bc082324
2019-03-27 14:19:40 +01:00
Minh-Quang Nguyen
4a1796fe76 OC-2G: Fix missing header
From-Commit: a9eefb54c62a
From-Remote: https://gitlab.com/nrw_noa/osmo-pcu
Change-Id: Ida0592c9da74588a57d9d2d5be40fcf79edcb596
2019-03-27 14:18:30 +01:00
Jean-Francois Dionne
c1e44908fe Initial commit for OC-2G support.
From-Commit: b77fd00608dd
From-Remote: https://gitlab.com/nrw_noa/osmo-pcu
Change-Id: I7cd89a549c9463e81893ca7dd925299f728e4453
2019-03-27 14:16:41 +01:00
Max
3fa235fe01 Update IA Rest Octets encoding
Write initial bits of 3GPP TS 44.018 §10.5.2.16 IA Rest Octets the same
way as  write_ia_rest_*() routines do.

This should also fix the issue addressed in
I75dd5bebc74eea85edf9582607c774d0bba0d2a6 initially by properly encoding
L/H bits.

Change-Id: I7ed5270bf95c3f6e9e026ff447eef8539f6f0314
2019-03-27 12:32:04 +00:00
Max
d4a39291e0 TBF-DL: cosmetic update for helper routines
* use enum values where appropriate
* reformat to proper code style to improve readability

Change-Id: If1d2bc69b0d43fc520e579457007704b7975117e
2019-03-27 12:32:04 +00:00
Max
fb59a93425 TBF: update MCS counters
* use enum CodingScheme directly instead of converting it to class and
  back
* drop useless mode check
* log errorneous update attempt

Change-Id: I763136c2f356d63aa3d28d09c57fd5faf5336258
2019-03-27 12:32:04 +00:00
Max
e742cc0997 Use Timing Advance Index in UL assignments
Write TAI (if available) when generating Rest Octets for UL
Assignment. This should not affect actual PCU behavior because TAI is
not yet supported by upper layers but we have to adjust corresponding
tests anyway.

That's updated version of reverted commit.

Change-Id: I69407793bdb863be5fc42adadf75842d22f27335
Related: OS#3014
2019-03-27 12:32:04 +00:00
Max
3eb47363ad Rewrite Packet Uplink IA Rest Octets for SBA
Use bitvec_set_*() directly without external write pointer tracking to
simplify the code. This is part of IA Rest Octets (3GPP TS 44.018
§10.5.2.16) which is the last part of the message so it should not
interfere with the rest of encoding functions.

The difference in the expected test output is due to proper handling of
TAI which should not be transmitted for SBA according to the Note in
Table 10.5.2.16.1 in 3GPP TS 44.018.

The change was manually tested against real mobile phone using options
'gprs mode gprs' in osmo-bsc.cfg and 'two-phase-access' in osmo-pcu.cfg
to make sure appropriate code path is actually triggered.

That's partially based on reverted commit 93d947f5e8.

Change-Id: I97d53c27c1ca9e032d431b3aa7f915027d63ddc0
Related: OS#3014
2019-03-27 12:32:04 +00:00
Max
0367ddd62b Rewrite Packet Uplink IA Rest Octets for MBA
Use bitvec_set_*() directly without external write pointer tracking to
simplify the code. This is part of IA Rest Octets (3GPP TS 44.018
§10.5.2.16) which is the last part of the message so it should not
interfere with the rest of encoding functions.

That's partially based on reverted commit 93d947f5e8.

Change-Id: Ibe294b26ac374b9264a734db9663cacc105a4474
Related: OS#3014
2019-03-27 12:32:04 +00:00
Max
6e96dd4665 Fix Channel Coding Command for MCS
Previously result of ".to_num() - 1" was used without any checks which
means that in case of to_num() returning zero we would effectively try
to encode (uint8_t)(-1).

Let's fix this by using proper mcs_chan_code() function which returns
Channel Coding Command for MCS without the need to further correct it
and adjust expected tests output accordingly.

Change-Id: I868062a81fffe6714a811c032215f25a79259905
2019-03-27 12:32:04 +00:00
Max
898dddb1d1 MCS: add Channel Coding Command encoder
Add function to encode MCS value as proper EDGE or GPRS Channel Coding
value according to 3GPP TS 44.060 and corresponding helpers.

Use it for everything except IA Rest Octet encoding which is done in a
follow-up patches to make sure that we distinguish between
encoding-related changes to test output and unrelated changes.

Change-Id: I127fb29f5aaf77a7f6c4c565dfeb3b711af9845d
2019-03-27 12:32:04 +00:00
Harald Welte
48b1e7a86f gprs_debug: Use named initializers and explicit array indicies
This is a much safe way, it allows for modifications of the debug
subsystem enum member values without breakage.  Also, the syntax
introduced here is what we do in all other Osmocom CNI projects.

Change-Id: I2be88586ca44b0b8361f96cf3c034c8459244c2c
2019-03-27 07:39:02 +00:00
Harald Welte
3447c4a8a4 Forward GPRS SUSPEND REQ from BTS to SGSN using BSSGP
As specified in 3GPP TS 03.60 Section 16.2.1 and 44.018 Section 3.4.15,
a Class B MS is sending a "RR GPRS SUSPEND REQ" via a DCCH to the BTS if
it wants to suspend GPRS services.  As of
Change-Id I3c1af662c8f0d3d22da200638480f6ef05c3ed1f, OsmoBTS forwards
this via the PCU socket, so we need to pick it up and send it via BSSGP
to the SGSN.

Change-Id: I7b4beb413a6f974373a404b5a11c44d86ba695d3
Closes: OS#2249
2019-03-27 07:39:02 +00:00
Harald Welte
1473b377c2 pcu_l1_if: Fix erroneous endian-swapping of the CellID
In Change-Id I787fed84a7b613158a5618dd5cffafe4e4927234 in February 2018
we accidentially introduced a change that would erroneously swap
the endianness of the CellID on the way between PCUIF socket and
BSGSP.  This meant that all OsmoPCU based BTSs would report the
wrong CellId to the SGSN.

Closes: OS#3854
Change-Id: I2f6cc930c5dbf8dac386b24b0756df2efe8199e4
2019-03-27 07:39:02 +00:00
Max
8a8e0fb267 MCS: add mcs_is_*() helpers
In preparation for Channel Coding Command encoder in follow-up patches
let's add necessary helpers. Those are similar to previously used
helpers from GprsCodingScheme class but without CamelCase and with less
typo chances between Gprs and Egprs cases.

Change-Id: I6699cbc8d7ae766fa4d2b3d37e5f9ff1cf158b7e
2019-03-26 11:19:30 +01:00
Daniel Willmann
fb3fd09353 Include pdch.h in bts.h even if we're not compiling C++
bts.h needs pdch.h whether we're compiling C or C++ code so move it out
of the #ifdef.

make[1]: Entering directory '/home/daniel/scm/osmo/oc2g/osmo-pcu-oc2g/src'
  CC       osmo-bts-oc2g/oc2g_l1_if.o
In file included from osmo-bts-oc2g/oc2g_l1_if.c:39:
./bts.h:74:26: error: array type has incomplete element type ‘struct gprs_rlcmac_pdch’
  struct gprs_rlcmac_pdch pdch[8];
                          ^~~~

Change-Id: Ib39e4424f73c677b34f921917440f211e400e14f
2019-03-26 09:29:17 +00:00
Max
a4de02db5d MCS: move Mode enum outside of class definition
Move Mode (EDGE/GPRS) definition and related functions outside of
GprsCodingScheme class. This allows us to use standard libosmocore
value_string functions.

Change-Id: I3baaac7f1ca3f5b88917a23c1679d63847455f47
2019-03-24 18:54:52 +01:00
Max
02fbfc15c7 Fix TA index encoder
The TAI is described as { 0 | 1 < TIMING_ADVANCE_INDEX : bit (4) > } in
3GPP TS 44.018 §10.5.2.16.1 so it should be encoded with if-else.

Change-Id: I54482790e1cf3cb13a635a99a481250576deabaf
2019-03-19 18:27:49 +01:00
Max
a0353547b1 TBF-DL: log MCS as string
Log MCS name instead of numeric value.

Change-Id: I3e1925a010a6def5fd14da63b73e0b75feddfafc
2019-03-19 18:27:49 +01:00
Max
136ebccc5e MCS: use value_string for conversion
Change-Id: I212ebb892ab162821633974d5a6c7e315d308370
2019-03-19 18:27:49 +01:00
Max
51754b6f35 MCS: move HeaderType enum outside of class definition
Move functions which compute number of blocks or bits depending on
header type and corresponding enum outside of GprsCodingScheme
class. This will allows us to use standard libosmocore value_sting
functions in upcoming patches for IA Rest Octet encoding/decoding.

Change-Id: Id0873f85e1f16a72e17e7fbc4ad76b194917067f
2019-03-19 18:27:06 +01:00
Max
d5ffeb5e63 Explicitly clean up BTS singleton
Add method to explicitly cleanup BTS singleton similar to GprsMsStorage
class and use it from main(). The destructor becomes trivial wrapper
around cleanup() method.

This prevents annoying SIGABRT on exit of OsmoPCU caused by
rate_ctr_group_free() being called after talloc_free() which removes the
context in which counter group is allocated.

Change-Id: I796d56a7de3f3a1f9d59708995c8e3e9b05a2747
2019-03-19 15:42:10 +00:00
Max
f4d3973688 MS store: move test helper to unit test
It's confusing to have test-specific helper with the same name as tested
function directly inside the GprsMsStorage class. Let's convert it into
static function and move to the unit test.

Change-Id: Ia2a5b90779051af894fe15d957c1d26f0a142f33
2019-03-19 15:05:51 +00:00
Oliver Smith
0fb91b736c tests: use -no-install libtool flag to avoid ./lt-* scripts
This ensures that the rpath of the generated binaries is set to use only
the just-compiled so-files and not any system-wide installed libraries
while avoiding the ugly shell script wrapper.

Change-Id: I2915f0de87598f9f23efc2b9a8f4a6bdf4966efb
2019-03-19 13:46:08 +01:00
Max
a3ff316c5f Use unique NSEI/BVCI/NSVCI in TBF tests
This works around the issue with colliding rate counter group index
highlighted by 86e35e4887 by using
different NSEI/BVCI/NSVCI parameters for different TBF tests.

Change-Id: Id7d2d1a48308a6b1fb17768aee0e79adbdee56ee
Related: OS#3827
2019-03-14 09:30:20 +00:00
Max
ed6e4acdf6 Debian: bump copyright year
Change-Id: If61a510fbbcd549dc7bdf6e38643a00d242be875
2019-03-13 17:12:57 +01:00
Max
0620656288 MCS: remove unused function
Change-Id: I32ab5ac36a0db90f2bea670b7684784b83a90b6b
2019-03-13 17:11:01 +01:00
Max
e43ef21d35 Make get_retx_mcs() into regular function
Moving from header-defined inline function allows us to hide
egprs_mcs_retx_tbl definition and simplify further changes.

Change-Id: I95258d1558a3b918ae83f1a69e7c3de2b97e5627
2019-03-12 15:35:40 +01:00
Max
bea2edbc46 MCS: move Coding Scheme enum outside of class definition
Move generic MCS enum to C header file to simplify further modifications
to GprsCodingScheme class in follow-up patches. This also allows us
to use standard libosmocore value_sting functions in upcoming patches
for IA Rest Octet encoding/decoding.

Related: OS#3014
Change-Id: I993b49d9a82b8c7ad677d52d11003794aeabe117
2019-03-12 15:35:40 +01:00
JF Dionne
1beed38b54 encoding: Fixes TMSI vs MI bit selection in repeated page info
Change-Id: Iddb00b9133f523f4ba09c8f1fc5694e62dc46fbf
2019-03-11 13:36:44 +00:00
Max
fa3085b45e Log (M)CS UL update errors
Previously some of the errors in update_cs_ul() call were silently
ignored. Let's log all those as errors with appropriate message.

Note: test output needs updating because we do not (yet) set proper meas
struct in TBF tests. That's likely wrong but it's better to update tests
in a separate commit.

Change-Id: I4084fb281dd9dad04a2a3a68cac2a8f7b462548e
2019-03-07 17:05:19 +00:00
Max
86e35e4887 Enable LGLOBAL logging for TBF tests
This exposes the bug in BSSGP rate counter group allocation in the
current tests version which should be fixed in a separate commit.

Change-Id: I6317eccfb1408c5c9d07110a8b059f5ceb5d2afc
2019-03-07 12:20:42 +01:00
Max
8119ecd2db Tighten lqual table limits check
Previously MAX_GPRS_CS was used for both EDGE and GPRS which means that
we waste extra memory in GPRS case. It also leads to misleading
name. Let's fix this by introducing separate definitions for GPRS and
EDGE cases and use them as appropriate in limit checks.

Change-Id: I3ae1ee64ec8e80247b8fe669cc79505b4dadf58f
2019-03-06 20:52:15 +00:00
Max
d3a0d91a38 Use msgb_eq_data_print() in tests
This allows to see exact byte which differs with expected output in case
of test failure.

Change-Id: If1285649b27843d68dfaa6f6dd3b80deee9aa148
2019-03-06 20:51:57 +00:00
Max
01f9bc7bf1 EDGE tests: remove no-op check
The headerTypeControl() function always return constant and is only used
inside OSMO_ASSERT() which compares it to the very same constant which
makes it no-op. Let's remove this clutter.

Change-Id: Ie0f81fe05a2b3f432de7d1f3446e8115d7524ff4
2019-03-05 12:10:52 +01:00
Max
9feaddc390 MCS: remove dead code
As a preparation for (M)CS fixes in follow-up patches, remove unused
operators from GprsCodingScheme class.

Change-Id: Ieef3b095a6732300e5efa395b989843112b9ca78
2019-03-04 16:25:12 +00:00
Max
360e021d0a EDGE tests: reduce code duplication
* move duplicated code into helper function
* use proper parameter types

Change-Id: I8a9528032629e5df629996da5cd8b808efede017
2019-02-26 23:01:02 +00:00
Max
807dde070f MCS: internalize 'family' parameter
There's no need to expose it in header file as it's only used internally
for consistency checks.

Change-Id: Ic705615cd2a8ca077efef9ea62a2a676f70b4aed
2019-02-26 19:59:46 +01:00
Harald Welte
57d3515abd Optionally Use the NS Sub-Network-Service (SNS) on Gb
This change add support for the recently-introduced GPRS Gb interface
auto-configuration using the NS IP Sub-Network Service (SNS) procedures.

It requires a Change-Id I84786c3b43a8ae34ef3b3ba84b33c90042d234ea of
libosmocore.

Related: OS#3372
Depends: I84786c3b43a8ae34ef3b3ba84b33c90042d234ea (libosmcore)
Change-Id: I256b40ac592d3b6e75dd581bf7b9512f69b11e83
2019-02-26 13:23:24 +01:00
Max
2a47c73217 Rewrite EGPRS Packet Uplink IA Rest Octets for SBA
Use bitvec_set_*() directly without external write pointer tracking to
simplify the code. This is part of IA Rest Octets (3GPP TS 44.018
§10.5.2.16) which is the last part of the message so it should not
interfere with the rest of encoding functions.

That's partially based on reverted commit 529ce88545.

Change-Id: I143b3dd02aa54b9ce206d9e780a5554f6d9fd118
Related: OS#3014
2019-02-26 11:20:15 +00:00
Harald Welte
b26854c276 Mark gprs_ns_reconnect() as static (not used outside of C file)
Change-Id: I95138adedacdc2d953284cff57f79ecb33616f0f
2019-02-26 11:11:51 +00:00
Max
bd5647ee92 Rewrite EGPRS Packet Uplink IA Rest Octets for MBA
Use bitvec_set_*() directly without external write pointer tracking to
simplify the code. This is part of IA Rest Octets (3GPP TS 44.018
§10.5.2.16) which is the last part of the message so it should not
interfere with the rest of encoding functions.

That's partially based on reverted commit 529ce88545.

Change-Id: I19cc4226e7e831e7d7f70212b2078f5589a87ff0
Related: OS#3014
2019-02-19 18:58:04 +01:00
Max
23c0e018e4 Rewrite Packet Downlink Assignment
Use bitvec_set_*() directly without external write pointer tracking to
simplify the code. This is part of IA Rest Octets (3GPP TS 44.018
§10.5.2.16) which is the last part of the message so it should not
interfere with the rest of encoding functions.

That's updated version of commit with the same topic reverted earlier.

Change-Id: Ie180733d2584ebb16fb80b84526d0dbc70e3d441
Related: OS#3014
2019-02-19 18:58:04 +01:00
Max
0160a29b6c Restructure IA Rest Octets encoders
In preparation for upcoming patches with 11 bit RACH and TA support,
let's restructure existing encoders to simplify further modifications:

* move consistency checks to top-level Imm. Ass. encoder
* use consistent formatting
* constify pointers where appropriate
* split SBA and MBA encoders into separate functions

Those changes also make it obvious which parameters are necessary for
Rest Octets in each specific case (DL, UL-SBA, UL-MBA, UL-SBA-EGPRS,
UL-MBA-EGPRS).

There're no functional code changes so there's no need to adjust tests.

Change-Id: I0ad1bc786c3a8055ea9666f64ae82c512bd01603
Related: OS#1548
2019-02-19 18:58:04 +01:00
Max
fc8afc2f33 Clarify write_immediate_assignment() signature
* remove unused variable
* use bool for boolean types
* add clarification comments

Change-Id: I363445063e2d873d9194b2a5924b9e59b8b7ea53
2019-02-19 18:58:04 +01:00
Max
81b58ccd94 Add encoding tests for Immediate Assignment
Change-Id: I63f4654b23c7c4f063f6b3254d77157fac798586
2019-02-19 18:58:04 +01:00
Max
7426c5f957 Add define for dummy burst string
Change-Id: I464920b3d6d47bb1c797a4ce06230f005a2e06a0
2019-02-19 18:58:04 +01:00
Max
0c55bf19a5 Move C include to proper place
Change-Id: Id58d1820b94d54ce73ed40edb7747ef975890a7b
2019-02-19 18:58:04 +01:00
Max
1f2e69fd35 Don't install pcuif_proto.h header
Both OsmoBTS and OsmoBSC use their own copies of this header nowadays so
we can simplify our installation slightly by making it local only.

Change-Id: I4a87395d4ab7212fe2fc055dae0a737e10d20c69
2019-02-14 16:35:36 +01:00
Rafael Diniz
f0af1b051a Added support for daemonize to osmo-pcu.
Change-Id: Ia889544e0a350b6bab55da4e4201a617e0241ea2
2019-01-29 12:32:58 -02:00
Harald Welte
99278b1050 Bump version: 0.5.1.38-5b52 → 0.6.0
Change-Id: Ibd7ac106f1e08319a592cf3246fc9fb6e298d226
2019-01-21 19:03:52 +01:00
Oliver Smith
5b521891ba contrib: fix makedistcheck with disabled systemd
EXTRA_DIST files need to be distributed, no matter if the systemd option
is configured or not.

Change-Id: I356aa59ab152ace89b247823a2c0517814a69ecb
2018-12-06 13:54:54 +01:00
Oliver Smith
64bc9400d4 contrib/jenkins.sh: build and publish manuals
Add new environment variables WITH_MANUALS and PUBLISH to control if
the manuals should be built and uploaded. Describe all environment vars
on top of the file.

When WITH_MANUALS is set, install osmo-gsm-manuals like any other
dependency and add --enable-manuals to the configure flags (for "make"
and "make distcheck"). Add the bin subdir of the installed files to
PATH, so osmo-gsm-manuals-check-depends can be used by ./configure.

Related: OS#3385
Change-Id: Ia5b112fc1663b78800d3c2c4ff2a0771cf5af11b
2018-12-05 13:47:26 +01:00
Oliver Smith
61469d1d86 Fix DISTCHECK_CONFIGURE_FLAGS override
Set AM_DISTCHECK_CONFIGURE_FLAGS in Makefile.am instead of
DISTCHECK_CONFIGURE_FLAGS. This is the recommended way from the
automake manual, as otherwise the flag can't be changed by the user
anymore.

Related: OS#3718
Change-Id: I10d1eef9838c0b843a3a4103b7b03e8e9457b69e
2018-12-04 15:31:28 +01:00
Oliver Smith
47aab58ec3 build manuals moved here from osmo-gsm-manuals.git
Moved to doc/manuals/, with full commit history, in preceding merge commit.
Now incorporate in the build system.

Build with:

$ autoreconf -fi
$ ./configure --enable-manuals
$ make

Shared files from osmo-gsm-manuals.git are found automatically if
- the repository is checked out in ../osmo-gsm-manuals; or
- if it osmo-gsm-manuals was installed with "make install"; or
- OSMO_GSM_MANUALS_DIR is set.

Related: OS#3385
Change-Id: I7270652de393a98748c0cdc51e626c17ab8f44c2
2018-11-27 18:30:56 +01:00
Neels Hofmeyr
dfb08d31fe Merge history from osmo-gsm-manuals.git
Change-Id: I33ce528bb58a8a730a15cc8a7a74852a14f42921
2018-11-27 18:30:39 +01:00
Daniel Willmann
96481c8d3f Change OpenBSC mentions to OsmoBSC where applicable
Change-Id: I4cc6874302b6089a54d44b09f08660a25e46d4dc
2018-11-27 18:30:23 +01:00
Harald Welte
2eeddee132 vty-ref: Update URI of docbook 5.0 schema
... to match the /etc/xml/catalog file on debian (no "www" in hostname)

Change-Id: Id9f3579c7f2bc3af13fe30b5268f249b6f59ed0d
2018-11-27 18:30:23 +01:00
Alexander Couzens
57d91ea785 OsmoPCU: add rate counter documentation
Change-Id: Ieb4e1dab415a70ded5c65c21752dca497856e96f
2018-11-27 18:30:23 +01:00
Neels Hofmeyr
d2829b89c1 refactor Makefile build rules, don't use the FORCE
The initial goal was to make sure we don't have overall FORCE rules causing
unnecessary rebuilds -- annoying while writing documentation. As I looked
through possible dependencies, I finally understood what's going on here.

Remove code dup and nicely sort which belongs where in build/Makefile.*.inc. In
each, describe in a top comment how to use it, and also unify how they are
used:

- Rename Makefile.inc to Makefile.docbook.inc and refactor
- Add Makefile.vty-reference.inc
- Add Makefile.common.inc

Make sure that we accurately pick up all dependencies.

Drop use of the macro called 'command', that silenced the actual command lines
invoked and replaced them with short strings: it obscures what is actually
going on and makes the Makefiles hard to read and understand.

Each manual's makefile is greatly reduced to few definitions and a Makefile
include, e.g. one for asciidoc, one for VTY reference.

Move common/bsc_vty_additions.xml to OsmoBSC/vty/libbsc_vty_additions.xml, link
from OsmoNITB. It applies only to OsmoBSC and OsmoNITB.

Add a script that combines a VTY reference file with *all* additions files
found in a manual's vty/ dir. Call this from Makefile.vty-reference.inc.

Change-Id: I9758e04162a480e28c7dc83475b514cf7fd25ec0
2018-11-27 18:30:23 +01:00
Pau Espin Pedrol
f605f3d891 Allow easily disabling GFDL references
All parts referencing GFDL can be easily disabled by removing the
'gfdl-enabled' attribute from the document.

Change-Id: I2489726ad2e90301bceadfada926e31ae0f85986
2018-11-27 18:30:23 +01:00
Philipp
452b533114 configuration: fixing typos
configuration.adoc has some minor typos in it, this commit fixes
that.

Change-Id: Id84238b89e5deeac99c043b79b26c7e7b8b8534b
2018-11-27 18:30:23 +01:00
Neels Hofmeyr
5c8f1ccff0 fix 'make clean': shell glob, ignore failure
Unfortunately a glob like osmo-x__*.{svg,png} doesn't work, so have the
suffixes in separate globs.

Add dashes to indicate that failure should be ignored.

Change-Id: I6bc4d9ea72b43a573acbc860c23397f748de2c7b
2018-11-27 18:30:23 +01:00
Neels Hofmeyr
6bc5c2aac6 add 'make check' target
Generate *.check files from asciidoc output and grep for WARNINGs.
Add *.check files to gitignore and to 'make clean'.

Change-Id: Ibccc83a3415930a528f2e8e4e4dda3b81c6d0b64
2018-11-27 18:30:23 +01:00
Neels Hofmeyr
5828b60af5 make clean: also remove generated image files
Change-Id: I80798e79b4ccee64f26f58f9754de02b2958e33e
2018-11-27 18:30:23 +01:00
Jonathan Brielmaier
58721eb350 fix various typos across all manuals 2018-11-27 18:30:23 +01:00
Harald Welte
6fb29639df gb/NS: Clarify the language regarding the UDP port numbers / socket 2018-11-27 18:30:23 +01:00
Harald Welte
032f94b099 consistently use '3GPP TS' not sometimes 3GPP TS and sometimes TS. 2018-11-27 18:30:23 +01:00
Harald Welte
32b58e6418 gb: Some language improvements, formatting changes 2018-11-27 18:30:23 +01:00
Harald Welte
a27873f1e2 Gb: Various spelling fixes 2018-11-27 18:30:23 +01:00
Harald Welte
3a89f21540 Gb message sequence chart: Add notion of PCU unix domain socket 2018-11-27 18:30:23 +01:00
Harald Welte
d930b4d5f4 Gb message sequence chart: flip sides (SGSN should be right)
... also, re-word some of th labels for more clarity
2018-11-27 18:30:23 +01:00
Max
8f934f55d7 OsmoPCU: add MSC chart 2018-11-27 18:30:23 +01:00
Max
b1776b65b3 OsmoPCU: expand BSSGP documentation 2018-11-27 18:30:23 +01:00
Max
4e2a1e3e98 OsmoPCU: expand NS documentation
Add table with NS messages.
Add corresponding sections.
Clarify spec numbers.
2018-11-27 18:30:23 +01:00
Max
c182b98998 OsmoPCU: fix Gb documentation front page
Add date and commit refs.
Add relevant standards.
Fix email typo.
2018-11-27 18:30:23 +01:00
Harald Welte
b682cd6a51 Initial place-holder for the new Gb/IP interface documentation 2018-11-27 18:30:23 +01:00
Harald Welte
4095f31fea Add link to Asciidoc source code of manual 2018-11-27 18:30:23 +01:00
Harald Welte
4ff37feb4c initial checkin of manuals to public repo
The manuals existed in different form for several years in an internal
sysmocom repository.  However, since they had just recently been
converted from docboox-xml to asciidoc and all files have been
re-shuffled for enabling the public release, there's not much point in
keeping the history with git-filter-branch.
2018-11-27 18:30:23 +01:00
Neels Hofmeyr
b9ba5ad239 Importing history from osmo-gsm-manuals.git
Change-Id: I23320be18612dd1eb800d3b16594166f33b3d984
2018-11-27 18:30:08 +01:00
Max
4214c4ae53 deb: add missing copyright file
File is imported as-is from current .deb package

Change-Id: Ib05480c0eea91bfb55bfc7ab446ea60932096d3d
2018-11-07 14:20:27 +01:00
Harald Welte
099f4f2169 gprs_rlcmac_received_lost(): Fix regression / uninitialized now_tv
In Change-Id I7d22e7b5902c230efeae66eb20c17026a4037887 we
introduced the use of timespecsub(). Unfortuantely, we also
accidentially removed the call to osmo_clock_gettime() along
with it, leaving now_tv completely uninitialized.

Change-Id: Ieced0c62700b2fe4ab0208258183154cc701490b
Related: OS#3225
Fixes: Coverity CID#188872
2018-10-21 11:50:10 +02:00
Stefan Sperling
173d7fdbb9 check for overlong unix socket paths
In pcu_l1if_open(), use osmo_strlcpy() instead of strncpy() and check for
overflow. This catches overlong and non-NUL-terminated socket paths.

Change-Id: I825190cbb34d052b797e9fb5208884d6f5992839
Related: OS#2673
2018-09-20 18:31:36 +02:00
Pau Espin Pedrol
076122f592 Install osmo-pcu.cfg to docdir/examples
Change-Id: I42938d9abd17575c2e0ce69cc20d44a131f26b6a
2018-09-13 11:36:01 +02:00
Pau Espin Pedrol
ac5e3e222a Move examples/ to doc/examples/
Change-Id: I1e163e10f8a2e22b9ebdcb2d0f13f6ad07c84efe
2018-09-13 11:36:01 +02:00
Pau Espin Pedrol
516697e29a Install systemd services with autotools
Change-Id: Ie4c7e81495181059d1dff1c194d52d11fb72ed03
2018-09-10 16:09:54 +02:00
Pau Espin Pedrol
3e9c071aa6 configure.ac: Set CXXFLAGS during --enable-sanitize
For some unknown reason ld was failing to find some asan symbols until I
enabled asan too in CXXFLAGS.

Change-Id: I695314b284277674dc336b40765313a37d238d6e
2018-09-10 14:52:21 +02:00
Pau Espin Pedrol
e63c72acfb Cleanup of systemd service files
Let's use a symlink in debian/ as we do in other projects,
and merge the two service files since anyway they call the same binary.

Change-Id: Ibd82ec12cbeb73a27ca5860266587efb58be14ab
2018-09-06 15:06:22 +02:00
Harald Welte
54af2dba78 debian/rules: Don't overwrite .tarball-version
The .tarball-version file should contain the *source version* uniquely
identifying the git commit, and not the Debian package name.

With https://gerrit.osmocom.org/#/c/osmo-ci/+/10343/ there is a correct
.tarball-version file in the .tar.xz of the nightly source packages.

Change-Id: I093c9c1943e5f09d8f91f94af438f697a93e7127
Related: OS#3449
2018-08-06 11:18:24 +02:00
Pau Espin Pedrol
448750e4e2 Bump version: 0.5.0.11-218e-dirty → 0.5.1
Change-Id: I0c5a3f3cee8332d5088982117037d5a0b077061b
2018-07-27 21:56:39 +02:00
Pau Espin Pedrol
218ee98de0 tbf: Replace '.' in counter names with ':'
The '.' is illegal character in counter names, as they are exported
via CTRL interface, where '.' has a special meaning that cannot be
used by strings comprising the variable name.

Change-Id: Ieb7496e1a30ab4f2bfe36c7b664dcdc034010a15
2018-07-11 22:20:31 +02:00
Pau Espin Pedrol
09269017d3 tbf: Use incrementing id for rate_ctr_group_alloc
Wrap-around of var handling next id will luckly happen
long after initially assigned TBFs are already released.

Change-Id: I90ef64133986c556c1a529f5b966e847e6cabbad
2018-07-11 22:20:31 +02:00
Stefan Sperling
3df1532e97 check bssgp_tlv_parse() return code in gprs_bssgp_pcu_rcvmsg()
The return code from bssgp_tlv_parse() was not checked for a parsing
error. In case of a parsing error the stored return code could have
been overwritten later in this function.

Explicitly check for a parsing error, log corresponding packets,
and return an "invalid mandatory information" error status to
the sender. To avoid loops, do not respond with an error status
to STATUS PDUs.

Change-Id: I56e10a97cda7fd2d40bc7b4b2e6202f97772e1b3
Related: OS#3178
2018-06-25 13:02:06 +02:00
Pau Espin Pedrol
e176a4d047 jenkins.sh: use flag --enable-werror for sysmo and none
The lc15 flavour still contains compilation warnings and thus the flag
cannot be enabled while building it.

Change-Id: I66a43822f8a40764d7d6e09503892cea6030e697
2018-06-20 23:30:40 +02:00
Stefan Sperling
082443d2c7 change log level of "DL packet loss" log messages
The TBF tests are failing on some machines due to unexpected
log output: "DL packet loss of IMSI= / TLLI=0xffeeddcc: 0%"
These messages are printed if >= 1 second has passed between
loss reports. This timing is machine-dependent so the test
is unstable as a result. Only print these messages at log
level debug to (hopefully) make TBF tests pass consistently.
Update expected test output accordingly.

Change-Id: Ie43f0e3a8740f0fc132809a09a153886c51fadf9
2018-06-05 11:42:12 +02:00
Stefan Sperling
78ab624c2a fix time-delta calculations for measurement reports
The previous implementation unconditionally subtracted nanosecond
values from different time measurements, causing overflow if the
current measurement was taken in less of a fraction of a second
than the past measurement. Use timespecsub() instead, which
accounts for nanoseconds correctly.

Also, fix calculations of KBit/s throughtput. It was not being
calculated correctly, since it was actually accounting for one
KB per 128th-part-of-a-second.

Change-Id: I7d22e7b5902c230efeae66eb20c17026a4037887
Related: OS#3225
2018-05-31 14:12:58 +02:00
Stefan Sperling
f0f7df1b87 read monotonic clock with clock_gettime() instead of gettimeofday()
There have been test failures on the osmo-pcu Jenkins builders due
to apparent clock drift. Switch relevant code from gettimeofday()
to clock_gettime() with CLOCK_MONOTONIC to prevent time from going
backwards and causing negative time deltas in calculations.

Change-Id: I775d85d0d3ac740330879e588bdab6fce7f0b46c
Related: OS#3225
2018-05-25 17:33:06 +00:00
Stefan Sperling
143b2da4f8 fix a one-byte stack buffer overrun in osmo-pcu
Address sanitizer uncovered a one-byte stack overrun due to an
off-by-one in the size of the 'data' buffer in pcu_l1if_tx_pch().
Fix the problem and add an assertion which triggers before the
overrun can occur.

Change-Id: I08a879d72fcb916f78f175612fd90467d7bdd57c
Related: OS#3289
2018-05-25 15:19:50 +02:00
Pau Espin Pedrol
7a9c1660cc rlc: Fix memset(0) on object with no trivial copy-assignment
As warned by gcc 8.1.0, the cs field is a class (GprsCodingScheme) and
should not be memset.

Change-Id: Id742f82aa856e696b5fb414991dfd0883d0ac7fe
2018-05-16 15:22:27 +02:00
Pau Espin Pedrol
0b0748a4be tbf: Fix memset(0) on object with no trivial copy-assignment
As warned by gcc 8.1.0:
osmo-pcu/src/tbf.cpp: In constructor ‘gprs_rlcmac_tbf::gprs_rlcmac_tbf(BTS*, gprs_rlcmac_tbf_direction)’:
osmo-pcu/src/tbf.cpp:222:33: error: ‘void* memset(void*, int, size_t)’ clearing an object of type ‘struct gprs_rlc’ with no trivial copy-assignment; use assignment or value-initialization instead [-Werror=class-memaccess]
  memset(&m_rlc, 0, sizeof(m_rlc));
                                 ^
In file included from osmo-pcu/src/tbf.h:24,
                 from osmo-pcu/src/bts.h:37,
                 from osmo-pcu/src/tbf.cpp:22:
osmo-pcu/src/rlc.h:234:8: note: ‘struct gprs_rlc’ declared here
 struct gprs_rlc {
        ^~~~~~~~

Change-Id: Ifb0529b9ae6cd4300e5cbbd9151054792edbfe06
2018-05-16 15:20:43 +02:00
Harald Welte
45143d270c Don't register SIGHUP handler without actually handling SIGHUP
In libosmocore, we normally register a SIGHUP handler for log file
rotation.

However, the osmo-pcu code so far installed its own signal handler,
which did exactly nothing in the SIGHUP case.

Let's fix this by removing SIGHUP handling here, letting libosmocore
take care about this.

Change-Id: Ifa20d79770bc4d88d40601b008a3a2a79d083c04
Closes: OS#3265
2018-05-15 16:23:04 +02:00
Pau Espin Pedrol
f1a334be63 Bump version: 0.4.0.115-513c-dirty → 0.5.0
Change-Id: I6ce6fb40690a66b0980eba4fa03b47da2f59ee6e
2018-05-03 16:20:01 +02:00
Stefan Sperling
513c9bca17 improve documentation of Encoding::write_paging_request()
Add pointers to relevant parts of the spec. Tweak comments to be
more specific about the values being written and abbreviations used.

Change-Id: Ia5bf3f7f8846198b7b4e25ff1accf6206764be74
2018-05-02 14:53:16 +02:00
Philipp Maier
33c52b6271 tbf: add frame number to log output
Currently, the TBF timer log messages lack the frame number in
the logoutput

- Add frame number to TBF timer related log-statements

Change-Id: I5a744dc5cd7c1de1baea13fffac026c83d091429
Related: SYS#4139
Patch-by: Octasic inc.
2018-04-12 12:46:44 +02:00
Philipp Maier
7e8e3978fe pcu_l1_if: add frame number to log output
Currently, the log output lacks the frame number.

 - make get_current_fn() public
 - add frame number to the log statements in pcu_l1_if.cpp

Change-Id: Idce994dbf86a2bbf861907d75418a2a3867244db
Related: SYS#4139
Patch-by: Octasic inc.
2018-04-10 13:35:24 +02:00
Philipp Maier
8ccf704608 cosmetic: remove runaway semicolon
Change-Id: I33c335dc8d564a8357ffb5b1163c2c4b1a578b49
Related: SYS#4139
Patch-by: Octasic inc.
2018-04-10 13:35:18 +02:00
Neels Hofmeyr
42f2d61ac9 use osmo_init_logging2() with proper talloc ctx
There is a duality of initialization: early_init() in bts.cpp wants to init
logging even before static instances get initialized. Make sure that
tall_pcu_ctx is initialized during early_init() as well. There is a build
context that does not seem to include bts.cpp (osmo-pcu-remote), so to be sure,
init tall_pcu_ctx as NULL and both in early_init() as well as pcu_main.cpp,
init both tall_pcu_ctx and logging if it is still NULL.

Change-Id: I2199b62d0270bd35dec2283e8f5b364b7c63915b
2018-04-01 16:57:42 +02:00
Neels Hofmeyr
e6e4898027 Revert "Rewrite EGPRS Packet Uplink Assignment"
This reverts commit 529ce88545,
I2139fb347b3290621bbc3f6a031f7f213d372e65.

Commit I52ec9b07413daabba8cd5f1fba5c7b3af6a33389 /
896574e92b was found (empirically) to be a
regression, rendering GPRS service fatally unreliable.

This reverted commit seems to be related to the regression and is reverted
along with it.

Related: OS#3013
Change-Id: I3e8cc0e8ba3ba5bd444124fd4cb95ef92a71fdfb
2018-03-30 14:30:13 +00:00
Neels Hofmeyr
9f06cbff6d configure: properly quote CFLAGS in lc15 check
Change-Id: I7bb7a7d7b5b9340cb41c95f848774ee378c59212
2018-03-29 22:10:57 +00:00
Neels Hofmeyr
a661bcd086 configure: fix --enable-sysmocom-dsp and --with-sysmobts flags
Fix multiple problems around the sysmobts DSP access and headers:

- Use the proper variable name to detect the choice: $enable_sysmocom_bts was
  not set anywhere and would actually be used from the current user env, if
  present, instead of from configure args.

- Quote the $CPPFLAGS when assigning to oldCPPFLAGS and back.

- When checking SYSMOBTS_INCDIR, do not allow an empty "-I" without a dir.

- Ensure the --with-sysmobts path is used as an absolute path.

- Error out if --with-sysmobts is paired with --disable-sysmocom-dsp.

Also tweak reporting.

The resulting behavior now is:

./configure --disable-sysmocom-dsp
checking whether to enable direct DSP access for PDCH of sysmocom-bts... no

./configure --enable-sysmocom-dsp
checking whether to enable direct DSP access for PDCH of sysmocom-bts... yes
checking for sysmocom/femtobts/superfemto.h... no
configure: error: sysmocom/femtobts/superfemto.h can not be found, see --with-sysmobts

./configure --disable-sysmocom-dsp --with-sysmobts=../../../sysmobts/layer1-api
checking whether to enable direct DSP access for PDCH of sysmocom-bts... error
configure: error: --with-sysmobts does not work with --disable-sysmocom-dsp

./configure --enable-sysmocom-dsp --with-sysmobts=../../../sysmobts/layer1-api
checking whether to enable direct DSP access for PDCH of sysmocom-bts... yes, using -I/n/s/sysmobts/layer1-api
checking for sysmocom/femtobts/superfemto.h... yes

./configure --with-sysmobts=../../../sysmobts/layer1-api
checking whether to enable direct DSP access for PDCH of sysmocom-bts... yes, using -I/n/s/sysmobts/layer1-api
checking for sysmocom/femtobts/superfemto.h... yes

./configure --with-sysmobts=/nonexisting/path
checking whether to enable direct DSP access for PDCH of sysmocom-bts... yes, using -I/nonexisting/path
checking for sysmocom/femtobts/superfemto.h... no
configure: error: sysmocom/femtobts/superfemto.h can not be found in -I/nonexisting/path, see --with-sysmobts

./configure --with-sysmobts=/var/log
checking whether to enable direct DSP access for PDCH of sysmocom-bts... yes, using -I/var/log
checking for sysmocom/femtobts/superfemto.h... no
configure: error: sysmocom/femtobts/superfemto.h can not be found in -I/var/log, see --with-sysmobts

Change-Id: I2f5988730dbbcf3b21d8c647c499623843ed3da9
2018-03-29 17:14:22 +02:00
Neels Hofmeyr
39f845848c Revert "Rewrite Packet Downlink Assignment"
This reverts commit 896574e92b,
I52ec9b07413daabba8cd5f1fba5c7b3af6a33389.

This commit was found (empirically) to be a regression, rendering GPRS service
fatally unreliable.

Related: OS#3013
Change-Id: Idcba0381f70eb7f7c9aefdee9dfeafd5de96a9be
2018-03-28 14:34:55 +00:00
Neels Hofmeyr
782da2cf95 Revert "Rewrite Packet Uplink Assignment"
This reverts commit 93d947f5e8,
I44db2eeea7448ff67e688ae716487bc6dbfc96a3.

Commit I52ec9b07413daabba8cd5f1fba5c7b3af6a33389 /
896574e92b was found (empirically) to be a
regression, rendering GPRS service fatally unreliable.

This reverted commit seems to follow after the regression and is reverted along
with it.

Related: OS#3013
Change-Id: If7038127e9a663c93006475b3add961adc0b1922
2018-03-28 14:34:55 +00:00
Neels Hofmeyr
89b85e078e Revert "Use Timing Advance Index in UL assignments"
This reverts commit 6298fbb7b2,
I8b17be78a46c0bc17516b7c90f35aa4768010ae4.

Commit I52ec9b07413daabba8cd5f1fba5c7b3af6a33389 /
896574e92b was found (empirically) to be a
regression, rendering GPRS service fatally unreliable.

This reverted commit seems to follow after the regression and is reverted along
with it.

Related: OS#3013
Change-Id: I5e0fd8c9c3b89e519e7382e3d0bb24e0aeddeff6
2018-03-28 14:34:55 +00:00
Neels Hofmeyr
f75381498c mslot_class: two more: use uint32_t to shift 1 << 31
Avoid runtime error seen on jenkins admin-deb9build slave, when building
osmo-pcu with_dsp=None,with_vty=False, during ts_alloc and tbf regression
tests:

+../../../src/mslot_class.c:271:36: runtime error: left shift of 1 by 31 places cannot be represented in type 'int'
+../../../src/mslot_class.c:272:22: runtime error: left shift of 1 by 31 places cannot be represented in type 'int'

This time it seems that these are all.

The master-osmo-pcu breaks on this since moving to a debian9 build slave.

Change-Id: I976a1dca9da19a05afc85a17b7ba60545b7bc1e5
2018-03-28 14:44:47 +02:00
Neels Hofmeyr
8b4bd46b95 mslot_class: find_free_tfi(): use uint32_t to shift 1 << 31
Avoid runtime error seen on jenkins admin-deb9build slave, when building
osmo-pcu with_dsp=None,with_vty=False, during ts_alloc and tbf regression
tests:

+../../../src/mslot_class.c:242:22: runtime error: left shift of 1 by 31 places cannot be represented in type 'int'

The master-osmo-pcu breaks on this since moving to a debian9 build slave.

Change-Id: I0cdf10e5fbc1173a7a09bd4fed8a66d06f80aeb1
2018-03-26 23:24:16 +02:00
Pau Espin Pedrol
74906224ca gprs_bssgp_pcu.cpp: Comment unused function parse_ra_cap
Commit 741d25cb6f commented the only user
of the function but forgot to comment too the function itself.

Change-Id: I8b291b45aaedfb0421cd28c0d9e24cefa5547b09
2018-03-17 01:43:14 +01:00
Neels Hofmeyr
5a5919435e configure: add --enable-werror
Provide a sane means of adding the -Werror compiler flag.

Currently, some of our jenkins.sh add -Werror by passing 'CFLAGS="-Werror"',
but that actually *overwrites* all the other CFLAGS we might want to have set.

Maintain these exceptions from -Werror:
a) deprecation (allow upstream to mark deprecation without breaking builds);
b) "#warning" pragmas (allow to remind ourselves of errors without breaking
   builds)

As a last configure step before generating the output files, print the complete
CFLAGS and CPPFLAGS by means of AC_MSG_RESULT.

Change-Id: I0f735913fc3bbda695c4e66449dcfc94f417dafb
2018-03-13 00:03:38 +00:00
Neels Hofmeyr
bdc55fad62 implement support for 3-digit MNC with leading zeros
Receive the mnc_3_digits flag from the PCU interface.

Bump the PCU interface to 9.
This is one part of the three identical pcuif_proto.h patches:
- I49cd762c3c9d7ee6a82451bdf3ffa2a060767947 (osmo-bts)
- I787fed84a7b613158a5618dd5cffafe4e4927234 (osmo-pcu)
- I78f30aef7aa224b2e9db54c3a844d8f520b3aee0 (osmo-bsc)

Add 3-digit flags and use the new RAI and LAI API from libosmocore throughout
the code base to be able to handle an MNC < 100 that has three digits (leading
zeros).

Depends: Id2240f7f518494c9df6c8bda52c0d5092f90f221 (libosmocore),
         Ib7176b1d65a03b76f41f94bc9d3293a8a07d24c6 (libosmocore)

Change-Id: I787fed84a7b613158a5618dd5cffafe4e4927234
2018-03-11 00:47:14 +01:00
Alexander Couzens
8343b4adbb pcuif_proto: add version 8 features
Add PCU_IF_MSG_DATA_CNF_DT and PCU_IF_SAPI_AGCH_DT to bring the
pccif_proto into sync. Both commands are required to support the
rb11 with an osmo-bsc co-located pcu.

Change-Id: Ieaf151447e5556b911be7e2483b7c154fc5ec42e
2018-02-28 03:03:49 +01:00
Alexander Couzens
d2a219e644 pcuif_proto.h: fix whitespaces and indention
Change-Id: I290967346af4e2707cfdfb62dccaccd43d195443
2018-02-28 03:03:01 +01:00
Max
731e2bb328 Simplify TS alloc: move slot check into functions
Move timeslot applicability check outside of nested for loop into
separate functions and document them. Add corresponding tests.

This allows us to clarify types used in TS-related computations.

Change-Id: Ic39e848da47dc11357782362fdf6206d2c1457c2
Related: OS#2282
2018-02-21 12:08:40 +00:00
Max
77988d469d Simplify TS alloc: move slot assignment
Move into separate functions:
* move timeslot reservation
* move UL timeslot assignment
* move DL timeslot assignment

Change-Id: I64cf78c5cfc78664766f9769dd5cde632dab92b0
Related: OS#2282
2018-02-21 12:08:38 +00:00
Max
847ed9f8cd TBF: make network counters internal
* store N310* counters in shared array similar to corresponding timers
* add functions to increment/reset counters

This avoids direct access to TBF counters from PDCH.

Change-Id: I8ffff9c7186f74bde7e6ac5f6e98f0b3e4c35274
Related: OS#1539
2018-02-20 18:16:11 +01:00
Max
4da385998a Simplify TS alloc: constify max dl slot func
Constify parameters of gprs_alloc_max_dl_slots_per_ms().

Change-Id: Ic90930d98560459eab0054cb9e1625cb99db61c8
Related: OS#2282
2018-02-20 10:20:55 +01:00
Max
c5407c775a Simplify TS alloc: don't use PDCH for free TFI
Don't use PDCH from free TFI lookup routine. This allows for simpler
function which can be moved to mslot_class.c alongside with other
similar helpers.

Change-Id: Ie154866900453d232a890f7b9a30911b451525a1
Related: OS#2282
2018-02-20 10:19:25 +01:00
Max
6dc90b8c86 Move PDCH-related functions into separate files
The PDCH class and corresponding functions are rather self-contained and
independent from BTS implementation. Let's move them into separate file
to make bts.cpp more manageable. As additional benefit it allow us to
somewhat untangle all the different cross-dependent includes.

Change-Id: Ie05e25361e6741a81b024679f9675c98d4923683
Related: OS#1539
2018-02-19 17:41:24 +01:00
Max
2afec6dba5 Simplify TS alloc: split USF/UL allocation
* move USF allocation into separate function
* document USF allocation

This allows to clearly see where selected UL TS is forced into single TS
in algorithm B allocator.

Change-Id: I563dc10827ce68295553f88f3bf2e1fc0ba595c1
Related: OS#2282
2018-02-19 09:00:21 +00:00
Max
0cc7212cfd Simplify TS alloc: split allocation
* generalize TS allocation and move it into separate function
* move single-slot allocation into separate function
* use common functions for TS allocation on both UL and DL

Change-Id: Ied45ae380c345bc76fe9d6fd9a6184d1109f83f2
Related: OS#2282
2018-02-19 09:00:20 +00:00
Max
adca67bcbb Simplify TS alloc: separate capacity computation
Move TRX capacity computation into separate function and document it.

Change-Id: Ifd88fc7ff818ea2a041eae61c5d457926a0df0f2
Related: OS#2282
2018-02-19 09:00:20 +00:00
Max
f633b8d8b2 Simplify TS alloc: split off RX mask computation
Move computation of RX mask into separate function and document it. This
allows to significantly shrink find_multi_slot() function and overall
improve code readability.

Since the test output requires cosmetic adjustment anyway due to change
in the sequence of log messages, use this opportunity to better group
and format log message.

Change-Id: I731726a096bba7ee97499e5cbe3e7401869d7392
Related: OS#2282
2018-02-19 09:00:19 +00:00
Max
1187a7719c Update header includes
Many files include unnecessary headers and don't include headers which
are actually used. Because of that combined with the fact that OsmoPCU
is a mixture of C and C++, it makes it hard to modularize code. Fix
this (using iwyu [1] tool):

* add missing headers
* remove unused headers

[1] https://include-what-you-use.org/

Related: OS#1539
Change-Id: I8c9f488a43b099c72b2d30d3245e7ba50872fc00
2018-02-19 08:43:46 +00:00
Max
910a387b0e Move include guard to the top
Having explicit include above the douible-include guard defines is
potential source for hard to track bugs. Let's move it inside the guard
statement.

Change-Id: I5114a63ce00b03c8eed23565d52969250bd505cc
Related: OS#1539
2018-02-19 08:43:45 +00:00
Max
4382e4e8fe Move paging generation into PDCH
Previously paging was prepared inside BTS function and than handed over
to PDCH function. Move the actual preparation into PDCH to better
decouple PDCH from BTS.

Related: OS#1539
Change-Id: I389fb16b6e54040770c21f88edbcb8e045636928
2018-02-19 08:43:33 +00:00
Max
735e435e8e Use explicit type for pcu_lsb()
It's only used for byte-long input so we can specify input and output
types explicitly.

Change-Id: Id0bef691e17e4331c7c4b491661e36173d85388a
2018-02-19 08:33:04 +00:00
Stefan Sperling
5b22fb7953 Make osmo-pcu wait for BTS to become available at start-up time.
After the PCU socket becomes available, the BTS might send an
INFO_IND message with the 'ACTIVE' flag cleared. If this happens,
do not exit immediately, but keep retrying until an INFO_IND
message with the 'ACTIVE' flag arrives.

Note that this change only affects behaviour at process start-up time.
If the BTS switches from active to inactive state then osmo-pcu will
still exit. If this behaviour should be changed as well it could be
done in a follow-up patch.

Tested against osom-bsc + osmo-bts-virtual.

Change-Id: Ic42a5601a43b81d260721fef5d9fa52447f9d309
Related: OS#2689
2018-02-14 19:55:05 +01:00
Max
c907b88ecd emu: use libosmocore definitions
Change-Id: I4eade528faeb3841549ad7a6c78e8c1357909614
2018-02-13 12:53:55 +01:00
Max
4c112dc5a6 TBF: move common test code into functions
* move common code into functions
* print error instead of failing test right away

This allows the tests to continue till completion even in case of
intermediate error which simplifies troubleshooting by allowing to
gather more errors in a single test run.

Change-Id: I1c4ad1dc94542835f15bd666f0821e0ccfcc78c1
Related: OS#1759
2018-02-08 09:40:57 +00:00
Max
137fd59bf4 RACH: improve single block detection
Replace unreadable if-else ladder in is_single_block() with regular
switch-case. This enables implementation of 11-bit RACH support in
follow-up patches.

Related: OS#1548
Change-Id: I9180478152f9341f11bb3dffe61671da683f24d8
2018-02-07 17:25:42 +01:00
Max
c9ce6f916e vty: drop unused function
Change-Id: I01f3773ca6a9b6d4e28ca2f59c944c6d48918dd1
2018-02-03 15:05:29 +00:00
Max
5441e1f2f0 TBF: show assignment kind in vty
Change-Id: Ic4e40d9c141ab7ee3f7c4dceec007dbe16359f93
Related: OS#1759
2018-02-03 15:05:29 +00:00
Max
5d7f757e49 TBF: add helpers for assignment type handling
* add function to set/unset given assignment type
* log assignment type flag changes
* update tests output with additional logs

This enables us to carefully track the TBF assignment type transitions.

Change-Id: I3fe9d52472be8b7f257e8326b2f84e8e7d7bd1f4
Related: OS#1759
2018-02-03 15:05:29 +00:00
Max
0fdaa9d383 TBF: decrease logging verbosity for traffic
Change-Id: If43aa9895abf58602556c986a633ff93a6f00b06
2018-02-03 15:05:28 +00:00
Max
7e4921d8e2 Simplify TS alloc: internalize TRX check
Move TRX check inside local tfi_find_free() wrapper to make main
algorithm easier to follow.

Change-Id: I02da2b8ba8c9c8815dae0e39e1fed277ca0df171
Related: OS#2282
2018-01-31 11:21:28 +01:00
Max
69d585e148 TS alloc: print suggested TRX on allocation errors
If TS allocation fails due to unavailable TFI, print TRX which was
suggested to allocator. This simplifies allocator debugging but requires
cosmetic modifications to test output.

Change-Id: Icaf97d71d71985d52dc0bda448c26b19fe5645e7
Related: OS#2282
2018-01-31 11:21:27 +01:00
Max
a76a7d0c6c Simplify TS alloc: adjust function signatures
* document used parameters and return values
* use consistent formatting
* constify function parameters where appropriate (adjusting parameter
  types if necessary)

Change-Id: I211b10b4da59c73d509b719346774515c761886a
Related: OS#2282
2018-01-26 12:57:05 +01:00
Max
d000d80968 Simplify TS alloc: use defines for constants
* define and use constant for occupied TFI instead copying the same
  magic number all over the place
* use libosmocore's define for bit pretty-printer

Change-Id: I2699ceebf0cbec01652a02fa68ccc9e9419d0293
Related: OS#2282
2018-01-26 12:57:05 +01:00
Max
92e9c17aec Simplify TS alloc: avoid TS reassignment
Assign reserved_*_slots only when multislot masks are found to avoid
reassignment and make code easier to follow.

Change-Id: I9b0482f4ea75ead9855cd78e33c8e70d0ccf4484
Related: OS#2282
2018-01-26 12:56:27 +01:00
Max
92b7a50605 Simplify TS alloc: fix allocation calls
Using the semantic patch below, adjust allocation-related calls to match
updated allocator signatures.

// spatch --c++ --dir src -I src --sp-file callfix.spatch --in-place --recursive-includes
// spatch --c++ --dir tests -I src --sp-file callfix.spatch --in-place --recursive-includes
@@ expression A, B, C, D, E; @@
tbf_alloc_ul_tbf(A, B, C, D, E,
(
- 1
+ true
|
- 0
+ false
)
 )
@@ expression A, B, C, D, E; @@
tbf_alloc_dl_tbf(A, B, C, D, E,
(
- 1
+ true
|
- 0
+ false
)
 )

Change-Id: I43c76cb49093b40eb854d324e898e821270053dc
Related: OS#2282
2018-01-26 12:55:59 +01:00
Max
e9fe0e3d06 Simplify TS alloc: adjust allocator signatures
* drop unused parameters (from both functions and structs)
* document used parameters and return values
* tighten types used for parameters
* use consistent formatting

Tests are adjusted accordingly but test results are left untouched to
avoid regressions.

Change-Id: I39d81ab64ff790b9c4c2d0312a574485cd83e755
Related: OS#2282
2018-01-26 12:55:29 +01:00
Max
a296118e6d TBF: override send function via linker option
Use --wrap linker facility to override pcu_sock_send() similar to other
Osmo* projects.

Change-Id: Ia3d436bd3d1fb0ce8e98526bd7457f4c57667ceb
2018-01-25 19:54:57 +01:00
Max
164b59d757 TBF: decrease L1 logging verbosity in test
Don't clutter output with low-level details.

Change-Id: I451f2472070dea2387bfaea45ca5bdd9e3b2276d
2018-01-25 19:54:57 +01:00
Max
d2d51ed109 cosmetic: fix whitespace issue with include files
Change-Id: I401fe88f5bd1665becd6fe6d4204b3877d548ccc
2018-01-25 16:24:34 +00:00
Max
01bd0cc42f Add multislot classes from latest spec
The table B.1 is copy-pasted from 3GPP TS 45.002 and reformatted via
Emacs macros into C struct to avoid typos. The test output expanded
accordingly.

The allocation test expectations and output are adjusted accordingly.

Note: classes 35-45 which need TA offset are not properly supported
yet. This can be extended once we have such devices available for tests.

Change-Id: I1ef2eb99c517f25e7d1e71b985a3e0eb3879eb2c
Related: OS#2282
2018-01-25 16:12:58 +00:00
Max
9f46071409 AllocTest: remove assumption on max MS class
So far the allocation was only tested up to hardcoded MS class 29. Drop
that assumption and test for all supported MS classes. Adjust expected
test output as necessary.

Note: using mslot_class_max() forces allocation for MS classes 30 and 31
for which no actual data is available (will be added in follow-up
patches) which current implementation treats differently depending on
TX/RX direction - see gprs_alloc_max_dl_slots_per_ms(). Because of that
we have to adjust the expected number of allocations in
test_successive_allocation() as well.

Change-Id: I7737f303d97197ef159b14a19c3312a11f07b433
Related: OS#2282
2018-01-25 16:12:57 +00:00
Max
c59ef12e51 AllocTest: expand test output
* print MS classes
* unify and print test mode description
* print additional info on test completion

This only changes meta info about test run but not the actual test
output.

Change-Id: I30a4b8f561a9677f4e9ded33a051a249bd15a6a2
Related: OS#2282
2018-01-25 16:12:57 +00:00
Max
2ecf0fdfc2 AllocTest: adjust test_alloc_b()
This function contains 3 independent test cases. Let's split them into
separate functions to simplify further modifications:

* split test cases into separate functions
* use them for mass test as well
* change function names to avoid confusion
* make individual test cases return error instead of failing via assert
  on allocation failure

The top-level test_alloc_b() is used as part of exhaustion tests in
test_all_alloc_b() for example, so it's expected that allocation might
fail (due to TFI or USF exhaustion for example) eventually. In this case
it's better to indicate it to caller instead of failing entire program.

The test output does not require any adjustements because we do not
exhaust to the point of allocation failure yet.

Change-Id: Id7e03a85ce96e7d617cecee963759bae589a3a1a
Related: OS#2282
2018-01-25 16:12:57 +00:00
Max
46fbfceac6 Add tests for find_multi_slots()
* make function public
* add tests

Change-Id: I4174703808335c19341cd5b5f4422496d958967f
2018-01-25 16:12:56 +00:00
Max
fdd79e9828 TBF: adjust test log levels
* enable debugging for DTBF*
* disable excessive DRLCMAC*

Change-Id: I122620941e7939d513742c8589a75e0ab76f79ab
2018-01-24 11:07:01 +01:00
Max
cac6b66638 TBF: make poll state internal
* add functions/macros for setting TBF's poll state
* add function for checking TBF's poll state

Change-Id: I6db1c4e7bd0a49aeb5e391afe371c36b96c6a702
Related: OS#1539
2018-01-24 11:06:55 +01:00
Max
088c7df571 TBF: make UL ack state internal
* add functions/macros for setting TBF's UL ack state
* add functions for checking TBF's UL ack state

N. B: this should not be confused with TBF-UL state.

Change-Id: I144483447d4b0b93e775da0e926ee45eb8ab39f3
Related: OS#1539
2018-01-24 11:06:37 +01:00
Max
0e5998087e TBF: make UL/DL state internal
* add functions/macros for setting TBF's UL/DL state
* add functions for checking TBF's UL/DL state
* move pre-free check into separate function

N. B: this should not be confused with TBF-UL or TBF-DL state.

Change-Id: Idcbf5775d17b1247f2ed01788f9b0788ce66e871
Related: OS#1539
2018-01-24 11:06:22 +01:00
Max
0524e38d9e TBF: add dedicated log categories
Previously all TBF-related events were logged as part of DRLCMAC which
is too broad to make it practically useful due to excessive amount of
log messages generated. Introduce dedicated log categories for
TBF-related events. Adjust test output as necessary.

Change-Id: I64d660e5971263d5c63d2ba95d50625c16a594aa
2018-01-19 18:49:16 +01:00
Max
d81b3bf360 Set V_N and V_B to known initial state
Reset V_N and V_B in UL/DL window class constructors to make sure we
always start from known initial state.

Related: OS#1759
Change-Id: I8e14ffa913b49c5394229220de9165cdfaabdf19
Fixes: CID70468, CID70469.
2018-01-17 15:57:26 +00:00
Max
4cb6e04914 jenkins.sh: Disable building doxygen for deps
Don't clutter build logs with irrelevant output.

Change-Id: If1784baa519c10ab0ab3e600f373c27a6c8ae4c6
2018-01-17 15:56:57 +00:00
Max
2399b1dbfc TBF: log source of state transitions
We use the same approach for osmo_fsm: when state transition happens,
it's not very useful to always log the transition function itself, it's
much more useful to see where the actual transition comes from.

Change-Id: I348ba89bdda2b44c7019e9c893c764ee08c80bec
Related: OS#1759
2018-01-17 15:47:32 +00:00
Max
186206cff2 Allow specifying sysmocom headers explicitly
The headers for LC1.5 are specified explicitly. Add corresponding option
to specify sysmoBTS headers location and use it in jenkins build. While
at it, unify header fixup code with the one used in OsmoBTS.

Change-Id: I5248e8b389fd240b4d5a0bcf6c954d6115262462
2018-01-17 11:17:43 +00:00
Max
6298fbb7b2 Use Timing Advance Index in UL assignments
Write TAI (if available) when generating Rest Octets for UL
Assignment. This should not affect actual PCU behavior because TAI is
not yet supported by upper layers but we have to adjust corresponding
tests anyway.

Change-Id: I8b17be78a46c0bc17516b7c90f35aa4768010ae4
2018-01-17 10:50:14 +00:00
Max
93d947f5e8 Rewrite Packet Uplink Assignment
Use bitvec_set_*() directly without external write pointer tracking to
simplify the code. This is part of IA Rest Octets (3GPP TS 44.018
§10.5.2.16) which is the last part of the message so it should not
interfere with the rest of encoding functions.

The tests are adjusted accordingly.

Change-Id: I44db2eeea7448ff67e688ae716487bc6dbfc96a3
Related: OS#1526
2018-01-17 10:50:14 +00:00
Max
896574e92b Rewrite Packet Downlink Assignment
Use bitvec_set_*() directly without external write pointer tracking to
simplify the code. This is part of IA Rest Octets (3GPP TS 44.018
§10.5.2.16) which is the last part of the message so it should not
interfere with the rest of encoding functions.

The tests are adjusted accordingly.

Change-Id: I52ec9b07413daabba8cd5f1fba5c7b3af6a33389
Related: OS#1526
2018-01-17 10:50:14 +00:00
Max
529ce88545 Rewrite EGPRS Packet Uplink Assignment
Use bitvec_set_*() directly without external write pointer tracking to
simplify the code. This is part of IA Rest Octets (3GPP TS 44.018
§10.5.2.16) which is the last part of the message so it should not
interfere with the rest of encoding functions.

Reusable fragments are split into static helpers.

Change-Id: I2139fb347b3290621bbc3f6a031f7f213d372e65
Related: OS#1526
2018-01-17 10:50:14 +00:00
Max
2141962baf Fix sanitizer build
Add sanitizer flags to linker as well to resolve linker error.

Change-Id: I695baaf8ce78ed938f6f71c40d17120fa690338b
2018-01-15 17:23:17 +01:00
Max
71affcedba Allocate global context for TypesTest
Missing allocation leads to LSAN error:
==24997==ERROR: LeakSanitizer: detected memory leaks

Indirect leak of 230 byte(s) in 2 object(s) allocated from:
    #0 0x7feaa1b2fb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
    #1 0x7feaa13dbc80 in _talloc_zero (/usr/lib/x86_64-linux-gnu/libtalloc.so.2+0x5c80)

Change-Id: I62c03dad353f459abcdb7a18a69b7782da38dfb7
SUMMARY: AddressSanitizer: 230 byte(s) leaked in 2 allocation(s).
2018-01-15 17:23:17 +01:00
Max
3e659ea9b7 Fix jenkins.sh to match jenkins job axis filter
The 'yes/no' values are automatically converted to True/False upon
jenkins job instantiation. Let's use those directly.

Change-Id: Ib2100c8345d1f07f488de8170348fec9f877dd9b
2018-01-12 17:07:13 +00:00
Max
00fd0df046 Don't access TBF internals in vty functions
Obtain corresponding window object of UL/DL TBF by using proper accessor
function instead of direct access to private member.

Change-Id: I89bcd2c2b0b6f120d40d20fd43c1e516de3e3950
2018-01-12 16:37:45 +01:00
Max
9d7357e4fe TBF: unify EGPRS window calculation
Move actual calculation into shared function and use it to set window
size for TBF. TBT test output requires cosmetic adjuestements due to
extended debug output.

Change-Id: Ib9f4a277082da3c71007f5f3b4f2acac8b994540
Related: OS#1759
2018-01-12 15:29:42 +01:00
Max
d0532b53eb TBF-DL: move priority computation into function
Improve readability by moving priority computation into separate
function.

Change-Id: Icdca0106a544036eaa94a25f0d4f84e4282f4568
2018-01-12 15:29:41 +01:00
Max
ea98b7d784 TBF: move window parameters to UL/DL level
The UL and DL TBF use different classes implementing window
management. Hence it's better to use it explicitly instead of using the
common window management superclass inside common TBF superclass. While
at it, also remove the direct access to window class - use accessor
functions instead.

Related: OS#1759
Change-Id: I0b55aa8947db65f7206adcf53ea32b74a831d9e6
2018-01-12 15:29:41 +01:00
Max
7d32f55e4e Avoid code duplication in TBF test
Move repetitive checks into corresponding macros to avoid copy-pasted
code. This also enables strickter checks some of which were apparently
omitted while copy-pasting.

This is part of preparation work to move to separate UL/DL windows.

Related: OS#1759
Change-Id: If7aa72f5aa66c5e9c255542c066b5494c098aab2
2018-01-12 15:29:41 +01:00
Max
2617bf2016 TBF-UL: add simpler test helper
Add function to set both V_R and V_Q values to 0 which is useful for TBF
test.
Related: OS#1759
Change-Id: I719abfbd5b88c694cbbd69d5c4dcb42baaca91b2
2018-01-12 14:26:28 +00:00
Max
58818585bc Clarify RACH-related interfaces
* make is_11bit parameter into bool
* remove is_single_block() from public interface and mark it as static
* move logging outside of if ladder
* move side-effects from is_single_block() into separate static
  functions
* simplify UL-TBF allocation in case of 11-bit RACH

This immediately makes it obvious that priority is never actually used
despite being computed - seems like a leftover from merge of incomplete
patch series.

Change-Id: If189b7166a29a87ffb17a7a9bc560f674851fd53
Related: OS#1548
2018-01-12 14:24:00 +00:00
Max
8dce1de6d2 TBF: cleanup state flag handling
* introduce generic function to check whether particular flag was set
   for'a TBF and clear it if necessary. Use this instead of
   clear_poll_timeout_flag()
 * add function to explicitly set assignment and appropriate state flags

Overall this makes the code easier to read and debug.

Related: OS#1759
Change-Id: Ic4560280c72f91700f2e19c6c7f6658dc29625c2
2018-01-12 14:17:52 +00:00
Max
5081806f4d Make TBF state private
Let's make sure no external function can mess with the TBF state.

Change-Id: I217f4c4bac21dd584c8682928a080a1a6e9507e1
2018-01-12 14:17:10 +00:00
Max
b3a17d6074 cosmetic: clarify coding scheme and puncturing
* use appropriate types for coding scheme parameters
* add comment regarding possible number of RLCMAC blocks

The code in create_dl_acked_block() has underlying assumption that
rlc.num_data_blocks can never be more than 2, which is true and is
enforced by appropriate asserts but is not obvious when looking at the
function code alone. It's equally hard for Coverity which leads to false
positives in scan.

Lets' make this assumption explicit by putting it into for(;;) condition
alongside with corresponding comment.

Fixes: CID143070
Change-Id: If599a6c8a6ef56d847604fcf41bb71decccd8a78
2018-01-04 16:35:55 +00:00
Max
a4f570fe7a window: move encoding into functions
* move window size encoding and writing into separate functions
* introduce necessary TBF wrappers to avoid direct m_window access

This is part of preparation work to move to separate UL/DL windows.

Related: OS#1759
Change-Id: I60184d5049bc7d7b119df5a9eb82d1c4b788c840
2018-01-04 10:15:59 +00:00
Max
7df82d412e TBF-DL: mark rcvd_dl_ack() parameters as boolean
The final(_ack) parameter of rcvd_dl_ack() only used as boolean - mark
it as such.

Change-Id: Icc4d68f049a45d4b42c5594f50594ff0d44c1bac
2018-01-04 10:15:59 +00:00
Max
869c0c2e55 Fix llc_queue_size() type
It either returns 0 or LLC queue size() which has size_t return
type. This means it can never be negative - hence it's better to use
size_t as return type.

Change-Id: I2a6e849d349ab12854976bd0d68537a370a9c83d
Fixes: CID181478
2018-01-03 12:00:36 +01:00
Max
0bc982e714 TBF: bail out for unknown timers
Return right after logging error if attempting to start or stop unknown
timer.

Change-Id: Ie6ae564d41a5e03270685c6bafb3504278eb3551
Fixes: CID181512, CID181514
2018-01-02 07:26:05 +00:00
Max
467f633b16 TBF: log timer invocation source
When troubleshooting TBF timers we're not only interested in timer
duration but also in the code which triggered it. Let's use LOGPSRC to
log it: wrap t_start() in a macro for convenience.

Change-Id: If5f883ae52c469e5158bad24da9904fdc455582f
Related: OS#2407
2018-01-02 07:26:05 +00:00
Max
b2de1f7888 TBF: unify timer handling
Use generic timer handling infrastracture to handle assignment/reject
internal timer. Rename timer array accordingly. Use defines with
explicit second/microsecond values to make it more readable.

Change-Id: I63fb7e6f0695383a83472c836a381a055f64690b
2018-01-02 07:26:04 +00:00
Max
effdec6e13 Add optional profiling support
This facilitates the use of programs like uftrace. It's disabled by
default due to associated overhead.

Change-Id: I5c16988cefa46e0b958030c0f3bff9efc5b4979d
2017-12-28 14:18:02 +01:00
Max
20c7c46bce Add tests for pcu_lsb()
This utility functions is used by TBF allocation routines and only
tested indirectly through allocation test. Let's add proper exhaustive
test which checks all uint8_t values.

This also requires adding missing include to pcu_utils.h

Change-Id: If08a7f0d31f0e5ad8a5efa5885880aed19c329ab
2017-12-22 14:20:05 +01:00
Max
406a1f0acf Enable sanitize for CI test
Change-Id: Ia33ffb9b25df587706367bc24925cf9cead3b9a0
2017-12-21 17:34:19 +01:00
Max
b2f0b62cd4 Add --enable-sanitize configure option
Change-Id: Idb2c1d6057012ed2f032e7504387a0767d02d75b
2017-12-21 17:27:34 +01:00
Max
327e121a0f Add function to get max supported MS class
It's useful for allocation tests.

Change-Id: I31d503af700ec3364042ff7e661710953cacf9f8
Related: OS#2282
2017-12-21 15:13:25 +01:00
Max
1714aeaa67 Fix warnings
Fix warnings detected by compiler and coverity scan.

Change-Id: If463c7f8769e18d3df74837f0cb0f545cca9b23e
Fixes: CID181479
2017-12-21 11:19:39 +01:00
Max
59e4a4fee1 TBF: add N3101 counter
Properly reset the counter when receiving valid RLCMAC block and update
it when no data is received as per 3GPP TS 44.060 §8.1.1.1

Change-Id: I2f79c6153dc4073c9d293b2824979e6381576682
Fixes: OS#2407
2017-12-20 18:01:55 +01:00
Max
ee5be3a009 TBF: implement independent T31xx timers
Previously TBF got single timer so the pending timer was automatically
cancelled when new one was scheduled. Let's make it more robust by
implementing independent T31 xx timers from 3GPP TS 44.060 §13.2 with
corresponding start/stop functions and counters.

The semantics of the timers is preserved as before: pending timers are
restarted unconditionally. It might be neecessary to change this later on
after spec review.

N. B. T0: used for assign/reject timeouts, have to be properly
attributed and documented first.

Change-Id: I0305873ca47534f53441247217881da59625e1f7
Related: OS#2407
2017-12-20 17:49:25 +01:00
Max
c21f007277 Introduce LOGTBF* for consistent logging
When troubleshooting complex issues with TBF lifecycle, it's much easier
to follow the logs which are consistently formatted. Add LOGTBF*() macro
similar to struct-specific log routines we use in other Osmocom project
and use it to log TBF-related messages in a unified way. Tweak test
output accordingly.

Related: OS#2407
Change-Id: I388249afefc32d2f6e5cb5e5abc6daf4dbd284ea
2017-12-20 14:14:40 +00:00
Max
ea9968f685 Fix tests after rate_ctr change
Recent change lin libosmocore disallow registering rate_ctr with the
same name and indexing multiple times. To accommodate to this check if
rate counters arealready allocated (by static allocator of BTS singleton
for example) and register rate counter with different index.

This fixes the tests for now but eventually we'll remove the BTS singleton
which will allow us to remove this hack.

Change-Id: I7c552ce653b44ec3a31049641728926adc07361d
Related: OS#2757
2017-12-18 22:58:28 +00:00
Max
ef784e4e9e Remove unused includes and forward declarations
Change-Id: I59da04edd1b8ff965bbfbe00ccae1f7c9b6e5301
2017-12-18 22:05:22 +00:00
Max
912131803b TBF: remove unused variable
The num_T_exp is write-only so it can be safely dropped.

Change-Id: I94d83ca8c9b2f0732b53fdf42b17ba93cd7f1c15
2017-12-15 17:44:47 +01:00
Max
1a11d1db09 TBF-DL: fix misleading idle time check
The dl_tbf_idle_msec is uint32_t so it cannot be < 0.

Change-Id: Ic88cb4698bcb9be52a5179529f81b8728bf4f93f
2017-12-15 14:28:34 +00:00
Max
25a3ca4e59 TBF: move EGPRS enablement into (U|D)L-TBF
This is preparation patch for transition to separate UL/DL window
variables instead of current shared generic window. The setting of
window parameters is performed in functions specific to UL/DL TBFs but
the general EGPRS flag remains the same and is set via the same function
which is now marked as protected since it's only meant to be used by
UL/DL subclasses.

Related: OS#1759
Change-Id: I6056194b28a1eb9d69093d1dfdc65a11bc1fc579
2017-12-14 12:20:53 +01:00
Max
ead08aae35 DL window: constify resend_needed() function
It doesn't change any state so mark it as const.

Change-Id: I5d672bfd654198aebb187772de464c52b3209435
2017-12-13 18:25:36 +01:00
Max
39eb95f130 vty: print class and TBFs for each MS
It's handy for troubleshooting to get quick overview of per-MS TBF
allocations and MS [EGPRS] classes.

Change-Id: Ie79c20f86da6db4565654b0f5856f4fddd83ef96
2017-12-06 13:15:32 +01:00
Max
cea806e5b9 TBF: expand timer logging
* log timer values
* log start/stop cause
* update test output as necessary

This simplifies debugging issues with TBF timers.

Related: OS#2407
Change-Id: Ib8e537416af9bec5d447356286f44e9e8bbf1b7a
2017-12-05 18:47:22 +00:00
Max
b4d368b576 TBF: fix compiler warning in test
tbf/TbfTest.cpp: In function ‘void egprs_spb_to_normal_validation(BTS*, unsigned int, unsigned int)’:
tbf/TbfTest.cpp:2788:26: warning: ‘<<’ in boolean context, did you mean ‘<’ ? [-Wint-in-bool-context]
  bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1)
         ~~~~~~~~~~~~~~~~~^~~~~
tbf/TbfTest.cpp:2788:53: warning: ‘<<’ in boolean context, did you mean ‘<’ ? [-Wint-in-bool-context]
  bsn1 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1)
                                   ~~~~~~~~~~~~~~~~~~^~~~~
tbf/TbfTest.cpp:2825:26: warning: ‘<<’ in boolean context, did you mean ‘<’ ? [-Wint-in-bool-context]
  bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) ||
         ~~~~~~~~~~~~~~~~~^~~~~
tbf/TbfTest.cpp:2825:53: warning: ‘<<’ in boolean context, did you mean ‘<’ ? [-Wint-in-bool-context]
  bsn2 = (egprs3->bsn1_hi << 9) || (egprs3->bsn1_mid << 1) ||
                                   ~~~~~~~~~~~~~~~~~~^~~~~
tbf/TbfTest.cpp:2844:26: warning: ‘<<’ in boolean context, did you mean ‘<’ ? [-Wint-in-bool-context]
  bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) ||
         ~~~~~~~~~~~~~~~~~^~~~~
tbf/TbfTest.cpp:2844:53: warning: ‘<<’ in boolean context, did you mean ‘<’ ? [-Wint-in-bool-context]
  bsn3 = (egprs2->bsn1_hi << 9) || (egprs2->bsn1_mid << 1) ||
                                   ~~~~~~~~~~~~~~~~~~^~~~~

Change-Id: Idf9e5f15faa7810411ed9d68ed43cf907eea2545
2017-12-05 18:47:21 +00:00
Pau Espin Pedrol
da0a194b57 Print error cause of pcu socket connect failure
This log is useful to quickly debug scenarions in which pcu never
connects to bts. For instance, if bts is started as root and pcu is not,
pcu will fail to connect to the socket and will fail with "Permission
Denied".

Change-Id: I6fd5736b5916cbad72b96f064929bb667ff97ded
2017-12-05 18:44:06 +01:00
Max
59f50c2718 TBF: log timer override
Currently TBF support only single Txxxx timer so scheduling another
timer will cancel out the one which is already running. Until the proper
fix is in place, let's at least log this situation as error.

Note: cosmetic adjustement to test output is required - we do not report
restart of the same timer twice because "restarting" assumes it anyway.

Change-Id: I462464a1e6df937b72cad65d19cd48e95dc4db45
Related: OS#2407
2017-12-04 10:55:47 +01:00
Max
701afa4b3a Fix compiler warning
Move function declarations which use gprs_rlcmac_ul_tbf into tbf.h to
avoid compiler warning:

In file included from pcu_vty.c:15:0:
bts.h:166:27: warning: ‘struct gprs_rlcmac_ul_tbf’ declared inside parameter list will not be visible outside of this definition or declaration
 void update_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, int8_t ta_delta);
                           ^~~~~~~~~~~~~~~~~~
bts.h:167:24: warning: ‘struct gprs_rlcmac_ul_tbf’ declared inside parameter list will not be visible outside of this definition or declaration
 void set_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, uint8_t ta);
                        ^~~~~~~~~~~~~~~~~~

Change-Id: Ic34c72c8bff6d7c775f56bb6026fec5425f7dcb4
2017-12-01 17:19:04 +01:00
Max
a5eb67d91c Replace '.' in counter names with ':'
The '.' is an illegal character in counter names, as they are exported
via CTRL interface, where '.' has a special meaning that cannot be used
by strings comprising the variable name.

Change-Id: I5ef60152a31dea25cb839c47edc93d5337ec3a3e
2017-11-21 20:24:54 +01:00
Max
842d781b5e Move multislot table to separate file
To facilitate testing and addition of support for new multislot classes,
hide multislot class struct internals:

* introduce mslot_class_get_*() functions
* use those functions instead of direct access to array of structs
* use ms_class as a parameter to find_multi_slot() instead of entire
  object

Change-Id: Id796bcff1322b1e273a0e3236c66c23b9da8fac6
2017-11-21 10:45:24 +00:00
Max
b709144f1b Remove unused parameter
Change-Id: Ifd6e04a29e27b1862cf9e98dec7481d3e0efcd48
2017-11-21 10:45:22 +00:00
Minh-Quang Nguyen
8d55563523 PCU: display TA information in TBF stats
Change-Id: I26886224c2ad6d5a29e92203635b8bf7459730a2
2017-11-16 10:06:58 -05:00
Minh-Quang Nguyen
1bcfa9aacf PCU: Fix TA adjustment
Promblem:
 TA provided from L1 PH-DATA-IND is a relative amount of TA adjustment to actual TA
 being used for given TBF. The current TA update algorithm in PCU simply applies the relative
 amount of TA to given TBF but does not take into account of current TA.
 As a result, the PCU will request wrong TA jump for given TBF if the MS is moving away from
 BTS more than 2 km.

 Related issue: http://osmocom.org/issues/2611

Fixes:
- The PCU needs increase or decrease current TA of given TBF on receiving of relative
  amount of TA adjustment provided by PH-DATA-IND from L1
- The PCU needs to set absolute TA of given TBF on receiving absolute TA provided by
  PH-RA-IND from L1.

Change-Id: I65212f8203f1a35278890f51db038d689b2493d5
2017-11-16 10:06:41 -05:00
Neels Hofmeyr
bfc54b551b vty: skip installing cmds now always installed by default
vty_install_default() and install_default() will soon be deprecated.

Depends: I5021c64a787b63314e0f2f1cba0b8fc7bff4f09b
Change-Id: I6c9f928f4a4d7fd6bf37c64a64ee5d843ad5bb7a
2017-11-01 00:51:51 +01:00
Neels Hofmeyr
49beba49eb jenkins: use osmo-clean-workspace.sh before and after build
See osmo-ci change I2409b2928b4d7ebbd6c005097d4ad7337307dd93 for rationale.

Depends: I2409b2928b4d7ebbd6c005097d4ad7337307dd93
Change-Id: If8aa657c4bf62ef62549fbe9dc15ce3fb018d8d9
2017-10-30 04:22:10 +00:00
Harald Welte
d34ec1b969 Tag/Release Version 0.4.0
Change-Id: I8559585a4513dddf1516c2a2b08968556c69b7ec
2017-10-29 12:10:13 +01:00
Harald Welte
47c682937c Debian: upgrade to debhelper 9 / Standards 3.9.8
Change-Id: I1fd274d85b8fd344517d62dd9e6adc4af6de3e26
2017-10-29 12:10:13 +01:00
Harald Welte
e64917a932 Debian: migrate from DEB_BUILD_HARDENING to DEB_BUILD_MAINT_OPTIONS
Change-Id: Ic400c509ecd0c6e8485e9433f144528f6abc600d
2017-10-29 12:10:13 +01:00
Harald Welte
9dab1baef8 Debian: print test results in case of failure + clean-up autotest
Change-Id: Id912a106d42bbd9d2ad89b67d16d52cb2344eb6d
2017-10-29 12:10:13 +01:00
Harald Welte
f826e8ab2b Debian: Cosmetic changes to control file; add better Description
Change-Id: I0a8bf134757f6ed754bfefd45a9fdac255447e43
2017-10-29 12:10:13 +01:00
Harald Welte
3e51d3e5bd Call osmo_init_logging() before static BTS constructor
The BTS constructor uses functions of libosmocore that could in turn
want to log something.  This requires the logging to be initialized
before.

The only way to achieve this is to add an __attribute__((constructor))
function *before* the BTS constructor is being run.

This solution might not be elegant, but  I guess it's the only way to
initialize a C library before calling C++ constructors of global static
instance of a class.

In case anyone comes up with a better / cleaner approach, we can always
change later.

This change requires libosmocore >= 0.10.1, as only that permits
multiple calls to osmo_init_logging() which may now occur.

Change-Id: I28dc4f0db229518348c92413959fed5ae85d753d
2017-10-29 11:02:34 +01:00
Harald Welte
ac0490ad2a tests: Don't use private version of log_info but global gprs_log_info
There's no need for each test case to carry their own log_info and
filter function.  They can simply use the global gprs_log_info and
configure the stderr log verbosity according to their needs.

Change-Id: I8706a624e5d06e062d1198711aa197fbd0860769
2017-10-29 11:02:34 +01:00
Philipp Maier
4c9ec22546 gb: allow only packets from a specific SGSN
Each PCU has a specifically assigned SGSN, which may send
packets to the PCU. Ensure that no one else except the
configured SGSN can send packets to the PCU.

Change-Id: Ic2009039fab7cf0fba916556239747ae5b410366
Depends: libosmocore Ifeb201d9006eec275a46708007ff342cdfc14e45
2017-10-24 10:50:17 +00:00
Max
a4f4822784 cosmetic: reformat multislot classes table
Add header similar to the one used in the standard, reformat to
facilitate further extention.

Change-Id: I786df6b154c0668d2cefa0ea84d7dea336b0da1d
Related: OS#2282
2017-10-10 19:02:43 +02:00
Max
5b0df1f1c5 TS alloc: properly count UL slots
Add cycle to mark multiple allocated UL slots similar to the way we
count DL slots in AllocTest. Until multislot UL allocation is
implemented it does not affect test output.

Change-Id: I2705405119421da3066c6c6bdd5830df4c133a36
Related: OS#2282
2017-09-12 11:58:29 +02:00
Max
5759a19020 TBF-DL: extend index check for RLC block copy
Log number of RLC blocks to copy and assert if trying to copy too many
blocks.

Change-Id: I01cbc26ec67400a44e9fff3f9a30d729320380f9
Fixes: CID143069
2017-09-08 12:58:28 +00:00
Max
1962136a33 Assert valid CS
The coding scheme converted to number make sense only if it's
valid. This is implicitly assumed by the code using this conversion as
non-zero value. Make those assumptions explicit with OSMO_ASSERT().

Change-Id: I8f62627b7b7b89dfa1b0d1a7e71b95b2c40fdffa
Fixes: CID70466
2017-09-08 12:51:03 +02:00
Max
5a6bcfb797 cosmetic: convert explicit warnings to fixme/todo
We do not use this style (#warning as an issue tracker replacement) in
any other Osmocom project. Also those warnings clutter compiler output
making it harder to spot warnings for the actual code.

Change-Id: I72070e2a027e60e8b80c12ccfa23ff075434689f
2017-09-04 13:06:01 +00:00
Max
8bfa659087 Move gsmtap and accounting into separate function
Change-Id: I3609da1850244f25bd4611c9d25795ca379d6325
2017-09-01 11:08:06 +02:00
Max
84bf0faed9 Support receiving SI13 from BTS
* store SI13 in BTS struct
* check and handle BCCH SAPI

Change-Id: I610a93ce23725b182ec14e3507331295bd542f74
Related: OS#2400
2017-09-01 11:08:06 +02:00
Max
b216c6b165 cosmetic: tighten direct-phy related code
* move the code to related SAPI case
* get rid of 'unused variable' warning if direct-phy is not used

Change-Id: If8cae6f3579cfdecc25bbe1d08fa88a4f664a03b
2017-09-01 11:08:06 +02:00
Max
10e37a5089 Use value string check from osmo-ci
Change-Id: Ib9c595ef80cb6b0d126d4da8244f6435e0526095
2017-08-24 19:04:44 +00:00
Max
d78adfb577 Facilitate future releases
* use release helper from libosmocore
* use semantic versioning

Change-Id: Ie0a7f5977550bd0a1ba8b03bdb7e2d619a398e4e
Related: OS#1861
2017-08-24 13:53:25 +02:00
Minh-Quang Nguyen
1f18909335 EDGE: Fix UL link adaptation.
We have seen that UL MCS5- MCS9 link adaptation has not been implemented in current PCU implementation.
If the MS slowly moves far away from the BTS, the UL MCS will always stick at MCS9 no matter UL link quality values leading to poor data service experience.
The UL MCS is expected to adapt from MCS9 -> MCSx due to bad UL quality.

Below PCU traces indicate that UL MCS is quickly increasing to MCS9 (max MCS 9 was used in this test) and it never changes to other UL MCS due zero thresholds.

<0004> gprs_ms.cpp:670 MS (IMSI ): Link quality 23dB (23dB) left window [0, 0], modifying uplink CS level: MCS-6 -> MCS-7
<0004> gprs_ms.cpp:670 MS (IMSI 000): Link quality 23dB (23dB) left window [0, 0], modifying uplink CS level: MCS-7 -> MCS-8
<0004> gprs_ms.cpp:670 MS (IMSI 000): Link quality 23dB (23dB) left window [0, 0], modifying uplink CS level: MCS-8 -> MCS-9

Change-Id: I9272c337ad6399da4a47cc6e2736e25f24e099d8
2017-08-18 18:09:24 +00:00
Harald Welte
b1be6112bb GSMTAP: fix category checks in pcu_rx_data_ind and pcu_l1if_tx_ptcch
We needto shift the PCU_GSMTAP_C_* constants before comparing against
the mask of enabled GSMTAP categories.

Change-Id: Ieb9332c65ed7bd57baf1aeab5ab722f92fc23b24
2017-08-17 00:50:24 +02:00
Max
f60cf62f4f Simplify polling troubleshooting
* introduce enum describing poll kind and use it in set_polling()
* move state change into set_polling()
* move logging into set_polling() and unify output
* move duplicated code into static function
* adjust tests to match unified logging output

Change-Id: I14074207f8bbc18b3ebd60875bb99a0a3a4b399d
Related: OS#1524
2017-08-14 15:19:08 +00:00
Max
a10c39866b Move DL assignment to TBF-DL
This function does not really belongs to BTS and it heavily relies on
direct access to TBF-DL members anyway.

Change-Id: I04584103018675a2f35cfb565473bfd81a208d7c
Closes: OS#1540
2017-08-14 15:50:47 +02:00
Max
341dccd7e2 Move common code into functions
* separate channel request responder into inline function
* move generic TBF poll check into inline function

Change-Id: I9ec3ab8de100f0bc75044f55ac769d1083d52806
Related: OS#1539
2017-08-14 15:49:59 +02:00
Max
fd13f6c199 Encapsulate handling of UL ACK timeout
Use helper methods instead checking and manipulating flag directly.

Change-Id: Ia3f009c52118db95b38a077e08eecda844e7f8d1
Related: OS#1539
2017-08-14 15:48:37 +02:00
Pau Espin Pedrol
c4178e55ea Add pcu-socket vty config
osmo-bts already supports configuring a different path for the bts<->pcu
socket by using the 'pcu-socket' config field.

Change-Id: I9b3e1171da467519750b201849ec892a1e318129
2017-08-09 12:17:39 +02:00
Harald Welte
0cd8e4eade README: Clarify that fixed allocations have been revmoved from 3GPP specs
In Release 5, Fixed Allocations were removed as part of a "GPRS
simplification project" inside 3PGPP.  This means that any MS compatible
with Rel-5 or higher may not support it, which makes implementation
in the PCU af historical interest only.  See Tdoc GP-021277 for the
actual removal, it happened at 5.0.0 time.

Change-Id: I8138bc0a47d3468b67cec866447fd4b0fc69d4c5
2017-07-29 22:15:02 +02:00
Harald Welte
bc219d5450 GSMTAP: Ad PTCCH as separate gsmtap category
This allows us to send GSMTAP for PTCCH only if requested by user/vty

Change-Id: Id720f4bebdce7f6152fbddddbe05036638c5866e
2017-07-29 13:43:30 +02:00
Harald Welte
cd34dd3b2b GSMTAP: Fix logical channel of downlink PTCCH
Change-Id: I29ecc968d56d4d0165cffa206297c42d6fb02cf4
2017-07-29 13:43:30 +02:00
Harald Welte
f7740aa44b GSMTAP: Fix channel type for data blocks: PDTCH instead of PACCH
PACCH is used only for RLC/MAC control messages, while PDTCH is used
for data.

Change-Id: I6c912e17d8c8d4178096679a541e61eeeb4b6643
2017-07-29 13:43:30 +02:00
Harald Welte
05d7b5dd59 BSSGP: Improve logging of received messages
We now differentiate clearly between messages that

a) we don't expect based on our reading of the spec
b) we have not implemented yet (but should)
c) we do not even know of

Also, unify the log string formats and provide BVCI whenever possible.

Change-Id: Ie32f5771d49960547ec5d7611f96a74facc1b035
2017-07-29 10:21:24 +02:00
Harald Welte
18a17aa487 Remove #warnings that have been adressed since 2015
In commit 9399046729 the lookup by
TLLI, TLLI-OLD and IMSI has been implemented, but the corresponding
compile-time warning was never removed.

Change-Id: I7a1767bc7cab01048e851fd4e63112bc676d6c78
2017-07-29 10:21:24 +02:00
Max
2813f931dd BSSGP: Use libosmocore for BVC-RESET
Implement proper BVC RESET procedure by using libosmocore code to handle
BVCI reset and initiate PTP BVC reset if necessary.

Requires I9bf8f4dd784ccddbb9926492a85fff3293a0e913 in libosmocore.
Related: OS#1638
Change-Id: I718c949759688cb34ce6bcbb3da2092fcdfa6989
2017-07-28 17:42:45 +00:00
Harald Welte
717cdf5405 Introduce GSMTAP categories
When looking at GSMTAP output so far, one is easily overwhelmed by way
too much information being presented.  A lot of is consists of DUMMY
frames, which are probably of lowest interest, ever.

A concept similar to the "gsmtap-sapi" of OsmoBTS is introduced, by
which the user can configure which particular categories (uplink or
downlink control or data, gprs or egprs, ...) he actually wants to
see in his logs.

Change-Id: I297183690e98a7234dfc1608c18847d8981306e4
2017-07-21 22:15:28 +02:00
Harald Welte
9530a404ce check for missing result of rate_ctr_group_alloc()
In case the counter group allocation fails, we must handle this
gracefully and fail the allocation of the parent object, too.

Change-Id: Id6d780c67b4af15aaa5c6f2b8b00f2a0b70a7385
Related: OS#2361
2017-07-12 00:47:10 +02:00
Harald Welte
8c8027c307 jenkins.sh: Proper error message if local environment isn't set up
Change-Id: Ibd24ba6024714f3d7aac14ef661acf52de2a3825
2017-07-10 14:01:07 +00:00
Max
aae1bfbbe0 Remove TBF knowledge from rcv_control*dl_ack_nack
Do not access TBF internals directly from rcv_control*dl_ack_nack() -
wrap corresponding code into TBF-DL method.

Change-Id: I3d1b5782001e45617b4a960612fcfc249904b37c
Related: OS#1539
2017-07-10 09:39:53 +00:00
Max
5579595464 Ignore test binaries using mask
Change-Id: Ic7930c6e715447e91572f7ed6b0d2bb2238cf367
2017-07-10 10:49:02 +02:00
Max
241f5bcb00 Copy sysmopcu.service to osmo-pcu
This way the name of systemd service file will match the name of the
binary similar to OsmoBTS. Add aliases so the user can use both old and
new names regardless of which file is installed. Once the corresponding
changes to OE recipes are applied old file can be removed.

Based on work by Pau Espin Pedrol <pespin@sysmocom.de>

Change-Id: I2ca6f6c486bd6fcf4d5b3d0a05d25dc04f020c26
2017-07-03 18:50:49 +02:00
Max
3741f14689 Remove comment warning
It's unclear why the warning was placed next to commented log statement
to begin with, so let's just follow that warning's advice and drop it.

Change-Id: I3ef7a45d015a28fdadf75f97294bc5d4f825b8ae
2017-06-26 12:10:12 +02:00
Max
865436dee0 lc15: use environment for firmware version
This allows to specify firmware version to use by jenkins builder via
environment variable. If environment variable does not exist than
default master branch is used.

Change-Id: If8b249aa00270e60a0449f089a16823976e54d54
Related: SYS#3683
2017-06-22 17:00:46 +00:00
Max
a468cfaf2e tests: remove unused definition
Fix compilation warning.

Change-Id: I1c95c6ec8bee68773643f9646b0319a83fbc6cfa
2017-06-22 13:28:39 +02:00
Max
062dfa1d0c lc15: use generic L1 headers helper
* use generic L1 headers helper for both sysmocom-dsp and lc15bts-phy
  options
* use sh instead of bash

Related: SYS#3683
Change-Id: I3dc621731f47650cbc15a5f17b9e899e9ed2770f
2017-06-19 12:53:26 +02:00
Harald Welte
49b78229ca use tlvp_val16be() rather than manual pointer-cast + ntohs()
Change-Id: Ib77cb703bb1710da396db3a939700515b5c20235
2017-06-11 11:40:19 +02:00
Harald Welte
c136be04f7 lc15: further fixes regarding --with-litecell15
The fix in 0fb294a8dd was only partially
valid, as it unconditionally used $includedir, without any prefix.  This
polluted the include path with host include files in cross-compiling
builds.

Let's take a different approach and simply define LITECELL15_CFLAGS
(similar to what pkgconfig does), which makes the "-I" go away if no
--with-litecell15 has been specified.

Change-Id: I63393decfe42a24dab56c7654f716c1580416ab2
2017-06-11 11:40:18 +02:00
Harald Welte
0fb294a8dd lc15: fix configure.ac variable substitution causing compile error
When "--enable-lc15bts-phy" is passed to './configure' without specifying
an explicit header file path using "--with-litecell15=", we ended up
generating an empty string as LITECELL15_INCDIR and rendered something
like "-DENABLE_DIRECT_PHY  -I -I../../git/src/osmo-bts-litecell15" as
part of the compiler invocation, where the -I with no argument will hide
the second -I, as the second one is supposed to be the optarg for the
first include.

This in turn made the "#include <lc15_l1_if.h>" fail, when using
separate source and build directories.

This patch fixes the configur script to use $includedir, rather than the
non-existant $incdir as default for LITECELL15_INCDIR

Change-Id: I483e62f8331e7867a92f8055c4d450fdd5288cb6
2017-06-11 10:35:56 +02:00
Max
9dabfa2c2b Cleanup FN scheduling
* replace magic number with defined constant
* move copy-pasted code to inline functions
* remove unused code

Change-Id: I6fee0714453d0c3c3f3f875f88daea2d9c477331
Related: OS#1524
2017-05-26 07:55:52 +00:00
Harald Welte
356ac618f1 Fix format string error (string needs %s)
In a49475b5a8 we introduce the use of
bssgp_pdu_str() and change from printing the numeric code to the
stringified version of the message code.  However, the format string
was not updated accordingly :/

Change-Id: I7173b692fb1f222aab44cd4f44a482038d0f51dc
Fixes: Coverity CID 169684
2017-05-25 19:05:32 +02:00
Max
e8284a7f92 Fix typo in logging
DL-TBD was errorneously printed as UL-TBF.

Change-Id: I94a224c0339a062e4c8d5aa6c4c858f3f0298a0d
2017-05-24 22:19:43 +00:00
Max
a49475b5a8 Print human-readable BSSGP PDU type
Change-Id: Ief4b5ce4e4020edaf771eaa24f4382ec368dd18c
2017-05-23 17:53:38 +02:00
Alexander Couzens
ccde5c9557 remove pcu own bitvector implementation
The osmocore bitvec is exact the same, but use a pointer instead of
a reference.

Change-Id: Id8f797631d89aa12b6e48efb2dc153a3e2f059f7
2017-05-15 12:46:33 +00:00
Neels Hofmeyr
3de6d0602f fix PACCH paging: don't return early in case of NULL TBF
Commit b78a4a6dfe tried to fix a NULL dereference
error, but apparently was overly eager to return, because it looked like all
code paths would dereference the tbf.

In fact the code path further above, for msg != NULL, has "always" dereferenced
the tbf, but the lower code path, the one effecting the paging, has only
started to dereference tbf since shortly before the overly eager fix: in
da7250ad2c, to "update the dl ctrl msg counter
for ms". It seems that this tbf dereference in the paging path is bogus and the
cause for the segfault that made me write the early exit fix.

Fix that fix:

Do not exit early if tbf == NULL, stay in there to be able to reach the paging
path below.

In case of a message to be sent, assume that tbf is present, and verify: print
an error message and abort if there is a msg but no tbf, so that we will see
the error if I'm wrong there. If a tbf is missing, free the msg.

In case of no message, go on to send pending pagings, but do not attempt to
count ctrl messages for a tbf -- IIUC there will never be a tbf if we're
paging.

This should avoid segfaults while keeping PACCH paging intact.

Tweak a comment for and add a blank line above the paging section.

Related: OS#2176 CID#158969
Change-Id: Ib79f4a945e211a13ac7d1e511cc37b0940ac6202
2017-05-15 10:40:34 +00:00
Alexander Couzens
333d7e6345 tbf.cpp: use new tlli instead of old tlli
The old tlli might be 0x00000000.

Change-Id: I2fd6fec022506e203d05e91c36ccd9e020ff816c
2017-05-01 16:57:48 +00:00
Neels Hofmeyr
e6d26ec09c bitcomp test: use expected rc instead of 'verify' flag
The 'verify' flag is useless, we always want to verify everything.  Replace
'verify' with 'expect_rc', expecting a specific decoding result per test set.

When an error code was returned, cut short the loop and skip printing expected
vs. decoded bits.

This uncovers the fact that the first test marked as "invalid inputs" does not
seem to be invalid after all, or at least does not produce an error to be
returned. For now, only uncover this fact, the fix shall be submitted later.

Change-Id: Icf815a8f1acb0e275463408450171df046879847
2017-03-27 00:24:28 +02:00
Neels Hofmeyr
5382e0fc1f bitcomp test: fix: also verify bits after decoded data
Before this, the expected data had seemingly random bits set after the end of
the expected decoding result. Make the test expect these extra bits as zero,
matching with the buffer initialization to zero.

In result_matches(), compare the full length of bytes instead of masking the
bits after the end of the decoded data (which caused us to not catch the wrong
expectation until now).

This fixes the underlying issues found in
http://lists.osmocom.org/pipermail/osmocom-net-gprs/2017-March/000876.html
  [osmo-pcu 0.2.896-0a8f] testsuite: 4 failed
  from: Arnaud ZANETTI
  on: Fri Mar 24 09:53:53 UTC 2017

Change-Id: I2501208e2f8b4f709efbcadbd1057c086472c9e6
2017-03-27 00:24:28 +02:00
Neels Hofmeyr
dd1700a397 bitcomp test: fix: only one hexdump per log; use printf
The test wants to write multiline results, so it should use printf instead of
the logging system.

Split logs to only one hexdump per printf(). One cannot use osmo_hexdump twice
in one printf(); before this, one of the two hexdumps won, both dumps would
show as the same. Very bad for a regression test!

This uncovers a discrepancy between expected and produced results, proving that
the expected stderr output was not capable of uncovering test failures. The
test's check_result() function *has* always verified the decoded data, but only
up to the last decoded bit. Our expected data contains seemingly random bits
after the end of the decoded bits, but check_result() never compares those,
hence we don't catch that error. The extra bits should definitely be zero,
because the destination buffer is pre-initialized to zero -- fixed in a
subsequent patch.

This should cosmetically fix the build failure found in:
http://lists.osmocom.org/pipermail/osmocom-net-gprs/2017-March/000876.html
  [osmo-pcu 0.2.896-0a8f] testsuite: 4 failed
  from: Arnaud ZANETTI
  on: Fri Mar 24 09:53:53 UTC 2017
The real fix will follow.

Change-Id: I24fc32eb55baaf22f9c6fdda917bfb8395d02b1c
2017-03-27 00:24:28 +02:00
Neels Hofmeyr
7783964bb9 cosmetic: BitcompTest: make readable
In order to understand what the bitcomp test is logging, cosmetically rearrange
the code:

- memset bits_data before assigning to destination bitvec.
- use macro CEIL_DIV_8 to clarify what (x+7)/8 does.
- rename check_result() to result_matches() and return a bool,
  also constify result_matches() args and pass a bitvec reference instead of
  copying the bitvec struct.
- rearrange logging lines to make readable what is going on there.
- drop unused 'init_flag'

There are obviously errors like double hexdumps per log line, multiple newlines
in a LOGP statement and so forth: these shall be fixed by subsequent patches.

Change-Id: Id0da9d9b67f4713d3a67e3532ed44b8cb1bd1d08
2017-03-27 00:24:03 +02:00
Max
0a8fae8d14 Support sending OML Alerts via BTS
* extend BTS <-> PCU protocol with TXT messages
* use it to implement OML alerts support
* use it to implement version message
* add function to transmit both of them them
* send alerts for internal encoding problems as an example
* send version when BTS socket is connected

Note: requires corresponding change
If57459c0610f2c7b36d599b13087c8deef8bdd9e in libosmocore.

Related: OS#1614, 1615
Change-Id: If4ea5b3f7409df2fb030681ad468df6b711790a7
2017-03-17 17:01:28 +00:00
Harald Welte
db84235a0b Update README file with general project info and use Markdown
Also, it seems the readme was so far not included in any tarballs (make
dist).  Let's change that.

Change-Id: I1967fbbdeadb967c0c0dce2c112ac692c539da1d
2017-03-17 17:24:55 +01:00
Neels Hofmeyr
20827374e9 jenkins: add value_string termination check
Change-Id: I27217c9162efd800eebcb403eab770f4528d21ac
Depends: libosmocore change-id I2bc93ab4781487e7685cfb63091a489cd126b1a8
2017-03-16 19:01:04 +00:00
Max
b86a30dc22 tests: include headers from include/
In addition to .h files from src/ add include/ as well: some headers are
now public and reside in separate directory.

Change-Id: I09c02a171fb3b2f2791ce938725db7d4ff397e95
2017-03-13 13:43:22 +00:00
Max
5dd8d1bbd8 bts.cpp: Fix overloading ambiguity
Fix error introduced in 1275a3f91a by
using signed 32 bit integer which is enough for Frame Number in
GSM. Also, mark parameter constraints more explicitly:
- add assert for expected FN values
- don't perform computation for non-relative FN

The error was:
bts.cpp: In member function ‘uint32_t BTS::rfn_to_fn(uint32_t)’:
bts.cpp:554:25: error: call of overloaded ‘abs(uint32_t)’ is ambiguous
  if (abs(rfn - m_cur_rfn) > RFN_THRESHOLD) {
                         ^
In file included from /usr/include/c++/6/cstdlib:75:0,
                 from /usr/include/c++/6/stdlib.h:36,
                 from /usr/include/osmocom/core/linuxrbtree.h:97,
                 from /usr/include/osmocom/core/timer.h:35,
                 from ./bts.h:29,
                 from bts.cpp:21:
/usr/include/stdlib.h:735:12: note: candidate: int abs(int)
 extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
            ^~~
In file included from /usr/include/c++/6/stdlib.h:36:0,
                 from /usr/include/osmocom/core/linuxrbtree.h:97,
                 from /usr/include/osmocom/core/timer.h:35,
                 from ./bts.h:29,
                 from bts.cpp:21:
/usr/include/c++/6/cstdlib:185:3: note: candidate: __int128 std::abs(__int128)
   abs(__GLIBCXX_TYPE_INT_N_0 __x) { return __x >= 0 ? __x : -__x; }
   ^~~
/usr/include/c++/6/cstdlib:180:3: note: candidate: long long int std::abs(long long int)
   abs(long long __x) { return __builtin_llabs (__x); }
   ^~~
/usr/include/c++/6/cstdlib:172:3: note: candidate: long int std::abs(long int)
   abs(long __i) { return __builtin_labs(__i); }

Change-Id: Ib6d895a97aa35414f245ea4406c6e78f1b4fb5b8
2017-03-13 11:25:14 +00:00
Max
727295f206 Add pkg-config file
We're installing header file pcuif_proto.h so it's better to use
pkg-config for proper version tracking similar to the way it's done for
OpenBSC.

Change-Id: I0520045e5655794df152b98b9755d7cbbd334049
2017-03-09 12:17:35 +01:00
Philipp Maier
1275a3f91a BTS: Convert relative frame numbers to absolute frame numbers
The implementation of the method rcv_rach() in class BTS, restores
the absolute frame number of the incoming RACH-Request by using
the relative frame number (RFn = Fn mod 42432) from the rach
request and the already known internal absolute frame number
m_cur_fn, which is continusly updated by the CCU interface.

In some rare cases, a RACH request might be received by the BTS,
a very short time before the frame number wraps in its 42432.
Depending on the PCU location, RACH request might be received
by the BSC, which forwards it to the PCU. It is then likely
that, while the RACH request is being forwarded to the PCU, the
PCU internal absolute frame number wraps before the RACH
can be processed. The relative frame number from the rach
request would then be interpreted as if it were received after
the wrapping of the internal frame number modulos.

This commit adds logic to detect and resolve this race condition.
Also a unit test is added to check some cornercases.

Change-Id: I74f00c11e5739d49f370ce6c357149e81d9aa759
2017-03-05 12:23:56 +00:00
Neels Hofmeyr
a01e2ee177 logging fixup: shorter names for LOGGING_FILTER_* and LOGGING_CTX_*
In libosmocore, my patch was merged to master a bit too soon. To accomodate the
request for naming that matches the general "LOG" prefix instead of "LOGGING",
a fixup was committed to libosmocore. Adjust for that.

Original patch: change-id I5c343630020f4b108099696fd96c2111614c8067
The fixup: change-id I424fe3f12ea620338902b2bb8230544bde3f1a93

Change-Id: I4db4a668f2be07f3d55f848d38d1b490d8a7a685
2017-02-23 18:11:44 +01:00
Neels Hofmeyr
d0a887b28b gprs_debug.h: remove unused cruft / cosmetic tweaks
Change-Id: Ied1ffc320332a605b140d23910eb0a13ef9a7a75
2017-02-20 15:30:18 +00:00
Neels Hofmeyr
4ae5406959 logging: use central filter and ctx consts from libosmocore
Change-Id: I7b41a5a26527864177c63403ad171d2987f0ff6a
Depends: libosmocore change-id I5c343630020f4b108099696fd96c2111614c8067
2017-02-17 17:23:36 +01:00
Neels Hofmeyr
b609190369 dl tbf: initialize punct values and verify
Solves a sanitizer issue where punct2 is unset when passed to
gprs_rlc_mcs_cps() and thus takes a value not defined in the enum.

Change-Id: I004cbbab15e6ffa2749f4b7f1df651517c2ae693
2017-02-14 12:20:57 +01:00
Neels Hofmeyr
49b83ec3a3 dl tbf: calculate CPS only for EGPRS
Patch-by: Aravind Sirsikar <Arvind.Sirsikar@radisys.com>
Change-Id: I81b8e1d10bfe9efba3a9f04bced66f87d93285dd
2017-02-14 12:19:18 +01:00
Neels Hofmeyr
78ce59137f main, tests: use msgb_talloc_ctx_init() (new)
msgb_set_talloc_ctx() is deprecated since libosmocore commit
f45334be29016a36594aacc07c90e262e4994525 / change-id
I747fbbf977c4d2c868c8dead64cfc5fd86eb8d4c

Change-Id: I8d40abec428b739460ed545c9983d1b63021bd08
2017-02-08 17:37:55 +01:00
Neels Hofmeyr
de9da39b33 tests: edge, tbf: assert return values
Numerous calls assign a return value without asserting its value. Add
assertions and thus also eliminate compiler warnings about unused values.

Change-Id: I7f14198cfd747dae68b8aaa3b8d6ff7fc49ab824
2017-02-08 17:37:55 +01:00
Neels Hofmeyr
d34646a865 Fix dozens of compiler warnings across the board
Change-Id: I166109dc05d3323b92cd2a42f0c7e6009950e15d
2017-02-08 17:37:55 +01:00
Philipp Maier
53f0b4deb6 cosmetic: Fix log output
In BTS::rcv_rach() the log output is messed up because of a stray
"\n". This commit removes that.

Change-Id: I40d01c71982ad83589f070cf0047a4ae04695411
2017-02-01 14:19:04 +00:00
Philipp
d935d88a8c BTS: accept also relative frame numbers with rach requst
The rach request contains a relative frame number (Fn % 42432),
while BTS::rcv_rach() accepts the full frame number only.

Since the BTS is always aware of the full frame number this is
not a problem. But for BSC co-located PCU schemes it is a problem
since the rach request only contains the relative frame number
as mentioned above.

The pcu continusly receives frame number updates with the GSM time
indication message. It is simple to re-calculate the full frame
number from that information.

This patch makes BTS::rcv_rach() compatible with relative frame
numbers, while not breaking the compatibility for full frame
numbers

Change-Id: Iaa182d8d29c6a0f5fa06064c2eb48b21b1ba2775
2017-01-26 11:19:21 +01:00
aravind sirsikar
e9a138e111 Handle packet access reject during packet resource request
When Packet resource request is received, PCU will generate the
packet access reject if no resources are present. The encoding is done
based on section 7.1.3.2.1 and 8.1.2.5 of 44.060 version 7.27.0 Release 7.
This patch also includes the test case to validate the generated
packet access reject message.

This patch is integration tested on Osmo-trx setup with Ettus B210 board
and LG F70 MS with some simulation code changes in Osmo-pcu.

Change-Id: I05ff25124b58905586caa0c0c37023d69724f121
2017-01-24 13:11:51 +00:00
sivasankari
1d8744ce96 Add test case for testing PUAN
This test case is for testing generation of
EGPRS PUAN. Corresponding log files .ok and .err
are modified.

Change-Id: I18e6d4a9e90fd6453fe14187beab27dfeae8dbe9
2017-01-24 15:53:35 +05:30
sivasankari
8adfcd06a1 Add compression support in EGPRS PUAN
This adds compression of bitmap in PUAN. The compressed bitmap
is used only if the number of bits in the bitmap does not fit in
the message and there is a gain after compression.
The algorithm is part of libosmocore and so there is dependency
on the libosmocore for compilation.
The algorithm is tested on integration setup by forcing compression.

Change-Id: Id2eec4b5eb6da0ebd24054b541b09b700b9b40ba
2017-01-23 12:26:09 +00:00
Max
127a1e0750 Log additional info for radio errors
Change-Id: I936a07ce87f05d9c3dc351dc3bdc4f00d78265e0
Related: OS#1553
2017-01-16 10:10:01 +01:00
Max
b3df58660f Log socket path on connection
Change-Id: I81c5c1068a8b59ee30399dac90b0f7e730fc19f4
2017-01-06 17:20:57 +01:00
Neels Hofmeyr
b78a4a6dfe fix segfault: check for NULL tbf in sched_select_ctrl_msg()
Apparently fixes a corrupted stack looking like this on sysmobts:

  (gdb) run
  Starting program: /usr/bin/osmo-pcu -c /etc/osmocom/osmo-pcu.cfg
  [Thread debugging using libthread_db enabled]
  Using host libthread_db library "/lib/libthread_db.so.1".
  <000b> telnet_interface.c:95 telnet at 127.0.0.1 4240
  <0001> osmobts_sock.cpp:227 Opening OsmoPCU L1 interface to OsmoBTS
  <0001> osmobts_sock.cpp:285 osmo-bts PCU socket has been connected
  <0001> pcu_l1_if.cpp:368 BTS available
  <0008> gprs_ns.c:233 NSVCI=65534 Creating NS-VC
  <0008> gprs_ns.c:233 NSVCI=100 Creating NS-VC
  <0008> gprs_ns.c:1568 NSEI=100 RESET procedure based on API request
  <0008> gprs_ns.c:393 NSEI=100 Tx NS RESET (NSVCI=100, cause=O&M intervention)
  <0001> pcu_l1_if.cpp:83 Sending activate request: trx=0 ts=2
  <0001> pcu_l1_if.cpp:495 PDCH: trx=0 ts=2
  <0001> pcu_l1_if.cpp:83 Sending activate request: trx=0 ts=3
  <0001> pcu_l1_if.cpp:495 PDCH: trx=0 ts=3
  <0001> pcu_l1_if.cpp:83 Sending activate request: trx=0 ts=4
  <0001> pcu_l1_if.cpp:495 PDCH: trx=0 ts=4
  <0001> pcu_l1_if.cpp:83 Sending activate request: trx=0 ts=5
  <0001> pcu_l1_if.cpp:495 PDCH: trx=0 ts=5
  <0001> pcu_l1_if.cpp:83 Sending activate request: trx=0 ts=6
  <0001> pcu_l1_if.cpp:495 PDCH: trx=0 ts=6
  <0001> pcu_l1_if.cpp:83 Sending activate request: trx=0 ts=7
  <0001> pcu_l1_if.cpp:495 PDCH: trx=0 ts=7
  <0001> pcu_l1_if.cpp:319 RACH request received: sapi=1 qta=0, ra=120, fn=103198
  <0009> tbf_ul.cpp:373 LLC [PCU -> SGSN] TBF(TFI=0 TLLI=0x7f2dd569 DIR=UL STATE=FLOW) len=6
  <0008> gprs_ns.c:684 All NS-VCs for NSEI 100 are either dead or blocked!

  Program received signal SIGSEGV, Segmentation fault.
  gprs_rlcmac_rcv_rts_block (bts=0x60a08, trx=trx@entry=0 '\000', ts=ts@entry=4 '\004', fn=7, fn@entry=103272,
      block_nr=block_nr@entry=0 '\000') at gprs_rlcmac_sched.cpp:349
  349	gprs_rlcmac_sched.cpp: No such file or directory.
  (gdb) bt
  #0  gprs_rlcmac_rcv_rts_block (bts=0x60a08, trx=trx@entry=0 '\000', ts=ts@entry=4 '\004', fn=7, fn@entry=103272,
      block_nr=block_nr@entry=0 '\000') at gprs_rlcmac_sched.cpp:349
  #1  0x0001151c in pcu_rx_rts_req_pdtch (trx=<optimized out>, ts=<optimized out>, fn=103272, block_nr=<optimized out>)
      at pcu_l1_if.cpp:279
  #2  0x0000bfcc in handle_ph_readytosend_ind (fl1h=0xafa40, rts_ind=0xb03f8) at osmo-bts-sysmo/sysmo_l1_if.c:142
  #3  l1if_handle_l1prim (wq=<optimized out>, fl1h=0xafa40, msg=0xb0330) at osmo-bts-sysmo/sysmo_l1_if.c:259
  #4  0x4fcd6330 in osmo_fd_disp_fds (_eset=0xbefffb68, _wset=0xbefffae8, _rset=0xbefffa68) at select.c:149
  #5  osmo_select_main (polling=<optimized out>) at select.c:189
  #6  0x0000b2a0 in main (argc=<optimized out>, argv=0x66628 <_ZStL8__ioinit>) at pcu_main.cpp:295

Fixes: coverity CID#158969
Related: https://lists.osmocom.org/pipermail/osmocom-net-gprs/2016-December/000785.html
Change-Id: I357492e558e98cfdbf5bb3438b5013029195b02b
2017-01-06 13:54:04 +00:00
Pravin Kumarvel
06bdb3550c Refactoring write_packet_ack_nack_desc_egprs to prepare for CRBB support
Change-Id: Ie5c25b6ee30f2f1b613e923c234b03a6ffe12ae2
2017-01-06 10:36:07 +00:00
sivasankari
67b89cae08 Array indexing for SPB counters in bts statistics.
Array indexing mismatch is corrected for SPB counters.
 (bts_ctr_description with the bts counter declaration).

Change-Id: I9b17ca0f838a37d9405cebf2319e722a302f5ed9
2017-01-06 10:31:56 +00:00
Max
e66de5b5ae Improve logging
Add value_string describing UL and DL TBF states and use it for logging
errors while freeing TBFs.

Change-Id: I292ec81ab602c65ef86e6e3e85740182b63474b6
2017-01-05 18:39:25 +01:00
sivasankari
ee78bf0882 Adds rate_ctr_init in the startup of osmo-pcu
Issue:Though the rate_ctr framework is used in osmo-pcu for bts statistics,
      the interval counters are always 0.
Fix:rate_ctr_init is added in the startup which arms the timer and hence
    the rate ctr intervals is displayed with proper values.

Change-Id: Ib0f33d2de9406aa7436aa9aeb6a8dabdff96383b
2016-12-22 14:09:43 +00:00
sivasankari
da7250ad2c Add counter at BTS level And statistics at TBF/MS level.
Adds spb counters at BTS level(show bts statistics).
Adds RLC/MAC downlink control msg at ms level(show ms imsi <imsi_val>).
Adds the number of coding schemes counter for UL at TBF level.

Change-Id: Icbe4ba95e34bea89ee36f532d099db68204b7c38
2016-12-22 14:09:04 +00:00
Harald Welte
963cdaffd5 Fix uninitialized members in pcu_l1_meas()
Change-Id: I76a03c9f54be474ab9ece908ef782807d555c6ac
Fixes: Coverity CID 57952
2016-12-16 11:56:45 +00:00
Harald Welte
1f2bb6e93e struct pcu_l1_meas_ts: initialize ms_i_level
Change-Id: I93de7589d746b91ba26b1b36bf2690f125277cd0
Fixes: Coverity CID 57953
2016-12-16 11:56:44 +00:00
sivasankari
5395073fff Add statistics in the ms and tbf level.
Adds DL throughput in show ms imsi <imsi_value>.
Adds the number of coding schemes counter and rlc nacked counter at TBf level.

Change-Id: Ia95b0404989b00db0e7ba416bc40d09ef41fde1c
2016-12-09 12:05:43 +00:00
aravind sirsikar
cc4214a429 Sanitizer build fix for TbfTest
Change-Id: Ia6993fd6f89c9d9ed00ec6cb4b27953e72fa1f52
2016-12-09 16:12:42 +05:30
Mrinal Mishra
0e63644d14 Add debugging log for RLC data block decoding
Added debugging log for RLC UL Data Block decoding for both GPRS/EGPRS cases.

Change-Id: I8c197bdc4cd1330cbab0adfd188336d27682cec4
2016-12-02 09:15:53 +00:00
Neels Hofmeyr
34bfbdaf9e debian: fix: add pcuif_proto.h to osmo-pcu.install
Following 68fc12775f
'Install the pcuif_proto.h header file'
we need to add pcuif_proto.h to the debian install file.

Change-Id: Ib8e185900826baadcc96fcde1491903dbaf85f8b
2016-11-30 00:37:32 +01:00
sivasankari
168911b438 Add new BTS level counters
Adds counters for Immediate Assignment Reject, Packet Access Reject,
Channel Request Description and Final Block resend.

Change-Id: I23e326d4ea489aa4967e452fe02773b44ab146f7
2016-11-25 19:55:38 +05:30
Harald Welte
68fc12775f Install the pcuif_proto.h header file
So far, we used to keep a copy of the header file around in
both osmo-pcu and osmo-bts projects.  Before we start introducing
a third copy in openbsc, let's have the osmo-pcu install the header
file and make the other programs use that.

Change-Id: I60976c9be5488256d1ff55fdc5aa548e3705400d
2016-11-17 21:09:55 +01:00
Harald Welte
5d93f0f4ec Fix GSMTAP logging in case direct PHY access is enabled
In the existing code, GSMTAP messages were only generated in case no
direct PHY access was being used (i.e. in the case all user traffic goes
over the PCU socket).  I'm not quite sure what the reason is for that
would be and conclud this is not intentional.

Let's first send the message to GSMTAP and then decide whether to send
it via the direct PHY access or via the PCU socket into the BTS/BSC.

Change-Id: I5d2e018f7009cb947abc874881c0c440feca3ade
2016-11-17 21:09:55 +01:00
Harald Welte
bb47d957a8 pcu_l1_if: get rid of magic numbers and use ARRAY_SIZE() for array iteration
Change-Id: I61d00950b4eb0b8bcbaf386d5081be84580dac75
2016-11-17 21:09:55 +01:00
Mrinal Mishra
f86307e1e4 Add BTS level counters
Adds counters for MCS blocks, 11 bit Rach counters and others.

Change-Id: I605b0d66eb217decd35cbb8f87abfa577760245a
2016-11-14 01:15:16 +00:00
aravind sirsikar
ed3413e397 Handle packet access reject during EPDAN/PDAN with channel description
When PDAN/EPDAN with channel description is received, PCU will generate the
packet access reject if no resources are present. The encoding is done
based on section 7.1.3.2.1 and 8.1.2.5 of 44.060 version 7.27.0 Release 7.
This patch also includes the test case to validate the generated
packet access reject message.

This patch is integration tested on Osmo-trx setup with Ettus B210 board
and LG F70 MS with some simulation code changes in Osmo-pcu.

Change-Id: I096a3bb44a65533b9e9b091925dd5f70a8696d6
2016-11-11 17:15:10 +05:30
aravind sirsikar
c0c3afd079 Handle Immediate assignment reject
When RACH is received, PCU will generate the Immediate assignment reject
message if no resources are present. The encoding is done based on section
9.1.20 of 44.018 version 11.7.0 Release 11. This patch also includes the
test case to validate the generated Immediate assignment reject message.

This patch is integration tested on Osmo-trx setup with Ettus B210 board
and LG F70 MS with some simulation code changes in Osmo-pcu.

Change-Id: I3d33e2b9746fa4f338fad0e6b63b1c5f07de6f9b
2016-11-09 16:27:00 +05:30
Max
ae4838101a Handle Timing Advance IE properly
Move writing Timing Advance IE and Timing Advance Index into separate
functions to simplify adding PTCCH support. This also fixes previous
incorrect (and unused) code for writing Packet TA IE which has not set
TS for TA.

Change-Id: I786bf7fc999d401cc3d9e7f1e7a1fba953b5d458
Related: OS#1545
2016-11-09 09:30:49 +00:00
aravind sirsikar
fb41afaaf6 EGPRS: fix for EPDAN out of window
Fix alignment of EPDAN outside the RLC transmit window,
according to section 9.1.8.2.4 in 44.060 version 7.27.0 Release 7.
The specification explains that a bit within the uncompressed bitmap
whose corresponding BSN is not within the transmit window shall be
ignored. Without this fix PCU was dropping the EPDAN message and not
updating the status of BSNs which are inside the RLC window. This patch
updates the status of the BSNs which are inside the window and ignores
the remaining bits.

Related: OS#1789

Change-Id: Id07d178970f168f5389016c1eea31eb6b82057b6
2016-11-02 15:48:00 +05:30
aravind sirsikar
9434e52af9 Modify return type of gprs_rlc_dl_window::distance to uint16_t
Since there is a "&mod_sns()" present in this function, the outcome
is always unsigned.

Change-Id: I66f3db4dc27a6cbef146c832bf8b43f1492358a4
2016-11-02 15:43:10 +05:30
aravind sirsikar
f276138202 EGPRS: add test case to show EPDAN BSN out of window bug
This patch adds a test case test_tbf_epdan_out_of_rx_window,
which expects a current bug with EPDAN for interpretation of the
bitmap explained in section 9.1.8.2.4 in 44.060 version 7.27.0
Release 7. The specification explains that a bit within the
uncompressed bitmap whose corresponding BSN is not within the
transmit window shall be ignored. But current PCU implementation
drops the EPDAN and does not update status of the BSN which are
inside the window. The test's expectation is corrected along with
the bug fix in a subsequent commit.

Related: OS#1789

Change-Id: If32b67f5c05707155281128b776a90a1e3d587b2
2016-10-30 03:15:22 +00:00
Mrinal Mishra
d453eaa788 Add logging support
This commit adds the TRX_ID in the output of VTY command "show tbf all".

Change-Id: Ia5412dddb899e20963f884e02bdf796b6ea7ee6c
2016-10-26 15:41:56 +05:30
Neels Hofmeyr
f868bdbe76 jenkins.sh: use osmo-build-dep.sh, output testlogs
Also make cosmetically similar to the other jenkins.sh scripts in various osmo
repositories.

Change-Id: I34c19ed7c80aa56bd131f738f37324aed1cd73db
2016-10-20 11:42:03 +00:00
Max
d71e8b32e3 Use qbit-TA to update Timing Advance
Separate qbit-TA to TA conversion into separate function and use it for
computing and updating Timing Advance.

Note: the code was tested with TA=0 only to make sure it does not
introduce regressions.

Change-Id: I96fdbb20b09fb85fdd9fb6dcf3c25f6bee7f80e4
Fixes: OS#1531
2016-10-19 08:23:29 +00:00
Neels Hofmeyr
4ea452689d Revert "tbf: Add state WAIT_ASSIGN"
This reverts commit f1a7b8fc66.

Conflicts:
	tests/tbf/TbfTest.err

The commit broke GPRS service at least for osmo-bts-sysmo on a SysmoBTS 1002
with current master of osmo-bts (ef30f50d5d6d5f863fc147d05ccdceb89284934e).

The error observed is the following log output (was viewing both osmo-bts-sysmo
and osmo-pcu logs interleaved):

<0002> tbf.cpp:874 TBF(TFI=0 TLLI=0x00000000 DIR=UL STATE=WAIT ASSIGN) T3169 timeout during transsmission
<0002> tbf.cpp:893 - Assignment was on CCCH
<0002> tbf.cpp:899 - No uplink data received yet
<0007> l1sap.c:904 RACH for packet access
<0001> pcu_l1_if.cpp:311 RACH request received: sapi=1 qta=0, ra=121, fn=13653
[repeat]

When removing this single commit from current osmo-pcu master, GPRS service
works well on SysmoBTS, with current osmo-bts master.

The TbfTest.err expected output needed adjustment after the revert.

Disclaimer: I am not aware of adverse effects this commit may have. I have no
idea what the WAIT_ASSIGN state is used for -- further review is required.

Change-Id: I1532f8e93194368cdc1e3846f82afa6d68cd5fbd
2016-10-18 14:48:36 +02:00
Alexander Couzens
e4727a3591 llc: remove NULL-pointer check of gprs_llc_queue::size()/octets()
All callers now check the pointer before calling it.
gcc6 is optimizing `if (!this) {CODE}` as this is assumed to never be a
std::nullptr here.

Change-Id: I918a094e0dc59098a9eb00d152c9ae42d36b3a99
2016-10-18 11:51:02 +02:00
Alexander Couzens
d38b92e972 tbf: add llc_queue_size() to check llc_queue is valid before calling size()
gcc6 is optimizing if (!this) {CODE} as this is assumed to never be a
std::nullptr here. Move the null check to the caller. In preparation of
removing the check within llc_queue->size(), all callers must check the object
before calling it. Make sure of that: make the llc_queue() access function
protected and offer only a public llc_queue_size() function that incorporates
the NULL check. All current callers are only interested in the
llc_queue_size().

Tweaked-by: nhofmeyr
Change-Id: I88cc3180f8f86785e3f07981895dabddf50b60a2
2016-10-18 09:49:57 +00:00
Pravin Kumarvel
0a4a6c1200 EGPRS: Add EPDAN CRBB Tree based decoding
Implemented tree based algorithm to decode compressed bitmap in EPDAN
as described in section 9.1.10 of 3GPP 44.060.
This algorithm intends to improve the performance over existing method.
New Regression test is added under bitcomp directory.
Test case is added to validate decompressed result of the bitmap
Present in EPDAN.
Test is done for multiple bitmaps of varying length.
Invalid inputs are also part of the test vector.

Change-Id: Ieae1992ed4b02bb1e09eec2d3de1a030eabd16ce
2016-10-17 11:00:57 +05:30
Neels Hofmeyr
6348aea6a2 build: add -Wall
I noticed that unused variables are not complained about by the build. Let's
add -Wall.

I also noticed that the Makefile.ams include STD_DEFINES_AND_INCLUDES, which is
never set in configure.ac, so using that to add -Wall to all build contexts.

Change-Id: I16711cf5a1ef8bd611074b3dd486ed7a0ae9df64
2016-10-03 10:02:17 +00:00
Neels Hofmeyr
da66f71ffe configure: check for pkg-config presence
Change-Id: Iaaeb2a926fc3832793dfb3f02e4ced2500950997
2016-10-01 01:06:19 +02:00
Neels Hofmeyr
da933e0ff8 build: be robust against install-sh files above the root dir
Explicitly set AC_CONFIG_AUX_DIR.

To reproduce the error avoided by this patch:

  rm install-sh        # in case it was already generated.
  touch ../install-sh  # yes, outside this source tree
  autoreconf -fi

This will produce an error like

  ...
  configure.ac:16: error: required file '../ltmain.sh' not found
  configure.ac:5: installing '../missing'
  src/Makefile.am: installing '../depcomp'
  autoreconf: automake failed with exit status: 1

See also automake (vim `which automake`) and look for 'sub locate_aux_dir'.

Change-Id: Ie9a10f14c5e8c5e9b6ea4910b4b9abb7e70f5e04
2016-10-01 01:06:19 +02:00
Neels Hofmeyr
fd9e16ce97 heed VTY 'line vty'/'bind' command
Like most other osmo-* programs, bind the telnet VTY to the address specified
by the 'line vty'/'bind' command. This is added by vty_init(), so until now the
PCU offered this config but ignored it.

Change-Id: I4cca05a212ec0d493b906014dc3a83e687ebbb1d
2016-09-22 07:06:41 +02:00
bhargava
465f5bbb6f Update the function immediate assignment for EGPRS
Encode the EGPRS fields of immediate assignment message in uplink
when EGPRS PACKET CHANNEL REQUEST (11 bit RACH) is received.
The series of patches for 11 bit RACH are dependent on libosmocore
and osmo-bts patches for 11 bit RACH.

Change-Id: Ie5e309156e5dbbb6add74a1b4d257c4ee2332e52
2016-09-16 05:55:41 +00:00
bhargava
628dcfbc97 Handle EGPRS 11 bit RACH in osmo-pcu
A function is_single_block is added to get request type of RACH.
EGPRS 11 bit RACH is handled.

Change-Id: I61d74a32f7764644ed86f7fdf97fa3c2f61503f7
2016-09-16 05:54:15 +00:00
Aravind Sirsikar
0ee31cfa38 Fix EGPRS DL window calculation during tbf update
Earlier there was no handling for recalculation of DL window
size during tbf update. Which has been fixed in this patch.

Related: OS#1808
Change-Id: I41aa807068520460fd665a55e3529e60f6bbb630
2016-09-15 17:54:46 +05:30
Aravind Sirsikar
8e70bb5bb4 tbf_dl: factor out EGPRS DL window size calculation
A subsequent patch needs to call this from gprs_rlcmac_tbf::update(),
so to avoid code dup, put the calculation in a separate function.

Related: OS#1808

Change-Id: I7c7777d43f843bbd3421503fc2a8600f148ca035
2016-09-15 17:51:16 +05:30
Aravind Sirsikar
22a901905c EGPRS: Fix issue with row 4 of Table 10.4.14a.1 of 44.060 version 7.27.0 Release 7
row 4 of Table 10.4.14a.1 of Spec 44.060 version 7.27.0 Release 7. Says
"The previous RLC data block contains a Upper Layer PDU, or a part of it,
that fills precisely the previous data block and for which there is no
length indicator in that RLC data block.
The current RLC data block contains a Upper Layer PDU that either fills
the current RLC data block precisely or continues in the next RLC data block."
So when we receive block with 1st LI: value=0 and Value of E bit in the
same octet as 1, we expect 2 chunks with 1st chunk as length as 0 and complete
and 2nd chunk as length non zero. But with this bug we see only 1 chunk causing
incorrect assembling

This issue has been fixed in this patch.

Related: OS#1811

Change-Id: I2cd0fca3ed28a553ede3f4b8a7d3267284dd2c9b
2016-09-15 17:24:49 +05:30
Aravind Sirsikar
3463bd4adc EGPRS: add test case to show LI decoding bug
This patch adds a test case test_tbf_li_decoding which
expects a current bug with LI decoding for row 4 of Table 10.4.14a.1
in 44.060 version 7.27.0 Release 7.
The test's expectation is corrected along with the bug
fix in a subsequent commit

Related: OS#1811

Change-Id: Ida410dab1aa4b0cf3e15b2090586377eb19b2469
2016-09-15 17:19:54 +05:30
Aravind Sirsikar
e26ee01d56 DL TS allocation: add test case to show TS allocation bug for 2nd DL TBF
This patch adds a test case test_2_consecutive_dl_tbfs which
expects a current bug with TS allocation for 2nd DL TBF.
The test's expectation is corrected along with the bug fix in a
subsequent commit

Related: OS#1792

Change-Id: I890e4fbb2b64037e051433e70082a197e2a929a6
2016-09-14 11:55:32 +00:00
Neels Hofmeyr
0241526836 Fix CSN1 decoding: CSN_LEFT_ALIGNED_VAR_BMP bounds
Fix attempted read past vector boundaries in case of a starting bit offset !=
0, so that the last amount of bits read should be < 8. In the case of
CSN_LEFT_ALIGNED_VAR_BMP, the mod-8 calculation was flawed, and in the final
step, 8 bits were read instead of the remainder < 8. This lead to -EINVAL being
returned by bitvec_get_bit_pos() and bogus resulting data.

Instead, read 8 bits only as long as at least 8 bits remain, and read any
remaining bits < 8 in a final step. Drop unneeded nB1 variable and an obvious
comment.

Adjust the unit test assertion in testCsnLeftAlignedVarBmpBounds() in
RLCMACTest.cpp.

Based on a fix by Aravind Sirsikar <Arvind.Sirsikar@radisys.com>, but
implemented differently.

Related: OS#1805
Change-Id: I490498c8da6b531f54acb673379379f7b10907c0
2016-09-14 01:26:34 +00:00
Aravind Sirsikar
9f5f008aed CSN1 decoding: add test to show bug in CSN_LEFT_ALIGNED_VAR_BMP
CSN1 decoding currently contains an attempted read past vector boundaries in
case of a starting bit offset != 0, so that the last amount of bits read should
be < 8. In the case of CSN_LEFT_ALIGNED_VAR_BMP, the mod-8 calculation is
flawed, and in what should be the final step of reading n < 8 bits, 8 bits are
read instead of n (with an extraneous read of n bits following after that).
This leads to -EINVAL being returned by bitvec_get_bit_pos() and bogus
resulting data.

Add testCsnLeftAlignedVarBmpBounds() in RLCMACTest.cpp to show and expect this
bug. The test's expectation shall be corrected along with the bug fix in a
subsequent commit.

Related: OS#1805
Tweaked-by: Neels Hofmeyr <nhofmeyr@sysmocom.de>
Change-Id: I4641f5d1d49f66cb1a5cd813befb3a2a266001b0
2016-09-14 01:26:33 +00:00
Aravind Sirsikar
8d2d9e8985 TBF flow: unit test compilation error fix
The test failure was introduced by 9bbe1600cc
"Fix Timing Advance handling": between patch build checking and patch
submission, a new section was added to TbfTest.cpp which also needs adjustment.

Tweaked-by: Neels Hofmeyr <nhofmeyr@sysmocom.de>
Change-Id: If077da5f21fd5cba54556f1dead05a1bc4ea5540
2016-09-12 15:16:38 +02:00
Max
9bbe1600cc Fix Timing Advance handling
* initialize with invalid TA instead of making assumption that phone is
  located within 550 meters (TA=0)
* only set valid TA

Change-Id: Idfc40ff0c11bdac13d9e28fbfa4e95dfc6b735b0
Related: OS#1526
2016-09-09 06:37:04 +00:00
Minh-Quang Nguyen
16ddc90eab LC15: Change TRX numbering for the latest Litecell15 hardware
Change-Id: If3c4aff0366587dd3e5baa3d15b9e91d8ebe7753
2016-09-06 10:27:11 -04:00
Aravind Sirsikar
7c7a86c080 Fix GPRS PUAN encoding: wrong BSN status
Earlier there was an incorrect encoding of BSN status in GPRS PUAN message.
This was a bottle neck for GPRS performance testing for UL. Which has been fixed
in this patch.

Related: OS#1806

Change-Id: I98e586aa5cb9200cf03e092556304211d4d459aa
2016-09-02 06:47:09 +00:00
Aravind Sirsikar
a35c911a91 GPRS: PUAN encoding: add test case to show wrong BSNs status
This patch adds a test case which expects a current bug with
GPRS PUAN encoding. The test's expectation
is corrected along with the bug fix in a subsequent commit

Related: OS#1806

Change-Id: Ied0f1dd3037d8fac6a772f4e097defb72634f955
2016-09-02 06:45:32 +00:00
Aravind Sirsikar
3c2eaebd21 DL: add test case to show wrong window size
This patch adds a test case test_tbf_update_ws. Which expects a
current bug with DL window size calculation. The test's expectation
is corrected along with the bug fix in a subsequent commit

Related: OS#1808

Change-Id: I4659494c6f93ae89e4cc4ac79fff5fcaf2d23699
2016-08-30 15:40:19 +05:30
Aravind Sirsikar
fd71384104 TBF flow: unit test compilation error fix
Change-Id: I89638ba908e7d9964a5525061ce0cf26049be438
2016-08-28 17:55:05 +05:30
Aravind Sirsikar
b119198992 TBF flow: Coverity fix
Related: CID#1361925, CID:#1361924

Change-Id: Ib1f71a8940eed7ad74211092275dfa29aa353fc7
2016-08-28 11:55:01 +00:00
Neels Hofmeyr
01826c13b1 vty: use OSMO_VTY_PORT_PCU instead of number
Include vty/ports.h and use the proper constant.

Change-Id: I9c5b7683f76994c539da5551f40df32379dc685e
2016-08-27 02:19:48 +00:00
bhargava
959d1dee67 Change interface in osmo-pcu for 11 bit RACH
Interface structure between osmo-bts and osmo-pcu is updated with
the parameters to differentiate the type of RACH and further
support 11 bit RACH. The function prototype and definitions are
changed accordingly. Interface version number is increased.

Change-Id: I265c2d92d36d6cbcbeee60cdd8407dafe1da06a4
2016-08-27 01:22:48 +00:00
Aravind Sirsikar
eebcb1e3e8 Fix EGPRS PUAN encoding: use correct urbb_len
Earlier there was an incorrect encoding of PUAN when VQ is not equal
VR case for EGPRS UL RLC window. The PCU was encoding the same PUAN
message always irrespective of radio condition. This was a bottle neck
for performance testing. Which has been fixed in this patch.

Related: OS#1793

unit test assertion in the previous commit is fixed in this patch.

Change-Id: Iba7b1995028bd81749ffb080616b2ad5f2540d57
2016-08-25 16:40:23 +05:30
Aravind Sirsikar
02352b487a EGPRS: PUAN encoding: add test case to show wrong urbb_len issue
This patch adds a test case which expects a current bug with EGPRS PUAN
encoding when VQ != VR. The test's expectation is corrected along with
the bugfix in a subsequent commit

Adds test_tbf_puan_urbb_len to describe the following bug:
EGPRS PUAN encoding disregards the urbb_len, leading to identical PUAN
messages regardless of the urbb_len.

Related: OS#1793

Change-Id: I00662a564f64c0c83627401ae8f7bfef0f0a5de8
2016-08-25 16:37:30 +05:30
Aravind Sirsikar
50b097003b Modify EGPRS DL TBF flow to support SPB
Modify the EGPRS DL TBF flow to support Split block during
Retx. This patch will also Upgrade the test suite with test cases
to validate the EGPRS Downlink SPB for Retransmission

Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3
MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested
in NuRAN 1.0 hardware thoroughly.

Change-Id: I242afdd8ae7622dec8593b26382ad66bad5b9516
2016-08-25 10:41:33 +00:00
Aravind Sirsikar
e6cadb4e3c Add data structure to handle SPB for EGPRS DL
Modify the header files with necessary data structure to handle
Split block for EGPRS DL TBF.

The EGPRS resegmentation feature allows PCU to retransmit
RLC blocks of HeaderType1, HeaderType2 by segmenting
them to 2 HeaderType3 blocks(Example MCS5 will be
retransmitted as 2 MCS2 blocks). Table 10.4.8b.2 of 44.060
explains the possible values of SPB in HeadrType3 for DL
direction. The PCU decides to retransmit the
blocks by resegmenting it based on Table 8.1.1.1 of 44.060.
The retransmission MCS is calculated based on current MCS of
the Block and demanded MCS by PCU. Section 10.3a.3.3 of 44.060
shows the HeadrType3 with SPB field present in it

Change-Id: I57673e53a9da2affa7e8aaa6551ac4b271c3d525
2016-08-25 10:34:00 +00:00
Aravind Sirsikar
1ec4d80176 Remove warning while using 'egprs only' command in VTY
This warning is not valid since the PCU is not failing when EGPRS is
activated. So removing this trace

Change-Id: I62278f998adc691b9a3563ac2a46d756e7bfb66c
2016-08-22 17:16:00 +00:00
Neels Hofmeyr
9876f4bb21 jenkins.sh: drop compat with old matrix params
Change-Id: I7b50a24cf5879cb473a5cf929768bdd30e863a26
2016-08-16 12:49:29 +02:00
Neels Hofmeyr
7fd177b91c jenkins.sh: change build matrix to $with_dsp and $with_vty
The new $with_dsp matrix parameter is defined as "sysmo" or empty/"none". The
lc15 DSP might be added in the future.

Fetch the sysmo layer 1 API only if with_dsp==sysmo.

The new $with_vty parameter is independent of $with_dsp, it is now up to
jenkins to define a matrix filter.

For compat, until jenkins is reconfigured with the new matrix parameters, use
$sysmodsp to init the new parameters to reflect previous behavior. The
$sysmobts matrix parameter made no sense, drop it.

Change-Id: Ia120f918342dc9563814252258b73bfb267e5253
2016-08-11 11:06:26 +00:00
Neels Hofmeyr
2d91260ea4 jenkins.sh: more quotes, cosmetics, less dup
Rename BTS_CONFIG to PCU_CONFIG.
More quotes.
Unify bash if-style.
Define *_PATH variables once globally instead of duping in every line.

Change-Id: If148632c3f340a8a395fa432135e593fecc41e82
2016-08-11 11:06:26 +00:00
Neels Hofmeyr
6bae2d11f1 jenkins.sh: use absolute paths instead of 'cd ..' and $PWD
Change-Id: If79d283fa0a559bb7ea319c513d09466eff523d1
2016-08-11 11:06:26 +00:00
Neels Hofmeyr
0b4da058ad jenkins.sh: ensure $MAKE is set
Change-Id: I2da8acdfe3abf79f68db4d00d04a7d162f0123ce
2016-08-11 11:06:26 +00:00
Max
79cb245157 LC: fix build error
Remove extra parameter which causes build to break. The error was
introduced in 878bd1f296

Change-Id: Id63187d925d448caa4fa85720582550919b1f216
2016-08-09 19:21:34 +02:00
Max
cbf9a721d6 Extend BTS <-> PCU protocol with measurement
Note: this increases the version of BTS <-> PCU protocol and thus
requires corresponding change in BTS.

Change-Id: Ide0e29b668ee38516605c1763fda85e87e867813
Related: OS#1616
2016-08-04 15:06:12 +00:00
Aravind Sirsikar
505a86d396 Add support for SPB handling for EGPRS UL TBF
This patch will modify the EGPRS UL TBF flow to support Split block
handling. This patch also contains test suite modification for SPB UL.
Scenarios like MCS6->MCS3, MCS4->MCS1, MCS5->MCS2, MCS9->MCS3
MCS7->MCS2, MCS8->MCS3 have been simulated and Integration tested
in NuRAN 1.0 hardware thoroughly. The scope of Unit testing is limited.

Change-Id: I39ca53218b6e0982abc2ab9c703c24c8bf0a09c0
2016-08-02 06:58:58 +00:00
Aravind Sirsikar
36bdc5f7a4 Add data structure for SPB in EGPRS UL
Modify header files with data structures required
to support split blocks for EGPRS UL TBF

This feature provides provision for MS to retransmit
RLC blocks of HeaderType1, HeaderType2 by segmenting
them to 2 HeaderType3 blocks(Example MCS5 will be
retransmitted as 2 MCS2 blocks). Table 10.4.8b.1 of 44.060
explains the possible values of SPB in HeadrType3 for UL
direction. When the MCS is changed at the PCU, PCU directs the
changed MCS to MS by PUAN or UPLINK ASSIGNMENT message along
with RESEGMENT flag, Then MS may decide to retransmit the
blocks by resegmenting it based on Table 8.1.1.1 of 44.060.
The retransmission MCS is calculated based on current MCS of
the Block and demanded MCS by PCU. Section 10.3a.4.3 of 44.060
shows the HeadrType3 with SPB field present in it.

Change-Id: I83ccd136bb361adcfd511c57c5a9d95ed72c36c2
2016-08-02 06:58:57 +00:00
Max
d572054ca7 Properly set TA_VALID bit
Check Timing Advance validity and set corresponding bit for Immediate
Assignment message. Previously !polling was errorneously used (polling
bit has nothing to do with TA validity according to 3GPP TS 44.018 Table
10.5.2.16.1) which lead to TA being always valid as polling is always 0
in other parts of the code.

Change-Id: I5d7ecc7f71402b945cae99332be2ebc0b17b9d44
Related: OS#1526
2016-07-28 06:20:41 +00:00
Max
878bd1f296 Remove useless ARFCN parameter
ARFCN is already part of TRX struct so there's no need to supply it
explicitly in a separate parameter. I've tested and those are the same
anyway.

Change-Id: I8e975c52cbc819427880093b1e5371fe1f8ce460
2016-07-26 00:20:23 +00:00
Max
1d7644b23a Cleanup readme
Remove note on PCCCH/PBCCH support because according to 3GPP TS 44.060
version 12.5.0 Release 12 § 1.6 "The network shall never enable PBCCH
and PCCCH".

The rationale behind this from GP-091955:

"Due to that P-channels are not deployed by any operator and are not
 expected ever to be, it has decided to remove the requirement on
 mandatory support of P-channels for the mobile stations in A/Gb mode."

Change-Id: I2b16413e1b6ce8f2bc2e8183165fb6b3aa14f2d0
2016-07-23 19:24:41 +00:00
Max
2ec6b8e758 Remove unused definitions
Those structs are not used anywhere (which was the case in the commit
which introduced them as well) but give false-positives while grepping
through the code. Better to just drop them.

Change-Id: I0a0bb0c641e4e081a57f72187ff96e9beef16588
2016-07-20 18:30:10 +02:00
Tom Tsou
df69809b82 egprs: Use RLC/MAC headers from libosmocore
EGPRS Type 1, 2, and 3 headers are used by OsmoPCU and OsmoBTS.
Move the header definitions to libosmocore to be shared by both
packages.

Modify the struct variable naming to use *_hi/*_lo instead of
*_a/*_b in order to be consistent with existing naming used in
libosmocore.

Change-Id: I98687ad981d27502aec42729611937ba1caf207c
2016-07-14 06:56:19 +00:00
Holger Hans Peter Freyther
5d94b5455f bitvector: Remove code clone and fallback to C implementation
This routine has been moved from from here to libosmocore and as
part of the C++ -> C the reference got converted to a pointer. We
have a lot of code that calls the method with the reference and
instead of updating the callers, create a short inline wrapper to
call the C routine.

Change-Id: Idd16ce251a42bad4401c2bf3a8fa6af70fb600ff
2016-07-13 16:26:32 +00:00
Aravind Sirsikar
1a679127af Add test cases to support ARQ-II for EGPRS DL Retx
During MCS upgradation such as MCS6->MCS9, 2 blocks which
were sent separately as MCS6, will be clubbed into one MCS9
block during retransmission. Same holds good for
MCS5->MCS7 transistion. During MCS reduction such as
MCS9->MCS6,2 blocks which were sent together will be
sent separately during the retransmission case.
Same is verified through the generated log file. Currently
MCS8->MCS6 transition is not supported. The retransmission
MCS is being calculated from Table 8.1.1.2 of TS 44.060.
The same test cases are also integration tested on Nuran
1.0 platform.

Change-Id: Ia357acfe30f4dea95e00749916c6818354f93285
2016-07-13 13:50:36 +00:00
Aravind Sirsikar
cf2152b24c Modify DL tbf flow for ARQ-II in EGPRS DL Retx
Modify the DL TBF flow to support ARQ-II EGPRS DL retransmission

Change-Id: I7a845c98f2018795f0f62240f228411b0bc030c7
2016-07-13 13:50:20 +00:00
Aravind Sirsikar
e8ccafc63d Add Accessor functions for ARQ-II in EGPRS DL
Add accessor function in existing classes to support ARQ-II for
retransmission in EGPRS DL

Change-Id: Iefff956bf2dcfe8fb0b2f5a7a7a2122d5d555f9e
2016-07-13 13:50:04 +00:00
Aravind Sirsikar
914955209e Add data structure for ARQ-II in EGPRS DL
Modify the existing data structure to support ARQ-II for Retx in EGPRS DL.
This will also hadle compilation issue related to renaming the variable.

Change-Id: I734b1024bb32f2daa43af4adf59f4a17f2294afe
2016-07-12 14:17:12 +05:30
Harald Welte
899d36d813 systemd service file: Stop using deprecated '-e' option
In commit 6d8884de49 in 2014, we
made the '-e' command line option deprecated.  Stop using it from the
systemd srevice file.

Change-Id: I322cadbee8980b78fff2984765c4b0216c50412e
Related: SYS#2749
2016-06-30 19:14:49 +02:00
Neels Hofmeyr
d32aa03520 typo in warning
(actually committing just to test gerrit, and if it goes through it's still
a valid change.)

Change-Id: I2ca9a1cc2f250801fbe62f3c50b73dff7101ee08
2016-06-20 18:17:03 +02:00
Aravind Sirsikar
2c9f980163 Add test cases for Header type1 in EGPRS UL
Update test suite with test cases for Header type 1 in EGPRS UL

Change-Id: I21811bb126dbe151b0708a964d3143bc2fd52389
Reviewed-on: https://gerrit.osmocom.org/272
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
2016-06-17 15:31:07 +00:00
Aravind Sirsikar
99ab0a8fa0 Add header type 1 support for EGPRS uplink
Function is added to parse the EGPRS header type 1 in uplink tbf path.
along with configuration parameter updation to reflect max mcs in UL

Change-Id: I13c250e2e07377982ac3f29745f3cffd4088552a
Reviewed-on: https://gerrit.osmocom.org/270
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Tested-by: Jenkins Builder
2016-06-16 14:32:07 +00:00
Aravind Sirsikar
550a54184b Add Header Type2 support in EGPRS UL
This patch will add support for MCS5,6 in EGPRS UL along with incorrect
assert correction to let MCS 6 work.

Change-Id: Iac2422c8acbdcefe20aafbba6a4eb87c9893e3ba
Reviewed-on: https://gerrit.osmocom.org/269
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
2016-06-16 14:18:53 +00:00
Aravind Sirsikar
23617c001d Remove GMSK only check in EGPRS UL
Since we are supporting MCS 5-9 in this patch series for EGPRS UL,
This condition is not relevant. So removing it.

Change-Id: I567acc012d8ad49681715f0104ba7e91625e1e7a
Reviewed-on: https://gerrit.osmocom.org/268
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
2016-06-16 14:17:17 +00:00
Aravind Sirsikar
189742b66c Add test cases for Header Type 2 in EGPRS UL
Updates the test suite to add test cases for Header type 2 parsing
in EGPRS UL.

Change-Id: I1dd46010065a6d6da21e8e45af71e6d5f649b0b0
Reviewed-on: https://gerrit.osmocom.org/271
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-06-15 14:05:28 +00:00
Alexander Couzens
e04fd0cf0f tbf: replace this == NULL check in tbf->name
All checks of (this == null) will be eliminated by GCC >= 6.1
(https://gcc.gnu.org/gcc-6/changes.html, Value range propagation now
assumes that the this pointer of C++ member functions is non-null.

Change-Id: Ifddaef70bb0a4402050c817b1000d515c3a7118b
Reviewed-on: https://gerrit.osmocom.org/136
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-06-10 11:14:10 +00:00
Alexander Couzens
6922bcd929 tbf_dl: correct tbf name in log message for moving a DL TBF
It makes no sense to call functions on null pointer object. Use
the name of the old tbf.

Change-Id: I93b8c07a0b2de40a11e94fd6c212897cbe3b50ef
Reviewed-on: https://gerrit.osmocom.org/212
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-06-10 11:13:23 +00:00
Alexander Couzens
7fdbf89ef3 add KPI counter to count bytes for RLC and LLC frames
rlc.dl_bytes		bytes before sending rlc
rlc.dl_payload_bytes	count data w/o LI
rlc.ul_bytes		bytes when received rlc (only valid)
rlc.ul_payload_bytes	count data fragments w/o LI
llc.dl_bytes		complete encapsulated LLC PDUs
llc.ul_bytes		complete received LLC PDUs

Change-Id: I9a98a5a375d39b3f4990360056c4d6145e755f4d
Reviewed-on: https://gerrit.osmocom.org/145
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Reviewed-by: Holger Freyther <holger@freyther.de>
Tested-by: Jenkins Builder
2016-06-07 10:56:25 +00:00
Alexander Couzens
6f0dc96929 encoding/rlc_copy_from_aligned_buffer: export written payload bytes via an argument
Require to count statistics for rlc_dl_payload_bytes.

Change-Id: I0e622acb1f13f7489946baf049de4ba1cde6a1fc
Reviewed-on: https://gerrit.osmocom.org/142
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-06-07 10:48:35 +00:00
Alexander Couzens
1a5066112f tbf_dl: comment why we sent a dummy LLC packets to delay the release of the TBF
Change-Id: I1862674437dffef4de3ffa7b183ecf690020b0ec
Reviewed-on: https://gerrit.osmocom.org/143
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Tested-by: Jenkins Builder
2016-06-07 10:42:19 +00:00
Alexander Couzens
d302e4fb28 decoding: remove superfluous double-semicolon
Change-Id: I48ec24f2e10620279cbcbf39c70a4be6438f6b0f
Reviewed-on: https://gerrit.osmocom.org/140
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Tested-by: Jenkins Builder
2016-06-01 13:38:35 +00:00
Alexander Couzens
68e2c6375e rlc.h: correct gprs_rlc_data comment
It's the block data, not the history.
Also add including LI headers.

Change-Id: Id4d99d1d21c7fa372771fd569d87bbcf2c6b6d22
Reviewed-on: https://gerrit.osmocom.org/144
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Tested-by: Jenkins Builder
2016-06-01 13:38:28 +00:00
Alexander Couzens
cb846ecbbc encoding: add doxygen for rlc_data_to_dl_append*
Change-Id: I6ead0f1d14a91c657448227e17438b49a54e6c4a
Reviewed-on: https://gerrit.osmocom.org/141
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
2016-05-31 11:52:19 +00:00
Alexander Couzens
b82bd92e57 decoding: improve and add comments
Change-Id: I45c9fc55243224909ca2fdece8cbfa686b0f444d
Reviewed-on: https://gerrit.osmocom.org/139
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
2016-05-31 11:51:59 +00:00
Alexander Couzens
2fcfc29020 add comments to describe functions
Change-Id: Ie351632001abbeb82008a5eecae0d0323a8ef7d7
Reviewed-on: https://gerrit.osmocom.org/106
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Tested-by: Jenkins Builder
2016-05-25 20:07:03 +00:00
Alexander Couzens
ce936f3cd4 tbf_ul: use correct size for chunk_size
The size of the hole array in bytes was used instead of the size of elements.

Change-Id: If6bf3e5f1ad773ddaa9fb2ce7c069e6b26659cbf
Reviewed-on: https://gerrit.osmocom.org/105
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-25 19:45:50 +00:00
Alexander Couzens
c1c9d6a9d8 rlc.h: remove duplicated define RLC_EGPRS_SNS
The second #define RLC_EGPRS_SNS is 3 lines below of the first one.

Change-Id: Ibb718ba9be21831c56c5949e730fab5acd691d7c
Reviewed-on: https://gerrit.osmocom.org/107
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-25 19:44:29 +00:00
Alexander Couzens
c8fd4b7c42 bts/counter: replace '_' with '-' in counter names
Conform to the convention.

Change-Id: I6162694aae8d354aba318cc1acfdac108239fef0
Reviewed-on: https://gerrit.osmocom.org/103
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-24 10:18:07 +00:00
Alexander Couzens
f929e62525 introduce new counter rlc_sent_control
Counts control messages (UL/DL assignment, UL ACKs or page requests)

Change-Id: Ib41031d430beddfb48d54470e632436f2c99c360
Reviewed-on: https://gerrit.osmocom.org/99
Reviewed-by: Holger Freyther <holger@freyther.de>
Tested-by: Jenkins Builder
2016-05-22 11:11:53 +00:00
Alexander Couzens
4acb6b7251 gprs_rlcmac_sched: fix mistype of CONTROL ACK
Change-Id: If37b33f69cd659d913ed81eb6060a42734ba524f
Reviewed-on: https://gerrit.osmocom.org/100
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-22 11:00:29 +00:00
Alexander Couzens
95e379241a tbf_dl: replace cross-file declaration with correct header
Change-Id: I9b4eb664d444258c9bcf53f9b44552d8dd3155e9
Reviewed-on: https://gerrit.osmocom.org/95
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-22 10:59:04 +00:00
Alexander Couzens
543756adbe bts/rate_ctr: replace spaces by tabs
Use tabs like other counters for seperation.
Introduced by 2cb1547

Change-Id: I32eebfe5934c919eccc1e28938ca00c49368297e
Reviewed-on: https://gerrit.osmocom.org/96
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-22 10:44:04 +00:00
Alexander Couzens
2cb1547993 introduce new counter rlc_sent_dummy
rlc_sent_dummy count the amount of dummy package which are
sent in case no data packet is in the queue.

Change-Id: Ia60eab853d9145980f30d63e4ce4b520b8c51381
Reviewed-on: https://gerrit.osmocom.org/85
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-21 17:59:37 +00:00
Alexander Couzens
9736d00b12 move statistics counter rlc_sent() to gprs_rlcmac_sched
The counter rlc_sent has nothing to do with the TBF.
The RLC packet got sent in the gprs_rlcmac_sched().

Change-Id: I5d2b910ea7cc250f17530406eda3be9b29b051fd
Reviewed-on: https://gerrit.osmocom.org/84
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-20 16:32:06 +00:00
Yves Godin
660709dc7c Add support for NuRAN Wireless Litecell 1.5 BTS
Layer 1 compatibility with previous generation or NuRan GSM product,
therefore the support for the Litecell 1.5 uses its own sources instead
of using tons of ifdef/endif.

Max's amendments:
* make headers path configurable
* use configured TRX instead of hardcoded value
* split subdir-objects into separate commit
* cosmetic changes

Change-Id: Ib1287375cb10a889625bbac8528fa60deed23a2b
Fixes: SYS#2443
Reviewed-on: https://gerrit.osmocom.org/61
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
2016-05-20 16:26:20 +00:00
Max
58b6646750 Change internal API for consistency
Make TRX API (void *) consistent with the way it's used (integer). Use
uint8_t for TRX numbering everywhere (we don't expect hardware with
more than 256 transceivers in the near future). This change helps to
avoid unnecessary casts and make API much clearer.

Change-Id: Ic584611184b0c8b5417ecff0ddae3d526b55a079
Related: SYS#2443
Reviewed-on: https://gerrit.osmocom.org/59
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-19 06:40:26 +00:00
Alexander Couzens
ed3ae4a392 add .gitreview
A .gitreview file is required to use git review.
More information about git review
https://www.mediawiki.org/wiki/Gerrit/git-review

Change-Id: I03cbdf3a95bcf36a7388b5fa2652fd774b8f0f5b
Reviewed-on: https://gerrit.osmocom.org/68
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-19 06:39:45 +00:00
Yves Godin
f0bb25450c Enable subdir-objects automake option
Change-Id: I01fd264fd1f990f39cdbf309149e0eb857d7732f
Related: SYS#2443
Reviewed-on: https://gerrit.osmocom.org/60
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Tested-by: Jenkins Builder
2016-05-17 16:41:19 +00:00
Max
de810f2005 Restructure sources
Move hardware-spicefic files into subdirectory similar to the way it's
done in OsmoBTS to make adding new hardware support easier.

Change-Id: I05004ad9032759a5dbfa57290ed1df83e89d5cb8
Related: SYS#2443
Reviewed-on: https://gerrit.osmocom.org/58
Tested-by: Jenkins Builder
Reviewed-by: Holger Freyther <holger@freyther.de>
2016-05-17 16:19:32 +00:00
Max
cad867ec8d Rename define for direct hw access 2016-04-22 14:41:36 +02:00
Max
280448ba7b Cleanup build leftovers 2016-04-22 14:41:16 +02:00
Holger Hans Peter Freyther
1aa7527302 jenkins: Add the build script from jenkins here
This can be used to replicate a build issue more easily.
2016-04-13 19:05:52 -04:00
Holger Hans Peter Freyther
ca025c02ef misc: Ignore test files and debian packaging 2016-04-01 19:27:56 +02:00
Holger Hans Peter Freyther
97e48a3252 debian: Initial debian packaging
Add initial debian package for plain osmo-pcu (without the
sysmoBTS supporot).
2016-04-01 19:26:09 +02:00
Harald Welte
63d33ad2d7 fix compiler warnings about format string for size_t
with gcc-5.3 on x86_64 I get the following compliler warnings:
warning: format ‘%d’ expects argument of type ‘int’, but argument 7 has
type ‘size_t {aka long unsigned int}

This patch resolves them
2016-03-30 22:08:18 +02:00
Aravind Sirsikar
7952282b78 Support puncturing scheme selection for EGPRS DL
Adds support to find the puncturing scheme for retransmission
with MCS change, retransmission with no MCS change, transmission
case. Puncturing scheme selection for retransmission case with
MCS change is aligned with TS 44.060 9.3.2.1. Puncturing scheme
selection for retransmission without MCS change, fresh transmission
is aligned with TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1
2016-03-30 22:02:48 +02:00
Aravind Sirsikar
a859a21800 Update CPS calculation with new data structures
Update existing CPS calculation function to align with new data
structure introduced
2016-03-30 22:02:47 +02:00
Aravind Sirsikar
7a05b039c8 Add data structure for CPS calculation in DL
Define new data structure with respect to TS 44.060
10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1 for puncturing scheme values
and initialize the variable introduced
2016-03-30 22:02:47 +02:00
Bhargava Abhyankar
e44383baa4 Refactor the Uplink RLC header parsing function
Parsing the uplink data header for GPRS and EGPRS header type 3
is handled in separate functions.
This patch will enhance modularity of the code.
2016-03-30 22:01:52 +02:00
Aravind Sirsikar
5a5d2b7a27 Introduce EGPRS header type1 and type2 in UL
Defines new structures for UL EGPRS header type1 and type2 for
supporting MCS5-MCS9
2016-03-16 15:02:54 +01:00
Saurabh Sharan
2b09c39c9c Fix issue in encoding CSN_RECURSIVE_ARRAY
The remaining_bits_len is correctly decremented while encoding
CSN_RECURSIVE_ARRAY for fixing the bug.
Details of the bug is in https://projects.osmocom.org/issues/1641

During introduction of basic EGPRS feature new hex dump message
PUASS, from a different working network log was used in Unit test.
It exposed the issue of incorrect handling of recursive array
encoding in osmo-pcu.

Fixes: OS#1641
2016-03-16 15:01:53 +01:00
Saurabh Sharan
bacb65b48b Add test vectors for EGPRS messages
This patch is the test suite modification for the fix encoding of
padding bits. New test vectors have been added both in downlink
and uplink.
2016-03-15 10:05:07 +01:00
Saurabh Sharan
656eed5975 Fix encoding of padding bits to start with 0 bit
This patch is for fixing encoding of padding bits according to the
3gpp spec 44.060 section 11, wherein it shall always start with 0
bit followed with spare padding bits.

During introduction of basic EGPRS feature new hex dump messages
from a different working network log were used in Unit test. These
exposed the issue of incorrect handling of padding bits encoding
in osmo-pcu.

Corrections in the existing test vector of rlcmac is also updated.
In testsuite tbf appropriate corrections for the Tbftest.err is
also done.
2016-03-15 10:04:34 +01:00
Holger Hans Peter Freyther
173ef90a53 pcu: Fix compiler warning about using string
Make the gsmtap hostname const to avoid turning a constant into
a mutable character. We never tried to modify the string so the
warning didn't reveal a genuine issue.

pcu_main.cpp:49:28: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
 static char *gsmtap_addr = "localhost"; // FIXME: use gengetopt's default value instead
2016-03-04 18:26:44 +01:00
Holger Hans Peter Freyther
fd263b0dfd tbf: Fix copy and paste in the set_mode routine
This is the second attempt to fix what looks like a copy and paste
issue. The code assigns m_current_cs_ul and then compares the _dl
variant, then assigns m_current_cs_ul with a default value. It seems
to indicate that _ul should be used.

Fixes: Coverity: CID 1351733
2016-03-04 18:26:43 +01:00
Holger Hans Peter Freyther
99db40ad2d Revert "Refactor coding scheme assignment code"
Roll-out the refactoring change. The code did not include the
necessary update to the test result and there are some concerns
about it in itself and the right approach would have been to
fix the copy and paste issue, then do the refactoring.

This reverts commit 22d7e75e1f.
2016-03-04 18:26:43 +01:00
Max
22d7e75e1f Refactor coding scheme assignment code
Previously this code used too much copy-paste of boilerplate code which
is error-prone and hard to read. Factor out actual (M)CS assignment into
separate function and use it for both DL and UL cases in respective
mode.

Fixes: Coverity: CID 1351733
2016-02-25 14:03:49 +01:00
Holger Hans Peter Freyther
f3f1bde4fc alloc: Fix UBSAN for accessing the array at -16
This test will check that we exhaust the available TFIs, so the last
TFI is -16 and then we try to store to that address. It is surprising
that it worked!
2016-02-22 15:14:01 +01:00
Max
528ff3910f Add gsmtap support to generic bts
Instrument TX and RX functions dealing with regular BTS (without direct
DSP access) to use GSMTAP. Previously only DSP-related functions were
instrumented.
2016-02-22 14:50:58 +01:00
Max
2efdf69734 Introduce --gsmtap-ip/-i option
This option allows user to use custom IP address instead of default "localhost".
Correspondingly gsmtap init moved from sysmoBTS-specific code up to "bts" struct
level. This way it can be easier reused by other implementations. The
lack of regressions was verified by checking following command on
sysmoBTS: "./osmo-pcu -c osmo-pcu.cfg -r 1 -i 192.168.10.1" where
192.168.10.1 is the host which was running wireshark and netcat:
"nc -u -l 192.168.10.1 -p 4729" to accept gsmtap flow.
2016-02-22 14:00:17 +01:00
Max
9d5580b6dd Ignore files generated by cscope tool
Signed-off-by: Max <msuraev@sysmocom.de>
2016-02-22 13:58:54 +01:00
Holger Hans Peter Freyther
4f8438a6cd Merge remote-tracking branch 'origin/jerlbeck/master'
This adds EDGE support and at the same time is changing a lot of code
on GPRS support as well. Due my business decision of completing as much
as possible during the time we had the unit test coverage is not as
extensive as I had hoped for.

This is just the beginning. We do not support mixed GPRS/EDGE support
and have plenty of things to improve throughput.

Thanks to On-Waves for supporting a project with so many unknowns and
uncertainty and Jacob for leading the effort at sysmocom.
2016-02-22 09:44:39 +01:00
Harald Welte
7f4841b3ac Fix missing '-V / --version' in print_help() 2016-02-14 12:14:18 +01:00
Jacob Erlbeck
7f28c97fcc edge: Support all coding schemes for BSSGP flow control
Currently the MCS schemes are not supported when the leak rate is
being computed. This leads to a lower value for the leak rate, thus
limiting the throughput to GPRS-like ranges.

Use the payload size reported by GprsCodingScheme instead.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:40 +01:00
Jacob Erlbeck
be881c028f edge: Work-around to not use MCS-6 with padding
Currently single BSN blocks of size 68 (a single unit from MCS-8)
are put into a MCS-6 block with padding according to TS 44.060
Annex J. Unfortunately, these packets are ignored by the E71. This
might be related to the currently incorrect usage of the puncturing
schemes and the RSB bit (the puncturing schemes are not updated and
the RBS flag is never set).

Avoid downgrading from MCS-8 to MCS-6 if there is no second block
available. Send the block twice instead.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:40 +01:00
Jacob Erlbeck
64e7b83139 edge: Compare len instead of using cs.isCombinable
Comparing the coding scheme properties doesn't seem to be strong
enough, since create_dl_acked_block(fn, ts, index, index2) sometimes
had to combine data units of different size this way.

Check the registered size of the BSN blocks instead, since these must
match if two blocks are to be combined in a single RLC data message
with MCS7-9.

It is not yet clear, what exactly goes wrong with the current
implementation, but this commit fixes the problem which trigger the
assertion in create_dl_acked_block.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:40 +01:00
Jacob Erlbeck
d6752491e1 edge: Send a second BSN block in an RLC message if possible
Currently only one BSN block is encoded in each RLC data message,
even if MSC7-9 are used, which transport two independant (except for a
max BSN delta of 512) BSN blocks. In that case, the same block is
just put twice into the same message.

The current create_dl_acked_block(fn, ts) method handles
block selection (resend, new BSN, dummy block, ...) and restart
handling in one method and is too complex to extend it accordingly.

Therefore this commit move the block selection/creation handling into
a new method (take_next_bsn) which delivers the next BSN along with a
hint, whether it may be combined with another block. In that case,
the function can be called a second time (this time with a valid
previous BSN, that's the one returned by the first call) to get the
second BSN. The real block generation method
create_dl_acked_block(fn, ts, index, index2) is then called with both
BSNs as indices (the second must be -1, if there is only one BSN).

Note that every BSN returned by take_next_bsn should be passed to
create_dl_acked_block to avoid state inconsistencies.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:40 +01:00
Jacob Erlbeck
be314d9a54 edge: Refactor create_dl_acked_block for multi-block support
Currently the method is hard-coded to support a single BSN only.
MCS-7 to MCS-9 encode 2 data blocks into a single RLC data message.

This commit refactors create_dl_acked_block to process any number
of blocks internally.

Note that this does not extend the parameter list accordingly and
just duplicates the BSN if these MCS are being used.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:40 +01:00
Jacob Erlbeck
14e26cbca3 ms: Fix GprsMs::current_cs_dl()
Currently the queue length is overwritten by the remaining chunk
length, which should be added instead. This may result in a lower
CS/MCS value than expected.

Add the chunk length instead if the TBF is present.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:40 +01:00
Jacob Erlbeck
2d2efb13e7 tbf/tests: Add tests for EGPRS TBF establishment
Add a test for EGPRS two phase access based on RA caps.

Add a test for DL TBFs where data block are encoded with each MCS.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:40 +01:00
Jacob Erlbeck
0f5c6956dd rlc: Use the rlc structure to access the data unit in the RLC message
Currently most offsets are hard-coded which makes it difficult to
access the data units and their headers when padding has to be taken
into account. These offset are already provided by the
gprs_rlc_data_info_init_ul/dl functions.

Change the encoder/decoder to use these values.

Note that some assumptions (bit alignment) are still present in the
code and checked by assertions.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:40 +01:00
Jacob Erlbeck
fbd82e4e9f rlc: Add gprs_rlc_mcs_cps_decode
To access EGPRS data blocks, the optional padding must be taken into
account. Whether padding has been used must be dervied from the CPS
field in the header of the RLC EGPRS data message.

Add this function to decode the CPS value and extract that
information.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
b55f313735 rlc: Add with_padding argument to gprs_rlc_data_info_init_dl/ul
The offsets of the data areas change when padding is used (see TS
44.060, 9.3.2.1 and Annex J for details).

Extend the parameter lists to pass the with_padding flag and use
that information to compute the correct offsets.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
215e18c9d4 cs: Add GprsCodingScheme::optionalPaddingBits
Return the amount of optional padding bits, which is 6*8 for
MCS-3 and MCS-6 and 0 for all other coding schemes. The padding
is needed the encode 68 byte data blocks (MCS-8) with these schemes.
See TS 44.060, 9.3.2.1 and Annex J for details.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
2305afd86c cs: Add family related methods
Add family handling and the related methods family,
isFamilyCompatible, isCombinable, decToSingleBlock to
GprsCodingScheme.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
4cc46d3e2a edge/vty: Set initial MCS
This adds the following VTY command (config-pcu node):

  - mcs <1-9>         sets initial DL and UL MCS to the same value
  - mcs <1-9> <1-9>   sets initial DL and UL MCS separately
  - no mcs            sets the default values

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
9e8593917f rlc: Support encoding of EGPRS header type 1 + 2
Currently only header type 3 (MCS-1 to MCS-4) is supported.

Add header structs to rlc.h and extend
Encoding::rlc_write_dl_data_header accordingly.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
f1a7b8fc66 tbf: Add state WAIT_ASSIGN
Currently the state on the TBF is set to ASSIGN when it is created
and in general changed to FLOW when it is acknowledged by the MS. The
moment when the assignment is really transmitted to the MS (which can
take some time) is not reflected by the state. A TBF can considered
to be valid, when the assignment is received by the MS.

Add the state WAIT_ASSIGN that is entered when the assigment has been
send to the MS (more precisely: when the corresponding RTS has been
processed or the message has been sent to the BTS).

The TBF, its PDCH(s), and its TFI can be assumed to be valid, when the
TBF has a state of WAIT_ASSIGN or higher (assuming that the TBF
starting time has not been set, which is currently only done for SBA,
which are not associated with a TBF).

Note that due to queuing in the BTS there can still be a invalid
time period for immediate assignments, when the request is lingering
in the AGCH or PCH queues.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
7c72acaa94 ms: Add current_pacch_slots method
The PACCH is specific to an MS and may change when a TBF is
established or removed (see TS 44.060, 8.1.1.2.2). For multislot
class type 2 phones, more than one timeslot may be used to transmit
RLC/MAC control messages.

Add a method that returns a set of TS which can be used for the
PACCH.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
1ff70c26e3 sched: Do PACCH assignments for the same direction last
Currently the selection of a pending control message is done round
robin. It can possibly happen, that a DL assigment is sent on a DL
TBF while an UL assignment is pending. The MS will replace the old
DL TBF in that case, so that it can no longer be used for the PACCH
so that the UL assignment is lost.

Give assigment requests for the same direction a lower priority.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
7d5157ee17 tbf: Only free TBF if it was replaced in rcv_control_ack
Currently the TBF whose PACCH has been used to send an assigment
is freed if it is in state WAIT_RELEASE. Sometimes this TBF could
be used for several assignments (e.g. an 'old' DL TBF is used to
assign an UL and then a DL TBF). The second of these assigments will
never be sent in that case. On the other hand, the MS replaces a
TBF of the same direction, so the old one can be freed in that case.

Only free the TBF if it is in state WAIT_RELEASE and has the same
direction like the new one.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:39 +01:00
Jacob Erlbeck
be80c3670e edge: Support EGPRS in IMM ASSIGNMENT
Tell the MS to use EGPRS if EGPRS is enabled on the TBF.

Note that only downlink TBF will be supported so far. Thus
single-phase uplink assignments may not work properly.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
2647a337a8 encoding: Redesign Encoding::write_immediate_assignment API
The EGPRS support will need more information to encode the IMMEDIATE
ASSIGMENT. Instead of adding more parameters pass a pointer to the
TBF unless an SBA shall be done (indicated by tbf == NULL). All
values that can be derived from the TBF and are not needed for an SBA
are removed from the parameter list.

Return a negative value on error.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
18831c3ca9 encoding: Refactor write_immediate_assignment
Move the IA rest encoding into separate functions fpr uplink and
downlink.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
7505f1d636 encoding: Use explicit LH encoding in write_immediate_assignment
Currently bitvec_write_field is used which just sets the bits as
given, while the spec 44.018 assumes LH encoding.

Use the bitvec_write_field_lh function instead.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
4e7424d47b pcu: Add bitvec_write_field_lh
While the bitvec functions from libosmocore support LH encoding, the
C++ wrapper does not.

Add a bitvec_write_field_lh function that is similar to
bitvec_write_field, but writes L and H instead of ZERO and ONE.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
9876a3ba5d tbf: Don't change type from CCCH to PACCH without ack
Currently the CCCH flag is cleared and the PACCH flag is set when a
multislot upgrade is scheduled for a downlink TBF, even if the MS has
never confirmed in any way that the PACCH really exists. This can
happen if the MS did not receive the DL IMM.ASS. Since the CCCH flags
gets cleared in that case, the IMM.ASSS is never retried and all
subsequent PACKET DOWNLINK ASSIGNMENTS will fail.

This commit delays the update of these flags until the MS has
responded with a corresponding CONTROL ACK.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
6b356a58d1 tbf: Use TLLI as ID if TFI not yet assigned
Currently the old TFI is always used as ID when a
PACKET DOWNLINK ASSIGNMENT is generated. This fails
if the old TBF has not been fully assigned yet. The
MS will then ignore the PDA.

This commit changes write_packet_downlink_assignment to accept
an additional parameter old_tfi_is_valid and uses the new TBF's
TLLI instead of the olf TFI if that parameter is set to false.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
f2694b74c9 tbf: Add check_polling/set_polling
Currently the checks for and the actual polling is done in several
places by copy & paste of several lines of code. This hinders changes
of they polling is handled internally and also is likely source of
programming mistakes.

Separate this into a check_polling function, that checks whether
polling is possible and returns the FN and the RRBP to be used in
that case. Otherwise the cause is logged (LOGL_DEBUG) and a negative
error value is returned. There are no other side effect beside the
logging.

If the call is successful, the set_polling method can be used to
actually register the polling.

Extend the encoder functions' parameters lists by an rrbp parameter.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
8eb17143f2 tbf: Add and use tbf->poll_ts
Currently tbf->control_ts is used to look up an incoming poll
response. Since that may eventually change, poll timeouts could
theoretically happen in that case.

Store the real poll TS in tbf->poll_ts at all places where
tbf->poll_fn is set. Do not use tbf->control_ts to look up
outstanding polls.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:38 +01:00
Jacob Erlbeck
81a04f7d79 tbf: Mark control slots in VTY TBF out
Put an '!' after the PDCH number in the output of the 'show tbf'
command, if is_control_ts() yields true.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
646da1ba8d tbf: Use is_control_ts() instead of comparing TS values directly
Currently there are some places where tbf->control_ts != ts is
evaluated to check, whether ts is a control slot.

Replace these expressions by tbf->is_control_ts(ts) which does
the same whitout exposing internal fields.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
5a3c84d0fd sched: Pass the current TS to the control create functions
Currently the checks in that function are based on the different
internal TS values of a TBF. It is assumed that they match the TS
that the current RTS refers to.

This commit adds a TS parameter to create_ul_ass, create_dl_ass,
and create_ul_ack to make this more explicit.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
5f93f855a7 tbf: Do not reuse old TBF after RACH requests
Currently existing TBF can be reused after an MS has sent a RACH
request. Since the MS can be or most probably is in packet idle mode
in that case, the TBF are no longer usable even if they share the
PDCHs and the control TS with the new one.

There are occasional freezes where the MS does no longer react to
messages sent on the PACCH.

This change aborts all pending TBFs if a new TBF is or has been
established via RACH.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
f04a5b33ec tbf: Add abort method for downlink TBF
Currently the is a release() function which takes care of
statistics and shutdown of properly finished TBFs, but which
cannot be used for aborted TBFs.

This commit add an abort() method which handles unacked RLC blocks
as lost and doesn't start a release timer. This method will be
invoked by tbf_free() for downlink TBF.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
0316dc6e48 tbf: Add counters for aborted TBF in state FLOW
Increment CTR_TBF_DL_ABORTED/CTR_TBF_UL_ABORTED if a TBF gets freed
that is still in state GPRS_RLCMAC_FLOW.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
29e3a2f0f3 Revert "tbf: Use the control TS for Immediate Assignments"
According to spec, the lowest numbered PDCH of the TBF shall be used
for the PACCH, only when concurrent TBF are active, the lowest common
PDCH shall be used. An immediate assigment is in general only sent,
if no TBF is active, so the latter case never applies.

This reverts commit fdd8a1ba2312be3f33576ee994c0b5da6272e815.
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
56d06f3e1e tbf: Use the control TS for Immediate Assignments
Currently the first TS is used, which can be different from the
control TS on downlink TBFs.

Use the control TS instead.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
2ca86afdec tbf: Refactor calls to write_immediate_assignment
Make use of variables, log them to LOGL_DEBUG, and reduce code
duplication.

This should help to narrow down the cause why snd_dl_ass are not
answered by the MS sometimes.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
741d25cb6f bssgp: Ignore downlink BSSGP RA Cap IE
That IE may contain inaccurate or completely bogus data.

This commit disables the parsing.

Note that this should be replaced by a config option.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:37 +01:00
Jacob Erlbeck
f4bb42459c tbf: Low prio for BSSPG values for GPRS/EGPRS MS class
Currently the values in the BSSGP RA Cap IE are eventually use
overwrite the 'good' values obtained from the MS earlier.

Use the 'good' values when the are present, which is assumed if
at least one of ms->ms_class() or ms->egprs_ms_class() is set.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
4a07a3be11 edge: Get EGPRS MS class from downlink BSSGP
In case there is no MS object present that matches a DL UNITDATA,
the EGPRS class is currently assumed to be 0, since the Radio
Access Capabilities IE is not fully decoded if present.

This commit uses the CSN.1 decoder to parse the IE and uses the
same functions like the uplink related code does to get the GPRS
and EGPRS multislot classes.

Remove the old parse_ra_cap_ms_class function.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
0df80be95e rlc: Add decode_gsm_ra_cap to decode Radio Access Caps
This uses the CSN.1 decoder to fully parse the radio access
capabilities as defined by TS 24.008, 10.5.5.12a.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
acf66fb456 Revert "bssgp: Add hand-coded extended RA Cap parser"
Just keep this for later reference, since a CSN.1 decoder based
implementation will be used.

This reverts commit b37ab36bb14d2d2c1363fbe521cd19984d0c3d4c.
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
a35122c496 bssgp: Add hand-coded extended RA Cap parser
Add an extended parse_ra_cap function based on the existing
parse_ra_cap_ms_class which also parses up to the EGPRS related
fields.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
9f6867033f tbf: Show window parameters in VTY
Add V(Q), V(R), V(A), V(S) to the output of the "show tbf" command.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
36df7740dd edge: Make window size configurable
Currently the window size is fixed to 64 even for EGPRS.

Support dynamic window sizes depending on the number of PDCH. The
WS can be set to b + f * N_PDCH. If the result is not valid according
to TS 44.060, Table 9.1.9.2.1, the value will be corrected to use the
next lower valid value (or 64).

The following VTY commands are added (config-pcu node):

  window-size <0-1024>          set base (b) value and leave f unchanged
  window-size <0-1024> <0-256>  set base (b) and factor (f)

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
08c72fb4a9 tbf/vty: Fix the CS output and show the EGPRS MS class
Currently only the GPRS MS class and the DL CS (even for UL TBFs)
are shown.

Add the EGPRS MS class and use the TBF's real CS.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
8cba7e9b6d utils: Add pcu_bitcount and pcu_lsb
These functions are currently defined in src/gprs_rlcmac_ts_alloc.cpp
but will be needed elsewhere.

Turn them into template functions to support different types and move
them to pcu_utils.h.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
13965aed74 tbf: Add gprs_rlcmac_tbf::window() method
This method returns a gprs_rlc_window independently of the TBF's
direction.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:36 +01:00
Jacob Erlbeck
db88380b76 rlc: Add unified gprs_rlc_window parent class
Currently gprs_rlc_ul_window and gprs_rlc_dl_window are completely
separate classes, containing several identical members and methods.

This commit add a shared parent class containing WS and SNS handling.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
3b1c553773 edge: Work-around to use EGPRS if there was no DL RA Cap
If the downlink BSSGP didn't contain a RA Capabilities IE, both
MS class values are 0. The phone will send valid RA Caps later on.
Currently in that case, the downlink TBF is not established
if EGPRS is enabled.

Just force egprs_ms_class to 1 if EGPRS (only) is enabled.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
9b3d7e0159 edge: Disable GPRS/EGPRS mixed mode
Currently the plain 'egprs' command enables EGPRS but doesn't prevent
phones from being served in GPRS mode if they do not support EGPRS.
This involves complex frame allocation implementations in dynamic
mode, especially if 8PSK is being used. This is due to the inability
of non-EGPRS phone to decode 8PSK USF and ES/P altogether. Since
polling has a higher priority than USF, collisions will have to be
prevented by the PCU by never using an GPRS USF if it refers to a FN
that is already being used for polling.

This commit just disables mixed usage by ignoring GPRS-only request
if EGPRS is enabled.

The following VTY command (config-pcu node) is changed:

  egprs     ->   egprs only

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
f9940ca8d7 edge: Fix MCS range in VTY
Change the range from MCS 1-4 to MCS 1-9.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
53bc1861c4 edge: Fix initial coding scheme selection
Currently the coding scheme gets reset when GprsMs::set_mode()
is called even if the mode did not change.

Make sure, that the CS is only reset, if it is not compliant to the
new mode.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
b4beb545f7 edge: Call update_window even if FINAL_ACK_INDICATION is set
The bitvec RBB is always valid, even when FINAL_ACK_INDICATION is
set. This is done by the ack/nack decoder function which fake a
bitmap starting with V(A) up to V(S)-1 in that case (see
Decoding::handle_final_ack).

Call gprs_rlcmac_dl_tbf::update_window unconditionally and only use
is_final for logging and TBF state changes in
gprs_rlcmac_dl_tbf::rcvd_dl_ack.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
d7630f2256 edge: Use bitvec based window methods for EGPRS
Currently a faked 'old' RBB with 64 ACKs is being used.

Use the new bitvec based methods instead.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
419b034975 tbf: Use bitvec based window methods for GPRS
Currently the old fixed 64 bit RBB based implementation is used for
GPRS.

Use the new bitvec based methods instead.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
b41262fa0b edge: Use num_blocks in gprs_rlcmac_dl_tbf::analyse_errors
Currently a window size of 64 is being hard coded.

Use the length of the show_rbb string instead.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:35 +01:00
Jacob Erlbeck
eb08f86c02 edge: Add bitvec based DL window updating methods
The current methods are based on the GRPS specific RBB and SSN values
and formats which are not compatible with EGPRS.

Add a second set of similar methods with the same semantics but
which are based on a bitvec and the first BSN instead.

The following methods are affected:

- gprs_rlc_dl_window::update
- gprs_rlcmac_dl_tbf::rcvd_dl_ack
- gprs_rlcmac_dl_tbf::update_window

Sponsored-by: On-Waves ehf
2016-02-08 00:45:34 +01:00
Jacob Erlbeck
f2f24b0959 edge: Add a bitvec based Decoding::extract_rbb function
This shall replace the old one after the transition to bitvec based
RBBs.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:34 +01:00
Jacob Erlbeck
192bf33ffb decode: Add bitvec based GPRS DL ACK/NACK decoder
Currently the RBB is used and passed directly to the window handling
methods. For EGPRS a more abstract bitvec is derived from the messages
and will passed around instead.

Add a similar function for GPRS so that the same window handling can
be used for GPRS and EGPRS.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:34 +01:00
Jacob Erlbeck
2bef4dbd43 edge: Enable CRBB decoding
Currently CRBB bitmaps are ignored if they are present.

This commit enables the decoding.

Note that this requires osmo_t4_decode in libosmocore.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:34 +01:00
Jacob Erlbeck
3fdcb2b84e edge: Add experimental support for uplink CRBB
Currently only uncompressed bitmaps (URBB) are supported in
PACKET UPLINK ACK/NACK messages.

Extend decode_egprs_acknack_bits to decode compressed bitmaps (CRBB),
too.

Note that this code is only active, if the macro WITH_CRBB_DECODING
is defined.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:34 +01:00
Jacob Erlbeck
ae9c575d2c edge: Handle EGPRS PACKET DOWNLINK ACK NACK
Currently this message is ignored.

Support decoding and handling of this message. Use a bitvec for the
decoder that just represents a BSN sequence without any encoding
details (first bit -> first BSN). Return the corresponding BSN range
(snsmod(bsn_begin + bits_in_bitvec) = bsn_end), so snsmod(bsn_end-1)
is the last BSN if there is at least 1. If bsn_begin == bsn_end, no
BSNs has been added.

Note that this bitvec is not yet used for RBB handling. It just calls
the old rcvd_dl_ack with a faked (all bits are 1) RBB map.

Sponsored-by: On-Waves ehf
2016-02-08 00:45:34 +01:00
Jacob Erlbeck
c2141c6064 edge: Workaround to fix decoding of EGPRS_AckNack_w_len_t
The presence of the LENGTH field adds an additional offset which
breaks the related M_SERIALIZE in gsm_rlcmac.cpp. In that case,
the Desc in EGPRS_AckNack_t is being cast to EGPRS_AckNack_w_len_t
and then ((EGPRS_AckNack_w_len_t *)Desc)->Desc is filled with the
parsed data, which is a platform dependant number of bytes apart the
real Desc struct.

Remove LENGTH field from EGPRS_AckNack_w_len_t so that the Desc field
is the first field.

Note that this is not a real fix. The rlcmac wireshark dissector
still has the same declaration but doesn't seem to suffer from this
problem.

Sponsored-by: On-Waves ehf
2016-02-05 18:27:10 +01:00
Jacob Erlbeck
70955c765c edge: Provide and use CS -> CPS conversion
The MS' RLC receiver needs a valid CPS field to decode the block.

Add the function gprs_rlc_mcs_cps to generate the CPS value based on
coding scheme, puncturing, and padding.

Sponsored-by: On-Waves ehf
2016-02-05 18:27:10 +01:00
Jacob Erlbeck
a88d065606 edge: Support MCS data block encoding
Currently only GPRS data block encoding is supported.

This commit adds rlc_data_to_dl_append_egprs which does the EGPRS
specific extension and chunk handling. It extends
Encoding::rlc_data_to_dl_append to use that function for MCS coding
schemes.

Sponsored-by: On-Waves ehf
2016-02-05 18:24:50 +01:00
Jacob Erlbeck
5058bd6e9e edge: Select implementation by mode in rlc_data_to_dl_append
Currently the GPRS data block encoding is applied to every
coding scheme, even if an MCS is selected.

This commit renames the actual encoding function to
rlc_data_to_dl_append_gprs (not exported) and puts
selection code into Encoding::rlc_data_to_dl_append. This
requires an additional cs argument.

Sponsored-by: On-Waves ehf
2016-02-05 13:46:21 +01:00
Jacob Erlbeck
fec94d1c5c edge: Use rlc_data_to_dl_append in create_new_bsn
Currently TBF related tasks (status changes, counter updates,
LLC dummy command insertion) as well as
RLC data block generation are done within create_new_bsn.
The data block creation part has already been copied to
the stateless Encoding::rlc_data_to_dl_append function.

This commit changes create_new_bsn to use the encoder function and
just care about the TBF related stuff.

Since the rlc_data_to_dl_append function has been validated against
the test cases being described in annex B of TS 44.060, this
commit fixes an encoder bug which leads to broken LLC frames in
a special case (see example B.2, the main header's E bit was
erroneously set to 1 in that case). When this happens, the LLC frame
will get discarded after reassembly, so that TCP will have to
retransmit the lost packet.

Sponsored-by: On-Waves ehf
2016-02-05 13:46:12 +01:00
Jacob Erlbeck
14bb0947b4 edge: Add Encoding::rlc_data_to_dl_append
This function appends a single chunk to an RLC downlink data block.
The implementation is basically taken from the
gprs_rlcmac_dl_tbf::create_new_bsn method without the TBF related
functionality and any side effects.

Note that it still only supports GRPS.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:34 +01:00
Jacob Erlbeck
3a3b6a7e86 edge: Use RLC data block encoding functions
This commit removes the use of struct rlc_dl_header from
gprs_rlcmac_dl_tbf::create_dl_acked_block and
gprs_rlcmac_dl_tbf::create_new_bsn. Instead of patching the
data area directly, the RLC block encoding functions are used.

Note that the data unit encoding is still hard-coded to GPRS in
create_new_bsn, so using MCS 1-4 (albeit being supported by the
encoder) will not work yet.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:34 +01:00
Jacob Erlbeck
53efa3eeb6 tbf/test: Add missing function name printfs
Some test function don't have the "=== start/end ===" printfs.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:34 +01:00
Jacob Erlbeck
314ec4db40 tbf: Remove obsolete TLLI functions
This commit removes gprs_rlcmac_tbf::extract_tlli and
Decoding::tlli_from_ul_data.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:34 +01:00
Jacob Erlbeck
f0e403911d edge: Add encoder for downlink RLC data blocks
Currently the (GPRS) RLC block encoding is done by setting the
header fields directly in gprs_rlcmac_dl_tbf::create_new_bsn.
This is much more complex with EGPRS, since the data fields are
not byte aligned, the header formats depend on the header type,
and the mapping of bits to bytes is LSB first.

This commit adds Encoding::rlc_write_dl_data_header which writes
the header according to the given gprs_rlc_data_header structure.
Encoding::rlc_copy_from_aligned_buffer is also added to copy
byte sequences into the message.

Note that the actual encoding of data units is not yet present.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:34 +01:00
Jacob Erlbeck
6e9f9c20e9 edge: Add init functions for gprs_rlc_data_info
Add the functions gprs_rlc_data_info_init_dl/ul which initialise a
gprs_rlc_data_info structure depending on the coding scheme. The
fields num_data_blocks, data_offs_bits, cs, and the data_blocks are
valid after this call. The other fields are set to 0.

The data blocks are initialised to the correct data_len, e == 1
(no extension header field), cv == 15 (not a final block). The other
data block fields are set to 0.

The gprs_rlc_data_block_info can also be initialised separately
by using the gprs_rlc_data_block_info_init function.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:34 +01:00
Jacob Erlbeck
cc34a5b43f rlc: Add info fields for downlink
This commit extends gprs_rlc_data_info and gprs_rlc_data_block_info
by the fields required for downlink RLC data messages.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:34 +01:00
Jacob Erlbeck
22f8087b98 edge: Add numDataHeaderBitsUL/DL and numDataBlockHeaderBits methods
These methods are added to GprsCodingScheme to avoid related
switch statements in the RLC block encoder for EGPRS.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:33 +01:00
Jacob Erlbeck
fc1b3e6c90 edge: Fix RLC message size
Currently the RLC message length that is obtained from the DSP is
reduced by 1 if the last byte of the buffer includes spare bits.
While this worked well with GPRS, these bits are being used to
encode RLC blocks in EGPRS mode. Thus this last byte must not be
chopped off. The functionality of the code is not affected by this,
since the modified length value is not used.

This commit adds GprsCodingScheme::usedSizeDL/UL to return
the number of bytes needed to encode the message block. If there are
single bits at the end that are to be used (EGPRS), the functions
return the number of full bytes plus 1 (which is the buffer size
reported by the DSP and returned by sizeUL/sizeDL). The commit also
removes the len parameter from rcv_data_block_acknowledged.

Sponsored-by: On-Waves ehf
2016-02-05 13:26:33 +01:00
Jacob Erlbeck
f2ba4cbf51 edge: Rename gprs_rlc_ul_header_egprs and gprs_rlc_ul_data_block_info
These struct names are more specific than necessary. They are used
for GPRS (uplink) already. In downlink direction, only a few fields
will be added to the header struct. Add addition,
gprs_rlc_ul_header_egprs does not map directly to an encoded
header, like many other 'header' structs do.

Change the names to fit both modes and both directions:

  gprs_rlc_ul_header_egprs    -> gprs_rlc_data_info
  gprs_rlc_ul_data_block_info -> gprs_rlc_data_block_info

Sponsored-by: On-Waves ehf
2016-02-05 13:26:33 +01:00
Jacob Erlbeck
7e7a261de0 edge: Remove int casting operator from GprsCodingScheme
This convenience operator rather hide implementation bugs and is thus
removed.

Sponsored-by: On-Waves ehf
2016-02-05 13:25:43 +01:00
Jacob Erlbeck
a47aaa4e7a edge: Add work-around to get DL EGPRS from MS object
The EGPRS multi-slot class need to be parsed from the CSN.1 RA
capability (see gprs_bssgp_pcu_rx_dl_ud).

This commit adds a workaround to get the EGPRS MS class from the MS
object if that is present.

Sponsored-by: On-Waves ehf
2016-02-05 13:25:43 +01:00
Jacob Erlbeck
08f631c197 edge: Enable EGPRS in downlink TBFs
Currently GPRS is always used for downlink, which violates TS 44.060
(concurrent TBF must have the same mode).

Enable EGPRS mode for downlink if the EGPRS MS class is != 0 and
EGRPS has been enabled.

Note that EGPRS Ack/Nack handling is not yet implemented, so enabling
EGPRS will not work still. But we will now get EGPRS DL ACK/NACK
messages now from the MS.

Sponsored-by: On-Waves ehf
2016-02-05 13:20:45 +01:00
Jacob Erlbeck
369c2fb7b4 tbf: Remove bogus gprs_rlcmac_dl_tbf::enable_egprs
This method is already present in gprs_rlcmac_tbf and should
not be present in gprs_rlcmac_dl_tbf.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:14 +01:00
Jacob Erlbeck
166c9fc827 edge: Support EGPRS in write_packet_downlink_assignment
Add an use_egprs parameter to write_packet_downlink_assignment
and add the EGPRS related fields if it is set to true. The
window size is fixed at 64 blocks, link quality measurement
reports have been disabled, and the other optional fields are not
present.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:14 +01:00
Jacob Erlbeck
7b57997874 edge: Show current mode in VTY
Add the current mode to the output of the 'show ms imsi' and
'show ms tlli' commands.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:14 +01:00
Jacob Erlbeck
cb7289094a edge: Replace integer cs by GprsCodingScheme
Currently the TBF and MS object use a plain integer value
(current_cs) to manage the coding scheme. This makes it difficult to
support the MCS schemes. GprsCodingScheme supports a partial ordering
of these values (CS and MCS) and provides safe increment and
decrement methods.

Use the GprsCodingScheme type instead of integer for cs fields and
variables. Add a 'mode' to GprsMs which can be set to either GPRS,
EGPRS, or EGPRS_GMSK which also set the initial values of
current_cs_ul/dl. Select the mode based on max_mcs_ul and max_mcs_dl.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:14 +01:00
Jacob Erlbeck
96ccea8436 edge: Add initial_mcs_dl and initial_mcs_ul config values
Provide the initial MCS values for EGPRS data blocks. They are set
to 1 (MCS-1) for each direction and there is no support to change
these configuration values yet (the automatic adaption still works,
so there is probably no need to set these values).

Sponsored-by: On-Waves ehf
2016-02-01 13:58:14 +01:00
Jacob Erlbeck
4c9e549aa3 edge: Add methods and operators to GprsCodingScheme
Add a few new operators and methods to support the use of
GprsCodingScheme instead of the plain integer currently used.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:14 +01:00
Jacob Erlbeck
0d05805b76 edge: Add max_mcs_ul and max_mcs_dl config
This sets the maximum MCS encoding used for EGPRS RLC data blocks
in either direction.

The following VTY command are added to node config-pcu:

 - mcs max <1-9>         set maximum for both, uplink and downlink
 - mcs max <1-9> <1-9>   set maximum for downlink and uplink (in that
                         order)
 - no mcs max            do not limit

Note that using a value of 4 or below for each direction implies
that a GMSK-only TBF may be assumed, which for instance would allow
the use of the GPRS MS class instead of the possibly more restrictive
EGPRS MS class.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
ed2dbf6954 tbf: Use LListHead instead of llist_pods
LListHead does basically the same like llist_pods, but more C++ish
and with type safety.

This commit turns the former list field of gprs_rlcmac_tbf into a
private field, provides accessors, moves the related code from
pcu_vty.c to pcu_vty_functions.cpp, and removes the llist_pods
type and related code.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
bf49f042d4 tbf/vty: Move tbf_print_vty_info to pcu_vty_functions.cpp
This function is similar to the show_ms function already present in
the target file. Since the TBF lists will be turned into LListHead
based lists, they will get an iteration function in
pcu_vty_functions.cpp, too.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
aa9daa1b9d tbf: Replace static casts by calls to as_ul_tbf/as_dl_tbf
Currently casts from gprs_rlcmac_tbf to gprs_rlcmac_ul_tbf and
gprs_rlcmac_dl_tbf are done by using static_cast. This doesn't provide
protection against converting a gprs_rlcmac_ul_tbf pointer to a
gprs_rlcmac_dl_tbf pointer and vice versa.

This commit provides two functions as_ul_tbf and as_dl_tbf, that
behave similar like dynamic_cast but use the direction field instead
of RTTI.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
38f18698b3 edge/test: Rename test_rlc_decoder to test_rlc_unit_decoder
This test only covers RLC data units and not whole RLC messages.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
5ffbb2744f encoding: Remove RlcMacDownlink_t based write_packet_uplink_ack
This is the CSN1-encoder based variant, which has been replaced and
is no longer being used.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
a24e1cd508 tbf: Use bitvec based write_packet_uplink_ack
Use the new bitvec based encoder for PACKET UPLINK ACK/NACK messages
and disable the old CSN.1 encoder based one.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
37005a165d encoding: Add bitvec based write_packet_uplink_ack
The current write_packet_uplink_ack implementation is based on the
CSN.1 encoder which makes it difficult to do the bitmap encoding for
EGPRS.

Add a new implementation based on bitvec functions to create the
PACKET UPLINK ACK/NACK messages.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
580edbc326 sched: Assert that the generated message is not empty
Currently the msg data is accessed and index 0 assuming the msg is
not empty. While this should be always the case, the msg can be
empty if there are software errors in the message creation functions.

This commit adds an assertion to catch this kind of bugs.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
8e323b39f9 edge: Set the EGPRS window parameters
Currently the GPRS parameters are used, which is ok for the WS but
not for the SNS.

This commit uses RLC_EGPRS_SNS and RLC_EGPRS_MIN_WS for the window
configuration.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
869449cdd0 edge: Move EGPRS setup from setup_tbf to tbf_alloc_ul_tbf
Currently the EGPRS mode is enabled in setup_tbf depending on the
values of egprs_ms_class and bts->egprs_enabled (both must be != 0).
This makes it difficult to set different values (like window
parameters) depending on the direction.

This commit moved the initialisation part to tbf_alloc_ul_tbf und
just leaves the setting of the ms_class to setup_tbf.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:13 +01:00
Jacob Erlbeck
8f8197f3fd rlc: Make WS and SNS variable
Currently the values for WS and SNS are fixed to 64 (WS) and 128
(SNS) which are the only values that can be used with GPRS. On the
other hand, EGPRS requires an SNS of 2014 and a WS in the range of
64 to 1024.

This commit adds member variables and setters to both window
classes. By default, the GPRS values are being used.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:12 +01:00
Jacob Erlbeck
a3a567e765 rlc: Add constructor to window classes
Currently the gprs_rlc_dl_window and gprs_rlc_ul_window do not have
constructors, but need to get initialized explicitly.

This commit adds constructors to both classes and removes explicit
external initialization code.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:12 +01:00
Jacob Erlbeck
e1ca87f057 rlc/edge: Consistently use uint16_t for BSNs and SSNs
Currently in some places uint8_t is being used to encode BSNs and
SSNs. This is inconsistent and (even worse) not enough for EPGRS
which uses an SNS of 2014.

This commit changes these to uint16_t.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:12 +01:00
Jacob Erlbeck
93c55d04e5 rlc: Add and use mod_sns(bsn) method
Currently there is only a mod_sns() method which is being used in
expression like bsn_expr & win.mod_sns(). This only works, because
it is known that mod_sns() is (sns() - 1) where sns() in turn is
always 2^n. This is error prone, hard to read, and relies on window
specifics that should be kept inside the respective module.

This commit adds a mod_sns(uint bsn) method to gprs_rlc_ul_window and
gprs_rlc_dl_window, that encapsulates and hides this optimized
computation.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:12 +01:00
Jacob Erlbeck
2b3121eebf edge: Support EGPRS uplink Ack/Nack messages
This commit adds EGPRS UL Ack/Nack encoding based on the CSN1 code.

Note that the bitmap encoding is still broken and not easy to fix
with the CSN1 framework, especially w.r.t. the length field.
Therefore this implementation will be abandoned and replaced by a
bitvec based one.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:12 +01:00
Jacob Erlbeck
2e3a81e4b3 rlc: Use a pointer instead of repeated selector chains
Currently the same selector chain is used several times in the same
function.

This commit adds a pointer to Packet_Uplink_Ack_Nack and uses that
instead.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:12 +01:00
Jacob Erlbeck
5c75480e90 edge: Move the GPRS UL Ack/Nack encoding into a separate function
Currently the Encoding::write_packet_uplink_ack function only
supports GPRS.

Split this function into a generic and a GPRS specific part.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:12 +01:00
Jacob Erlbeck
d88bb2e825 rlc: Dump RLC data for debugging
Log incoming RLC data messages and RLC data units to LOGL_DEBUG.

Sponsored-by: On-Waves ehf
2016-02-01 13:58:12 +01:00
Jacob Erlbeck
c362df25a2 pcu: Fix memory corruption bugs (ASAN)
ASAN has found improper deletion of objects. These only occur
on shutdown but makes it impossible to run the test cases with
full ASAN support.

This commit fixes some of them and deactivates the freeing of the_pcu.bctx
which may cause a corruption in BTS::~BTS() later on.

Note that the latter is only a work-aound and should be fixed
properly. It will leak bctx objects, but this is currently not
critical, since gprs_bssgp_destroy is only called once, immediately
before a call to exit().

Ticket: OW#1572
Sponsored-by: On-Waves ehf
2016-02-01 13:56:32 +01:00
Jacob Erlbeck
27dc941475 edge: Remove leftover comments from encoding.c
Sponsored-by: On-Waves ehf
2016-01-08 11:14:15 +01:00
Jacob Erlbeck
ead5e4724c edge: Fix data block decoder (Coverity)
Use a signed integer instead of an unsigned one for num_chunks
which can set to a negative value on error.

Ensure that chunks is not dereferenced if it is NULL. In fact
that will not happen currently, since num_chunks is now always
<= 0 if chunks == NULL.

Fixes: Coverity CID 1347433, 1347434, 1347435

Sponsored-by: On-Waves ehf
2016-01-08 10:14:50 +01:00
Jacob Erlbeck
6e75bc7fe3 sched: Change next_ctrl_prio increment
Currently the control block scheduler does not seem to be fair in all
cases. At least it happend while testing the EGPRS code, that a
Uplink Ack/Nack message got never be sent, because a Downlink
assignment took over all the times.

This commit changes the round robin code to always increment the
priority offset by 1 instead of (i + 1). The former definitely
ensures that every message type gets the highest priority after some
steps. The latter might be more fair in some situations, but that and
its correctness are not proven.

Sponsored-by: On-Waves ehf
2015-12-16 19:57:13 +01:00
Jacob Erlbeck
845c01ef3f edge: Remove unused GPRS functions
This commit removes the code that is no longer used due to the commit
"Use a single PDCH rcv_data_block method for GPRS and EGPRS".

Sponsored-by: On-Waves ehf
2015-12-16 19:57:13 +01:00
Jacob Erlbeck
554a835e90 edge: Use a single PDCH rcv_data_block method for GPRS and EGPRS
Currently GPRS is handled by the old code path while EGPRS already
uses the unified functions. The rcv_block_egprs is basically not
specific to EGPRS and just needs minor modifications to handle GPRS.

This commit turns gprs_rlcmac_pdch::rcv_block_egprs into a unified
rcv_data_block method and uses it for GPRS, too.

Note that the logging messages of the new parser are different.

Sponsored-by: On-Waves ehf
2015-12-16 19:57:09 +01:00
Jacob Erlbeck
39c6c7f738 edge: Implement gprs_rlcmac_pdch::rcv_block_egprs
This commit replaces the stub by a method that decodes the block
first, and passes it to the TBF object associated with the TFI.

Sponsored-by: On-Waves ehf
2015-12-16 19:55:52 +01:00
Jacob Erlbeck
b3100e187b edge: Add methods for unified GPRS/EGPRS UL data block handling
The current rcv_data_block_acknowledged_gprs method is tightly
coupled to GPRS.

This commit adds variants of the involved methods that support
EGPRS and GPRS RLC encodings likewise.

Sponsored-by: On-Waves ehf
2015-12-16 19:55:18 +01:00
Jacob Erlbeck
e8f5fe5255 tbf: Refactor parts of extract_tlli into set_tlli_from_ul
Currently gprs_rlcmac_tbf::extract_tlli takes care of decoding and
the TBF update. These are really different things and doing the
decoding in extract_tlli makes EGPRS support more complex.

This commit moves the TBF state related part into a new method
gprs_rlcmac_tbf::set_tlli_from_ul.

Sponsored-by: On-Waves ehf
2015-12-16 19:37:49 +01:00
Jacob Erlbeck
ce1beb423c edge: Store GprsCodingScheme in gprs_rlc_data
Currently the coding scene is stored as number N, where there scheme
is CS-N.

This commit replaces this by a GprsCodingScheme type cs value. The
gprs_rlcmac_cs table is no longer needed and thus removed.

Sponsored-by: On-Waves ehf
2015-12-16 19:37:08 +01:00
Jacob Erlbeck
784a0bd000 edge: Add is_received and invalidate_bsn to gprs_rlc_ul_window
These methods will be needed for EGPRS decoding.

The is_received method returns true iff a block with the given BSN
has already been received in the current window. A call to
invalidate_bsn marks the block as not received.

Sponsored-by: On-Waves ehf
2015-12-16 19:37:08 +01:00
Jacob Erlbeck
d87e1d6ab7 rlc: Do not raise_v_q in receive_bsn
Currently gprs_rlc_ul_window::receive_bsn calls raise_v_q and returns
the number of RLC data blocks that can be taken from the queue. This
does not fit the EGPRS feature to put 2 independant data blocks in a
single RLC block.

This commit removes raise_v_q from receive_bsn, hence it must be
called explicitely to get the number of processable data blocks.

Sponsored-by: On-Waves ehf
2015-12-16 19:37:08 +01:00
Jacob Erlbeck
6167925147 edge: Add test cases for rlc_data_from_ul_data
This checks the example test cases given in appendix B of
TS 44.060.

Sponsored-by: On-Waves ehf
2015-12-16 19:36:10 +01:00
Jacob Erlbeck
4abc686d76 edge: Add unified decoder methods for GPRS/EGPRS
This commit adds new RLC block decoder functions that support both
GPRS and EGPRS. The code path is selected based on the value of the
GprsCodingScheme cs object.

- rlc_parse_ul_data_header
        parses the header of an RLC data block including the E and FBI/TI
        flags (currently supported CS-1 - CS-4, MCS-1 - MCS-4).

- rlc_copy_to_aligned_buffer
        copies an RLC data unit to a byte aligned buffer and returns
        the unit's length.

- rlc_get_data_aligned
        is a convenience wrapper around rlc_copy_to_aligned_buffer
        that avoids copying if the data unit is already byte aligned.

Sponsored-by: On-Waves ehf
2015-12-16 19:36:09 +01:00
Jacob Erlbeck
392a545336 edge: Add information about data blocks to GprsCodingScheme
This commit adds the methods maxDataBlockBytes and numDataBlocks
which provide information about the data areas within RLC messages.
In these areas, the extension bytes, TLLI, and the LLC data are
stored.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:43 +01:00
Jacob Erlbeck
4aa78a8bea rlc: Check endianness for bit field declarations
Currently the declarations of rlc_ul_header, rlc_dl_header, and
rlc_li_field silently assume that a gcc for a little endian platform
is being used.

This commit adds '#if OSMO_IS_LITTLE_ENDIAN' the ensure the correct
byte ordering.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:43 +01:00
Jacob Erlbeck
6c3dc61db5 edge: Add header type property to GprsCodingScheme
The header type depends on the coding scheme, for GPRS there is a
single data header type per direction, for EGPRS there are 3 per
direction. In addition, control block header types are used with CS-1
only, so there is one of the per direction altogether for GRPS and
EGPRS.

This commit adds the header type enum and two methods headerTypeData
and headerTypeControl.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:43 +01:00
Jacob Erlbeck
3b802e3c4a edge: Rename rcv_data_block_acknowledged
This commit renames rcv_data_block_acknowledged to
rcv_data_block_acknowledged_gprs to separate it from EGPRS data block
decoding.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:43 +01:00
Jacob Erlbeck
690a734ebf edge: Add gprs_rlcmac_pdch::rcv_block_egprs stub
This stub function gets called when an EGPRS data package arrives.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:42 +01:00
Jacob Erlbeck
9e862e1e7f edge: Use GprsCodingScheme to adjust the UL RLC block size
Currently the block size is mapped by a switch statement to strip
extra bits that are not used for RLC blocks. That information is
already available via the GprsCodingScheme class.

This commit moves the CS/MCS detection to the rcv_block message and
passes the cs object via rcv_block_gprs, where the length gets
adjusted, to gprs_rlcmac_pdch::rcv_data_block_acknowledged. There the
switch statement is removed.

Note that the TbfTest.err changes due to an additional log message.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:42 +01:00
Jacob Erlbeck
d0222cfe2d edge: Add test for GprsCodingScheme
This test checks constructors, predicates, and operators of the
GprsCodingScheme class.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:42 +01:00
Jacob Erlbeck
409f980a18 edge: Add GprsCodingScheme class
Currently the coding scheme is checked and compared at different
places which makes in cumbersome to extend it for EGPRS.

This class encapsules the coding scheme and provides required meta
information like sizes as well as helper methods.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:42 +01:00
Jacob Erlbeck
14e00f8f66 edge: Extend gprs_rlcmac_dl_tbf::handle by egprs_ms_class
The multislot (MS) class and the EGPRS MS class can also be passed
via BSSGP in an MS Radio Access Capability element which can
optionally be contained in a DL-UNITDATA PDU. While this case is fully
supported for GPRS, the EGPRS MS class in BSSGP messages is ignored.

This commit extends gprs_rlcmac_dl_tbf::handle to pass the EGPRS MS
class, too.

Note, that the EGPRS class is not yet taken from the CSN.1 RA
capability and is always set to 0. Note also, that append_data
still uses ms_class only.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:42 +01:00
Jacob Erlbeck
5265f59525 edge: Enable EGPRS if configured and egprs_ms_class present
Enable the TBF to use EGPRS if the bts->egprs_enabled config variable
has been set via the VTY "egprs" command and if the MS has signaled a
EGPRS multislot class.

Tell the MS to use EGPRS if the condition above holds.

Note that this will cause the MS to use EGPRS RLC block formats for
further messages which are not yet understood by the PCU.

Sponsored-by: On-Waves ehf
2015-12-15 15:19:42 +01:00
Jacob Erlbeck
86b6f05d19 edge: Support EGPRS multislot class handling in tbf_alloc
Add an egprs_ms_class argument to the allocation functions and
set/pass it where necessary.

Sponsored-by: On-Waves ehf
2015-12-15 15:17:51 +01:00
Jacob Erlbeck
5643f35fb4 edge: Add m_egprs_enabled and related methods to TBF
Add the following methods to gprs_rlcmac_tbf:
  - is_egprs_enabled
  - enable_egprs
  - disable_egprs

Also show the value of the flag in name() by displaying "EGPRS" if
it is set.

Sponsored-by: On-Waves ehf
2015-12-15 15:17:51 +01:00
Jacob Erlbeck
76d767cbe8 edge: Support EGPRS in packet uplink assignment message
Currently the Encoding::write_packet_uplink_assignment method only
supports the GPRS variant of the message.

This commit adds the missing EGPRS variant to the encoder.

Sponsored-by: On-Waves ehf
2015-11-30 12:20:36 +01:00
Jacob Erlbeck
953c78987a edge: Add egprs config command
Add a global config flag to enable the use EDGE/EGPRS.

The following VTY commands are added to node config-pcu:

 - egprs              Enables EGPRS
 - no egprs           Disable EGPRS

Note that enabling EGPRS is experimental and will most likely break
packet transmission until a minimal required set of EGPRS
functionality is implemented.

Sponsored-by: On-Waves ehf
2015-11-30 12:20:36 +01:00
Jacob Erlbeck
c3c58046c7 edge: Get EGPRS multislot class
The EGPRS MS class ist contained in the MS_RA_capability information.
Its presence indicates, that the MS is able (and willing) to use
EGPRS.

This commit implements basic support for retrieving, storing, and
showing it in the VTY. The information is stored in the MS object.

Sponsored-by: On-Waves ehf
2015-11-30 12:20:36 +01:00
Jacob Erlbeck
111ebe84c2 Revert "pcu: Improve default config"
This reverts commit acfb883011.

The values are now the default values of the application, so they
do not need to be set in this file.

Sponsored-by: On-Waves ehf
2015-11-30 12:11:48 +01:00
Jacob Erlbeck
eb93f592e5 pcu: Enable dl-tbf-idle-time and idle-ack-delay by default
Currently these are enabled in the default config file. Since CoDel
is enabled by default in main() but should not be used without at
least dl-tbf-idle-time, the current default config may lead to
packet loss and performance problems.

This commit enables both features to provide a good (GPRS) performance
experience even without a configuration.

Sponsored-by: On-Waves ehf
2015-11-30 12:11:39 +01:00
Jacob Erlbeck
f5898a0528 stat: Add global stat group
Add a global stat_item group for measurement values and a
corresponding macro to get and set the values.
Add a stat_item STAT_MS_PRESET to monitor the number of
MS objects in the storage.

Sponsored-by: On-Waves ehf
2015-11-30 12:11:29 +01:00
Jacob Erlbeck
edfd7e3d94 encoder: Whitespace fixes
Sponsored-by: On-Waves ehf
2015-11-27 15:09:10 +01:00
Jacob Erlbeck
acfb883011 pcu: Improve default config
Currently the optional features dl-tbf-idle-time and idle-ack-delay
are not enabled when using the default config. Without the former,
the packet loss is significantly increased since CoDel is enabled by
default, eventually throwing away packets from ongoing paging and TBF
establishment procedures.

This commit changes the default config for satisfactory results even
with a single PDCH.

Sponsored-by: On-Waves ehf
2015-11-27 15:09:10 +01:00
Jacob Erlbeck
42aba81c2f stats: Enable stats subsystem
Sponsored-by: On-Waves ehf
2015-11-17 15:42:01 +01:00
Harald Welte
08e5d604d3 remove obsolete OpenBTS PCU interface support
This OpenBTS socket interface was originally added to enable GPRS
capabilitie with a forked version of OpenBTS, at a time when the public
OpenBTS release didn't yet have any GPRS support.

Meanwhile, the later OpenBTS releases included their own version of
GPRS, without any external PCU/SGSN/GGSN, so this interface is no longer
needed.

This also means that the OsmoBTS socket interface is now the default at
compilation time.  There is no other interface.
2015-11-13 16:07:25 +01:00
Harald Welte
19d1e9270d osmobts_sock.cpp: Add missing space in log statement. 2015-11-12 01:08:19 +01:00
Harald Welte
218482769b print/log OpenBTS / OsmoBTS variant in PCU startup
Otherwise it can be very confusing, as Max had to figure out today...
2015-11-12 01:07:41 +01:00
Harald Welte
d32cbbb130 rename sysmo_sock.cpp to osmobts_sock.cpp
This also renames the --enable-sysmbts option to --enable-osmobts

This socket interface was nevery sysmoBTS specific, but it is a generic
socket interface to any OsmoBTS supported layer1/hardware.  So it was a
mis-nomer so far.
2015-11-12 01:01:35 +01:00
Holger Hans Peter Freyther
8df447dc77 stats: Include the header file for the new class identifier 2015-11-07 21:04:40 +01:00
Holger Hans Peter Freyther
b8a5426cf0 stats: Attempt to compile fix the new rate_ctr
We wanted to support gcc-4.2 and this didn't allow us to use
the C99 initializers inside C++ code. Attempt to initialize
the class_id correctly.
2015-11-07 21:01:23 +01:00
Jacob Erlbeck
2db0f08e08 bssgp: Use measured leak rate for flow control
The leak rate sent to the SGSN does not reflect the current CS level,
lost frames, and control message overhead. So the SGSN cannot do
proper queue control under non-optimal conditions.

This commit computes the leak rate for the last flow control interval
by computing the maximum theoretical leak rate and basically
substracting control blocks, nacked blocks, and reduced block sizes
due to CS downgrade. By using this approach, the value will by more
stable on low load, where the value will tend to be near the value
derived from the configuration. On full load the transmitted value is
completely derived from the measurements.

Note that the MS default values are no adapted to the adapted BVC
leak rate, since a single MS which has a lower link quality would
otherwise be reducing the rate of another MS with good radio
conditions, which would not make much sense if they did not share any
PDCH.

Sponsored-by: On-Waves ehf
2015-09-11 11:52:02 +02:00
Jacob Erlbeck
7c8d39a67b poll: Count failed procedures
When a timeout has occured several times, the procedures handled by
poll_timeout are aborted. This happens when the number of repetitions
exceed N3105. Currently only the timeouts themselves are counted.

This commits adds counters that are incremented if a procedure has
really failed.

New counter:
- rlc.ass.failed:   Count failing UL and DL assigments via PACCH
- rlc.ack.failed:   Count failing DL Ack/Nack requests

Sponsored-by: On-Waves ehf
2015-09-07 14:10:35 +02:00
Jacob Erlbeck
c8cbfc2c98 bts: Start a DL TBF if needed after establishment of an UL TBF
Currently an existing DL TBF can get lost in the process of
establishing an UL TBF via RACH. This can lead to stalled connections
until the network sends more LLC frames.

This commit adds a check for a non-empty LLC queue after the UL TBF
has been established to rcv_control_ack (GPRS_RLCMAC_UL_ASS_WAIT_ACK
path) to eventually establish a new DL TBF on the UL TBF's PACCH.

Sponsored-by: On-Waves ehf
2015-09-01 12:01:20 +02:00
Jacob Erlbeck
ae0a799f44 bts: Release DL TBF instead of killing in rcv_resource_request
Currently an existing DL TBF is freed immediately, when a resource
request is received. This makes sense since the MS might have dropped
it when switching to the PDCH signaled via the AGCH for the SBA. But
if the TBF still is assumed to exist on the MS side, there might be
TFI collisions if the old TBF object is not kept to block its TFI
for some time.

This commit changes rcv_resource_request to call release() instead of
tbf_free() on the DL TBF object (if it exists).

Sponsored-by: On-Waves ehf
2015-09-01 12:00:31 +02:00
Jacob Erlbeck
91ff7d1864 tbf: Refactor reuse_tbf into releasing and DL TBF establishment
Currently reuse_tbf (partly) resets the old DL TBF and uses its PACCH
to establish a new DL TBF. The method can not be used with UL TBFs.

This commit replaces the reuse_tbf method into a
gprs_rlcmac_dl_tbf:release method which triggers the TBF's timer
based deletion (so that the TFI is still reserved for some time) and
a gprs_rlcmac_tbf::establish_dl_tbf_on_pacch which can establish DL
TBFs on existing PACCHs of either DL or UL TBFs.

Sponsored-by: On-Waves ehf
2015-09-01 11:49:04 +02:00
Jacob Erlbeck
9659d59307 tbf: Keep the old MS object alive in extract_tlli
Currently when a second MS object has been created for an MS, because
the TLLI was not known yet, the will be detected in
gprs_rlcmac_tbf::extract_tlli and the two objects will be merged by
update_ms. But when the dl_tbf is moved from the old to the new
(second) MS object, the old MS object can get idle and be removed
before the object are merged. This can cause LLC frame loss when the
MS object is deleted immediately after getting idle (no timeout
configured).

This commit adds a guard to keep the MS object until extract_tlli has
been executed.

Sponsored-by: On-Waves ehf
2015-09-01 11:48:26 +02:00
Jacob Erlbeck
cf6ae9d12f Revert "tbf: Do not kill DL TBF on Packet Resource Request"
This reverts commit e91bd3babd.

That commit seems to cause hanging DL TBFs when there was a RACH
based UL TBF establishment while it that TBF is active. This could be
caused by the use of a different PDCH for the SBA.

Conflicts:
	tests/tbf/TbfTest.cpp
	tests/tbf/TbfTest.err
2015-09-01 11:48:25 +02:00
Jacob Erlbeck
af75ce8e15 l1: Use the FN of all data_ind/ra_ind DSP messages
Currently all of these messages are discarded if they are assumend to
be caused by noise. But even in these cases, the FN and TN values
which are added by the DSP are valid. So these can be used to update
the current_frame value.

The osmo-bts sets the fBFILevel of a physical channel to -200dB if it
is used for PDTCH or PACCH which is the case for all PDCH. This way
a data_ind or ra_ind message is already send at least once per block
period (4 frames) per PDCH. These messages are passed to either
handle_ph_data_ind or handle_ph_ra_ind even if they contain garbage
data.

The ra_ind messages are sometimes sent a few frames earlier than
data_ind messages using the same frame.

This commit adds calls to update the current_frame value based on all
of these messages before they are discarded. The FN taken from ra_ind
are passed with an increased max_delay (5) to compensate for early
ra_ind messages.

Sponsored-by: On-Waves ehf
2015-08-28 12:23:07 +02:00
Jacob Erlbeck
be4a08b58a poll: Count unexpected block FN values
Currently a log entry is written if FN_data_ind - FN_time_ind <= -13.

This commit adds a counter 'rlc.late-block' that is incremented in
these cases.

Sponsored-by: On-Waves ehf
2015-08-28 12:23:07 +02:00
Jacob Erlbeck
60f77033ad poll: Use the data_ind FN as time source for current frame
The FN of the data_ind taken from the DSP are monotonic, so latency
does not affect the detection of poll timeouts if these FN are used.
If the FN is larger than a poll_fn value, it can safely be assumed
that the poll response will not arrive later on.

Currently a max_delay of 60 frames is used, which has the drawback
that additional ~250ms will pass until a lost ACK is detected.

Using the data_ind's FN alone breaks the poll timeout detection if
there are no other MS sending data blocks.

This commit adds BTS::set_current_block_frame_number that is called
with the FN taken from data_ind messages. The max_delay is set to 0
which removes the additional delay, when this FN is used to detect
poll timeouts. So the average additional delay decreases with the
number of data_ind per time. The current_frame is updated unless it
seems to have been updated already (assumed if 0 < cur_fn - block_fn
< 500). Thus the time_ind has still priority to update the
current_frame value.

Sponsored-by: On-Waves ehf
2015-08-28 12:23:07 +02:00
Jacob Erlbeck
e77d49f2a2 poll: Set the max_delay to 60 frames
Currently the max_delay parameter is set to 13, since that is
slightly above maximum number of frames that a time_ind can preceed a
block's data_ind of the same frame. This assumes that these messages
are not reordered after thay have been obtained from the DSP. In the
current implementation, the GPRS data_ind can directly be taken from
the DSP by the PCU while the time_ind messages are provided via the
BTS. So the messages are queued differently in that case, resulting
in a additional delay of the data_ind with respect to the time_ind.
The propability for this raises with a increased CPU load of the PCU.

If this happens, a poll timeout is detected by mistake and the poll
is either retried or cleared.

This commit increases the tolerance to 60 frames, since
values for FN_data_ind - FN_time_ind of up to 50 frames have been
observed under heavy PCU load.

Sponsored-by: On-Waves ehf
2015-08-28 12:23:07 +02:00
Jacob Erlbeck
ac49d0943a poll: Add a max_delay parameter to PollController::expireTimedout
Currently the maximum additional delay is hard coded to 13. This
value depends on the source of the frame number value.

This commit adds the max_delay parameter to make it caller dependant.

Sponsored-by: On-Waves ehf
2015-08-28 12:23:07 +02:00
Jacob Erlbeck
16d29c7da4 tbf: Add logging for polling
This commit adds the relevant frame number to the "poll timeout"
logging message. In addition, logging is added to the places where
poll_fn gets set.

The goal is to track down the source for frequent "poll timeout"
messages.

Sponsored-by: On-Waves ehf
2015-08-28 12:23:07 +02:00
Jacob Erlbeck
b6b3c7eb27 tbf: Use explicit initialisations in constructor (Coverity)
Currently when allocating tbf_alloc_ul_tbf or tbf_alloc_dl_tbf
objects, the allocated memory area is pre-initialised by talloc_zero
before the C++ constructors are called. This is not recognised by
Coverity, since there is no talloc model file yet. Thus Coverity
complains about missing initialisers.

On the other hand, it is still planned to convert the TBF classes
into real C++ ones. So instead of silencing Coverity directly, this
is an opportunity to do it the C++ way.

This commit adds initialisers and initialisation code for all
members that relied on talloc_zero. The corresponding calls to
talloc_zero are replaced by calls to talloc to give ASAN/valgrind
a chance to detect future initialisation errors. Some initialisation
code is also moved from setup_tbf to the constructors, notably the
initialisation of the bts pointer.

Fixes: Coverity CID 1320604, 1320605, 1320606

Sponsored-by: On-Waves ehf
2015-08-28 12:07:14 +02:00
Jacob Erlbeck
1c95bd383e openbts: Remove unused declaration of fl1h in udp_read_cb
Fixes:
openbts_sock.cpp:94:22: warning: unused variable 'fl1h'

Sponsored-by: On-Waves ehf
2015-08-27 11:47:35 +02:00
Jacob Erlbeck
159d4de370 ms/vty: Show LLC queue octets and packets in both views
Currently the per IMSI/TLLI view only shows the number of packets and
the 'all' view does not show any LLC related information at all. A
constant LLC queue length is often an indication for a stalled TCP
connection where the RLC layer has stopped to send downlink data
messages.

This commit adds the number of packets to the 'all' view and the
number of octets to the IMSI/TLLI views.

Sponsored-by: On-Waves ehf
2015-08-27 10:33:10 +02:00
Jacob Erlbeck
c62216b4fc ms/vty: Show old TBFs
This commit extends the 'show ms imsi|tlli' command to show the old
TBFs, too.

Sponsored-by: On-Waves ehf
2015-08-24 12:23:50 +02:00
Jacob Erlbeck
6835cead8c ms: Store references to replaced TBFs in the MS object
Currently when calling GprsMs::attach_tbf and a TBF of the same
direction already exists, the old TBF gets detached from the MS
object.

Therefore that TBF object loses access to that MS object including
for instance TLLI and IMSI.

This leads to failing DL TBF reuses, since the downlink assigment
cannot be sent on the PACCH later on because that must be sent on the
old DL TBF which ms() is NULL and the new DL TBF cannot be retrieved.

This commit fixes this bug by changing the GprsMs implementation to
keep a list of replaced (old) TBFs. TBFs are only removed when they
are being detached explicitely (see tbf_free and set_ms).

Addresses:
tbf.cpp:741 We have a schedule for downlink assignment at uplink
TBF(TFI=1 TLLI=0xf35a680e DIR=UL STATE=RELEASING), but there is no
downlink TBF

Sponsored-by: On-Waves ehf
2015-08-24 12:23:50 +02:00
Jacob Erlbeck
6e013a136a bssgp: Only call bssgp_tx_llc_discarded if the bctx exists
While this does not happen in real use, and unset btcx can lead to
segfaults in test cases. The other code outside of gprs_bssgp_pcu.cpp
does not depend on bctx being non-NULL:

Sponsored-by: On-Waves ehf
2015-08-24 12:23:50 +02:00
Jacob Erlbeck
af387e2199 llist: Add missing const qualifier in llist cast method
The missing const qualifier prevents the llist_empty() C++ wrapper
function from being compiled successfully when it is used.

Sponsored-by: On-Waves ehf
2015-08-24 12:23:50 +02:00
Jacob Erlbeck
444bc82081 tbf: Use C++/talloc magic to support TBF constructors/destructors
The TBF object are currently created by using talloc_zero/talloc_free
directly from plain functions. Therefore C++ constructors and destructors
are not called. So the only initialisation that is done is setting
every member to 0. Non POD members do not have their constructors
called either, which makes it impossible to use the current LListHead
class for real members when the LListHead::m_back member has to be set.

This commit changes the TBF allocation functions to call the
corresponding C++ constructor after the call to talloc_zero and to
register the C++ destructor with the talloc context, so that is is
called before talloc_free actually frees the memory.

With this change, non-POD members and custom
constructors/desctructors can be used with gprs_rlcmac_tbf,
gprs_rlcmac_dl_tbf, and gprs_rlcmac_ul_tbf.

Note that this change is only a single step of the plan to turn the
TBF classes into real C++ classes.

Sponsored-by: On-Waves ehf
2015-08-24 12:23:50 +02:00
Jacob Erlbeck
23c4b3f158 tbf/test: Add test_tbf_dl_reuse
This tests the usage of an existing TBF that is no longer in FLOW
state to request a new DL TBF via the old TBF's PACCH.

The test triggers a bug that breaks the association between both TBF
objects, resulting in packet loss and transmission stalling.

Sponsored-by: On-Waves ehf
2015-08-24 12:23:50 +02:00
Jacob Erlbeck
af45473cd5 tbf/test: Do RLC based ack instead of just faking
Currently the assignment is completed by manipulating the state of
the TBF objects directly by setting the state fields to fixed values.
This way, the PCU's code that is responsible to update the state
accordingly is not tested.

This commit changes this to simulate RLC Control Acknowledgement
messages instead.

Sponsored-by: On-Waves ehf
2015-08-24 12:19:18 +02:00
Jacob Erlbeck
cef20ae67a tbf/test: Rename send_rlc_block to request_dl_rlc_block
This function basically request the generation of the next downlink
RLC block. Since this will no really send somthing to the PCU, the
current name can be misleading.

This commit just renames the function.

Sponsored-by: On-Waves ehf
2015-08-24 12:04:41 +02:00
Jacob Erlbeck
ee31090b2e tbf/test: Simplify RLC block number handling
The block number can always be deduced from the frame number. The
current test code handles the block number explicitely, which makes
the code more complex and has also led to block number errors cause
by not wrapping the numbers (valid block numbers range from 0 to 11).

This commit changes send_rlc_block to always compute the block number
based on the frame number. It also turns the block_nr into an
optionaly output-only parameter.

Sponsored-by: On-Waves ehf
2015-08-24 11:55:17 +02:00
Jacob Erlbeck
64921d217b tbf/test: Add send_rlc_block function with a TBF as parameter
The current implementation takes a lot of parameters (bts, trx_no,
...) that can also be taken from a TBF object.

This commit adds an alternative variant with just takes a TBF, the fn
(in/out), and the block number (in/out).

Sponsored-by: On-Waves ehf
2015-08-24 11:50:27 +02:00
Jacob Erlbeck
56f99d19c3 tbf/test: Move UL MAC block encoding into a separate function
This commits adds send_ul_mac_block() to encode and send a
RlcMacUplink_t to the PCU.

Sponsored-by: On-Waves ehf
2015-08-21 19:02:18 +02:00
Jacob Erlbeck
e0b21f41c2 tbf: Move pending LLC frames when merging MS objects
Currently the pending LLC packets are lost in some cases when MS
objects are merged, for instance after a RACH when there were 2 MS
object for the same MS (they get merged, when the TLLI is known for
both objects).

This patch modifies GprsMs::merge_old_ms to move all pending LLC
packets (if there are any) to the current MS object.

Sponsored-by: On-Waves ehf
2015-08-21 19:02:18 +02:00
Jacob Erlbeck
257b630216 llc: Add move_and_merge method to llc_queue
This methods takes all LLC frames from the old LLC queue and moves
them into the current. If both queues are ordered chronologically
(recv_time), the resulting queue is also ordered.

Sponsored-by: On-Waves ehf
2015-08-21 19:02:18 +02:00
Jacob Erlbeck
e91bd3babd tbf: Do not kill DL TBF on Packet Resource Request
Currently all active TBF of an MS are killed if a Packet Resource
Request is received from the MS. In general this happens after a RACH
request. This does not happen after a resource request that has been
included into a Downlink Ack/Nack.

Sometimes an UL TBF is requested by an MS via RACH while a DL TBF is
running for instance to send a TCP Ack. This can happen, if a former
request via PACCH did not work.

This commit removes the killing of the DL TBF from
gprs_rlcmac_pdch::rcv_resource_request().

Sponsored-by: On-Waves ehf
2015-08-21 19:02:18 +02:00
Jacob Erlbeck
b139598b1c tbf/test: Add tests for RACH while DL TBFs are active
This adds tests for
- RA update with RACH for the RAUpdateComplete message
- RACH for UL while DL is active (LLC queue not empty)

Sponsored-by: On-Waves ehf
2015-08-21 19:02:18 +02:00
Jacob Erlbeck
076f5c794d tbf/test: Fix existing tests
This commit fixes several issues:
- Set MS class in request
- Set IMSI in establish_ul_tbf_two_phase
- Fake assigment acknowledgement in establish_ul_tbf_two_phase
- Fix TFI bit offset to 1 (was 2)

Sponsored-by: On-Waves ehf
2015-08-21 19:02:18 +02:00
Jacob Erlbeck
537b149828 tbf: Fix typos in log messages concerning UL/DL
The TBF in create_dl_ass can be of any direction. The text in
rcv_resource_request uses DL instead of UL.

Sponsored-by: On-Waves ehf
2015-08-21 18:59:14 +02:00
Jacob Erlbeck
4a6fe534ce tbf/test: Move UL TBF establishment into separate functions
Currently the functions test_tbf_single_phase and test_tbf_two_phase
do the test logging, BTS intialisation, and the complete message
sequencing on their own. Therefore they cannot be used to test more
complex sequences like TBF reestablishment.

This commit moves the code that does the actual messaging into own
functions. The frame number handling is generalised which also fixes
a block number wrapping error on the way.

Sponsored-by: On-Waves ehf
2015-08-21 16:56:56 +02:00
Jacob Erlbeck
2b349b5d33 ms: Move MS information merging to GprsMS
Currently the merging of the meta information (MS class, IMSI) takes
place in gprs_rlcmac_tbf::merge_and_clear_ms(). This makes it
difficult to merge the internal state and does not directly relate to
TBFs anyway.

This commit moves this into a new method GprsMs::merge_old_ms.

Sponsored-by: On-Waves ehf
2015-08-18 11:55:03 +02:00
Jacob Erlbeck
ebebad1c92 ns: Reconnect NSVC after timeout
Currently the signal S_NS_ALIVE_EXP emitted by the NS layer if the
alive check has timed out too often is ignored. This prevents the PCU
from reconnecting to the SGSN if it has not been accessible for some
time.

This commit modifies nsvc_signal_cb to reset the NSCV if
S_NS_ALIVE_EXP is sent, so that the PCU continues to send NS RESET
message if that happened.

Sponsored-by: On-Waves ehf
2015-08-17 16:29:34 +02:00
Jacob Erlbeck
56af6d55ed ns: Add logging support
Currently there is not support for Network Service (NS) logging.

This commit adds the missing definitions and sets the default level
to INFO. Further configuration can now be done with the 'logging
level ns' VTY command.

Sponsored-by: On-Waves ehf
2015-08-17 16:24:11 +02:00
Jacob Erlbeck
f76fedeed5 vty: Change API to have node installation be done by int
This commit fixes the go_parent_cb API according to libosmocore's
commit of the same name.

Fixes:
pcu_vty.c:799:2: warning: initialization from incompatible pointer
type [enabled by default]
  .go_parent_cb = pcu_vty_go_parent,

Sponsored-by: On-Waves ehf
2015-08-17 16:23:27 +02:00
Jacob Erlbeck
fea17f8b8c ms: Do not retrieve MS with IMSI 000 from the storage
The IMSI '000' is used as default value for an incoming BSSGP
message's IMSI IE. This can lead to the retrieval of the wrong MS
object from the storage.

This commit changes the get_ms method to skip the IMSI search if such
an IMSI is passed as selector.

Note that changing the default value in the BSSGP code does not help
here.

Sponsored-by: On-Waves ehf
2015-08-17 16:23:27 +02:00
Jacob Erlbeck
af9a39d954 tbf: Use update_ms instead of confirm_tlli in handle()
The confirm_tlli method does not handle TLLI clashes in the MS
storage.

This commit changes gprs_rlcmac_dl_tbf::handle() to use update_ms
instead.

Sponsored-by: On-Waves ehf
2015-08-17 16:23:27 +02:00
Jacob Erlbeck
28c40b1757 tbf: Clean old MS objects if they have the same TLLI
Currently if an MS retries to access the PCU by using RACH and if
there is already an entry for that MS, a duplicated MS object
referring to the same TLLI is created. This is caused by blindly
setting the TLLI without querying the MS storage to avoid
inconsitencies.

This leads to several entries in the MS storage that are assigned to
the same TLLI. If that happens, 'show ms all' can display multiple
entries with the same TLLI (note that an MS object can belong to
several TLLIs, so there might be an intersection that is not visible
in the list) or 'show tbf all' can show entries with MS_CLASS == 0 in
some cases.

This commit changes update_ms() to merge and clean up old entries
that belong to the given TLLI if they exist. Some data (like the MS
class) is copied to the new MS object.

Note that TBF belonging to the old MS object are deleted immediately
if they have not registered a timer.

Sponsored-by: On-Waves ehf
2015-08-17 16:23:01 +02:00
Jacob Erlbeck
3449a61032 pcu: Update example config file
This commits sets the initial CS to 2 to allow a successful
connection setup if the radio link has a low quality. The slot
allocation algorithm is changed to 'dynamic', which is the binary's
current default anyway.

Sponsored-by: On-Waves ehf
2015-08-17 16:16:51 +02:00
Jacob Erlbeck
1c3b8998bc ms: Set default CoDel interval to 4s
The current default interval is 2s which seems to be too short when
the DL TBF has to be established. This may cause freezing or really
slow TCP connections.

This commit increases the default value to 4s. When the
dl-tbf-idle-time is set, DL TBF are established less frequent, so
smaller values (like 2s or below) can be used to improve the average
latency when the load is high.

Sponsored-by: On-Waves ehf
2015-08-14 16:35:34 +02:00
Jacob Erlbeck
ac28905082 tbf: Handle TLLI change on DL
When doing an RA Update the network can request to change the TLLI.
In this case, there can be 2 MS objects with different TLLI for a
single real MS. The first is associated with the old TLLI and the
IMSI, while the second is associated with the new TLLI and no IMSI if
it had been created for the uplink TBF. When the first message with
the new TLLI and the IMSI arrives from the network, the PCU is able
to detect this.

Currently this is not handled properly. The TBFs of the old MS object
are not cleaned up properly, keeping the old MS from being deleted.

This patch modifies gprs_rlcmac_dl_tbf::handle to check for this and
if neccessary to move an existing DL TBF and to clean up the old MS
object to ensure its deletion.

Sponsored-by: On-Waves ehf
2015-08-14 16:35:29 +02:00
Jacob Erlbeck
04e72d34f5 tbf: Always start T3193 when changing state to GPRS_RLCMAC_WAIT_RELEASE
Currently when receiving a PACKET DL ACK/NACK message with the Final
Ack Indicator bit set, the TBF's state is set to
GPRS_RLCMAC_WAIT_RELEASE but T3193 is only started when the LLC queue is
empty. Otherwise the reuse_tbf() method is called to establish a new
DL TBF. In that case, the timer is not started. This will leave the
current TBF without a timer so it is potentially not released later
on.

This is recognisable by sticky entries in the output of the
'show tbf all' command and possibly allocation failures if there are
too many of them.

This commit changes the code to always start T3193 to make sure, that
a timer is always active when the the state is set to
GPRS_RLCMAC_WAIT_RELEASE.

Note that TS 44.060, 9.3.2.6 requests to release the 'old' TBF
immediately in some cases, which is not implemented by this change.
This will lead to a longer reservation period of the TFI only, which
is safer than reassigning it too early.

Sponsored-by: On-Waves ehf
2015-08-13 19:51:50 +02:00
Jacob Erlbeck
6eed1911fd bssgp: Fix leak rate computation CS value
Currently the initial_cs_dl value is used to compute the maximum leak
rate. This can be too low if adaptive CS selection is used.

This commit changes gprs_bssgp_tx_fc_bvc to derive the max CS level
from the configuration.

Sponsored-by: On-Waves ehf
2015-07-21 19:22:36 +02:00
Jacob Erlbeck
b31f5ef699 pcu: Enable LLC CoDel by default
Currently CoDel is disabled by default.

This commit enables CoDel on start up with the default interval time,
equivalent to the 'queue codel' VTY command.

To disable CoDel, use the 'no queue codel' command.

Sponsored-by: On-Waves ehf
2015-07-21 19:22:36 +02:00
Jacob Erlbeck
d4ad731bae llc: Use CoDel to drop packages from the LLC queue
Currently packets are only dropped if they have reached their maximum
life time. This leads to LLC queues being constantly filled under
load, increasing the latency up to the maximum life time. This kind
of bufferbloat hinders TCP's congestion avoidance algorithms. To keep
the queues short, the CoDel active queue management algorithm can be
used.

This commit changes to llc_dequeue method to apply the CoDel
algorithm to selectively drop LLC frames before they passed to the
TBF layer to be encoded in BSNs. This feature is currently disabled
by default.

The CoDel state is managed per MS since the LLC queues are also kept
in the MS objects.

Note that there is still some buffering in the TBF objects, in the
worst case (CS4) 3.5kByte + LLC-MTU octets are stored there. The
resulting additional packet delay is not (yet) taken into account for
CoDel.

Also note that configuration changes are applied to new MS objects
only.

The following VTY commands are added to the 'pcu' node:

- queue codel           activates CoDel, the interval is selected by
                        the implementation
- queue codel interval <1-1000>
                        activates CoDel with a fixed interval given
                        in centiseconds (10ms-10s)
- no queue codel        deactivates CoDel

Which interval value to use is still an open issue. For high speed
links (e.g. Ethernet), CoDel suggests 100ms. For slower links, the
expected RTT is recommended. The current implementation uses a
default value of 2000ms.

Measurements:

Note that the following measurements depend on several other factors,
most notably the interaction with the SGSN's flow control. They are
just examples to give an idea how CoDel might influence some
parameters.

The measurements have been done with a single E71, first with a
running ping only (Idle), then with an additional TCP download
of a 360k file (Busy). The CoDel interval was set to 1s.

- Idle :
        ping ~400ms, avg queue delay 0ms, dropped 0
- Busy, No CoDel:
        ping ~6s, avg queue delay 4-6s,
        dropped  0, scheduled  948, duration 54s
- Busy, CoDel:
        ping 500-1500ms, avg queue delay ~600ms,
        dropped 77, scheduled 1040, duration 60s

More measurements with two MS downloading in parallel (two
independant measurements per case).

- Busy, No CoDel:
        dropped  0, scheduled 1883, duration 121s
        dropped 19, scheduled 2003, duration 133s
- Busy, CoDel:
        dropped 22, scheduled 1926, duration 116s
        dropped 22, scheduled 1955, duration 108s

Sponsored-by: On-Waves ehf
2015-07-21 19:22:36 +02:00
Jacob Erlbeck
4f666bc113 llc: Add CoDel AQM implementation
This commit adds an implementation of the CoDel algorithm based on
the reference pseudocode presented in
http://queue.acm.org/appendices/codel.html. Instead of abstracting
the queue itself, the implementation provides a time stamp based
automaton which is invoked after a package has been dequeued.

Note that the modifications of the algorithm shown in
https://tools.ietf.org/html/draft-ietf-aqm-codel-01 are not yet
applied.

Sponsored-by: On-Waves ehf
2015-07-21 19:22:32 +02:00
Jacob Erlbeck
7f79f0d332 bssgp: Adapt flowcontrol MS default to current alloc algorithm
Currently the values Bmax/R default MS are computed under the
assumption than min(4, N_PDCH) DL slots are allocated for an MS, even
if multislot assignment is not enabled.

This commit changes the computation to assume 1 DL slot if algorithm
A is selected or the dynamic algorithm is used and has disabled
multislot assigment due to high load.

Sponsored-by: On-Waves ehf
2015-07-17 12:06:19 +02:00
Jacob Erlbeck
77da35515c alloc: Make alloc_algorithm_dynamic stateful
Currently there is no persistent state being used in
alloc_algorithm_dynamic. So algorithm B is even used in persistent
high usage scenarios. If there are many active TBFs, multislot
assigments are not fair, because MS of a "higher" multislot class get
higher troughputs. On the other hand, as long as all PDCH are busy no
bandwidth will be wasted even if all MS use algorithm A.

This commit modifies alloc_algorithm_dynamic to disable algorithm B
when that call fails. It then keeps it disabled until there is a
single PDCH which is idle (it is considered idle, if there is at most
one active DL TBF assigned to it).

Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
7b3675bf7a alloc/test: Fix trx_no assertion
Currently the value of trx_no2 is used in the assertion, even if the
call to tfi_find_free has failed.

This commit fixes the asserted expression to only compare the trx_no
values if the function call has succeeded.

Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
0f352a6f22 alloc/test: Free the TBF if the recursion has failed
Currently if both an uplink and a downlink TBF are to be allocated by
alloc_tbfs() and the second allocation fails, the first TBF is not
freed.

This commit changes the recursive function to free the TBF if the ms
variable has been changed to NULL.

Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
bf9042203d alloc/test: Use lower case for slots with TFI shortage
Indicate those slots with lower case letters that do not have a spare
TFI for the other direction if such a TBF has not been attached to
the MS object yet.

Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
7af53e61f0 alloc: Use a separate usage computation for algo A
Currently algorithm A can select an TBF even when there is no free
TBF in the reverse direction. While this does not necessarily lead to
an allocation failure, the probabily is higher. In addition, the
current slot reservations are not taken into account.

This commit changes the selection algorithm to prefer slots where TFI
are available in both directions and which are less reserved.

Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
88fb6136fb alloc/test: Show expectation before failure
To simplify debugging, show the actuals value before the assertion
fails in some cases.

Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
e21b79cb21 alloc: Change tx_window optimization strategy
Currently each tx_window combination is checked only once by using a
set containing the sets of TX slots that have been checked already.
This approach does not ensure, that num_tx and ul_ts really match the
tx_window being tested. This does not make a difference with the
current test cases probably because num_tx starts with 1 and is
increased each iteration. Since the bitmap optimization is equivalent
to a cache optimization strategy that only uses tx_window as key. On
the other hand, ul_ts, num_tx, and rx_mask cannot be derived from
tx_window, but these values are also refered to after the call to
test_and_set_bit(). This makes it difficult to prove that correctness
of the caching. While this will not lead to a defect, the results
might be less optimal.

This commit changes the optimization strategy to skip all tx_window
where ul_ts and ul_ts+num_tx-1 are not both contained.  This provides
a similar degree of optimization like the set approach (only the
iteration with num_ts == 8 is not optimized, which only applies to to
ms class 18 and 29 MS) but ensures that the values of the related
variables have a clear relationship.

Note that the bitset based optimization for rx_window does not suffer
from a possible cache inconsistency, since only tx_window and
rx_window (tx_slot_count and rx_slot_count can be derived from the
windows and thus are covered by the cache key) are used after the call
to test_and_set_bit(). tx_window is constant over the whole lifetime
of the cache.

Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
f16a069fd7 pcu: Use alloc_algorithm_dynamic by default
The dynamic algorithm behaves like B until there are no TFI left.

This commit changes the default algorithm to to former.

Ticket: #1934
Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
5979fe9d8a alloc: Add counters for successful algo A/B allocations
This adds counters for algorithm A and B with count successful
allocation combined for UL and DL.

Ticket: #1934
Sponsored-by: On-Waves ehf
2015-07-16 19:24:16 +02:00
Jacob Erlbeck
400ec02e8a alloc: Add 'dynamic' allocation algorithm
The idea behind this meta algorithm is to automatically select one of
the other algorithms based on the system state. Basically algorithm B
will be selected if the PDCH usage is low to improve throughput and
latency. Algorithm A will be selected to support more concurrent MS.

This commit adds a first simple state-less version of this algorithm
that always tries B first and only if that fails A is tried
afterwards.

The following VTY command is added to the 'pcu' node:

 - alloc-algorithm dynamic

Ticket: #1934
Sponsored-by: On-Waves ehf
2015-07-16 19:24:15 +02:00
Jacob Erlbeck
40da3e17e5 alloc: Remove disabled code fragment for multi-UL allocation
This part of algorithm_b has already been disabled. Further work may
depend on this, but it is going out of sync. So this commit removes
it completely.

Sponsored-by: On-Waves ehf
2015-07-16 19:24:15 +02:00
Jacob Erlbeck
5a2b8be3f5 alloc: Refactor alloc algorithms to only apply changes on success
Currently these algorithms modify other objects (MS, TBF, PDCH) even
if the allocation will fail later on. To implement an algorithm that
dynamically tries another algorithm on failure (e.g. A after B), the
first (failing) algorithm should not change or damage anything.

This commit refactors algorithm A and B to delay the actual allocation
until it is known that the allocation will not fail.

Ticket: #1934
Sponsored-by: On-Waves ehf
2015-07-16 19:24:13 +02:00
Jacob Erlbeck
2b558857dd alloc: Remove redundant first_common_ts handling
Currently this code path is only used, if an allocation has been
taken place in a former call to an allocation algorithm function.
If this was for an DL TBF, the first common TS was selected,
otherwise the least used common TS was selected for an UL TBF.
The shrinking of the UL set (to 1<<first_common_ts) is done in the
latter case.

This commit removes an additional code path that aligns the UL set to
first_common_ts, because it has no more influence on the set of
common TS after both UL and DL TBF have been allocated.

Sponsored-by: On-Waves ehf
2015-07-16 18:51:40 +02:00
Jacob Erlbeck
a8c2aaf6f0 alloc/test: Add test for interleaved TBF chains
MS iniated TCP connections generally result in a sequence
of short time UL and longer lasting DL TBFs, being interleaved
between several MS. This scenario is not covered by the existing
tests.

This commit adds a test, that allocates as man as possible TBFs
several times with different test modes without clearing the BTS (and
thus the TBF list) in between. The number of allocated DL TBFs in
each round is expected to be constant.

Sponsored-by: On-Waves ehf
2015-07-16 18:51:31 +02:00
Jacob Erlbeck
69c9bfa089 alloc/test: Put TBF allocation loop into alloc_many_tbfs
Currently all TBFs are deleted after the allocation loop finishes.
This make it difficult to interleave the TBF allocation like it
happens with real MS.

This commit refactors the allocation loop into alloc_many_tbfs and
adds support for TLLIs, which are derived from the counter value and
used to retrieve an old MS object if alloc_many_tbfs is called a
second time.

Note that this does not make a difference for the existing tests.

Sponsored-by: On-Waves ehf
2015-07-16 10:25:14 +02:00
Jacob Erlbeck
b2439bbb8a ms: Add is_idle() method to GprsMs::Guard
Currently there is no simple way to determine, whether the MS object
protected by a guard will continue to exist after the guard object is
destroyed.

This patch adds a is_idle() method that will return true if the MS
object is just kept by the guard from being idle. In that case, the
MS object would either be deleted or return true for
GprsMs::is_idle() after the guard's destruction, provided that no
TBF attachment took place in between.

Sponsored-by: On-Waves ehf
2015-07-16 10:25:14 +02:00
Jacob Erlbeck
3a10dbd564 tbf: Put the TFI->TBF mapping into the PDCH objects
Currently the TBFs are registered in a TFI indexed array within the TRX
objects. TBFs can be searched globally by TFI and TRX number. This
conflicts with the use of the same TFI for different TBF on different
PDCH. This use case requires the specification of the PDCH as
additional search dimension.

This commit moves the TFI index TBF arrays into the PDCH objects. The
related methods are updated accordingly.

Ticket: #1793
Sponsored-by: On-Waves ehf
2015-07-16 10:25:14 +02:00
Jacob Erlbeck
e0853cdf42 alloc: Allocate TFI per slot (algorithm A)
Currently the TFI are managed per TRX, thus only a maximum of 32 TBF
per direction and per TRX are possible simultaneously.

This commit modifies algorithm_a() to allow the sharing of TFI
between different PDCH. Since algorithm A only assigns a single slot
to each TBF, the TFI of each PDCH can be assigned independently.
This increases the maximum to 32 TBF per direction and per PDCH
concerning the TFI allocation.

Ticket: #1793
Sponsored-by: On-Waves ehf
2015-07-16 10:25:14 +02:00
Jacob Erlbeck
5879c6493f tbf: Move TFI selection into alloc_algorithm
Currently the TFI and the TRX have to be determined before the actual TBF
allocation function is called, passing TFI and TRX number as
parameters. This does fit to TFI reuse for different slots, since
this were tightly coupled with the slot selection.

This commit just moves the TFI selection into the alloc_algorithm
functions. The tfi parameter is removed from the the TFI alloc
functions. The trx parameter is changed into use_trx to optionally
limit the trx selection (same semantics like in tfi_find_free).

Sponsored-by: On-Waves ehf
2015-07-16 10:25:14 +02:00
Jacob Erlbeck
47a57f6f86 pdch: Manage TFIs per direction
Currently a single bit set is used to maintain a set of used TFI
without distinguishing between uplink and downlink. Since the
namespaces of UL and DL TFI are separate, this implementation is
not correct.

This commit changes gprs_rlcmac_pdch to use a separate bit set for
each direction. It also replace the corresponding conditional fprintf
statement in check_tfi_usage (AllocTest.cpp) by an equivalent
OSMO_ASSERT.

Sponsored-by: On-Waves ehf
2015-07-16 10:25:14 +02:00
Jacob Erlbeck
61205a7e65 alloc/test: Check for TFI conflicts
This commit adds the check_tfi_usage function that checks the TFI
usage. It iterates through all TBFs, records on which PDCH it uses
which TFI and check for conflicts. It also checks the bits returned
by pdch->assigned_tfi(). The latter suffers from an bug in that
method (no separation of uplink and downlink), so a conditional
fprintf is used instead of an assertion. The method tfi_find_free
is checked for conflicts after allocations.

Sponsored-by: On-Waves ehf
2015-07-16 10:25:14 +02:00
Jacob Erlbeck
57cf69a18c alloc: Fix MS_B/MS_C interpretation
Currently the handling of MS_B and MS_C is not compliant with TS
45.002, annex B.1. These values may only interpreted as 0, if
frequency hopping is not enabled and if there is no change from Rx to
Tx or vice-versa.

This commit sets Ttb/Trb to 1 if the table entry is MS_B/MS_C, since
only combined down/up access modes are supported.

Sponsored-by: On-Waves ehf
2015-07-16 10:24:37 +02:00
Jacob Erlbeck
dd08ac86e6 alloc: Do not use masking for multislot class type 2 MS
Currently the masks are computed equally for each class type. This
does not make much sense for class type 2 MS, since those are capable
to work in full duplex mode.

This commit sets the masks to 0xff for class type 2 MS.

Sponsored-by: On-Waves ehf
2015-07-16 10:24:37 +02:00
Jacob Erlbeck
bae33a7001 alloc: Select applicable Tta/Tra
According to TS 45.002, 6.4.2.2 the choice whether Tta or Tra has to
be applied, depends on the medium access mode (currently always
dynamic) and the number of UL/DL slots. Currently either value can be
used which might result in combinations not covered by the spec.

This commit changes find_multi_slots() to skip non-compliant
combinations.

Note that this code will have to be extended, if other medium
access modes are implemented.

Sponsored-by: On-Waves ehf
2015-07-16 10:24:37 +02:00
Jacob Erlbeck
5e46a20e03 alloc: Use an enum instead of numbers to select the mask
The local enums MASK_TT and MASK_TR replace the hard coded indices.
The variable m_idx is renamed to mask_sel for more clarity.

Sponsored-by: On-Waves ehf
2015-07-16 10:24:37 +02:00
Jacob Erlbeck
c135b878cd alloc: Merge find_least_busy_pdch and find_least_reserved_pdch
Both functions only differ in the computation of the value for
num_tbfs.

This commit merge both functions and adds a parameter containing a
function for that compuation.

Sponsored-by: On-Waves ehf
2015-07-16 10:24:37 +02:00
Jacob Erlbeck
1139ec1d0f sba: Fix loop exit in SBAController::alloc (Coverity)
The commit 506f156f7a has reverted the
TS search order. The outer loop exit condition was not updated
accordingly. This bug would would only lead to an error if there were
multiple TRX where the first TRX has not got any PDCH assigned.

This commit corrects the break condition.

Fixes: Coverity CID 1311776
Sponsored-by: On-Waves ehf
2015-07-15 14:17:19 +02:00
Jacob Erlbeck
3db617f14a llc: Fix comparison warning
Fixes: Jenkins build #609 warning

Addresses:
  llc.cpp:56, GNU C Compiler 3 (gcc), Priority: Normal
  comparison between signed and unsigned integer expressions

Sponsored-by: On-Waves ehf
2015-07-14 08:51:55 +02:00
Jacob Erlbeck
efe62a7395 alloc: Use least reserved PDCH for algo A
Currently the slot selection of algorithm A is based on the current
slot usage by active TBF. Especially in the Dl after UL case which
reflects the commen use case "MS initiates TCP connection", the
resulting distribution is not optimal with respect to PDCH usage.

This commit changes the implementation to use the slot reservation
information instead.

Sponsored-by: On-Waves ehf
2015-07-07 11:52:28 +02:00
Jacob Erlbeck
14376a73a5 alloc/test: Delete first TBF after the second is allocated
Currently when using the test modes TEST_MODE_DL_AFTER_UL or
TEST_MODE_UL_AFTER_DL, the first TBF is deleted before the second is
allocated. The far more interesting case were to keep the first TBF a
little bit longer until the second TBF has been created and delete
then. This comes closer the the situation observed with real MS,
where the first TBF takes some time (timeout or waiting for Ack)
before it gets deleted and thus detached from the MS object.

This commit delays the call to tbf_free accordingly.

The effect can be observed in the results of the algo A tests, where
the uniform distribution of the allocated PDCH is lost.

Sponsored-by: On-Waves ehf
2015-07-07 11:51:07 +02:00
Jacob Erlbeck
506f156f7a sba: Reverse TS search order
Currently the search for an enabled PDCH slot for SBA start with the
first TS. If there are more than 2 PDCH slots enabled, this slot will
conflict with an existing multislot reservation for most multislot
classes. This were less likely if the search were reversed and
started with the last slot due to the 3 slot shift between Tx and Rx.

When multislot allocation is enabled and several MS are connected,
and increased rate of poll timeouts can be observed.

This commit tries to reduce the number of poll timeouts by reverting
the slot search order for SBA allocation.

Sponsored-by: On-Waves ehf
2015-07-07 10:41:44 +02:00
Jacob Erlbeck
1653f837e3 alloc: Disable inner loop debugging by default
The current logging statements within the inner loop of
find_multi_slots drain quite a lot of CPU resources even if
LOGL_DEBUG is not enabled. This might cause issues on the target
hardware.

This commit disables these LOGP calls unless the
ENABLE_TS_ALLOC_DEBUG macro has been set explicitly. This results in
a reduction in the CPU usage reported by callgrind for
find_multi_slots from 42% to 25% when executing AllocTest.

Sponsored-by: On-Waves ehf
2015-07-07 10:35:28 +02:00
Jacob Erlbeck
20b7ba7501 alloc: Optimize find_free_usf
According to callgrind, this function consumes 33% CPU when running
the AllocTest program.

This commit uses the assigned_usf() method to get the USFs allocated
by a PDCH instead of traversing the TBFs.

Sponsored-by: On-Waves ehf
2015-07-07 10:35:28 +02:00
Jacob Erlbeck
cc9358f95a tbf: Keep a set of used TFI and USF per PDCH
Currently is is rather expensive to get TFI and USF usage per PDCH,
because the TBFs need to be scanned to get that information.

This commit adds corresponding bit sets which get updated by the
attach_tbf/detach_tbf methods of the gprs_rlcmac_pdch class.

Sponsored-by: On-Waves ehf
2015-07-07 10:35:28 +02:00
Jacob Erlbeck
16c6ecc365 alloc: Skip common TS without free USF when rating
Currently the search of the "best" slot combination is done
separately from the UL slot selection, which can lead to an
allocation failure due to USF exhaustion even if another combination
had been possible.

This commit reduces the probability for this event by skipping UL
slots without free USF while calculation the capacity.

Note that the implementation is rather inefficient which will be
fixed by the following commits.

Sponsored-by: On-Waves ehf
2015-07-07 10:29:12 +02:00
Jacob Erlbeck
5f494b8415 alloc: Only reserve 1 UL slot with algorithm B
Since currently the algorithm B will only allocate a single UL slot
and will have to stick to it (first common TS), the other possible UL
slots will not be allocated while the reservation is kept.

This commit adds code to update the reserved set of UL slots to only
reserve the single common TS when the UL TBF is allocated.

Interestingly this leads to fewer allocated TBF in some cases due to
USF exhaustion. This will be improved by the following commit "alloc:
Skip common TS without free USF".

Sponsored-by: On-Waves ehf
2015-07-07 10:22:18 +02:00
Jacob Erlbeck
9ae282372c alloc: Set minimum slot capacity to 1
Currently the capacity of a PDCH slot is calculated as 32 - N_reserved
for each direction. This can result in a capacity of 0 and even
negative values.

This commit forces the capacity of an usable slot to be at least zero
under the assumption, that an overly reserved PDCH is still better
than none.

Sponsored-by: On-Waves ehf
2015-07-07 10:03:29 +02:00
Jacob Erlbeck
ed46afda6f alloc: Only use common UL slots when calculating the capacity
Currently al possible UL slots are included in the capacity
calculation which is the base of the slot selection. Nevertheless
UL-only slots will never be used, since only one uplink slot (which
must be a common slot) will be used.

This patch changes the code to only include common slots in the
capacity sum.

Note that this might not be optimal if algorithm B supported
multiple uplink slots.

Sponsored-by: On-Waves ehf
2015-07-07 09:35:26 +02:00
Jacob Erlbeck
ea65c72d06 alloc: Replace Algorithm B implementation
The current implementation always starts the downlink slot allocation
with the first possible slot, depending on which channels are enabled
and which multislot class is offered by the MS. So in configurations
with many (>4) PDCH, some PDCH are not really used.

The new implementation introduced by this commit differs as follows:

 - The reservation mechanism provided by GprsMs is used to avoid
   incompatibilities is used in the same way like algo A does. This
   basically means, that the allocation is done once when the first
   TBF is requested and then used until all TBF have been released.

 - All combinations of Rx and Tx slots are checked for compatibility
   with the multiscot class. Basically the combination with the most
   usable PDCH and the least number of reservations is used.

 - Only one UL slots is provided.

 - Tta and Tra are checked.

Sponsored-by: On-Waves ehf
2015-07-07 09:35:26 +02:00
Jacob Erlbeck
c91c18e6ef tbf: Add Poll Timeout counters
This commits adds three poll timeout counters

  - RLC Assign Timeout
  - RLC Ack Timeout
  - RLC Release Timeout

to help diagnosing to cause for these events. There seems to be an
increased rate of these when a PDCH is shared by multiple TBFs.

Sponsored-by: On-Waves ehf
2015-07-07 09:33:29 +02:00
Jacob Erlbeck
e0c734dcfe Revert "tbf: Add GprsMs* argument to update() and use it in reuse_tbf"
This reverts commit 2272a83a13b57ea7e99fe96ac76e4ad892e19e90.

The modification is no longer needed, since the call to update has
been removed from reuse_tbf().

Conflicts:
	src/tbf_dl.cpp

Sponsored-by: On-Waves ehf
2015-07-03 15:58:45 +02:00
Jacob Erlbeck
07111668d4 tbf: Remove call to update() in reuse_tbf
Since both TBF are based on the same reservation which means that
they should be compatible with respect to the slot usage, and since
the new TBF has not been forced to single slot usage, an update of
the allocation is not necessary now.

This commit removes the call to update() from within reuse_tbf().

Sponsored-by: On-Waves ehf
2015-07-03 15:58:43 +02:00
Jacob Erlbeck
4944c195d4 tbf: Set ms in call to tbf_alloc_dl_tbf
The call to tbf_alloc_dl_tbf misses the pointer to the GprsMs object
which is already known in that case (tbf_reuse). This leads to a full
reallocation of the PDCH slots, which is possibly incompatible with
the old set of slots. This can result in hanging TCP connections and
TCP connection failures.

This commit replaces the old NULL value by the actual GprsMs object.
Since the set_ms() is also done within the tbf_alloc_dl_tbf method,
that call is removed.

Sponsored-by: On-Waves ehf
2015-07-03 15:53:15 +02:00
Jacob Erlbeck
5cd496d208 alloc: Base algo A on reserved PDCHs
Currently algorithm A bases its time slots selection on the number of
TBF actively using the PDCHs. This statistically prefers the first
time slots, especially with short living TBFs. So when the first TBF
is triggered by an uplink transfer (which generally results in a
short-lived TBF) the potentially longer living DL TBF will be bound
to the same slot. When another MS then requests an uplink TBF, it
will get the same slot (no UL TBF currently active).

This commit changes the algorithm to base its selection on reserved
slots instead.

Sponsored-by: On-Waves ehf
2015-07-03 15:37:16 +02:00
Jacob Erlbeck
83426b20a3 alloc: Ignore slots with differing TSC if multiple slots are requested
According to TS 45.002, 6.4.2 the training sequence (TSC) must be the
same for all slots in a multi-slot set.

This commit updates find_possible_pdchs() to only consider slots with
the same TSC if more that 1 slot shall be assigned.

Note that the first PDCH's TSC will be used as reference, so if two
or more groups with a common TSC are configured, only the first will
be used. This restriction does not apply to algorithm A, since it
will not assign more than one slot and therefore sets the max_slots
parameter to 1.

Sponsored-by: On-Waves ehf
2015-07-03 15:37:16 +02:00
Jacob Erlbeck
617c7127f4 ms: Get the set of slots currently active
This commits adds methods to GprsMs and gprs_rlcmac_tbf to retrieve
the slots that are actively used.

Sponsored-by: On-Waves ehf
2015-07-03 15:37:16 +02:00
Jacob Erlbeck
23f93a15ca ms: Add support for slot reservation
In contrast to the slots currently used by existing TBFs, the
reserved slots refer to the time slots that can be used for newly
allocated TBFs without causing conflicts (given that the first common
TS does not change). They correspond to the potential use of the
PDCHs and can be used to achieve a more uniform slot allocation.

This commit adds bit set based methods to GprsMs and gprs_rlcmac_trx
and a counter to gprs_rlcmac_pdch. The current TRX will also be
stored in the MS object.

Sponsored-by: On-Waves ehf
2015-07-03 15:37:16 +02:00
Jacob Erlbeck
ec478756cc alloc: Load balancing for algo A
Currently only the first enabled PDCH will be used. Beside the
throughput this will also limit the number of TBFs:

  - number of UL TBFs <= 7
  - number of DL TBFs <= 32

This commit changes the allocation algorithm to use the PDCH with the
least number of attached TBFs. This will improve the troughput in
both directions and the UL limits:

  - number of UL TBFs <= min(32, N_PDCH * 7) UL TBFs

Ticket: #1794
Sponsored-by: On-Waves ehf
2015-07-03 15:37:15 +02:00
Jacob Erlbeck
9380f5d218 tbf: Add GprsMs* argument to update() and use it in reuse_tbf
Since set_ms() is caled on the new DL TBF, the old DL TBF loses the
reference to the MS object. This will lead to a segfault, when
update() is called in reuse_tbf().

This commit adds an optional GprsMs* parameter to update() and uses it
for the slot allocation.

This fixes a TbfTest crash that would otherwise occur after applying
the next commit.

Sponsored-by: On-Waves ehf
2015-07-03 15:30:26 +02:00
Jacob Erlbeck
ac89a555fa ms: Add tbf() method to get the TBF based on the direction
To avoid the need for a switch or conditional statement when needing
a TBF from an MS object in direction independant code, this method
contains that case distinction. For additional flexibility, a
reverse() function is added to get the opposite direction.

Sponsored-by: On-Waves ehf
2015-07-03 13:17:22 +02:00
Jacob Erlbeck
699b8dca49 ms: Add first_common_ts method to GprsMs
This method gets the index (0 based) of first common time slot used
by the TBFs attach to it. It expects that all of them have the same
notion of this. If no TBF is attached, -1 will be returned.

Sponsored-by: On-Waves ehf
2015-07-03 13:17:22 +02:00
Jacob Erlbeck
ccc34e4d30 tbf: Maintain the number of TBF per PDCH
Currently the PDCH object do not know anything about the TBFs using
them. To make the slot allocation load dependant, at least some
numbers are required.

This commit adds TBF counters (one per direction) and the related methods
attach_tbf, detach_tbf, and num_tbfs to gprs_rlcmac_pdch.

Sponsored-by: On-Waves ehf
2015-07-03 13:17:22 +02:00
Jacob Erlbeck
c6d4ceeda6 tbf/test: Add assertions
These assertions check for the TBF allocation result before the tbf
object is dereferenced the first time.

Sponsored-by: On-Waves ehf
2015-07-03 12:05:51 +02:00
Jacob Erlbeck
9ec49e2411 alloc/test: Use LOGL_DEBUG environment variable
When this environment variable is set, the logging level is set to
LOGL_DEBUG to help debugging without putting everything into
AllocTest.err.

Sponsored-by: On-Waves ehf
2015-07-03 12:05:51 +02:00
Jacob Erlbeck
fa464bbce9 alloc/test: Enhance test_alloc_a
This commit adds:
 - an assertion to check that count is valid,
 - an assertion the verify that tbf_alloc did not fail
 - a slots parameter to specify the enabled slots
 - additional test invocations with more slots enabled

Sponsored-by: On-Waves ehf
2015-07-03 12:05:51 +02:00
Jacob Erlbeck
e565564bc9 alloc/test: Add test for successive allocation
This test allocates as many as possible UL/DL TBF pairs, shows their
PDCH usage, and checks how many of them has been created
successfully.

Sponsored-by: On-Waves ehf
2015-07-03 12:05:46 +02:00
Jacob Erlbeck
cb1b494c89 tbf: Add BTS::ms_alloc method
Currently the code that creates the MS objects with tbf.cpp is
duplicated.

This commit moves the corresponding code into a new method. Since
there is no TLLI available there, the GprsMsStorage::create_ms method
has been refactored into two variants: one with TLLI/direction and
one without.

Sponsored-by: On-Waves ehf
2015-06-29 11:43:17 +02:00
Jacob Erlbeck
6d86628e5b tbf: Always create an MS object on TBF allocation
Currently the MS object are created when the TLLI gets known.
Therefore some information (TA, MS class) must be stored in the TBF
itself and is copied to the MS object later on. This would get even
more complex, if the allocation algorithms were extended based on
this scheme.

This commit ensures, that an MS object will always be created on TBF
allocation, even if the TLLI is not yet known. These 'anonymous'
objects are still managed by the MS storage. To avoid dangling
entries without a TLLI there (which cannnot be retrieved anyway), the
timer in the MS objects is not started after all TBF have been
detached, so that they get deleted immediately in that case.

Note that an MS object can still be removed (e.g. by replacement)
from an existing TBF, so tbf->ms() can be NULL.

Ticket: #1794
Sponsored-by: On-Waves ehf
2015-06-29 10:53:32 +02:00
Jacob Erlbeck
e2e004e7a9 tbf: Pass the MS object around instead of old_tbf
Currently the old TBF (either uplink or downlink) is passed around at
TBF allocation mainly to get information about the MS. To implement
more complex allocation algorithms, the MS object itself will be
needed anyway.

This commit replaces the old_tbf arguments by MS object arguments.

Sponsored-by: On-Waves ehf
2015-06-29 10:53:32 +02:00
Jacob Erlbeck
ace7b570a0 tbf: Remove update_tlli method
This method does not do anything anymore, it's functionality has been
taken over by update_ms.

This commit removes gprs_rlcmac_tbf::update_tlli completely.

Sponsored-by: On-Waves ehf
2015-06-29 10:53:32 +02:00
Jacob Erlbeck
f1379346f7 vty: Fix documentation for 'no cs downgrade-threshold'
The NO_STR is missing, this commit adds it.

Fixes: Jenkins #603
Sponsored-by: On-Waves ehf
2015-06-29 10:49:30 +02:00
Jacob Erlbeck
34cf156b80 llc/test: Use a portable way to set timeval variables
Using complex initialiser lists doesn't seem to work well with Debian
Squeeze.

This commit changes the initialisation to use separate assignments
instead.

Fixes: Jenkins #601, #602
Addresses:
  CXX    LlcTest.o
  ../../tests/llc/LlcTest.cpp: In function 'void test_llc_meta()':
  ../../tests/llc/LlcTest.cpp:137: error: expected primary-expression
  before '.' token
  ../../tests/llc/LlcTest.cpp:137: warning: extended initializer
  lists only available with -std=c++0x or -std=gnu++0x

Sponsored-by: On-Waves ehf
2015-06-29 10:28:36 +02:00
Jacob Erlbeck
9cc783a87d Revert "llc/test: Explicitly enable extended initialiser lists"
This reverts commit a99d95e3af.

That commit has only removed the warning but not the error.

Sponsored-by: On-Waves ehf
2015-06-29 10:27:25 +02:00
Jacob Erlbeck
a99d95e3af llc/test: Explicitly enable extended initialiser lists
To support extended initialiser lists some platforms (at least debian
squeeze) require to add -std=c++0x or -std=gnu++0x to CXXFLAGS. While
that option is deprecated on newer platforms (at least gcc 4.8) this
options is still supported on every platform currently in use.

This commit adds -std=gnu++0x to the CXXFLAGS used to compile
LlcTest.cpp.

Sponsored-by: On-Waves ehf
2015-06-29 10:06:29 +02:00
Jacob Erlbeck
e500e2e5d1 llc: Add missing include directive for struct timeval
While including time.h is sufficient with Ubuntu's current libc6
2.19, the correct (and portable) include file is sys/time.h.

This commit modifies the include directive in llc.h accordingly.

Fixes: Jenkins #600

Addresses:
    In file included from gprs_ms.h:28,
        from gprs_ms.cpp:22:
        llc.h:68: error: field 'recv_time' has incomplete type
        llc.h:69: error: field 'expire_time' has incomplete type

Sponsored-by: On-Waves ehf
2015-06-29 09:46:17 +02:00
Jacob Erlbeck
b671dbfe94 llc: Move storage of timestamps into gprs_llc_queue
Currently the receive and expiry timestamps are prepended to the LLC
msgb before it is passed to gprs_llc_queue::enqueue(). Since this meta
information should not be counted as LLC octets, the gprs_llc_queue
needs to known about this (unless the correction was done in the LLC
layer).

This commit moves the meta information storage code into
gprs_llc_queue.  The meta data is now stored in the control block
(cb) area of the msgb.

Note that the info pointer that is returned from the dequeue method
is only valid if that method returns a (non-NULL) msgb. It must not
be used after that msgb has been modified or freed.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
1e50a3dade llc: Make timeval arguments const
Some struct timeval pointer arguments do not have the const qualifier,
albeit the methods do not write to the structures. The next commit
will change related pointers to const, so this commit provides the
required constness.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
70b96aa232 ms: Reduce DL CS level if only a few LLC bytes are left
If just a few bytes are left to send to the MS, it makes sense to
reduce the coding scheme level to increase the throughput. This
has been shown by Chen and Goodman in their paper "Theoretical
Analysis of GPRS Throughput and Delay". See their throughput over C/I
measurement graphs (figures 4 and 5 in the paper) for details.

This commit implements a simplified CS downgrade feature for the
downlink. The coding scheme will be downgraded if there are only a
few octets are left to be send over the TBF (see the
downgrade-threshold command below) and the NACK rate is not low (the
CS will not get degraded on a high quality RF link). As an exception,
CS-3 will be degraded to CS-1, since CS-2 does not improve the
throughput in general when a few small packets are sent and the
signal fades slowly (see Chen/Goodman).

The following VTY command is added to the config-pcu node:

- cs downgrade-threshold <1-10000>
- cs no downgrade-threshold

to set the threshold of the number of remaining bytes to be RLC/MAC
encoded. The CS will only be reduced, if the number is below the
threshold. The 'no' command disables this feature completely. The
default value is 200 octets.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
07eb655244 llc: Keep track of the number of stored LLC octets
To get the number of LLC octets that are stored in the queue, this
commit adds a m_queue_octets member along with a octets() method.
This value is updated similarly to m_queue_size on each modifying
method call.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
1eae96ca2f llc: Add missing include directive to llc.h
Currently struct llist_head is used without declaration which
accidently did not produce an error so far.

This commit adds the missing include directive.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
626369c2fb llc/test: Add test program for LLC related tests
Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
409efa1ec8 tbf: Fix downlink packet loss
When the MS is pinged with a longer interval, many packets get lost
even if the GprsMs object is kept. If the interval is above the time
where the DL TBF is in state FLOW (mainly influenced be the
dl-tbf-idle-time command), an new TBF must be requested via AGCH for
each ICMP PING message.

Currently the LLC frame containing the PING is immediately stored
in the TBF and gets lost, if TBF establishment fails for some reason.

This commit moves all calls to put_frame() to schedule_next_frame(),
where the data is moved from the LLC queue to the frame storage
within the TBF object. This method is only called from within
create_new_bsn() when the TBF is in the FLOW state and the frame is
going to be encoded immediately.

At all other places, where put_frame() has been called before, the
LLC message is just appended to the LLC queue in the GprsMs object.
This change effectively simplifies the related code parts, since
date/len information and discard notifications is no longer needed
there.

Ticket: #1759
Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
411686402b tbf/test: Add test for DL LLC packet loss
Currently LLC frames are lost or even reordered when the TBF has be
established via the AGCH and the procedure fails for some reason.

This test tries to reproduce this behaviour by throwing away the
first TBF while calling the handle() method several times. The
results of create_dl_acked_block() are checked against expected
values (this is currently party disabled because the bug still
persists).

Ticket: #1759
Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
04a108617a ms: Store the NACK rate in the MS object
Currently the NACK/unconfirmed ratio is already passed to the
corresponding MS object, but the value is not being stored there.

This commit adds a member and a getter method and include the values
into the output of the 'show ms' command.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
e1d2b3568a tbf: Include CS into create_new_bsn log message
This change lets the test suite fail, so it get its own commit.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
da1a79ef5b l1: Add debug log messages for I_LEVEL
The I_LEVEL values that are obtained now look suspicious. They do not
seem to be contained in messages recorded via gsmtab.

To help debugging this issue, this commit adds related debug messages
that are generated while the encoded values are taken from the
RLC/MAC messages.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
51b1151044 l1: Store measurement values sent by the MS
This commit extends the pcu_l1_meas structure by MS side measurement
values which are transmitted by PACKET DOWNLINK ACK/NACK and
PACKET RESOURCE REQUEST messages. The encoded values are remapped to
dB respectively % values. The values are stored in the corresponding
MS object (if there is one).

Note that the values are store as (rounded) integers, so some
different encodings are mapped to the same decoded value.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
94cde130ca ms: Add UL CS selection based on L1 link quality
Currently the UL CS values are set to the corresponding DL CS value,
eventually limited by a maximum value. This approach does not reflect
the general situation of the RF link between ME and BTS, which is
rather asymmetric e.g. due to a lower degree of TX efficiency of the
built-in antenna. This means, that UL and DL CS control should be
decoupled for better results.

This commit adds automatic UL CS selection based on the link quality
measurement parameter. Each coding scheme is mapped to a link quality
range. If the link quality value leaves that range, the current UL CS
value is increased/decreased accordingly. This value will be copied
when the next PACKET_UPLINK_ACK_NACK or PACKET_UPLINK_ASSIGMENT is
sent to the MS.

The following VTY command will be added to the config-pcu node:

-  cs link-quality-ranges cs1 <0-35> cs2 <0-35> <0-35>
          cs3 <0-35> <0-35> cs4 <0-35>

which sets the ranges for the four coding schemes. For instance the
example below reflects the current default values:

  cs link-quality-ranges cs1 6 cs2 5 8 cs3 7 13 cs4 12

set the following ranges, where the overlapping is used to configure
a hysteresis:

  CS1: -inf ..  6
  CS2:    5 ..  8
  CS3:    7 .. 13
  CS4:   12 .. inf

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
e4bcb62dbf ms: Store the L1 measurement values in the MS objects
This commits adds the GprsMs::update_l1_meas() and GprsMs::l1_meas()
methods to store and access the measurement values. The internal
state is updated depending on which values are actually set.

In addition, these values are shown in the output of the 'show ms
imsi|tlli' command.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
20f6fd1b63 l1: Pass all L1 measurements upwards
Currently only the RSSI value is passed to the upper layers. Other
values like TA and BER which are needed for TA update respectively CS
selection are not propagated.

This commit introduces and passes a struct that contains a set of
measurement values.

Sponsored-by: On-Waves ehf
2015-06-22 10:39:06 +02:00
Jacob Erlbeck
b4584ff6c4 build: Add -lrt to AM_LDFLAGS
This is needed to link programs using clock_gettime and related
functions when compiling with older glibc versions.

This should fix the Jenkins build. Nevertheless fixing this in
configure.ac were probably nicer.

Sponsored-by: On-Waves ehf
2015-06-22 10:36:50 +02:00
Jacob Erlbeck
0808f68601 ms: Fix timer start condition (Coverity)
Currently the timer can be started even if m_ul_tbf is attached.

Replace m_dl_tbf by m_ul_tbf to only start the timer if _both_ TBF
are detached.

Fixes: Coverity CID 1304683
Sponsored-by: On-Waves ehf
2015-06-11 13:13:55 +02:00
Jacob Erlbeck
25db7c6116 ms: Add missing initialiser for m_delay (Coverity)
Set m_delay to 0 in the constructor to disable the timer feature by
default.

Fixes: Coverity CID 1304682
Sponsored-by: On-Waves ehf
2015-06-11 13:13:55 +02:00
Jacob Erlbeck
7bf9f49728 tbf: Check for NULL in name() (Coverity)
The gprs_rlcmac_tbf::name() method is generally used to generate log
messages. To avoid the need for an explicit NULL check for the tbf
and to get a consistent text if it is NULL, this commit adds a
NULL check to the method itself so that it can be called with this ==
NULL.

Fixes: Coverity CID 1304680, 1304681
Sponsored-by: On-Waves ehf
2015-06-11 13:13:55 +02:00
Jacob Erlbeck
0ae4313800 bssgp: Calculate the avg_delay_ms in 32bit only (Coverity)
Currently the delay_sum is stored in 64 to avoid overflow errors.
But only the result of tv_sec * 1000 is casted to 64 bit, resulting
in an overflow if the accumulated queue delay reached 25 days (which
will not happen in practice, unless there are >200k LLC messages with
a max of 10s delay each in the queue). If that were the case, the
only impact would be a wrong number in a log message and in the BSSGP
FLOW CONTROL message.

This commit changes the calculations so that they are done in 32 bit
only, rather than to do the calculation in 64 bit properly.

Fixes: Coverity CID 1298705
Sponsored-by: On-Waves ehf
2015-06-11 13:13:55 +02:00
Jacob Erlbeck
d0aee85b29 llc: Fix LLC UI frame detection (Coverity)
Currently the wrong nibble is masked out, so the conditional
expression always yields true.

Therefore gprs_llc::is_user_data_frame() always returns true. As a
consequence, the low watermark feature of
gprs_rlcmac_dl_tbf::llc_dequeue() is not being used in fact.

This commit fixes the mask value.

Fixes: Coverity CID 1292834, 1292835
Sponsored-by: On-Waves ehf
2015-06-11 13:13:55 +02:00
Jacob Erlbeck
09fdf6622a bssgp: Handle btcx == NULL in gprs_bssgp_pcu_rx_sign (Coverity)
Currently it is assumed, that btcx is non-NULL. The btcx is only used
to obtain the BVCI in some log messages.

This commit changes that by using -1 as shown BVCI value.

Fixes: Coverity CID 1040961
Sponsored-by: On-Waves ehf
2015-06-11 13:13:55 +02:00
Jacob Erlbeck
37e896dff1 vty: Add command to show detailed MS info
This commit extends the "show ms" command to display an extended set
of information for a single MS.

The following VTY commands are added:

- show ms tlli TLLI
- show ms imsi IMSI

Sponsored-by: On-Waves ehf
2015-06-08 09:41:24 +02:00
Jacob Erlbeck
b33e675e5a ms: Add support for maximum CS values
Currently the CS values can be increased to CS4 even when the "cs"
configuration command has been used with a lower value. The "cs"
command just sets the initial coding scheme, so other means are
needed to limit the selection. One approach is to use the CS flags
passed in SI, but these are currently ignored.

To make it possible to limit the CS selection by configuring the PCU,
this commit adds the following VTY commands to config-pcu:

- cs max <1-4>             Limit DL and UL CS to the given value
- cs max <1-4> <1-4>       Limit DL and UL CS separately (DL first)
- no cs max                Don't limit

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-06-08 09:41:07 +02:00
Jacob Erlbeck
8158ea7288 ms: Add blocking period for CS upgrade
Currently the CS level is immediately increased if the error rate
drops below the lower threshold. Since the measurement values are not
damped, this behaviour leads to a quick return to higher CS values
even under bad radio conditions. Since with GPRS RLC/MAC blocks
cannot be resent with another coding scheme, increasing the CS value
should be done carefully.

This commit adds a blocking period that only allows higher CS values
if all error rate measurements were below the LOW threshold for a
certain amount of time (currently fixed to 1s).

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-06-08 09:40:48 +02:00
Jacob Erlbeck
144a1d0516 tbf: Ignore lost+recv == 1
Currently the CS level gets changed quickly if single RLC/MAC blocks
are sent (e.g. LLC dummy commands), since the rate is either 0% or
100%.

This commit ignores measurements which are based on a single block
only.

Sponsored-by: On-Waves ehf
2015-06-08 09:40:41 +02:00
Jacob Erlbeck
8322d08071 tbf: Add adaptive coding scheme configuration
This commit adds the following VTY commands to config-pcu:

- cs threshold <0-100> <0-100>    Enables adaptive CS selection
- no cs threshold                 Disables it

The "cs threshold LOW HIGH" command sets the water marks
(cs_adj_lower_limit and cs_adj_upper_limit) used to
decide about switching coding schemes.

Ticket: #1739
Sponsored-by: On-Waves ehf
2015-06-08 09:40:35 +02:00
Jacob Erlbeck
a17fccbcf4 tbf: Add debugging output to analyse_errors()
To help with the debugging, optimisation, and understanding of this
method, this commit adds an info string containing a flag character per
RLC/MAC data block in the current window.

Note that the blocks are shown in reversed order (highest BSN first)
in comparison to other logging output.

Sponsored-by: On-Waves ehf
2015-06-08 09:40:28 +02:00
Jacob Erlbeck
1751c62c98 tbf: Add adaptive DL CS adjustment
To cope with transmission failures due to bad radio conditions, a
different coding scheme with more redundance can be used.

This commit adds an implemenation that is based on the Ack/Nack
ratio per PACKET DOWNLINK ACK/NACK message received from the MS.

Basically the CS level is decreased, if the block error rate goes
above cs_adj_upper_limit (default 33%), and it is increased, if the
rate drops below cs_adj_lower_limit (default 10%). Only blocks that
have been encoded with the current CS are taken into account.

Note that this approach doesn't measure the MS->BTS conditions and
that the measurement values reported by the MS are not taken into
account.

Ticket: #1739
Sponsored-by: On-Waves ehf
2015-06-08 09:40:09 +02:00
Jacob Erlbeck
f47f68a9d8 vty: Add 'show ms all' command
This command lists the entries of the ms_store by a line per MS.
Beside TLLI and IMSI, some measurement and state information is
shown.

A ms_list() getter method is added to GprsMsStorage to obtain a list
of the MsGprs objects.

The following VTY command is added to the 'enable' node:

 - show ms all

Sponsored-by: On-Waves ehf
2015-06-08 09:39:51 +02:00
Jacob Erlbeck
62e96a3535 vty: Add a file for C++ functions
Currently the pcu_vty.c doesn't compile with C++. Thus C++ object
cannot be access directly there.

This commit adds a helper C++ file that exports all functions with C
calling conventions and naming to work around that limitation until
the transition of pcu_vty.c is completed.

Sponsored-by: On-Waves ehf
2015-06-08 09:39:43 +02:00
Jacob Erlbeck
a700dd9e11 tbf: Move the current CS field to GprsMs
Currently the current CS value is stored in the cs field of
gprs_rlcmac_tbf and initialised when it is used the first time.

This commit adds separate fields for UL and DL CS values to the
GprsMs class and provides corresponding getter methods for GprsMs and
gprs_rlcmac_tbf.

Ticket: #1739
Sponsored-by: On-Waves ehf
2015-06-08 09:39:25 +02:00
Jacob Erlbeck
17214bb06d ms: Add back pointer to BTS
Since more functionality will be moved to the GprsMs class, a pointer
to the current BTS object is added to allow access to configuration
data and other methods.

Sponsored-by: On-Waves ehf
2015-06-08 09:39:07 +02:00
Jacob Erlbeck
befc760f86 tbf: Store MS class in GprsMs objects
The ms_class value is a property of the MS and thus belongs to the
GprsMs class. Nevertheless the MS object is created after the TLLI
gets known, so the value still has to be stored in the TBF initially.

This commit add the ms_class value to the GprsMs class and introduces
TBF accessor functions which either access that object or, if that is
not available, the value stored locally.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-06-08 09:38:49 +02:00
Jacob Erlbeck
489a2b35d8 tbf: Move the LLC queue to GprsMs
Currently the enqueued DL LLC messages which have not yet passed to
RLC/MAC encoding are eventually copied from one TBF to the next one
(see gprs_rlcmac_dl_tbf::reuse_tbf). Since the enqueued LLC messages
are related to a specific MS, they should be stored at that layer.

This commit moves the gprs_llc_queue object to GprsMs and changes the
TBF's accessor methods accordingly. The LLC copying code is removed
from gprs_rlcmac_dl_tbf::reuse_tbf().

Sponsored-by: On-Waves ehf
2015-06-08 09:38:44 +02:00
Jacob Erlbeck
10ed79553a tbf: Make the ms() getter method const
Currently this method cannot be used in other const methods.

This commit adds the missing const keyword.

Sponsored-by: On-Waves ehf
2015-06-08 09:35:47 +02:00
Jacob Erlbeck
1d0a52a349 llc: Add missing declarations to llc.h
Currently llc.h relies on the structs BTS, timeval, and msgb being
declared before the file is included.

This commit adds forward declaration for these structs, because they
will only be used for pointer types.

Sponsored-by: On-Waves ehf
2015-06-08 09:35:29 +02:00
Jacob Erlbeck
6dbe822062 llc: Separate LLC queue handling from gprs_llc
Currently the gprs_llc class handles both LLC queueing and the
partition into smaller pieces for RLC/MAC encapsulation. This hinders
the separation of TBF and MS related data, since LLC queueing belongs
to the MS related code while the RLC/MAC encoding/decoding belongs to
the TBF layer.

This commits takes the LLC queueing related methods and members and
puts them into a new class gprs_llc_queue. It puts the queueing
object into gprs_rlcmac_tbf and adds accessor functions. The
implementation in tbf.cpp and tbf_dl.cpp is adapted accordingly.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-06-08 09:35:11 +02:00
Jacob Erlbeck
b3f713bd7b l1: Fix warning by logging acc_delay
The acc_delay value is computed but not used, resulting in a warning.

This commit adds a logging message it case the function is executed
to make the warning disappear. It also adds a CPP warning to remind
of the incomplete implementation.

Addresses:
  sysmo_l1_if.c:226:10: error: variable ‘acc_delay’ set but not used
[-Werror=unused-but-set-variable]

Sponsored-by: On-Waves ehf
2015-06-08 09:34:45 +02:00
Jacob Erlbeck
3c91cb881d pcu: Set ms_idle_sec to 60s
Since the timing advance storage has been removed, the TA values are
lost, when the last TBF of a single MS is freed. The TA storage has
at least saved the last 30 TA values. So now in more cases a wrong TA
value can be transmitted to an MS. Note that this also could have
happened before the removal of the storage, especially if more than
30 MS were in use.

This commit changes the default value of ms_idle_sec to 60s which is
higher than default value for T3314 (44s, see TS 24.008, 11.2.2),
after which the SGSN will have to start paging anyway. In that case,
a RACH request will be triggered, that will trigger an update of the
TA value in the PCU.

Sponsored-by: On-Waves ehf
2015-06-05 13:49:06 +02:00
Jacob Erlbeck
a098c19b55 tbf: Set MS timeout
This commit sets the MS timeout when the MS object is created. The
value is taken from the ms_idle_sec field in gprs_rlcmac_bts which
can be changed by the VTY commands shown below.

The following VTY commands are added to the config-pcu node:

- ms-idle-time <1-7200>      Set the timeout in seconds
- no ms-idle-time            Disable the timeout

Another timer that is related is T3314 (Ready Timer, default 44s, GSM
24.008, 11.2.2) which requires the SGSN to use paging after its
expiry. Longer timeouts can help if adaptive coding scheme selection
is used (not yet implemented). On the other hand, measurement values
(TA, signal quality) can get invalid after some time, especially with
a moving MS. So a value slightly above T3314 is probably a good value
to start with.

Sponsored-by: On-Waves ehf
2015-05-28 17:40:15 +02:00
Jacob Erlbeck
d9e102472a ms: Add timer
Currently the MS object is immediately idle when all TBFs are
detached and if no guard is being used. Since the plan is to use the
MS objects to pass information from one TBF to the next one even
across the gap of some seconds of inactivity, a mechanism is needed
to keep the MS objects around for some time.

This commit extends the GprsMs class by a timer that keeps the MS
objects in non-idle state for some time after all TBFs have been
detached. The set_timeout method must be used with a non-zero value
to activate this feature.

Sponsored-by: On-Waves ehf
2015-05-28 16:38:16 +02:00
Jacob Erlbeck
1db67e0a35 tbf: Remove TimingAdvance storage
Currently the TA storage stores up to 30 TLLI->TA mappings, if more
entries are created the oldest one is dropped. In theory this can
lead to missing TA information if many MS are present.

This commit removes the TimingAdvance class completely, since the TA
value is now stored in the GprsMs objects.

Note that the GprsMs objects are currently not kept after the TBFs
have detached from them, so the TA values are now kept for a shorter
time than before.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-28 13:59:25 +02:00
Jacob Erlbeck
9200ce6019 tbf: Store the timing advance (TA) value in the GprsMs object
The TA value rather relates to an MS and not to a single TBF. So all
TBFs share the same TA value. Currently the TA value is stored per
TBF and eventually copied from an old TBF to a new one. It is in
general only passed with an RACH request when the TLLI and thus the
MS is not yet known.

This commit adds a TA member to the GprsMs class and uses that one
when the TBF is associated to an MS object. Since the TBF is not
always associated with an MS object (after RACH or when it has been
replaced by another TBF), the TA value is still stored in each TBF
and that value is used as long as no MS object is being associated.

Sponsored-by: On-Waves ehf
2015-05-28 13:58:23 +02:00
Jacob Erlbeck
ddfc0d5763 tbf/test: Add tests for single and two phase access
These tests cover the message exchange from receiving from the first
RACH request to the first data block when establishing an uplink TBF.

This will be used to check, whether TA and other values are passed to
an MS object correctly.

In addition, the RX RACH log message in rcv_rach is extended to
contain the single block fn.

Sponsored-by: On-Waves ehf
2015-05-28 12:29:43 +02:00
Jacob Erlbeck
d3eac2867a tbf: Remove TBF chaining (m_new_tbf and m_old_tbf)
Currently a new TBF is chained to an existing older one, either of
the other direction (active or releasing) or of the same direction
(releasing). This does not work properly work if and uplink and a
downlink TBF are being established at the same time while an old TBF
is being released. In that case, one of them is thrown away and the
pending procedure is cancelled.

The chaining is no longer necessary since the GprsMs objects have
been introduced which keep track of the active TBFs.

This commit removes the TBF members m_new_tbf and m_old_tbf and the
related methods and code paths.

Note that a new TBF can replace an older TBF entry of the same
direction within an MS object when it is associated with an MS (e.g.
by TLLI or because it is assigned via another, already associated
TBF). In that case, the old TBF is no longer associated with an MS
object.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-28 12:29:43 +02:00
Jacob Erlbeck
1c68abaffa tbf/test: Attach TLLI and MS objects to TBFs
Currently the DL TBF's TLLI are not set. This will have to change in
the future, when the m_new_tbf chaining is replaced by the usage of MS
object to group TBFs.

This commit just calls update_ms() on newly created TBFs. This
changes many of the lines written to stderr due to the TLLI change,
but doesn't change other aspects or messages beside creating and
destroying MS objects.

Sponsored-by: On-Waves ehf
2015-05-28 12:29:43 +02:00
Jacob Erlbeck
71e55118f5 tbf: Remove IMSI handling from trigger_dl_ass
Currently the BTS::trigger_dl_ass() method assigns the IMSI to the MS
object. This should be (and is already) done earlier where the MS
object is retrieved/created.

This commit removes the corresponding code along with the 'imsi'
parameter from trigger_dl_ass.

Sponsored-by: On-Waves ehf
2015-05-28 12:29:42 +02:00
Jacob Erlbeck
7b9f825ae8 ms: Use the IMSI to retrieve the MS object
This commit extends get_ms() to really compare the IMSI if it has
been given. Matching by TLLI has a higher precedence than matching by
IMSI.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-28 12:29:40 +02:00
Jacob Erlbeck
b0e5eaf59a tbf: Move IMSI to MS object
Currently the IMSI is stored in the TBFs. Since it directly refers to
an MS, it should rather be stored in an MS object.

This patch move the m_imsi field from gprs_rlcmac_tbf to GprsMs,
changes gprs_rlcmac_tbf::imsi() to get the IMSI from the associated
MS object, and adds getter and setter to GprsMs. Before changing the
IMSI of the associated MS object, assign_imsi() checks if there is
already another MS object with the same IMSI and eventually resets
the IMSI of that one. So using update_ms() and assign_imsi() ensures
that there are not two MS object entries is the storage with the
same TLLI or the same IMSI.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-28 12:28:40 +02:00
Jacob Erlbeck
9a2845d491 tbf/test: Fix IMSI creation
Currently the generated IMSI contains blanks due to a missing '0'
flag in the corresponding snprintf statement. In addition, the buffer
is effectively limited to 15 bytes which is shorter than the
generated character sequence, such that the last character of the
IMSI is removed.

This patch fixes both issues. Since snprintf itself will add a
terminating \0 character, the whole buffer can be passed to snprintf.

Sponsored-by: On-Waves ehf
2015-05-27 13:30:01 +02:00
Jacob Erlbeck
0e50ce6145 tbf: Always call set_tlli/confirm_tlli in update_ms
Currently the m_tlli member in GprsMs is set by the constructor,
circumventing the TLLI confirmation mechanism.

This commit replaces the get_or_create_ms() method by a create_ms()
method which takes the TLLI and the direction (UL or DL) as
parameters to select either set_tlli() or confirm_tlli(). The MS
object is instantiated with TLLI = 0, and therefore GprsMs::tlli() is
extended to return the DL TLLI if both of the other TLLI are not set.

Note that create_ms() will not check whether an MS object with a
matching TLLI is already stored in the list, so it should only be
called after a corresponding get_ms() in general.

Sponsored-by: On-Waves ehf
2015-05-27 13:30:01 +02:00
Jacob Erlbeck
767193e20b tbf: Remove the TLLI from the TBFs
Currently the TLLI is stored in each TBF. Since each MS is now
represented by a GprsMs object which takes care of TLLI updating,
and each TBF that has been associated with an TLLI also contains a
reference to a GprsMs object, per TBF TLLI handling is no longer
needed. Keeping all TBF m_tlli members up to date is complex and
doesn't currently work correctly in all circumstances.

This commit removes m_tlli and related members from the TBF class and
the tbf_by_tlli functions from the BTS class.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-27 13:29:59 +02:00
Holger Hans Peter Freyther
d1cb41bfd0 write_queue: Check the result of osmo_wqueue_enqueue and free
The write_queue is designed to have a maximum amount of pending
messages and will refuse to take new messages when it has been
reached. The caller can decide if it wants to flush the queue
and add the message again, create a log. But in all cases the
ownership of the msgb has not been transferred. Fix the potential
memory leak in the failure situation.
2015-05-22 10:37:57 +02:00
Holger Hans Peter Freyther
5752285bc5 misc: Update the email address to point to the current ML
We have unified all PS related communication to the
osmocom-net-gprs mailinglist, update configure.ac to
point there.
2015-05-22 10:33:46 +02:00
Holger Hans Peter Freyther
b75e23143b llist: Reduce the external dependencies of this test
Debian is using the classic bfd linker and when passing
libosmogb as link dependency it always wants/needs to
resolve the bssgp_prim_cb symbol (which is to be provided
by the application).

Only keep the libosmocore dependency.

Fixes:
lib/libosmogb.so: undefined reference to `bssgp_prim_cb'
collect2: error: ld returned 1 exit status
Makefile:511: recipe for target 'llist/LListTest' failed
2015-05-22 10:33:35 +02:00
Jacob Erlbeck
4f459799e3 tbf: Just pass the MS object in reuse_tbf
Currently the MS will be searched based on the TLLI in resue_tbf().
Since the MS object is already known in the TBF when the TLLI is set,
it can just be passed to the new TBF.

This commit removes the call to update_ms() and just adds
new_tbf->set_ms(ms()) which will also work as expected if ms() == NULL.

Sponsored-by: On-Waves ehf
2015-05-21 17:11:40 +02:00
Jacob Erlbeck
be0cbc1b7e tbf: Explicitly pass the direction to update_ms()
The type of the TBF update_ms() is being called on does not always
reflect whether the TLLI has been signaled by the MS or the SGSN.

This commit adds an additional parameter to tell the method, in which
direction the TLLI has been passed.

Sponsored-by: On-Waves ehf
2015-05-21 17:11:14 +02:00
Jacob Erlbeck
87597358cf tbf: Get the TLLI from the MS object
Since the synchronisation of the TBF's concerning the TLLIs has been
removed in 'Support new and old TLLI's', gprs_rlcmac_tbf::tlli() can
return the old TLLI which is probably different to ms()->tlli() in
that case. This can lead to a wrong TLLI being used in BSSGP messages.

This commit modifies the TBF's tlli() method to get the current TLLI
from the MS object.

Sponsored-by: On-Waves ehf
2015-05-21 17:10:49 +02:00
Jacob Erlbeck
9399046729 ms: Support new and old TLLIs
According to the specification (GSM 04.08/24.008, 4.7.1.5) after a
new P-TMSI has been assigned, the old P-TMSI must be kept basically
until it has been used by both sides. Since the TLLI will be derived
from the P-TMSI, the old TLLI must also be kept until the new TLLI
has been used by both MS and SGSN.

This commit modifies the TLLI handling of GprsMs accordingly.
set_tlli() is only used with TLLIs derived from MS messages,
confirm_tlli() is used with TLLIs derived from messages received from
the SGSN. tlli() returns the value set by the MS. check_tlli()
matches each of the TLLI used by either MS or SGSN as well as the old
TLLI until it has been confirmed.

Sponsored-by: On-Waves ehf
2015-05-21 17:10:42 +02:00
Jacob Erlbeck
e43460b50f ms: Integrate the MS storage
Use the MS storage to find a MS object for a given TLLI instead of
searching the TBF lists. The TBFs are then taken from the MS object,
if one has been found. If all TBF might be temporarily detached from
the MS object, a GprsMs::Guard is added to prevent the deletion of
the object, in case another TBF gets attached later on in the scope.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-20 11:36:12 +02:00
Jacob Erlbeck
5367086175 ms: Add MS storage class
Currently the MS objects are contained in the TBF objects only. To
allow for an extended life time after the TBF objects have been freed
and to find them based on TLLI, a container for the MS objects is
needed.

This commit adds the container class and also adds the corresponding
m_list member to GprsMs. Further integration into the PCU code is not
yet done.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-20 11:36:12 +02:00
Jacob Erlbeck
dfef28de88 llist: Add a C++ wrapper for linux_list
This commit adds the LListHead class which is a wrapper around the
linuxlist. It adds an additional member to refer to the container,
since the container_of macro doesn't work properly with C++ classes.
All functions and macros from linuxlist.h are support except for the
entry macros (e.g. llist_entry, llist_for_each_entry, ...). To access
the container (entry), an entry() method is provided instead:

  llist_for_each(pos, &elems) {
      pos->entry()->do_something();
  }

Sponsored-by: On-Waves ehf
2015-05-20 11:36:06 +02:00
Jacob Erlbeck
67c385046d tbf/test: Optionally show talloc report
To show the talloc report more easily, this commit adds a call to
talloc_report_full if the TALLOC_REPORT_FULL environment variable is
set (the value is ignored). Since the stderr output is checked by the
test suite, this feature is not enabled by default.

Sponsored-by: On-Waves ehf
2015-05-20 11:31:07 +02:00
Jacob Erlbeck
fecece0e59 tbf: Add MS object management to TBF code
This commit adds MS object creation and cleanup to the TBF related
code. MS objects are created when a TBF that has been "anonymous" so
far gets associated with a TLLI. When a TBF is replaced by another,
the old TBF is detached and the new one is attached to the MS. When
all TBFs have been detached, the MS object gets deleted.

The TBF related code should not call attach_tbf/detach_tbf directly
but use set_ms instead to make sure, that the references are updated
properly. GprsMs::detach_tbf also calls set_ms(NULL) on the detached
TBF object.

The MS object is not really used yet, the focus is still on object
creation, TBF association, and cleanup.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-20 11:31:07 +02:00
Jacob Erlbeck
e04e0b0a20 ms: Add GprsMs class to hold per-MS information
Currently only TBF objects are used to handle the data flow between
the MS and the SGSN. MS specific data (e.g. pending LLC frames, TLLI)
is copied between successive TBFs. If all TBFs (uplink and downlink)
are idle for some time, all information about the MS is discarded in
the PCU. This makes the implementation of some features more
difficult, e.g. proper TLLI and timing advance handling,
connection based CS selection, and proper management of multiple TBF.

This commit adds the GprsMs class that is intended to hold
information directly related to the MS and to keep references to the
active TBFs.

The class is not yet integrated with the other PCU code. A GprsMs
object container and MS specific fields (TA, CS) will be added in
later commits.

Note that calling detach_tbf() can possibly delete the MS object
depending on the callback implementation.

Ticket: #1674
Sponsored-by: On-Waves ehf
2015-05-20 11:30:41 +02:00
Jacob Erlbeck
6eeb7c7e74 bssgp: Increment BSSGP flow control tag value
Currently the tag value in FLOW CONTROL BVC messages is always 1.

This commit changes the implementation to increment that value with
each of the FLOW CONTROL BVC messages that is sent to the SGSN.

Sponsored-by: On-Waves ehf
2015-05-06 15:26:08 +02:00
Jacob Erlbeck
6e4ccec6c4 bssgp: Compute and transmit queue delay
The specification 28.018,  allows to transmit the average LLC downlink
queueing delay in FLOW CONTROL BVC messages (BVC Measurement IE, see
GSM 28.018, 10.4.4 and 11.3.7).

This commit extends gprs_bssgp_pcu.cpp to compute the average delay
time between two subsequent FLOW CONTROL BVC messages. The average is
implemented as an arithmetic average without any weighting.

Ticket: OW#1432
Sponsored-by: On-Waves ehf
2015-05-06 15:22:57 +02:00
Jacob Erlbeck
0288cdb0a8 bssgp: Add VTY command to Limit the bucket size by time
Currently the bucket size is by default being computed based on the
leak rate and the expected life time of LLC frames. The latter is
either taken from 'queue lifetime' (if given) or a fixed value is
used. Using 'queue lifetime' has the drawback that it sets a 'hard'
limit, since frames will be dropped if they stay in the queue
for a longer time.

This commit adds a VTY command to specifically set the time used for
the computation of the bucket size advertised to the SGSN. It does
not affect the PCUs queue handling in any way. If the bucket time is
not set (or if the 'no' command has been used), the old behaviour
(see above) is applied.

The following VTY commands are added (config-pcu node):

- flow-control bucket-time <1-65534>  Sets the time in centisecs
- no flow-control bucket-time         Don't use this time

Ticket: OW#1432
Sponsored-by: On-Waves ehf
2015-05-06 15:22:33 +02:00
Jacob Erlbeck
3d62fc55d8 bssgp: Compute BVC bucket size and leak rate
Currently the PDCH assignment and coding scheme does not influence
the values transmitted by the FLOW-CONTROL-BVC messages.

This commit adds the computation of those values. If the leak rate is
not given explicitly, it is derived from the number of PDCH and the
allowed coding scheme. If the BVC bucket size is not given
explicitly, it is derived from the leak rate and the maximum buffer time.
The latter is taken from the 'queue lifetime' command (or 10s if this
has not been used). The MS default bucket size is set to 50% of the
BVC bucket size. The MS default rate computation assumes, that each MS
only supports up to 4 time slots for GPRS RX.

Sponsored-by: On-Waves ehf
2015-05-06 15:20:43 +02:00
Jacob Erlbeck
87d7341fbe bssgp: Make BVC bucket size / leak rate configurable
Currently the FLOW-CONTROL_BVC message contains fixed values: The tag
is 1, the BVC bucket size is 6MB, the BVC bucket leak rate is
820kbit/s, the MS bucket size is 50kB, and the MS leak rate is
50kbit/s.

This commit makes the BVC parameters configurable and adds the
following VTY commands:

- flow-control force-bvc-bucket-size <1-6553500>
- no flow-control force-bvc-bucket-size
- flow-control force-bvc-leak-rate <1-6553500>
- no flow-control force-bvc-leak-rate
- flow-control force-ms-bucket-size <1-6553500>
- no flow-control force-ms-bucket-size
- flow-control force-ms-leak-rate <1-6553500>
- no flow-control force-ms-leak-rate

The 'no' variants restore the default behaviour.

Sponsored-by: On-Waves ehf
2015-05-06 15:20:35 +02:00
Jacob Erlbeck
29d91e9271 tbf: Added calls to llc_dropped_frame
Currently this function which increments the corresponding counter is
just called in gprs_llc::clear(). It is not called on places where
LLC DISCARDED messages are sent.

This commit adds calls to llc_dropped_frame() at these places.

Sponsored-by: On-Waves ehf
2015-05-06 15:20:25 +02:00
Jacob Erlbeck
801d6fe40c tbf/test: Fix old_tbf argument to tbf_alloc_ul_tbf
Currently the ul_tbf is used in its own declaration as an argument to
tbf_alloc_ul_tbf, where dl_tbf can be used instead and makes more
sense.

This commit uses dl_tbf instead of ul_tbf as old_tbf.

Addresses:
  tbf/TbfTest.cpp:71:14: warning: ‘ul_tbf’ may be used uninitialized in
      this function

Sponsored-by: On-Waves ehf
2015-05-04 10:02:01 +02:00
Jacob Erlbeck
0494c75a53 pcu_emu/test: Initialise current_test
Currently the global current_test is not initialised, which leads to
memory access failures. In addition, the variable is signed but used
in comparisons with unsigned values.

This commit changes the type to size_t and initialises the variable
to 0.

Sponsored-by: On-Waves ehf
2015-05-04 10:02:01 +02:00
Jacob Erlbeck
0d39dc92b5 l1if: Add missing function prototypes
A few prototypes are not part of any header files, leading to
corresponding compiler warnings.

This commit adds the missing prototypes to sysmo_l1_if.h.

Addresses:
  sysmo_l1_if.c:347:2: warning: implicit declaration of function
      ‘l1if_transport_open’
  sysmo_l1_if.c:364:3: warning: implicit declaration of function
      ‘l1if_transport_close’
  sysmo_l1_fwd.c:89:3: warning: implicit declaration of function
      ‘l1if_handle_sysprim’
  sysmo_l1_fwd.c:91:3: warning: implicit declaration of function
      ‘l1if_handle_l1prim’
  sysmo_l1_hw.c:109:3: warning: implicit declaration of function
      ‘l1if_handle_sysprim’
  sysmo_l1_hw.c:118:3: warning: implicit declaration of function
      ‘l1if_handle_l1prim’

Sponsored-by: On-Waves ehf
2015-05-04 10:02:01 +02:00
Jacob Erlbeck
1f33294b1c pcu: Fix non-critical warnings
These fixes do not affect the semantics of the code. They either help
gcc by providing default values that won't be used ("may be
uninitialised"), remove unused variables, or change signed to
unsigned variables to avoid comparison warnings.

Addresses:
  bts.cpp:494:32: warning: 'tbf' may be used uninitialized in this
      function
  emu/test_replay_gprs_attach.cpp:81:27: warning: comparison between
      signed and unsigned integer expressions
  emu/test_pdp_activation.cpp:95:23: warning: unused variable ‘budh’
  emu/test_pdp_activation.cpp:97:6: warning: variable ‘rc’ set but
      not used
  emu/pcu_emu.cpp:109:26: warning: unused variable ‘bts’
  alloc/AllocTest.cpp:74:27: warning: unused variable ‘tbf’
  osmocom/core/utils.h:13:50: warning: comparison between signed and
      unsigned integer expressions
  types/TypesTest.cpp:319:7: warning: unused variable ‘count’
  types/TypesTest.cpp:320:11: warning: unused variable ‘rbb’
  alloc/AllocTest.cpp:74:27: warning: unused variable ‘tbf’
  alloc/AllocTest.cpp:132:11: warning: unused variable ‘ts_no’
2015-05-04 10:01:25 +02:00
Jacob Erlbeck
2acfbebfd3 vty: Fix value range of commands accepting csecs
Currently an uint8_t csec variable is used to temporarily store
the number of centiseconds which can be set within the range
1 - 65535. This way values above 255 cannot be set properly. This
affects the VTY commands "queue lifetime", "queue hysteres", and
"queue idle-ack-delay".

This commit replaces the uint8_t by an uint16_t.

Sponsored-by: On-Waves ehf
2015-05-04 09:58:34 +02:00
Jacob Erlbeck
c0c580c414 vty: Fix warnings about undeclared functions
This commit adds missing includes to pcu_vty.c and fixes the
llist_head type (missing struct keyword) used by tbf_print_vty_info.

Sponsored-by: On-Waves ehf
2015-05-04 09:58:34 +02:00
Jacob Erlbeck
56e8d71090 tbf: Remove double assigment to m_last_dl_drained_fn
Currently the value -1 is assigned twice to m_last_dl_drained_fn
within append_data().

This commit removes the first of these assigments.

Sponsored-by: On-Waves ehf
2015-04-30 15:23:16 +02:00
Jacob Erlbeck
00fc6b13f2 pcu: Call bssgp_set_log_ss(DBSSGP) in main()
Currently the BSSGP functions in libosmocore do not log correctly to
DBSSGP since the DBSSGP variable in common_vty.c is left
uninitialized.

This commit adds the call to bssgp_set_log_ss() to inform libosmocore
which sub system id it shall use for BSSGP.

Sponsored-by: On-Waves ehf
2015-04-09 19:26:39 +02:00
Jacob Erlbeck
90de3a7ffe tbf: Send BSSGP LLC discarded on TBI exhaustion
Currently the PCU silently discard LLC frames from the SGSN if a
DL TBF cannot be allocated.

This commit changes tbf_new_dl_assignment and reuse_tbf to send an
LLC discarded message to the SGSN in this case.

Ticket: #607
Sponsored-by: On-Waves ehf
2015-04-09 19:24:47 +02:00
Jacob Erlbeck
d58b711eec tbf/test: Add test for DL TBF exhaustion
This test calls gprs_rlcmac_dl_tbf::handle() with varying TLLI and
IMSI until the function fails.

Sponsored-by: On-Waves ehf
2015-04-09 19:24:00 +02:00
Jacob Erlbeck
cc12f02658 vty: Use libosmocore VTY standards
This commit applies to following changes to pcu_vty.c:

- Use vty_install_default() instead of install_default()
- Add a blank after the '#' of the prompt
- Rename the 'pcu' configuration node to 'config-pcu'

Sponsored-by: On-Waves ehf
2015-04-09 17:05:19 +02:00
Jacob Erlbeck
d0261b72de tbf: Force ACK after the last DL LCC frame has been received
If the protocol layers above LLC (e.g. TCP) need an acknowledgement
to continue, it can take up to 400ms (single TS) until the MS is
polled for Ack/Nack which it can use to request an uplink TBF
quickly. The 400ms result from requesting an DL Ack/Nack every 20 RLC
blocks until all pending LLC frames have been sent.

Especially TCP's slow start mechanism can lead to a high delay at the
start of the connection, since the sender will eventually stop after
having sent the first packets (up to 4 (RFC2581) or 10 (RFC6928)).

This commit modifies append_data() to (re-)start
a timer every time it handles an LLC packet and to request an
Ack/Nack every time it expires. So if the server ceases to send IP
packets, the MS is polled in the assumption, that the server is
waiting for an ACK.

The following VTY commands are added (pcu node):

 - queue idle-ack-delay <1-65535>  timeout in centiseconds
 - no queue idle-ack-delay         disable this feature (default)

A sensible value is 10 (100ms) that at gave promising results when
testing locally.

Sponsored-by: On-Waves ehf
2015-04-02 18:14:08 +02:00
Jacob Erlbeck
0c1c8778df tbf: Use a hysteresis when discarding DL LLC frames
Currently single LLC blocks are discarded when the PDU lifetime
expires. If an IP packet has been fragmented either on the IP or on
the LLC layer and is therefore distributed over several LLC frames,
the kept fragments are transmitted and then discarded by the MS
because of the missing PDU. This can cause massive IP packet loss
when there are many fragmented packets (e.g. when trying 'ping
-s1800' or if the GGSN chops downlink IP packets into several SNDCP
packets).

On the other hand, discarding too many packets might disturb the
congestion handling of TCP. Dropping plain TCP ACKs might also hinder
flow control and congestion avoidance.

This commit adds a hysteresis algorithm to the LLC discard loop. If
an LLC message's age reaches the high water mark, further message's
with an age above the low water mark are discarded, too. This is
aborted, if a GMM, a non-UI, or a small message is detected. In
these cases, that message is kept.

The following VTY commands are added (pcu config node):

- queue hysteresis <1-65535>   set the difference between high
                               (lifetime) and low watermark in
                               centiseconds
- no queue hysteresis          disable this feature (default)

Since the SGSN will most probably send all fragments of a single
N-PDU without much delay between them, a value slightly above the
average transmission delay jitter between SGSN and PCU is probably a
sensible value to discard all fragments of a single IP packet.

This is an experimental feature that might be replaced by more
advanced means of active queue management in the future.

Sponsored-by: On-Waves ehf
2015-04-02 12:34:48 +02:00
Jacob Erlbeck
0a0b5dcb32 pcu: Add pcu_utils.h to Makefile.am
Addresses:
src/gprs_rlcmac_sched.cpp:26:23: error: pcu_utils.h: No such file or directory

Sponsored-by: On-Waves ehf
2015-03-29 13:55:42 +02:00
Jacob Erlbeck
502bd1feea tbf: Poll MS on idle DL TBFs
If an MS wants to open a new UL TBF, it can either use (P)RACH or
request one in a Ack/Nack message for a DL TBF (PACCH). When a TBF
becomes idle (LCC queue is empty but the TBF is kept open), there
aren't any Ack/Nack requests that can be used by the MS to ask for an
UL TBF, therefore it has to use the RACH. This leads to many RACH
requests even for a single HTTP transaction, so it takes some time to
retrieve even a simple web page.

This commit modifies the scheduler to regularly send Ack/Nack
requests on idle DL TBFs. It does so by extending the priority based
scheduling algorithm to have 5 priority levels (highest priority
first):

  - Control block is pending
  - High age (100%) threshold reached (-> request Ack/Nack)
  - Data is waiting or there are pending Nacks
  - Low age (200ms) threshold reached (-> request Ack/Nack)
  - Pending Nacks that have been resent already
  - None of the above (-> send DL dummy control block)

The 'age' refers to the time since since the last control block has
been sent on the TBF. This high age threshold is set to
dl-tbf-idle-time or to 50% of T3190 (whichever is smaller), aiming
for at least a poll (and TBF shutdown) after the TBF has expired and
to safely prevent expiry of T3190. So if dl-tbf-idle-time > 200ms,
there will be a poll every 200ms and a final poll after
dl-tbf-idle-time. On high load, the interval between polls can get
higher, but the 'high age' poll should be in place.

This commit implements the scheduling with respect to GSM 44.060,
9.3.1a ("Delayed release of downlink TBF").

Ticket: #556
Sponsored-by: On-Waves ehf
2015-03-25 12:34:38 +01:00
Jacob Erlbeck
e25b5b91f6 tbf: Only create dummy frames if necessary
Currently a lot of LLC dummy commands will be generated while waiting
for an ACK for the DL TBF, even if there are blocks that could be
resent instead.

This patch modifies create_dl_acked_block to only call
create_new_bsn() if there is unsent LLC data or m_window is empty.
If the TBF is in state FLOW, no unsent LLC data is left, but there
are blocks left in m_window, those are resent instead.

Sponsored-by: On-Waves ehf
2015-03-25 12:34:38 +01:00
Jacob Erlbeck
2cbe80b53e tbf/test: Add test for delayed release
This tests checks the implementation of the delayed release of an
downlink TBF.

Ticket: #556
Sponsored-by: On-Waves ehf
2015-03-25 12:34:34 +01:00
Jacob Erlbeck
3bed5d11d2 tbf: Implement delayed release of a downlink TBF
Currently a DL TBF is immediately closed, when the LLC queue is
drained. This will lead to a new DL assignment if data is received
afterwards. In addition, it is not possible to keep the PACCH open
to poll the MS for UL establishment requests there.

GSM 44.060, 9.3.1a suggests to delay the release of an inactive TBF
for some time (max 5s).

This commit mainly changes create_new_bsn() to send LLC dummy
commands as filler if no LLC data is available until keep_open()
returns false. The keep_open() functions returns true unless a
configurable time has passed after the LLC data store drained. By
default, that time is not set which causes keep_open() to always
return false, so that delayed release is effectively disabled.

The following VTY commands are added:
  - dl-tbf-idle-time <1-5000>    to set the delay in ms
  - no dl-tbf-idle-time          to disable delayed release

Ticket: #556
Sponsored-by: On-Waves ehf
2015-03-25 12:32:35 +01:00
Jacob Erlbeck
cbb1e70554 tbf: Insert LLC dummy command if no frame is available
If a BSN is going to be created but there is no frame stored in
m_llc, an empty LLC message would be created. This shouldn't happen
currently, but this will be a common case, when delayed TBF release
is implemented.

This commit changes create_new_bsn() to create an LLC dummy
command in that case and to put it into the frame buffer.

Sponsored-by: On-Waves ehf
2015-03-25 12:21:55 +01:00
Jacob Erlbeck
c495209122 tbf: Use put_frame in append_data if the TBF has no data
Currently if append_data() is used when there is no LLC data in the DL TBF,
it will either call reuse_tbf() which in turn will call put_frame(),
or it will append the LLC message to the queue, even if the queue and
the frame buffer are empty. This only happens with the test case so
far, but this would change when idle DL TBFs are kept open for some
time. It results in empty LLC message being sent to the MS (see log
below).

This commit changes append_data to check for this case and to
eventually use put_frame() instead of appending the LLC data to the
queue.

Addresses:
  TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=FLOW) downlink (V(A)==0 ..
  V(S)==0)
  - Sending new block at BSN 0
  -- Chunk with length 0 is less than remaining space (20): add length
    header to to delimit LLC frame
  Complete DL frame for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=FLOW)len=0
  - Dequeue next LLC for TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=FLOW)
    (len=200)

Sponsored-by: On-Waves ehf
2015-03-25 12:12:29 +01:00
Jacob Erlbeck
005ee7f862 tbf: Add frames_since_last_poll method
This functions calculates the number of frames that have passed since
the last DL poll (RRBP flag set) has been sent. It returns a value
less than zero (fn_now - fn_sched) if the block has been scheduled but
not yet sent.

If the function is called before the first data block has been sent
it will return -1.

If the function is called before the first DL poll is sent, it
returns the number of frames since the first data block has been
sent.

Sponsored-by: On-Waves ehf
2015-03-25 12:12:27 +01:00
Jacob Erlbeck
2493c660e9 tbf/test: Fix fn/block_nr in test_tbf_final_ack
Currently fn and block_nr are not incremented correctly. In addition,
the comments around the sending of blocks are not accurate either.

This commit introduces the send_rlc_block helper function which takes
care of the increments, updates the comments to reflect what is
really happening, and adds assertion to verify at least some aspects
of what is now stated in the comments.

Sponsored-by: On-Waves ehf
2015-03-25 12:10:48 +01:00
Jacob Erlbeck
a3e4509ff9 tbf/test: Put BTS setup and DL TBF creation into helper functions
Put the generic parts of test_tbf_final_ack into helper functions to
reduce the size of the test and to avoid too much code duplication
when creating new tests.

Sponsored-by: On-Waves ehf
2015-03-25 12:10:48 +01:00
Jacob Erlbeck
eceb910fef tbf: Add helper functions for DL TBFs
Some properties of a DL TBF are explicitly calculated within modules
using DL TBFs.

This commit introduces the methods need_control_ts(), have_data(),
is_control_ts() to hide internals of the DL TBF implementation.

Sponsored-by: On-Waves ehf
2015-03-25 12:10:45 +01:00
Jacob Erlbeck
95340242ed tbf: Refactor create_dl_acked_block
Turn the big nested if statement into a sequence of smaller ones. The
call to create_new_bsn is moved upwards.

Sponsored-by: On-Waves ehf
2015-03-20 14:32:20 +01:00
Jacob Erlbeck
612e93e360 llc: Add put_dummy_frame to create an LLC dummy command
The LLC dummy command is needed for RLC block stuffing, e.g. when a
TBF should be kept open if no LLC data is available. The RLC block
headers do not support stuffing, only the last block of a TBF can be
used partially. LLC dummy commands are discarded by the receiver
immediately, because the have an invalid FCS checksum.

This commit adds the function put_dummy_frame, which puts a LLC dummy
command into the frame buffer. The requested length is given as an
argument, but the real length might be adjusted according to the
specification (see GSM 44.064, 6.4.2.2).

Sponsored-by: On-Waves ehf
2015-03-20 14:12:28 +01:00
Jacob Erlbeck
39645b824a bssgp: Handle BSSGP STATUS messages
Currently incoming BSSGP STATUS messages are just logged and apart
from that ignored. Since it is possible that the gbproxy can
eventually send both valid replies (from the primary SGSN) and
STATUS(unknown BVCI) messages (from the secondary SGSN). Since the
PCU assumes in this case that the BVC has been successfully reset and
unblocked, it will not send a BVC RESET message after receiving an
NS_UNBLOCK.

This commit changes gprs_bssgp_pcu_rcvmsg to pass BSSGP STATUS
messages to bssgp_rcvmsg() which will in turn call bssgp_prim_cb()
with primitive NM_STATUS. Then the BVC RESET or UNBLOCK procedure
will be started if the IE in the message matches and the PCU assumes
that the BVC should have been successfully reset and unblocked
respectively while the STATUS message tells otherwise.

Note that bssgp_rcvmsg() from libosmocore is otherwise used for the
SGSN side only, albeit it generally just decodes messages, does basic
protocol handling and eventually invokes PRIM indications. The only
exception here is the handling of BVC RESET, which is implemented
specifically for the SGSN.

Ticket: OW#1414
Sponsored-by: On-Waves ehf
2015-03-17 10:44:07 +01:00
Jacob Erlbeck
1e96af6325 bssgp: Set blocking and reset timer to 30s
Currently the timer T1 and T2 are hard-coded to 1s which is pretty
low in consideration of a possible high latency connection to the
SGSN.

This commit introduces macros for the timer values and sets them to
30s.

Sponsored-by: On-Waves ehf
2015-03-17 10:43:42 +01:00
Jacob Erlbeck
7c44415d78 tbf: Fix scheduling for DL Ack/Nack request
Currently the DL Ack/Nack is not requested, if the last chunk of the
final LLC frame in the TBF fits exactly into the remaining space of
the RLC block. It is also not requested, if the RRBP flag cannot be
set due to scheduling issues (single block allocation, polling
already pending for this TBF, ...). So up to POLL_ACK_AFTER_FRAMES
(20) RLC data blocks will have to be resent, before requesting the
Ack/Nack will be retried.

This commit removes the first_fin_ack parameter of
create_dl_acked_block entirely and adds a request_dl_ack() method
that should be called, when the TBF's state changes to FINISHED. This
request will be reset, when the block has been scheduled
successfully. Since the first_fin_ack hasn't been set if chunk ==
space, calling request_dl_ack() on both places in create_new_bsn()
when the state is changed to FINISHED will also fix the first issue
described above.

Note that DL scheduling might not be fair concerning access to
first_ts when multiple TS are used for a TBF. In theory, a TBF might
never get access to first_ts in the worst case.

Sponsored-by: On-Waves ehf
2015-03-12 18:08:18 +01:00
Jacob Erlbeck
0eabffdc35 sched: Modify DL scheduling to use different priorities
Currently the DL blocks are scheduled round robin to each TBF that is
either in state FLOW or FINISHED and not waiting for an IMM.ASS
confirmation. This way, if single blocks has been NACK'ed by the MS
and the PCU has already resent the missing packets, the PCU starts
retransmitting them until it has received an ACK/NACK even if other
TBF have RLC blocks that need to be transmitted.

This commit changes sched_select_downlink to select the next TBF with
the highest priority, where blocks that are going to be resent again
have a lower priority unless the window is stalling. If there is only
one TBF the old behaviour is kept, since there is no other TBF that
can have a higher priority.

If there is much packet loss on a single phone, this modification can
lead to a higher latency for that MS.

Sponsored-by: On-Waves ehf
2015-03-06 19:28:10 +01:00
Jacob Erlbeck
1842c921b3 tbf: Reduce m_new_tbf logging messages
Currently tbf->m_new_tbf may point to itself if no new TBF is
assigned. But this leads to additional logging messages, since the
code in set_new_tbf and tbf_free assumes, that a real new TBF is
assigned and generates log messages accordingly.

This commit adds checks to avoid those messages in the above case.

Sponsored-by: On-Waves ehf
2015-03-06 19:28:08 +01:00
Jacob Erlbeck
adcdf150a6 tbf: Add name() method and put the buf into the tbf
Currently tbf_name() must not be used twice in a printf statement
with different TBFs, since the same baffer will be used for each.

This commit puts the text buffer into struct gprs_rlcmac_tbf to avoid
this problem.

Sponsored-by: On-Waves ehf
2015-03-06 19:25:53 +01:00
Jacob Erlbeck
a41a71e2d4 pcu: Fix log message
This commit adds a missing LF to a log message.

Sponsored-by: On-Waves ehf
2015-02-26 16:24:32 +01:00
Jacob Erlbeck
297edf754f tbf: Don't use 'old' DL TBFs after reuse_tbf
Currently two DL TBF objects with the same TLLI exist after reuse_tbf
which make the result of tbf_by_tlli undefined. This leads to several
DL TBFs belonging to the same TLLI.

This commit extends tbf_by_tlli to check the m_tlli_valid flag for
DL, too. That flag is set to 0 in reuse_tbf to mark the 'old' DL TBF
as invalid after its LLC data has been copied to the new one.

Sponsored-by: On-Waves ehf
2015-02-26 16:22:34 +01:00
Jacob Erlbeck
08fe76a893 tbf: Fix dangling m_new_tbf pointer
Currently if a 'new' TBF is freed before the 'old' one (where
old_tbf->m_new_tbf == new_tbf), the old_tbf->m_new_tbf is not cleared
and can be accessed later on. This can lead to inconsistencies or
segmentation faults.

This commit adds m_old_tbf which points back from new_tbf to old_pdf.
m_new_tbf and m_old_tbf are either both set to NULL or one is the
reverse pointer of the other (tbf->m_new_tbf->m_old_tbf == tbf and
tbf->m_old_tbf->m_new_tbf == tbf). It extends set_new_tbf and
tbf_free to update the pointee accordingly.

The TBF test is extended to check this invariant at several places.

Sponsored-by: On-Waves ehf
2015-02-23 15:10:20 +01:00
Jacob Erlbeck
5e9f40d3d9 tbf/test: Modify test to create a dangling TBF pointer
When new_tbf is freed before dl_tbf in test_tbf_final_ack, dl_tbf
still contains a pointer to it in m_new_tbf.

This patch changes the test to accept a test mode parameter and runs
it twice which a different order of tbf_free in each run. Consistency
checks are added, to check for a danglilng m_new_tbf pointer in both
cases.

Sponsored-by: On-Waves ehf
2015-02-23 15:07:06 +01:00
Jacob Erlbeck
18fef10641 tests: Fix library link order
Currently libgprs.la is listed after libosmocore.so which leads to
link errors when compiling under Ubuntu with the system build tools
(no cross compiling).

This patch moves libgprs.la in front of the external libs.

Sponsored-by: On-Waves ehf
2015-02-23 14:17:01 +01:00
Holger Hans Peter Freyther
f5c97476de tbf: Fix dereference before null check
m_new_tbf might be NULL. Assign was_releasing _after_ we have
done the NULL check.

Related: Coverity CID#1238847
2014-12-26 18:32:00 +01:00
Holger Hans Peter Freyther
49f26bf6e8 Fix VTY documentation
Documentation error (missing docs):
<command id='show tbf all'>
        <param name='all' doc='(null)' />
2014-12-20 15:22:09 +01:00
Daniel Willmann
07e39302ec tests/tbf: Commit TbfTest.err *with* whitespace "errors"
Otherwise the diff and hence the test will fail...
2014-09-19 12:01:39 +02:00
Daniel Willmann
0f58af6627 tests/tbf: Use correct function to enqueue llc data
The test called the llc enqueue() function directly which didn't take
care of prepending the tv values for the timeout to the data.

Now the test uses dl_tbf.append() which takes care of prepending the tv
values. With this patch make distcheck on jenkins should no longer fail
with "Discarding LLC PDU because lifetime limit reached." messages.
2014-09-19 11:57:21 +02:00
Daniel Willmann
635d47c78c tbf_dl: Fix warnings
Remove unused log argument (cnp bug) and unused variable
2014-09-17 17:59:03 +02:00
Daniel Willmann
1c15573012 poll_controller: Be stricter with the timeout handling
There is no reason to believe that an ACK that was polled for FN X and
has not arrived on the next frame will arrive sometime after.

Ticket: SYS#382
Sponsored-by: On-Waves ehf.
2014-09-10 19:19:58 +02:00
Daniel Willmann
efd5dbb168 tbf: Handle DL ACK/NACK poll timeout correctly
If the PCU didn't receive the downlink ack/nack when it was polled there
is no reason to assume it will arrive at a later time. In that case
N3105 is already increased, but the next block sent should have a valid
RRBP set as well to poll again.
This can happen if either the BSN with the valid RRBP gets lost on the
downlink or the DL ACK/NACK gets lost on the uplink path.

Ticket: SYS#382
Sponsored-by: On-Waves ehf
2014-09-10 19:19:58 +02:00
Daniel Willmann
510d7d36ed tests/tbf: Test for final ack issue
Ticket: SYS#382
Sponsored-by: On-Waves ehf
2014-09-10 19:19:58 +02:00
Daniel Willmann
e481815583 tbf,bts: Keep track of new TBF for dl/ul assignment in m_new_tbf
There are a couple of possibilities where one TBF is used to assign a
new one:

1. Assign a DL TBF from a UL TBF
2. Assign a UL TBF from a DL TBF
3. Assign a DL TBF from a DL TBF which is in wait-release state (T3193 is
   running)

In these cases the assignment is sent on the existing TBF and triggers
the assignement of the new TBF (with different TFI/direction).

The current code detects these situations by looking at dl/ul_ass_state
and then chosing the TBF with the opposite direction (DL/UL) that has
the same TLLI. This does not work in the case 3 above where a new DL TBF
is triggered for a DL TBF. The current code reuses the old TBF (and
TFI), but this violates the spec.

This patch introduces a m_new_tbf member which is set to the new TBF to
be assigned. When receiving a control ack the code looks up the
n_new_tbf member of the tbf that requested the control ack and completes
the ul/dl assignment. If the old TBF was in the wait release state
(T3193 is running) it is released.

From 3GPP TS 04.60 9.3.2.6:
"""
If the network has received the PACKET DOWNLINK ACK/NACK message with
the Final Ack Indicator bit set to '1' and has new data to transmit for
the mobile station, the network may establish a new downlink TBF for the
mobile station by sending the PACKET DOWNLINK ASSIGNMENT or PACKET
TIMESLOT RECONFIGURE message with the Control Ack bit set to '1' on
PACCH. In case the network establishes a new downlink TBF for the mobile
station, the network shall stop timer T3193.
"""

reuse_tbf() is modified to allocate a new TBF with a new TFI and trigger
a dl assignment for that TBF on the old TBF. All pending data is moved
to the new TBF.

Ticket: SYS#382
Sponsored-by: On-Waves ehf
2014-09-10 19:04:46 +02:00
Daniel Willmann
08e57c8366 tbf: Include TBF state in tbf_name output
Sponsored-by: On-Waves ehf
2014-08-15 18:28:45 +02:00
Daniel Willmann
341689d6c5 TbfTest: Make logging more verbose
Sponsored-by: On-Waves ehf
2014-08-15 18:28:45 +02:00
Holger Hans Peter Freyther
ad1fcccf60 Merge branch 'sysmocom/tbf-split' 2014-08-12 19:25:32 +02:00
Daniel Willmann
ca102af92b tbf: Split out UL/DL TBF methods into separate files
tbf_ul.cpp for UL TBF methods
tbf_dl.cpp for DL TBF methods

This commit contains no code changes.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-12 19:24:49 +02:00
Daniel Willmann
eb100244b0 tbf, bts: Use tbf set_state method instead of tbf_new_state function
All the function did was add debug output and call the set_state method.
Move the debugging into the method and remove the function.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-08 14:15:24 +02:00
Daniel Willmann
418a4230e0 tbf, gprs_rlcmac_meas: Move the DL bandwidth variables to the DL TBF
The bandwidth calculation as well as loss report is only done for DL TBF
so move everything related to that in there.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-08 14:15:24 +02:00
Daniel Willmann
cf706b0775 tbf: Make llc_dequeue a method of DL TBF
llc_dequeue is only used in DL TBF to send the data from the BSSGP to
the MS.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-08 14:15:24 +02:00
Daniel Willmann
e2732e2f59 tbf: Make snd_ul_ud() and assemble_forward_llc() methods of UL TBF
They are only called for UL TBF.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-08 14:15:24 +02:00
Holger Hans Peter Freyther
f72fcfe219 Merge remote-tracking branch 'origin/sysmocom/tbf-split'
the TBF handling in osmo-pcu mixes UL and DL TBFs together. They
are quite different, however, and should be treated differently.

This patch series continues the work of splitting up UL and DL TBFs
into their own classes and explicitly using a DL TBF or UL TBF
instead of the base class in those parts of the code that deal
with only one variant.

I didn't test every single commit, but each should compile and
the result passes make check as well as our iperf test against
a GSM modem.

[Text from Daniel's cover mail]
2014-08-08 08:49:03 +02:00
Daniel Willmann
7e994e392d tbf, ...: Make the fields in the dl/ul struct member variables
There is no need for the union/struct anymore. Make the variable members
of the UL/DL class.

As a result gprs_rlc_dl_window gets a reset() method because
memset(&dir.dl, 0, sizeof(dir.dl)) doesn't work anymore in reuse_tbf().

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
6a8a1dcda2 tbf: Move the dir.dl/ul members out of the base class into DL/UL TBF
Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
d1d1633121 tbf: Remove unused function sns()
The current code uses dir.*l.window.sns() directly. The current
implementation only returns the dl.window.sns() which will cause
problems.
Remove now and re-add it as a method of DL/UL TBF if and when it is
needed.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
cd44ec41c5 gprs_rlcmac_ts_alloc: Be explicit about which TBF is used
Use UL/DL TBFs instead of the base class wherever it is clear that the
code only deals with one kind of TBF.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
f55e58f5cf encoding: Change function signature to use UL TBFs where it makes sense
encode_rbb() and write_packet_uplink_assignment are only called with UL
TBFs so change the function signature to reflect that.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
350f64d9e2 tbf: Move UL TBF methods from base class into UL TBF
The methods create_ul_ack(), rcv_data_block_acknowledged(),
maybe_schedule_uplink_acknack() are only used for UL TBFs so make them
methods of that class instead of the base class.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
4f3c420852 gprs_rlcmac_sched: Use UL/DL TBFs in scheduler
Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
b2886f1a0d tbf: Split UL and DL TBFs up in create_dl_ass()
Explicitly use UL and DL TBFs where they are needed.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
93d1711011 poll_controller: Use DL/UL TBFs in PollController::expireTimedout()
Be specific about where we are handling an UL and DL TBF

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:05 +02:00
Daniel Willmann
6a16e0c092 tbf: Use DL/UL TBFs in poll_timeout codepaths that deal only with one type
Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:04 +02:00
Daniel Willmann
351a573396 tests/alloc: Use the specific UL/DL TBF classes instead of the base
Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:04 +02:00
Daniel Willmann
3016888ee0 tbf, gprs_bssgp_pcu: Move some methods to DL TBF
These methods are only used on DL TBFs and can be moved to the subclass.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:04 +02:00
Daniel Willmann
532a4b54f5 bts: Change parameter in BTS::trigger_dl_ass() to DL TBF
This method is always called with a DL TBF as argument so make it clear.

Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:04 +02:00
Daniel Willmann
1dac2ebb71 bts: Make use of DL TBF explicit in rcv_imm_ass_cnf()
Ticket: SYS#389
Sponsored by: On-Waves ehf
2014-08-07 16:12:04 +02:00
Daniel Willmann
b8f260176e tbf: Make create_new_bsn and create_dl_acked_block a method of DL TBF
These functions are only used for DL TBFs so move them.
sched_select_downlink() in src/gprs_rlcmac_sched.cpp now needs to deal
with DL TBFs instead of the base class.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-08-07 13:03:10 +02:00
Daniel Willmann
6c813fc9bc bts, tbf: Make rcvd_dl_ack a method of the DL TBF
This method is only userul for DL TBFs so move it. As a result
gprs_rlcmac_pdch::rcv_control_ack needs to work with dl_tbfs.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-08-07 13:03:10 +02:00
Daniel Willmann
538ac5b574 tbf: Make append_data a function of DL TBFs
This function is only used in DL TBFs (called by handle).

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-08-07 13:03:09 +02:00
Daniel Willmann
2354402b7a tbf: Make tbf_lookup_dl() return and handle() use a dl_tbf
These two functions only deal with DL TBFs so make it clear

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-08-07 13:03:09 +02:00
Daniel Willmann
057c285cd7 bts: Remove the OSMO_ASSERTs for TBF direction
llist_add is called on the TBF lists in tbf_alloc_ul/dl_tbf or in
rotate_in_list. All three places check the direction/add the new TBF to
the correct list so an ASSERT on entry is not needed.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-08-07 13:03:09 +02:00
Daniel Willmann
1b3864fc47 tbf: Use plain old data structure (PODS) for llist management
The PODS struct has a back pointer to access the actual object.
llist_pods_for_each_entry traverses the list of struct llist_pods and
makes the entry available (through the back pointer).

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-30 18:27:30 +02:00
Holger Hans Peter Freyther
4bbe3349c2 Merge branch 'sysmocom/tbf-split'
We start to separate the UL and DL part of the TBF now as they
really behave differently. One works on RLCmac frames (plural)
and sends them, the other is just assembling one of them. The
code will become more clear now.
2014-07-22 12:37:18 +02:00
Daniel Willmann
48aa0b0d99 bts, tbf: Split alloc_tbf function into separate UL and DL versions
UL and DL tbfs are used in very separate parts and are not the same
thing so split the alloc function and use the UL/DL version throughout
the code.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-22 12:36:31 +02:00
Daniel Willmann
0d12a2fa89 bts, tbf: Change the TBF return type of functions to the ul/dl version
Many functions only ever deal with or return a UL or a DL TBF.
Explicitly change the type to reflect which TBF is used where.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-22 12:36:13 +02:00
Daniel Willmann
fe6e2e4a08 bts: Return the special type for {ul,dl}_tbf_by_* functions
Start returning the special type instead of the base gprs_rlcmac_tbf
when retrieving a TBF.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-16 22:10:17 +02:00
Daniel Willmann
078bb713e1 tbf: Add ul and dl TBF types and allocate them in tbf_alloc()
Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-16 19:03:36 +02:00
Daniel Willmann
2207c5e4ef bts: Ensure tbf direction with OSMO_ASSERT()
In the lookup functions make sure that we are actually returning tbfs
with the expected direction.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-16 19:03:36 +02:00
Daniel Willmann
febf1a0ac9 bts: Split tbf_by_poll_fn into separate dl and ul functions
rcv_control_dl_ack_nack is only meaningful for dl tbf while
rcv_control_ack can be sent in response to a dl or ul tbf. So
rcv_control_ack still needs to check for ul and dl tbfs.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-03 15:36:52 +02:00
Daniel Willmann
54044b0635 bts: Separate functions for dl/ul tbf_by_tfi lookup
Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-03 15:36:52 +02:00
Daniel Willmann
b59d61b4b4 bts, tbf: Separate functions for dl/ul tbf_by_tlli lookup
In the future we want to separate ul and dl tbf into different
classes that inherit from a common base.

Ticket: SYS#389
Sponsored-by: On-Waves ehf
2014-07-03 15:36:46 +02:00
Holger Hans Peter Freyther
e8915b9d9d misc: Add missing include for the rate counter
pcu_vty.c:285:2: warning: implicit declaration of function 'vty_out_rate_ctr_group' is invalid in C99 [-Wimplicit-function-declaration]
        vty_out_rate_ctr_group(vty, "", bts_main_data_stats());
        ^
2014-07-02 14:57:47 +02:00
Holger Hans Peter Freyther
2c98f1db78 misc: Add missing include for atoi
pcu_vty.c:128:21: warning: implicit declaration of function 'atoi' is invalid in C99 [-Wimplicit-function-declaration]
        bts->fc_interval = atoi(argv[0]);
                           ^
2014-07-02 14:56:36 +02:00
Holger Hans Peter Freyther
c421e8aaf2 misc: Add {} to avoid nested if/if/else ambigiouty
pcu_vty.c:89:3: warning: add explicit braces to avoid dangling else [-Wdangling-else]
                else
2014-07-02 14:55:17 +02:00
Holger Hans Peter Freyther
35cc1c0ff3 misc: Do not mix struct/class in the forward declaration 2014-07-02 14:48:44 +02:00
Holger Hans Peter Freyther
f3405e5b03 sysmobts: Add a hot-fix to avoid dumping -1 amount of data 2014-06-16 21:51:36 +02:00
Daniel Willmann
6d8884de49 Always exit and don't try to recover
The current code tries to recover from dropped connections and resets the
pcu state so it can keep running. However, this never worked correctly
which is why the -e option is used. This option exits the pcu as soon as
the internal state needs to be reset.

This patch removes this option and makes this behaviour default.

Ticket: SYS#390
Sponsored-by: On-Waves ehf
2014-06-15 19:28:51 +02:00
Daniel Willmann
77e58f602d bts: Remove outdated comment
There is no parameter in the function and the bts has a memeber trx
which has a member pdch.

Sponsored-by: On-Waves ehf
2014-06-04 19:01:56 +02:00
Daniel Willmann
5d77f14904 csn1: Add spaces between string literal and identifier
This is required by C++11

csn1.cpp:1147:44: error: invalid suffix on literal; C++11 requires a space between literal and identifier [-Wreserved-user-defined-literal]
LOGPC(DCSN1, LOGL_NOTICE, "%"PRIu64"|", bitvec_read_field(vector, readIndex, bits_to_handle));

Sponsored-by: On-Waves ehf
2014-06-04 17:17:48 +02:00
Daniel Willmann
17a1d5e162 gprs_rlcmac_pdch: Get rid of ul/dl_tbf
The current code keeps a reference to all tbfs in the bts and another
reference in the pdch. This allows for the possibility of both lists to
go out of sync.

This patch removes the pdch-specific list of ul and dl tbfs and uses the
lists in the bts to lookup tbfs everywhere.

Performance for going through the global list is not an issue yet. We
can optimize this later and in a better way.

Sponsored-by: On-Waves ehf
2014-06-04 17:17:45 +02:00
Daniel Willmann
1e0c61032f gprs_rlcmac_pdch: Don't access private members
This patch introduces methods to get ul and dl tbf by tfi and uses them
in gprs_rlcmac_sched.

Sponsored by: On-Waves ehf
2014-06-04 17:14:22 +02:00
Daniel Willmann
cf1fae7f38 tbf: Re-send dl assignment if we can upgrade to multislot
The current code would only ever assign one PDCH for the initial
assignment (from CCCH). Only if reuse_tbf is called the algorithm would
actually use multiple DL PDCHs if possible.

This patch introduced a tbf attribute upgrade_to_multislot that is set
if we have multiple PDCH configured, and support multislot assignment,
but can only assign a single PDCH (alloc_algorithm_b, parameter single
is set). In this case after the assignment completes (and the MS is
listening on a PDCH) we resend a DL assignment though the PACCH and this
time we can assign multiple timeslots.
2014-05-30 18:23:17 +02:00
Daniel Willmann
73191a443f tbf/bts, encoding: Keep track of WAIT_RELEASE state for DL assignment
The current code does not properly distinguish between DL assignments to
reuse a tbf (after it was put in state WAIT_RELEASE) and DL assignments
for an active tbf to change the allocation of the PDCH timeslots.

This patch introduces a new variable was_releasing which remembers if
trigger_dl_ass() was called with a tbf in state WAIT_RELEASE. In that
case we have to set the CONTROL_ACK field in the download assignment.

This should allow us to send DL assignments to change PDCH TS allocation
of a tbf before we enter FLOW state.
2014-05-30 18:21:00 +02:00
Daniel Willmann
fc03bbe078 tbf/bts: Rename tbf->snd_dl_ack to tbf->rcvd_dl_ack
This function is called to act upon a received DL ACK packet so this
name makes more sense.
2014-05-30 18:19:06 +02:00
Andreas Eversberg
9167055ed2 Fixed calculation of colliding UL/DL slots in TS allocation algorithm B
Counter j must be wrapped to prevent beeing negative, when it is
initialized. This wrapping happens, if TS 0 is used for PDCH in
combination with regular GPRS phones (MS class 12 or similar).
2014-05-30 18:18:09 +02:00
Holger Hans Peter Freyther
8f3520579a Merge remote-tracking branch 'origin/sysmocom/master' 2014-05-15 12:24:12 +02:00
Holger Hans Peter Freyther
f81e2f7621 systemd: Do not re-start in case of exit(1) (e.g. a config issue) 2014-03-21 18:18:36 +01:00
Holger Hans Peter Freyther
59fe8f79cc systemd: Reduce the re-start interval to a couple of seconds
With the exit on failure/disconnect option we restart the PCU a
lot more and might not want to wait five seconds.
2014-02-04 13:20:54 +01:00
Holger Hans Peter Freyther
d8f339592d sysmopcu: Re-start the PCU on disconnect
During the refactorings I highlighted that the PCU has two
equally broken clean-up paths.

Fixes: SYS#134
2014-01-21 16:59:33 +01:00
Holger Hans Peter Freyther
a09e33cdeb TODO: Update the todolist with some musings... 2014-01-16 10:11:57 +01:00
Holger Hans Peter Freyther
e5109ba1f0 tbf: Change the log area to RLCMACDL so we see it in a DL trace 2014-01-16 10:11:22 +01:00
Holger Hans Peter Freyther
3d0cc2f97d tbf: Make finding use-after-free more easy and set to NULL or return
Make finding use-after-free more easy by setting things to NULL
or simply return after tbf_free(this) has been called.
2014-01-16 10:09:42 +01:00
Holger Hans Peter Freyther
a004799699 tbf: Use past-tense and call it created_ts 2014-01-16 10:07:20 +01:00
Holger Hans Peter Freyther
b293043e2d Merge remote-tracking branch 'sysmocom/tbf-vty' into sysmocom/master 2014-01-16 10:06:22 +01:00
Daniel Willmann
80367aae17 tbf: Save a timestamp at tbf allocation and print it in the VTY 2014-01-15 17:41:45 +01:00
Daniel Willmann
772415fd8a pcu_vty: Add a command to print info about all TBFs 2014-01-15 17:41:45 +01:00
Daniel Willmann
afa72f5210 tbf: Add a function to output tbf info to VTY 2014-01-15 17:41:44 +01:00
Holger Hans Peter Freyther
85c1ea5cb6 Merge remote-tracking branch 'sysmocom/window-rework' into sysmocom/master 2014-01-15 17:25:49 +01:00
Daniel Willmann
3ce011f44f rlc: Rename state() to show_state() to better reflect its function
show_state() is only used for debugging output to make the v(b) array
human readable.
2014-01-15 15:23:35 +01:00
Daniel Willmann
d54d9f5c75 rlc: Use an enum for the state array instead of chars
gprs_rlc_bsn_state is now used to hold the ACK state of sent/received
rlc packets.
2014-01-15 15:23:35 +01:00
Daniel Willmann
146514e180 rlc/tbf: Move v_b into DL window
Move functions resend_needed(), mark_for_resend(), update(),
move_window(), state(), count_unacked() out of v_b directly into the UL
window and provide a function get_state in v_b to access the v_b
elements.
2014-01-15 15:23:21 +01:00
Daniel Willmann
55844795be rlc/tbf: Add function receive_bsn that updates v_r, v_q, v_n
We don't need to expose the mecanics of updating the variables to the
outside.
2014-01-15 15:23:21 +01:00
Daniel Willmann
7c3751b10b rlc/tbf: Move v_n into gprs_rlc_ul_window and adapt the tests
v_n is part of the UL window handling so move it inside the ul_window
2014-01-15 15:23:21 +01:00
Daniel Willmann
f4a1ec6ce7 rlc: Rename the simple raise_v_r method to avoid naming conflicts 2014-01-15 15:23:21 +01:00
Holger Hans Peter Freyther
c2fab7a6ff alloc: Update the test result now that everything is back to working again 2014-01-15 14:42:58 +01:00
Andreas Eversberg
0a940087b2 alloc_algorithm_b: Remove obsolete 'i' incrementation from for-loop 2014-01-15 14:33:49 +01:00
Holger Hans Peter Freyther
2bf3446f7a misc: Allow to cross-execute the tests using qemu
When cross-compiling osmo-bts/osmo-pcu one can not easily
execute the testsuite. By adding the OSMO_QEMU variable in
front of the normal execution we can execute the tests. This
should work for native and cross builds.

$ OSMO_QEMU="qemu-arm -L /opt/poky/1.1.2/sysroots/armv5te-poky-linux-gnueabi/" make check
2014-01-15 11:14:52 +01:00
Holger Hans Peter Freyther
746b390201 Merge branch 'sysmocom/allocation-corrections' into sysmocom/master
Merge the refactorings we did at sysmocom and the new test cases that
test the easy success cases of the allocation algorithm. Include the
multislot fixes from Andreas.
2014-01-15 10:39:26 +01:00
Andreas Eversberg
1cd9d886e6 alloc_algorithm_b: Add seperate function to shrink rx window when TS are removed
After reduce_rx_window() and update_rx_win_max() was called, one or more TS
might be removed. tx_win_min and tx_win_max must be adjusted to the new range
of allocated slots.
2014-01-15 10:39:08 +01:00
Andreas Eversberg
fe2dcc8aec alloc_algorithm_b: Increment 'i', so allocated TS will not exceed tx_range 2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
f3eec04655 alloc/test: Add a crazy test that tests each possible combination
Make a crazy test that will test each possible PDCH configuration
and MS Class and verify that the UL/DL assignments work and that
they are on the same first_common_ts.
2014-01-15 10:39:08 +01:00
Andreas Eversberg
765736dc77 alloc_algorithm_b: Do not select uplink slots that cannot be used for downlink
In order to poll MS, the mobile must be able to receive polling request.

In order to allow the MS to transmit, the USF must be received by the mobile.
2014-01-15 10:39:08 +01:00
Andreas Eversberg
7a16d46fdc alloc_algorithm_b: Set tx_range to 8, if all 8 TS are supported by MS 2014-01-15 10:39:08 +01:00
Andreas Eversberg
ccde4c462d alloc_algorithm_b: For type 1 MS, limit number of donwlink TS to 5
The algorithm does not support more than 5 TS on downlink for type 1 MS.
Supporting more than 5 TS would require adding more complexity to this
algorithm. MS that support more than 4 (or 5) TS on downlink are rare,
if they really exist.
2014-01-15 10:39:08 +01:00
Andreas Eversberg
b03d427b08 alloc_algorithm_b: Correctly increment RX/TX window, even if TS is not useable 2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
73193110f2 alloc: Move the uplink ts selection/pre-assignment out of the code
Create a select_ul_slots which is very (95%) similar to the
select_dl_slots handling. This needs to be refactored and the
todo for multiple uplink slots should be handled too.

Add a warning about a potential failure on a busy PCU.
2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
1fe69323ad alloc: Move the selection of the first enabled pdch to a new method 2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
3fd2ddf1a2 alloc: Move the tx window calculation to a new method 2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
dd4af8045f alloc: Move upating of the rx window max for Type==1 to a new method 2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
e45c19b3e8 alloc: Move the collision handling to a new method
The naming of RX/TX still looks fishy and it should use DL/UL instead.
Work on pointers right now. We could introduce a struct with the window
min and max and pass this struct. The usage of 'D' appears wrong in the
ul_usage..
2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
882fc9b174 alloc: Move the selection of downlink slots to a new method
This code could evolve into working for Uplink and Downlink. The
only different for the final Uplink assignment is that free USFs
are collected.
2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
f34f34495b alloc: Simplify the assignment of Trb and Ttb
Put the cases for MS_A/MS_B and MS_A/MS_C together.
2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
df022f6cb2 alloc: Add a note that the tx window handling differs from rx
It looks like the code is different (without a reason) a good
reason.
2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
c7b998cc73 alloc/test: Go through all possible ms_classes for the allocation
Generate results for all possible classes.
2014-01-15 10:39:08 +01:00
Holger Hans Peter Freyther
4af30533f0 alloc/tests: Create an allocation test for various scenarious
The allocation in the TBF/BTS code is quite complex. In parts this
is due the assignment and requests occuring under differen circumstances.
Attempt to re-create the commono scenarios.

Remove the bogus msclass check in gprs_rlcmac_tbf::update as the
allocation code will check the ms class anyway.
2014-01-15 10:39:07 +01:00
Holger Hans Peter Freyther
f37e514a96 bts: Rename ts and trx to ts_no and trx_no as we operate on number 2014-01-15 10:34:22 +01:00
Holger Hans Peter Freyther
8f399de135 tbf: Kill the tsc member as it duplicates data
We can just use first_ts and the trx/pdch to extract this information.
Avoid duplication of data.
2014-01-15 10:34:09 +01:00
Holger Hans Peter Freyther
ba26368040 tbf: Fix typo and call it same 2014-01-15 10:33:56 +01:00
Holger Hans Peter Freyther
6f791d049a sched: Document a possible race condition 2014-01-15 10:33:28 +01:00
Daniel Willmann
6f0796a33a Set csnStream direction *after* csnStreamInit
Fixes a bug introduced in commit 402cdc. That commit sets direction to
zero so setting it to 1 should be done after the call to
csnStreamInit().

This issue was discovered by the rlcmac test.
2014-01-15 10:03:42 +01:00
Daniel Willmann
fdcdde2756 Set csnStream direction *after* csnStreamInit
Fixes a bug introduced in commit 402cdc. That commit sets direction to
zero so setting it to 1 should be done after the call to
csnStreamInit().

This issue was discovered by the rlcmac test.
2014-01-15 09:57:07 +01:00
Ivan Kluchnikov
402cdcd02f Fix warnings in gsm_rlcmac.cpp
1. ar.direction variable was not initialized
2. overrunning array "data->RLC_DATA" of 20 bytes at byte offset 22 using index "i" (which evaluates to 22)
2014-01-09 20:01:48 +01:00
Daniel Willmann
2f1974b5ac sysmo_l1_if: Fix off-by-one bug when sending UL messages to gsmtap
The first byte in data_ind->msgUnitParam.u8Buffer is not part of the GSM
frame, but something else, it is also skipped in the call to
pcu_rx_data_ind_pdtch().

This patch fixes GSM RLC/MAC UL packet decoding in wireshark, especially
ACK/NACK packets are now displayed correctly (amongst others).
2014-01-09 20:00:00 +01:00
Ivan Kluchnikov
1b517342ae Fix warnings in gsm_rlcmac.cpp
1. ar.direction variable was not initialized
2. overrunning array "data->RLC_DATA" of 20 bytes at byte offset 22 using index "i" (which evaluates to 22)
2013-12-30 14:56:26 +04:00
Holger Hans Peter Freyther
705653b2d7 sched: Attempt to improve the fairness and schedule UL/AL ACK/ASS
It is possible that certain UL ACK messages are not sent when there
are many many uplink and downlink assignments. Try to be more fair
and schedule them round-robin. This way no starvation should occur.
2013-12-25 15:31:46 +01:00
Holger Hans Peter Freyther
aadfc2e121 sched: Remove unused bts parameter from the internal method 2013-12-25 15:19:54 +01:00
Daniel Willmann
9c623892f5 llc: Calculate the average queuing delay of the LLC queues
Use a formula like it is used with TCP. This can help to make
decisions about if frames should be dropped or not at the time
we enqueue them.

This code will store two timeval structs in fron the of the
actual data and compute the average at the time of the dequeue.
2013-12-25 14:55:04 +01:00
Holger Hans Peter Freyther
a42b2ad5ed llc: Initialize the LLC frame with garbage to detect wrong usage 2013-12-25 14:27:07 +01:00
Holger Hans Peter Freyther
550bb88a9e llc: Count the number of frames queued inside the LLC queue 2013-12-18 12:11:27 +01:00
Holger Hans Peter Freyther
88553abf4d rlc: Use sizeof() for the memset instead of ARRAY_SIZE
In this case both will give the same result but it is better to use
sizeof. But it is better to use the raw number of bytes instead of
the number of elements.
2013-12-18 12:11:10 +01:00
Henning Heinold
c92b964e2d systemd: Add a service for the sysmopcu
Provide a systemd service file for sysmopcu, leaves
the bundled combined sysvinit for sysmobts and sysmopcu
for legacy systems.

Sponsored-by: sysmocom
2013-12-17 19:16:10 +01:00
Holger Hans Peter Freyther
b3a87ced5a test: Remove the side-effect from the assertion
Coverity complains about this code as it doesn't know that the
OSMO_ASSERT is always on. But it is good practice to now have the
side-effect in here.

Fixes: Coverity CID 1080724
2013-12-12 14:42:35 +01:00
Holger Hans Peter Freyther
81e8f0a8a2 l1if: Include string.h to fix possible coverity issue
Coverity warns about the below lines of code. strerror is supposed
to return a char* and %s should work on char. Let's see if including
string.h will make coverity more happy. The pre-processes file looked
sane as well.

 LOGP(DL1IF, LOGL_ERROR, "error writing to L1 msg_queue: %s\n",
               strerror(errno));

Coverity: CID 1040951, CID 1040950, CID 1040952
2013-12-12 14:32:33 +01:00
Holger Hans Peter Freyther
752a3b2baa Merge branch 'sysmocom/gprs-window-handling' into sysmocom/master
Daniel and me worked on the window handling. We now test that what
we encode is compatible to what we decode. The char array now includes
SSN-1 to the right of the array (reflecting a time axis that grows
towards the right..)
2013-12-12 11:11:02 +01:00
Daniel Willmann
5e94cd4fde decoding: Cosmetic - change rbb decoding 2013-12-12 11:09:17 +01:00
Daniel Willmann
cc5a4cbe9b rlc: Make the update loop more understandable
Add bitnum_to_bsn() as a convenience function to get the BSN, use it
in the update handling and ignore rbb for values outside of our tx
window.
2013-12-12 11:07:47 +01:00
Daniel Willmann
48df40d2a4 tests/TypesTest: Check rbb handling in DL 2013-12-12 11:06:40 +01:00
Daniel Willmann
f1786a375f tests/TypesTest: Ensure that extract_rbb(encode_rbb(x)) == x 2013-12-12 11:05:43 +01:00
Daniel Willmann
6f7cb2cb4f decoding: Use 'I' and 'R' in rbb array for DL
We want to match up rbb decoding and encoding so it helps to use the
same chars.
2013-12-12 11:03:50 +01:00
Daniel Willmann
0f2b5fc749 tests/TypesTest: Print the result of Encoding::encode_rbb() 2013-12-12 11:03:35 +01:00
Daniel Willmann
5241c1a018 encoding: Factor out encode_rbb to help testing 2013-12-12 11:03:13 +01:00
Daniel Willmann
52ea8a0d87 encoding: Use ul_window ssn()/update_rbb() methods when encoding ul ACK
Use the ssn() and update_rbb() methods of gprs_rlc_ul_window when
encoding the ACK/NACK packet in write_packet_uplink_ack()
2013-12-12 11:02:09 +01:00
Daniel Willmann
e6e605ba86 encoding: Change wording to match that of 3GPP TS 04.60
The spec (in ch. 9.1.8.1) speaks of RECEIVED or INVALID in the RLC
receiver, so change the wording in the log message to match.
2013-12-12 11:01:52 +01:00
Daniel Willmann
c3f4330fa3 tests/TypesTest: Add OSMO_ASSERT_STR_EQ which prints out the parameters
Use it to compare rbb
2013-12-12 11:01:32 +01:00
Daniel Willmann
f86fb7a953 tests/TypesTest: Test ssn() and update_rbb() uplink window methods in TypesTest
Test that ssn and rbb are updated correctly.
2013-12-12 11:01:13 +01:00
Daniel Willmann
8a31f9e016 rlc: Manage the received block bitmap in the ul_window
Added two methods to gprs_rlc_ul_window
* ssn() returns the starting sequence number
* update_rbb() returns an array of chars representing the state of the
  received   block bitmap. Each element is either 'I'nvalid or
  'R'eceived. The rbb is generated from v_n

rbb[63] relates to BSN ssn-1
...
rbb[0] relates to BSN ssn-64
2013-12-12 10:59:56 +01:00
Holger Hans Peter Freyther
11f2d58dbd rlc: Create a testcase for the uplink window 2013-12-04 21:05:18 +01:00
Holger Hans Peter Freyther
3cbf9e040c rlc: Make the RLC types only operate on the BSN
The code has an internal optimization to only use window_size
space. This means that the caller needed to know that only half
of the size was used. Change the API to work on the BSN and do
the mapping internally. The compiler should have plenty of
opportunity to propagate the constant(s) but this has not been
verified.
2013-12-04 21:01:02 +01:00
Holger Hans Peter Freyther
3c95776805 tbf: Separate the handling for rh->si and call in case of re-transmission
In case of a retransmission ack the window again..
2013-12-04 13:51:43 +01:00
198 changed files with 574482 additions and 10772 deletions

39
.gitignore vendored
View File

@@ -5,6 +5,7 @@
Makefile.in
Makefile
.deps
src/cscope*
aclocal.m4
autom4te.cache
@@ -13,11 +14,13 @@ config.guess
config.sub
config.status
configure
compile
depcomp
install-sh
missing
libtool
*libtool
ltmain.sh
*~
core
core.*
@@ -30,12 +33,38 @@ src/osmo-pcu-remote
# tests
.dirstamp
__pycache__/
tests/atconfig
tests/package.m4
tests/alloc/AllocTest
tests/rlcmac/RLCMACTest
tests/tbf/TbfTest
tests/types/TypesTest
tests/*/*Test
tests/*/*_test
tests/emu/pcu_emu
tests/testsuite
tests/testsuite.log
# ignore debian files
.tarball-version
debian/autoreconf.after
debian/autoreconf.before
debian/files
debian/*.debhelper*
debian/*.substvars
debian/osmo-pcu-dbg/
debian/osmo-pcu.substvars
debian/osmo-pcu/
debian/tmp/
osmo-pcu.pc
# manuals
doc/manuals/*.html
doc/manuals/*.svg
doc/manuals/*.pdf
doc/manuals/*__*.png
doc/manuals/*.check
doc/manuals/generated/
doc/manuals/osmomsc-usermanual.xml
doc/manuals/common
doc/manuals/build
contrib/osmo-pcu.spec

3
.gitreview Normal file
View File

@@ -0,0 +1,3 @@
[gerrit]
host=gerrit.osmocom.org
project=osmo-pcu

View File

@@ -1,5 +1,14 @@
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
SUBDIRS = src examples tests
EXTRA_DIST = osmoappdesc.py
SUBDIRS = include src doc tests contrib
EXTRA_DIST = \
README.md \
contrib/osmo-pcu.spec.in \
debian \
osmoappdesc.py \
$(NULL)
AM_DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
@RELMAKE@

20
README
View File

@@ -1,20 +0,0 @@
This is an implementation of Packet Control Unit (PCU) according to TS 04.60
The PCU is part of BSS, so it connects directly to SGSN.
== Current limitations ==
* No PFC support
* No fixed allocation support
* No extended dynamic allocation support
* No unacknowledged mode operation
* No PCCCH/PBCCH support
* Only single slot assignment on uplink direction
* No half-duplex class support (only semi-duplex)
* No handover support
* No measurement support
* No TA loop
* No power loop
* No CS loop
* No EGPRS

85
README.md Normal file
View File

@@ -0,0 +1,85 @@
osmo-pcu - Osmocom Packet Control Unit
======================================
This repository contains a C/C++-language implementation of a GPRS
Packet Control Unit, as specified by ETSI/3GPP. It is part of the
[Osmocom](https://osmocom.org/) Open Source Mobile Communications
project.
The Packet Control Unit is terminating the Layer 2 (RLC/MAC) of the GPRS
radio interface and adapting it to the Gb Interface (BSSGP+NS Protocol)
towards the SGSN.
The PCU interfaces with the physical layer of the radio interface.
OsmoPCU is typically used co-located with the BTS, specifically
[OsmoBTS](https://osmocom.org/projects/osmobts/wiki).
For legacy BTSs that run proprietary sotware without an interface to
OsmoPCU, you may also co-locate it with the BSC, specifically
[OsmoBSC](https://osmocom.org/projects/openbsc/wiki/Osmo-bsc)
Homepage
--------
The official homepage of the project is
https://osmocom.org/projects/osmopcu/wiki/OsmoPCU
GIT Repository
--------------
You can clone from the official osmo-pcu.git repository using
git clone git://git.osmocom.org/osmo-pcu.git
There is a cgit interface at http://git.osmocom.org/osmo-pcu/
Documentation
-------------
We provide a
[user manual](http://ftp.osmocom.org/docs/latest/osmopcu-usermanual.pdf)
as well as a
[vty reference manual](http://ftp.osmocom.org/docs/latest/osmopcu-vty-reference.pdf)
Please note that a lot of the PCU configuration actually happens inside
the BSC, which passes this configuration via A-bis OML to the BTS, which
then in turn passes it via the PCU socket into OsmoPCU.
Mailing List
------------
Discussions related to osmo-pcu are happening on the
osmocom-net-gprs@lists.osmocom.org mailing list, please see
https://lists.osmocom.org/mailman/listinfo/osmocom-net-gprs 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-pcu can be seen at
https://gerrit.osmocom.org/#/q/project:osmo-pcu+status:open
Current limitations
-------------------
* No PFC support
* No fixed allocation support (was removed from 3GPP Rel >= 5 anyway)
* No extended dynamic allocation support
* No unacknowledged mode operation
* Only single slot assignment on uplink direction
* No half-duplex class support (only semi-duplex)
* No TA loop
* No power loop
* Multi-BTS support not tested

38
TODO
View File

@@ -1,12 +1,34 @@
* Make the TBF ul/dl list per BTS
* Make the SBA per BTS
* Make the tbf point to the BTS so we can kill plenty of parameters
* Group more into in classes.. remove bts pointers.
* Change functions with 100 parameters to get a struct as param
* Move move into the TBF class
* Replace trx/ts with pointers. E.g. a PDCH should know the trx
it is on... then we can omit trx, ts and parameters and just pass
the pdch.
* On global free/reset... also flush the timing advance..
* tbf/llc window code appears to be duplicated and nested in other
methods. This needs to be cleaned.
* Possible race condition:
When scheduling a Downlink Assignment on the UL-TBF we need to make
sure that the assignment is sent _before_ the final ack. With my fairness
changes it gets more likely that this event is trigerred.
* Optimize:
After receiving an ACK/NACK.. schedule another one if the window
is kind of stalled anyway. This way we avoid resending frames that
might have already arrived. It could increase the throughput..
Do not re-transmit after we got ack/nacked and where in the resending
mode... and increase the window.
<0004> tbf.cpp:907 - Sending new block at BSN 111
...
tbf.cpp:858 - Restarting at BSN 48, because all window is stalled.
...
tbf.cpp:1383 - V(B): (V(A)=59)"NNAAAAAAANAAAAANNAAAAAAAAAAAAAAAAAAAXXXXXXXXXXXXXXXXX"(V(S)-1=111) A=Acked N=Nacked U=Unacked X=Resend-Unacked I=Invalid
.. retransmitting the nacked.. and then the ones that migh have
already arrived
<0004> tbf.cpp:834 TBF(TFI=0 TLLI=0xd7b78810 DIR=DL) downlink (V(A)==59 .. V(S)==112)
<0004> tbf.cpp:840 - Resending BSN 111
Figure out scheduling issue. Why do we reach the 20 re-transmits and
stil haven't received the ACK/NACK? was it scheduled? The whole
scheduler could be re-worked to be more determestic.. and answer
questions like if it has been sent or not

9
TODO-RELEASE Normal file
View File

@@ -0,0 +1,9 @@
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
# according to https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
# In short:
# LIBVERSION=c:r:a
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0.
# If any interfaces have been added since the last public release: c:r:a + 1.
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line

View File

@@ -1,14 +1,24 @@
dnl Process this file with autoconf to produce a configure script
AC_INIT([osmo-pcu],
m4_esyscmd([./git-version-gen .tarball-version]),
[osmocom-pcu@lists.osmocom.org])
[osmocom-net-gprs@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)
CXXFLAGS="$CXXFLAGS -std=gnu++03"
CFLAGS="$CFLAGS -std=gnu11"
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
@@ -16,32 +26,146 @@ AC_PROG_CXX
AC_PROG_INSTALL
LT_INIT
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
AS_CASE(["$LD"],[*clang*],
[AS_CASE(["${host_os}"],
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
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
dnl checks for libraries
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.9)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.3.3)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.5.1.4)
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"
CXXFLAGS="$CXXFLAGS -fsanitize=address -fsanitize=undefined"
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
LDFLAGS="$LDFLAGS -fsanitize=address -fsanitize=undefined"
fi
AC_MSG_CHECKING([whether to enable sysmocom-bts hardware support])
AC_ARG_ENABLE(sysmocom-bts,
AC_HELP_STRING([--enable-sysmocom-bts],
[enable code for sysmocom femto-bts [default=no]]),
[enable_sysmocom_bts="$enableval"],[enable_sysmocom_bts="no"])
AC_MSG_RESULT([$enable_sysmocom_bts])
AM_CONDITIONAL(ENABLE_SYSMOBTS, test "x$enable_sysmocom_bts" = "xyes")
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
AC_ARG_ENABLE(profile,
[AS_HELP_STRING([--enable-profile], [Compile with profiling support enabled], )],
[profile=$enableval], [profile="no"])
if test x"$profile" = x"yes"
then
CFLAGS="$CFLAGS -pg"
CPPFLAGS="$CPPFLAGS -pg"
fi
dnl checks for libraries
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.6.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.6.0)
AC_MSG_CHECKING([whether to enable direct DSP access for PDCH of sysmocom-bts])
AC_ARG_ENABLE(sysmocom-dsp,
AC_HELP_STRING([--enable-sysmocom-dsp],
[enable code for sysmocom DSP [default=no]]),
[enable_sysmocom_dsp="$enableval"],[enable_sysmocom_dsp="no"])
AC_MSG_RESULT([$enable_sysmocom_dsp])
AC_HELP_STRING([--enable-sysmocom-dsp],
[enable code for direct sysmocom DSP access[default=no]]),
[enable_sysmocom_dsp="$enableval"], [enable_sysmocom_dsp="unset"])
AC_ARG_WITH([sysmobts],
[AS_HELP_STRING([--with-sysmobts=INCLUDE_DIR],
[Location of the sysmobts API header files, implies --enable-sysmocom-dsp])],
[sysmobts_incdir="$withval"], [sysmobts_incdir=""])
if test "x$sysmobts_incdir" != "x"; then
# --with-sysmobts was passed, imply enable_sysmocom_dsp
if test "x$enable_sysmocom_dsp" = "xno"; then
AC_MSG_RESULT([error])
AC_MSG_ERROR([--with-sysmobts does not work with --disable-sysmocom-dsp])
fi
enable_sysmocom_dsp="yes"
# 'readlink' should make an absolute path, but must not return empty if the path does not exist,
# so we can still report on it below.
sysmobts_incdir="$(readlink -fm "$sysmobts_incdir")"
AC_SUBST([SYSMOBTS_INCDIR], $sysmobts_incdir)
AC_MSG_RESULT([yes, using -I$SYSMOBTS_INCDIR])
else
AC_SUBST([SYSMOBTS_INCDIR], "")
AC_MSG_RESULT([$enable_sysmocom_dsp])
fi
AM_CONDITIONAL(ENABLE_SYSMODSP, test "x$enable_sysmocom_dsp" = "xyes")
if test "x$enable_sysmocom_dsp" = "xyes"; then
oldCPPFLAGS="$CPPFLAGS"
_sysmobts_include=""
_sysmobts_include_msg=""
if test -n "$SYSMOBTS_INCDIR"; then
_sysmobts_include="-I$SYSMOBTS_INCDIR"
_sysmobts_include_msg=" in -I$SYSMOBTS_INCDIR"
fi
CPPFLAGS="$CPPFLAGS $_sysmobts_include -I$srcdir/include $LIBOSMOCORE_CFLAGS"
AC_CHECK_HEADER([sysmocom/femtobts/superfemto.h],[],
[AC_MSG_ERROR([sysmocom/femtobts/superfemto.h can not be found$_sysmobts_include_msg, see --with-sysmobts])],
[#include <sysmocom/femtobts/superfemto.h>])
CPPFLAGS="$oldCPPFLAGS"
fi
AC_MSG_CHECKING([whether to enable direct PHY access for PDCH of NuRAN Wireless Litecell 1.5 BTS])
AC_ARG_ENABLE(lc15bts-phy,
AC_HELP_STRING([--enable-lc15bts-phy],
[enable code for Litecell 1.5 PHY [default=no]]),
[enable_lc15bts_phy="$enableval"],[enable_lc15bts_phy="no"])
AC_ARG_WITH([litecell15], [AS_HELP_STRING([--with-litecell15=INCLUDE_DIR], [Location of the litecell 1.5 API header files])],
[litecell15_cflags="-I$withval"],[litecell15_cflags=""])
AC_SUBST([LITECELL15_CFLAGS], $litecell15_cflags)
AC_MSG_RESULT([$enable_lc15bts_phy])
AM_CONDITIONAL(ENABLE_LC15BTS_PHY, test "x$enable_lc15bts_phy" = "xyes")
if test "$enable_litecell15" = "yes"; then
oldCPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $LITECELL15_CFLAGS -I$srcdir/include $LIBOSMOCORE_CFLAGS"
AC_CHECK_HEADER([nrw/litecell15/litecell15.h],[],
[AC_MSG_ERROR([nrw/litecell15/litecell15.h can not be found using $litecell15_cflags])],
[#include <nrw/litecell15/litecell15.h>])
CPPFLAGS="$oldCPPFLAGS"
fi
AC_MSG_CHECKING([whether to enable direct PHY access for PDCH of NuRAN Wireless OC-2G BTS])
AC_ARG_ENABLE(oc2gbts-phy,
AC_HELP_STRING([--enable-oc2gbts-phy],
[enable code for OC-2G PHY [default=no]]),
[enable_oc2gbts_phy="$enableval"],[enable_oc2gbts_phy="no"])
AC_ARG_WITH([oc2g], [AS_HELP_STRING([--with-oc2g=INCLUDE_DIR], [Location of the OC-2G API header files])],
[oc2g_incdir="$withval"],[oc2g_incdir="$incdir"])
AC_SUBST([OC2G_INCDIR], $oc2g_incdir)
AC_MSG_RESULT([$enable_oc2gbts_phy])
AM_CONDITIONAL(ENABLE_OC2GBTS_PHY, test "x$enable_oc2gbts_phy" = "xyes")
if test "$enable_oc2g" = "yes"; then
oldCPPFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS -I$OC2G_INCDIR -I$srcdir/include $LIBOSMOCORE_CFLAGS"
AC_CHECK_HEADER([nrw/oc2g/oc2g.h],[],
[AC_MSG_ERROR([nrw/oc2g/oc2g.h can not be found in $oc2g_incdir])],
[#include <nrw/oc2g/oc2g.h>])
CPPFLAGS=$oldCPPFLAGS
fi
AC_ARG_ENABLE([vty_tests],
AC_HELP_STRING([--enable-vty-tests],
@@ -58,8 +182,80 @@ AC_MSG_CHECKING([whether to enable VTY tests])
AC_MSG_RESULT([$enable_vty_tests])
AM_CONDITIONAL(ENABLE_VTY_TESTS, test "x$enable_vty_tests" = "xyes")
STD_DEFINES_AND_INCLUDES="-Wall"
AC_SUBST(STD_DEFINES_AND_INCLUDES)
# Generate manuals
AC_ARG_ENABLE(manuals,
[AS_HELP_STRING(
[--enable-manuals],
[Generate manual PDFs [default=no]],
)],
[osmo_ac_build_manuals=$enableval], [osmo_ac_build_manuals="no"])
AM_CONDITIONAL([BUILD_MANUALS], [test x"$osmo_ac_build_manuals" = x"yes"])
AC_ARG_VAR(OSMO_GSM_MANUALS_DIR, [path to common osmo-gsm-manuals files, overriding pkg-config and "../osmo-gsm-manuals"
fallback])
if test x"$osmo_ac_build_manuals" = x"yes"
then
# Find OSMO_GSM_MANUALS_DIR (env, pkg-conf, fallback)
if test -n "$OSMO_GSM_MANUALS_DIR"; then
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from env)"
else
OSMO_GSM_MANUALS_DIR="$($PKG_CONFIG osmo-gsm-manuals --variable=osmogsmmanualsdir 2>/dev/null)"
if test -n "$OSMO_GSM_MANUALS_DIR"; then
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (from pkg-conf)"
else
OSMO_GSM_MANUALS_DIR="../osmo-gsm-manuals"
echo "checking for OSMO_GSM_MANUALS_DIR... $OSMO_GSM_MANUALS_DIR (fallback)"
fi
fi
if ! test -d "$OSMO_GSM_MANUALS_DIR"; then
AC_MSG_ERROR("OSMO_GSM_MANUALS_DIR does not exist! Install osmo-gsm-manuals or set OSMO_GSM_MANUALS_DIR.")
fi
# Find and run check-depends
CHECK_DEPENDS="$OSMO_GSM_MANUALS_DIR/check-depends.sh"
if ! test -x "$CHECK_DEPENDS"; then
CHECK_DEPENDS="osmo-gsm-manuals-check-depends"
fi
if ! $CHECK_DEPENDS; then
AC_MSG_ERROR("missing dependencies for --enable-manuals")
fi
# Put in Makefile with absolute path
OSMO_GSM_MANUALS_DIR="$(realpath "$OSMO_GSM_MANUALS_DIR")"
AC_SUBST([OSMO_GSM_MANUALS_DIR])
fi
# https://www.freedesktop.org/software/systemd/man/daemon.html
AC_ARG_WITH([systemdsystemunitdir],
[AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
[with_systemdsystemunitdir=auto])
AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
AS_IF([test "x$def_systemdsystemunitdir" = "x"],
[AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
[AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
with_systemdsystemunitdir=no],
[with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
[AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
AC_MSG_RESULT([CFLAGS="$CFLAGS"])
AC_MSG_RESULT([CXXFLAGS="$CXXFLAGS"])
AC_MSG_RESULT([LDFLAGS="$LDFLAGS"])
AC_OUTPUT(
include/Makefile
src/Makefile
examples/Makefile
doc/Makefile
doc/examples/Makefile
tests/Makefile
doc/manuals/Makefile
contrib/Makefile
contrib/systemd/Makefile
contrib/osmo-pcu.spec
Makefile)

1
contrib/Makefile.am Normal file
View File

@@ -0,0 +1 @@
SUBDIRS = systemd

107
contrib/jenkins.sh Executable file
View File

@@ -0,0 +1,107 @@
#!/bin/sh
# jenkins build helper script for osmo-pcu. This is how we build on jenkins.osmocom.org
#
# environment variables:
# * with_dsp: the DSP to configure ("sysmo", "lc15" or "none")
# * with_vty: enable VTY tests if set to "True"
# * WITH_MANUALS: build manual PDFs if set to "1"
# * PUBLISH: upload manuals after building if set to "1" (ignored without WITH_MANUALS = "1")
#
if ! [ -x "$(command -v osmo-build-dep.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
if [ -z "$MAKE" ]; then
echo 'The $MAKE variable is not defined, cannot build'
exit 1
fi
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
osmo-clean-workspace.sh
mkdir "$deps" || true
# Collect configure options for osmo-pcu
PCU_CONFIG=""
if [ "$with_dsp" = sysmo ]; then
PCU_CONFIG="$PCU_CONFIG --enable-werror --enable-sysmocom-dsp --with-sysmobts=$inst/include/"
# For direct sysmo DSP access, provide the SysmoBTS Layer 1 API
cd "$deps"
osmo-layer1-headers.sh sysmo
mkdir -p "$inst/include/sysmocom/femtobts"
ln -s $deps/layer1-headers/include/* "$inst/include/sysmocom/femtobts/"
cd "$base"
elif [ "$with_dsp" = lc15 ]; then
PCU_CONFIG="$PCU_CONFIG --enable-lc15bts-phy --with-litecell15=$deps/layer1-headers/inc"
cd "$deps"
osmo-layer1-headers.sh lc15 "$FIRMWARE_VERSION"
cd "$base"
elif [ "$with_dsp" = oc2g ]; then
PCU_CONFIG="$PCU_CONFIG --enable-oc2gbts-phy --with-oc2g=$deps/layer1-headers/inc"
cd "$deps"
osmo-layer1-headers.sh oc2g "$FIRMWARE_VERSION"
cd "$base"
elif [ -z "$with_dsp" -o "$with_dsp" = none ]; then
echo "Direct DSP access disabled, sanitizer enabled"
PCU_CONFIG="$PCU_CONFIG --enable-werror --enable-sanitize"
else
echo 'Invalid $with_dsp value:' $with_dsp
exit 1
fi
if [ "$with_vty" = "True" ]; then
PCU_CONFIG="$PCU_CONFIG --enable-vty-tests"
elif [ -z "$with_vty" -o "$with_vty" = "False" ]; then
echo "VTY tests disabled"
else
echo 'Invalid $with_vty value:' $with_vty
exit 1
fi
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
# Build deps
osmo-build-dep.sh libosmocore "" --disable-doxygen
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
export PATH="$inst/bin:$PATH"
if [ "$WITH_MANUALS" = "1" ]; then
PCU_CONFIG="$PCU_CONFIG --enable-manuals"
fi
set +x
echo
echo
echo
echo " =============================== osmo-pcu ==============================="
echo
set -x
autoreconf --install --force
./configure $PCU_CONFIG
$MAKE $PARALLEL_MAKE
DISTCHECK_CONFIGURE_FLAGS="$PCU_CONFIG" \
$MAKE $PARALLEL_MAKE distcheck \
|| cat-testlogs.sh
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
make -C "$base/doc/manuals" publish
fi
$MAKE $PARALLEL_MAKE maintainer-clean
osmo-clean-workspace.sh

83
contrib/osmo-pcu.spec.in Normal file
View File

@@ -0,0 +1,83 @@
#
# spec file for package osmo-pcu
#
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
Name: osmo-pcu
Version: @VERSION@
Release: 0
Summary: Osmocom GPRS Packet Control Unit (PCU)
License: GPL-2.0-only
Group: Productivity/Telephony/Servers
URL: https://osmocom.org/projects/osmopcu
Source: %{name}-%{version}.tar.xz
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: gcc-c++
BuildRequires: libtool
BuildRequires: pkgconfig >= 0.20
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libosmocore) >= 1.6.0
BuildRequires: pkgconfig(libosmogb) >= 1.6.0
BuildRequires: pkgconfig(libosmogsm) >= 1.6.0
BuildRequires: pkgconfig(libosmovty) >= 1.6.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.6.0
%{?systemd_requires}
%description
Osmocom PCU code (RLC/MAC/PCU) for OpenBTS and OsmoBTS.
%prep
%setup -q
%build
echo "%{version}" >.tarball-version
autoreconf -fi
%configure \
--enable-shared \
--disable-static \
--docdir=%{_docdir}/%{name} \
--with-systemdsystemunitdir=%{_unitdir}
make %{?_smp_mflags}
%install
%make_install
%if 0%{?suse_version}
%preun
%service_del_preun %{name}.service
%postun
%service_del_postun %{name}.service
%pre
%service_add_pre %{name}.service
%post
%service_add_post %{name}.service
%endif
%check
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%files
%license COPYING
%doc README.md
%doc %{_docdir}/%{name}/examples
%{_bindir}/osmo-pcu
%dir %{_sysconfdir}/osmocom
%config(noreplace) %{_sysconfdir}/osmocom/osmo-pcu.cfg
%{_unitdir}/%{name}.service
%changelog

View File

@@ -0,0 +1,6 @@
EXTRA_DIST = osmo-pcu.service
if HAVE_SYSTEMD
systemdsystemunit_DATA = \
osmo-pcu.service
endif

View File

@@ -0,0 +1,16 @@
[Unit]
Description=Osmocom osmo-pcu
[Service]
Type=simple
ExecStart=/usr/bin/osmo-pcu -c /etc/osmocom/osmo-pcu.cfg
Restart=always
RestartSec=2
RestartPreventExitStatus=1
# The msg queues must be read fast enough
CPUSchedulingPolicy=rr
CPUSchedulingPriority=1
[Install]
WantedBy=multi-user.target

1180
debian/changelog vendored Normal file

File diff suppressed because it is too large Load Diff

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
9

46
debian/control vendored Normal file
View File

@@ -0,0 +1,46 @@
Source: osmo-pcu
Section: net
Priority: optional
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Build-Depends: debhelper (>= 9),
dh-autoreconf,
autotools-dev,
pkg-config,
libosmocore-dev (>= 1.6.0),
osmo-gsm-manuals-dev (>= 1.2.0)
Standards-Version: 3.9.8
Homepage: http://osmocom.org/projects/osmopcu
Vcs-Git: git://git.osmocom.org/osmo-pcu
Vcs-Browser: http://git.osmocom.org/osmo-pcu/
Package: osmo-pcu
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Osmocom GPRS/EDGE Packet Control Unit (PCU)
The GPRS Packet Control Unit is co-located with the GSM BTS or GSM BSC
in order to provide packet-switched services for 2G (2.5G, 2.75G)
networks. OsmoPCU is the Osmocom implementation of this network
element. It interfaces to osmo-bts via the PCU socket of OsmoBTS
and via Gb (NS-over-IP) interface with the SGSN such as OsmoSGSN.
Package: osmo-pcu-dbg
Architecture: any
Section: debug
Priority: extra
Depends: osmo-pcu (= ${binary:Version}),
${misc:Depends}
Description: Debug symbols for the Osmocom GPRS/EDGE Packet Control Unit (PCU)
The GPRS Packet Control Unit is co-located with the GSM BTS or GSM BSC
in order to provide packet-switched services for 2G (2.5G, 2.75G)
networks. OsmoPCU is the Osmocom implementation of this network
element. It interfaces to osmo-bts via the PCU socket of OsmoBTS
and via Gb (NS-over-IP) interface with the SGSN such as OsmoSGSN.
Package: osmo-pcu-doc
Architecture: all
Section: doc
Priority: optional
Depends: ${misc:Depends}
Description: ${misc:Package} PDF documentation
Various manuals: user manual, VTY reference manual and/or
protocol/interface manuals.

133
debian/copyright vendored Normal file
View File

@@ -0,0 +1,133 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: osmo-pcu
Source: git://git.osmocom.org/osmo-pcu
Files-Excluded: debian
Files: *
Copyright: 2009-2015 Holger Hans Peter Freyther <zecke@selfish.org>
2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
2016-2019 sysmocom s.m.f.c. GmbH <info@sysmocom.de>
2015 by Yves Godin <support@nuranwireless.com>
License: AGPL-3.0+
Files: src/gprs_ms_storage.h
src/gprs_ms_storage.cpp
src/gprs_ms.h
src/gprs_coding_scheme.cpp
src/gprs_coding_scheme.h
src/coding_scheme.c
src/coding_scheme.h
src/cxx_linuxlist.h
src/pcu_vty_functions.cpp
src/pcu_vty_functions.h
src/pcu_utils.h
src/gprs_codel.c
src/gprs_codel.h
Copyright: 2016-2019 sysmocom s.m.f.c. GmbH <info@sysmocom.de>
License: GPL-2.0+
Files: osmoappdesc.py
Copyright: 2013 by Katerina Barone-Adesi <kat.obsc@gmail.com>
License: GPL-3.0+
Files: src/gprs_debug.cpp
src/gprs_debug.h
src/pcu_main.cpp
src/pcu_l1_if.h
Copyright: 2012 Ivan Klyuchnikov
License: GPL-2.0+
Files: src/tbf.cpp
src/tbf_ul.cpp
src/tbf_dl.cpp
src/sba.cpp
src/sba.h
src/llc.cpp
src/encoding.cpp
src/encoding.h
src/gprs_rlcmac.cpp
src/gprs_rlcmac_ts_alloc.cpp
Copyright: 2012 Ivan Klyuchnikov
2012 Andreas Eversberg <jolly@eversberg.eu>
2013 by Holger Hans Peter Freyther
License: GPL-2.0+
Files: src/gprs_rlcmac.h
src/gprs_bssgp_pcu.cpp
src/gprs_bssgp_pcu.h
src/bts.h
Copyright: 2012 Ivan Klyuchnikov
2013 by Holger Hans Peter Freyther
License: GPL-2.0+
Files: src/rlc.h
src/decoding.cpp
src/decoding.h
Copyright: 2012 Ivan Klyuchnikov
2012 Andreas Eversberg <jolly@eversberg.eu>
License: GPL-2.0+
Files: src/rlc.cpp
src/llc.h
src/tbf.h
Copyright: 2013 by Holger Hans Peter Freyther
License: GPL-2.0+
Files: src/pcu_l1_if.cpp
src/gprs_rlcmac_meas.cpp
src/gprs_rlcmac_sched.cpp
src/osmobts_sock.cpp
Copyright: 2012 Andreas Eversberg <jolly@eversberg.eu>
License: GPL-2.0+
Files: src/csn1.h
src/csn1.c
src/csn1_dec.c
src/csn1_enc.c
src/gsm_rlcmac.cpp
src/gsm_rlcmac.h
Copyright: 2011 Vincent Helfre
2011 ST-Ericsson (Jari Sassi)
License: GPL-2.0+
License: AGPL-3.0+
All rights not specifically granted under this license are 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.
License: GPL-3.0+
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/>.
.
On Debian systems, the complete text of the GNU General Public License
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
License: GPL-2.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, 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'.

1
debian/osmo-pcu-doc.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/share/doc/osmo-pcu-doc/*.pdf

4
debian/osmo-pcu.install vendored Normal file
View File

@@ -0,0 +1,4 @@
etc/osmocom/osmo-pcu.cfg
lib/systemd/system/osmo-pcu.service
usr/bin/osmo-pcu
usr/share/doc/osmo-pcu/examples/osmo-pcu/osmo-pcu.cfg

31
debian/rules vendored Executable file
View File

@@ -0,0 +1,31 @@
#!/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-pcu-dbg
override_dh_clean:
dh_clean
$(RM) tests/package.m4
$(RM) test/testsuite
# Print test results in case of a failure
override_dh_auto_test:
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
override_dh_auto_configure:
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
override_dh_compress:
dh_compress -X.pdf

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (native)

4
doc/Makefile.am Normal file
View File

@@ -0,0 +1,4 @@
SUBDIRS = \
examples \
manuals \
$(NULL)

7
doc/examples/Makefile.am Normal file
View File

@@ -0,0 +1,7 @@
examples_pcudir = $(docdir)/examples/osmo-pcu
examples_pcu_DATA = osmo-pcu.cfg
osmoconfdir = $(sysconfdir)/osmocom
osmoconf_DATA = osmo-pcu.cfg
EXTRA_DIST = osmo-pcu.cfg

View File

@@ -1,6 +1,5 @@
pcu
flow-control-interval 10
cs 4
alloc-algorithm b
alpha 0
cs 2
alloc-algorithm dynamic
gamma 0

28
doc/manuals/Makefile.am Normal file
View File

@@ -0,0 +1,28 @@
EXTRA_DIST = osmopcu-gb.adoc \
osmopcu-gb-docinfo.xml \
osmopcu-usermanual.adoc \
osmopcu-usermanual-docinfo.xml \
osmopcu-vty-reference.xml \
regen_doc.sh \
chapters \
gb \
vty
if BUILD_MANUALS
ASCIIDOC = osmopcu-usermanual.adoc osmopcu-gb.adoc
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
osmopcu-gb.pdf: $(srcdir)/gb/*.adoc $(srcdir)/gb/*.msc
osmopcu-usermanual.pdf: $(srcdir)/chapters/*.adoc
VTY_REFERENCE = osmopcu-vty-reference.xml
BUILT_REFERENCE_XML = $(builddir)/vty/pcu_vty_reference.xml
$(builddir)/vty/pcu_vty_reference.xml: $(top_builddir)/src/osmo-pcu
mkdir -p $(builddir)/vty
$(top_builddir)/src/osmo-pcu --vty-ref-xml > $@
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
OSMO_REPOSITORY = osmo-pcu
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
endif

View File

@@ -0,0 +1,492 @@
== Configuring OsmoPCU
Contrary to other network elements (like OsmoBSC, OsmoNITB), the
OsmoPCU has a relatively simple minimum configuration.
This is primarily because most of the PCU configuration happens
indirectly from the BSC, who passes the configuation over A-bis OML via
OsmoBTS and its PCU socket into OsmoPCU.
A minimal OsmoPCU configuration file is provided below for your reference:
.Example: Minimal OsmoPCU configuration file (`osmo-pcu.cfg`)
----
pcu
flow-control-interval 10 <1>
cs 2 <2>
alloc-algorithm dynamic <3>
gamma 0
----
<1> send a BSSGP flow-control PDU every 10 seconds
<2> start a TBF with the initial coding scheme 2
<3> dynamically chose between single-slot or multi-slot TBF allocations
depending on system load
However, there are plenty of tuning parameters for people interested to
optimize PCU throughput or latency according to their requirements.
=== Configuring the Coding Schemes and Rate Adaption
As a reminder:
- GPRS supports Coding Schemes 1-4 (CS1-4), all of them use GMSK modulation
(same as GSM).
- EGPRS supports MCS1-9, where MCS1-4 is GMSK, and MCS5-9 use 8-PSK modulation.
The range of Coding Schemes above only apply to RLCMAC data blocks; RLCMAC
control blocks are always transmitted with CS1 (GMSK). Hence, CS1 is always
supported and must be always permitted.
The BSC includes a bit-mask of permitted [E]GPRS coding schemes as part of the
A-bis OML configuration, controlled by VTY `gprs mode (none|gprs|egprs)`. This
is passed from the BTS via the PCU socket into OsmoPCU, and the resulting set
can be further constrained by OsmoPCU VTY configuration.
Some additional OsmoPCU parameters can be set as described below.
==== Initial Coding Scheme
You can use the `cs <1-4> [<1-4>]` command at the `pcu` VTY config node
to set the initial GPRS coding scheme to be used. The optional second
value allows to specify a different initial coding scheme for uplink.
Similarly, `mcs <1-9> [<1-9>]` can be used to set up the initial EGPRS coding
scheme.
[[max_cs_mcs]]
==== Maximum Coding Scheme
You can use the `cs max <1-4> [<1-4>]` command at the `pcu` VTY config
node to set the maximum GPRS coding scheme that should be used as part of the
rate adaption. The optional second value allows to specify a different maximum
coding scheme for uplink.
Similarly, `mcs max <1-9> [<1-9>]` can be used to set up the maximum EGPRS
coding scheme.
The actual Maximum Coding Scheme for each direction used at runtime is actually
the result of taking the maximum value from the permitted GPRS coding schemes
received by the BSC (or BTS) over PCUIF which is equal or lower tho the
configured value.
Example: PCUIF announces permitted MCS bit-mask (`MCS1 MCS2 MCS3 MCS4`) and
OsmoPCU is configured `mcs max 6`, then the actual maximum MCS used at runtime
will be `MCS4`.
==== Rate Adaption Error Thresholds
You can use the `cs threshold <0-100> <0-100>` command at the `pcu` VTY
config node to determine the upper and lower limit for the error rate
percentage to use in the rate adaption. If the upper threshold is
reached, a lower coding sheme is chosen, and if the lower threshold is
reached, a higher coding scheme is chosen.
==== Rate Adation Link Quality Thresholds
You can use the `cs link-quality-ranges cs1 <0-35> cs2 <0-35> <0-35> cs3
<0-35> <0-35> cs4 <0-35>` command at the `pcu` VTY config node to tune
the link quality ranges for the respective coding schemes.
==== Data Size based CS downgrade Threshold
You can use the `cs downgrade-threshold <1-10000>` command at the `pcu`
VTY config node to ask the PCU to down-grade the coding scheme if less
than the specified number of octets are left to be transmitted.
=== Miscellaneous Configuration / Tuning Parameters
==== Downlink TBF idle time
After a down-link TBF is idle (all data in the current LLC downlink
queue for the MS has been transmitted), we can keep the TBF established
for a configurable time. This avoids having to go through a new one or
two phase TBF establishment once the next data for downlink arrives.
You can use the `dl-tbf-idle-time <1-5000>` to specify that time in
units of milli-seconds. The default is 2 seconds.
==== MS idle time
Using the `ms-idle-time <1-7200>` command at the `pcu` VTY config node
you can configure the number of seconds for which the PCU should keep
the MS data structure alive before releasing it if there are no active
TBF for this MS.
The OsmoPCU default value is 60 seconds, which is slightly more than
what 3GPP TS 24.008 recommends for T3314 (44s).
The MS data structure only consumes memory in the PCU and does not
require any resources of the air interface.
==== Forcing two-phase access
If the MS is using a single-phase access, you can still force it to
use a two-phase access using the `two-phase-access` VTY configuration
command at the `pcu` VTY config node.
=== Configuring BSSGP flow control
BSSGP between SGSN and PCU contains a two-level nested flow control
mechanism:
. one global flow control instance for the overall (downlink) traffic
from the SGSN to this PCU
. a per-MS flow control instance for each individual MS served by this
PCU
Each of the flow control instance is implemented as a TBF (token bucket
filter).
==== Normal BSSGP Flow Control Tuning parameters
You can use the following commands at the `pcu` VTY config node to tune
the BSSGP flow control parameters:
`flow-control-interval <1-10>`::
configure the interval (in seconds) between subsequent flow
control PDUs from PCU to SGSN
`flow-control bucket-time <1-65534>`::
set the target downlink maximum queueing time in centi-seconds.
The PCU will attempt to adjust the advertised bucket size to match this
target.
==== Extended BSSGP Flow Control Tuning parameters
There are some extended flow control related parameters at the `pcu` VTY
config node that override the automatic flow control as specified in the
BSSGP specification. Use them with care!
`flow-control force-bvc-bucket-size <1-6553500>`::
force the BVC (global) bucket size to the given number of octets
`flow-control force-bvc-leak-rate <1-6553500>`::
force the BVC (global) bucket leak rate to the given number of bits/s
`flow-control force-ms-bucket-size <1-6553500>`::
force the per-MS bucket size to the given number of octets
`flow-control force-ms-leak-rate <1-6553500>`::
force the per-MS bucket leak rate to the given number of bits/s
=== Configuring LLC queue
The downlink LLC queue in the PCU towards the MS can be tuned with a
variety of parameters at the `pcu` VTY config node, depending on your
needs.
`queue lifetime <1-65534>`::
Each downlink LLC PDU is assigned a lifetime by the SGSN, which
is respected by the PDU *unless* you use this command to
override the PDU lifetime with a larger value (in centi-seconds)
`queue lifetime infinite`::
Never drop LLC PDUs, i.e. give them an unlimited lifetime.
`queue hysteresis <1-65535>`::
When the downlink LLC queue is full, the PCU starts dropping
packets. Using this parameter, we can set the lifetime
hysteresis in centi-seconds, i.e. it will continue discarding
until "lifetime - hysteresis" is reached.
`queue codel`::
Use the 'CoDel' (Controlled Delay) scheduling algorithm, which
is designed to overcome buffer bloat. It will use a default
interval of 4 seconds.
`queue codel interval <1-1000>`::
Use the 'CoDel' (Controlled Delay) scheduling algorithm, which
is designed to overcome buffer bloat. Use the specified
interval in centi-seconds.
`queue idle-ack-delay <1-65535>`::
Delay the request for an ACK after the last downlink LLC frame
by the specified amount of centi-seconds.
=== Configuring MS power control
GPRS MS power control works completely different than the close MS power
control loop in circuit-switched GSM.
Rather than instructing the MS constantly about which transmit power to
use, some parameters are provided to the MS by which the MS-based power
control algorithm is tuned.
See 3GPP TS 05.08 for further information on the algorithm and the
parameters.
You can set those parameters at the `pcu` VTY config node as follows:
`gamma <0-62>`::
Set the gamma parameter for MS power control in units of dB.
Parameter `ALPHA` is set on the BSC VTY configuration file on a per-BTS basis,
and forwarded by OsmoPCU to the MS through the SI13 received from the former
over PCUIF. OsmoPCU VTY command `alpha <0-10>` overrides the value received over
PCUIF to keep backward compatibility with existing config files, but it is
currently deprecated and its use is discouraged; one should configure it per-BTS
in OsmoBSC VTY instead.
=== Configuring Network Assisted Cell Change (NACC)
Network Assisted Cell Change, defined in 3GPP TS 44.060 sub-clause 8.8, is a
feature providing the MS aid when changing to a new cell due to autonomous
reselection. In summary, the MS informs the current cell its intention to change
to a new target cell, and the network decides whether to grant the intended cell
change or order a change to another neighbor cell. It also provides several
System Informations of the target cell to the MS to allow for quicker
reselection towards it.
OsmoPCU will automatically provide the required neighbor System Information when
the MS requests NACC towards a target cell also under the management of the same
OsmoPCU instance, since it already has the System Information of all BTS under
their control, obtained through PCUIF when the BTS registers against OsmoPCU, so
no specific user configuration is required here.
In general, OsmoPCU requires to gather the information from somewhere else
before being able to provide it to the MS requesting the NACC.
If OsmoPCU fails to gather the System Information, it will simply answer the MS
allowing the proposed changed but without previously providing the System
Information of the target cell.
==== Neighbor Address Resolution
First of all, it needs to translate the <ARFCN + BSIC> identity of the target
cell to change to, provided by the MS, into an identity that the Core Network
can use and understand to identify the target cell, which happens to be a key
composed of <RAI + Cell Identity>. This key is also named conveniently as
CGI-PS, since it actually equals to the Circuit Switch CGI + RAC.
In order to apply this target cell identity translation, OsmoPCU uses the
OsmoBSC Neighbor Resolution Service. This service is nowadays provided by means
of PCUIF container messages, which are transparently forwarded in both directions
by the BTS using the IPA multiplex of the OML connection against the BSC. No
specific configuration is required in any of the involved nodes, they should
behave properly out of the box.
These neighbor address resolutions (<ARFCN + BSIC> => <RAI + CI>) are by default
cached for a while, in order to avoid querying the BSC frequently. As a result,
the resolution time is also optimized.
.Example: Configure Neighbor Resolution cache and timeouts
----
pcu
timer X1 500 <1>
timer X0 60 <2>
----
<1> Time out if the BSC doesn't answer our resolution request after 500 ms
<2> Keep resolved neighbor addresses cached for 60 seconds
===== OsmoBSC CTRL interface (deprecated)
CAUTION: This interface is nowadays considered deprecated and should not be used
anymore. Any related VTY options should be dropped from configuration files, to
let OsmoPCU use the new interface instead. This section is kept here for a while
as a reference for old deployments using old versions of the programs.
This Neighbor Address Resolution Service was initially implemented by means of a
separate CTRL interface (see OsmoBSC User Manual), where OsmoPCU would create a
CTRL connection to the BSC each time an address resolution was required.
Older versions of OsmoBSC may not support the current Neighbor Address
Resolution Service over the IPA multiplex (see above). For those cases, OsmoPCU
can be configured to use the old deprecated CTRL interface.
By default, the use of this interface is not configured and hence disabled in
OsmoPCU. As a result, until configured, the network won't be able to provide the
System Information to the MS prior to allowing the change during NACC against
remote cells, which means the cell change will take longer to complete. In order
to configure the interface, the OsmoBSC IP address and port to connect to must
be configured in OsmoPCU VTY.
.Example: Configure Neighbor Resolution CTRL interface against OsmoBSC
----
pcu
neighbor resolution 172.18.13.10 4248 <1>
----
<1> Port 4248 is the default and hence could be omitted in this case
==== System Information Resolution
Once OsmoPCU gains knowledge of the target cell's address in the Core Network,
it can query its System Information.
OsmoPCU will gather the requested System Information of target cells under its
control without need for any external query, since the System Information of all
BTSs it manages are received over PCUIF and stored internally in OsmoPCU.
For those targets cells not managed by the OsmoPCU instance, the query is
accomplished by using RIM procedures (NACC RAN-INFO application) over the Gb
interface against the SGSN that OsmoPCU is connected to. In its turn, the SGSN
will potentially forward this query to the PCU serving the target cell, which
will provide back the System Information of that cell.
The System Information received from external PCUs over RIM are by default
cached for a while in order to avoid querying the SGSN frequently and, as a
result, optimizing the resolution time too.
.Example: Configure System Information resolution
----
pcu
timer X2 500 <1>
timer X11 60 <2>
----
<1> Time out if the SGSN doesn't answer our RIM RAN-INFO request request after 500 ms
<2> Keep resolved remote neighbor System Information cached for 60 seconds
=== GPRS vs EGPRS considerations
==== Configuration
OsmoPCU can be configured to either:
- Allocate only GPRS TBFs to all MS (no EGPRS)
- Allocate EGPRS TBFs to EGPRS capable phones while still falling back to
allocating GPRS TBFs on GPRS-only capable MS.
These two different modes of operation are selected by properly configuring the
Coding Schemes (see <<max_cs_mcs>>).
The first mode of operation (GPRS-only for all MS) can be accomplished
configuring OsmoPCU so that the resulting MCS set is empty. This can be done in
two ways:
- Announcing an empty MCS bit-mask over PCUIF to OsmoPCU:
That's actually done automatically by OsmoBSC on BTS with VTY config set to
`gprs mode gprs`.
- Configuring OsmoPCU to force an empty set by using VTY command `mcs max 0`.
Hence, if the resulting MCS bit-mask is not empty, (BSC configuring the BTS with
`gprs mode egprs` and OsmoPCU VTY containing something other than 'mcs max 0'),
EGPRS TBFs will be allocated for all MS announcing EGPRS capabilities.
It is important to remark that in order to use MCS5-9, the BTS must support
8-PSK modulation. Nevertheless, in case 8-PSK is not supported by the BTS, one
can still enable EGPRS and simply make sure 8-PSK MCS are never used by
configuring OsmoPCU with `mcs max 4 4`.
Similarly, a BTS may support 8-PSK modulation only on downlink, since it is
easier to implement than the uplink, together with the fact that higher downlink
throughput is usually more interesting from user point of view. In this
scenario, OsmoPCU can be configured to allow for full MCS range in downlink
while still preventing use of 8-PSK on the uplink: `mcs max 9 4`.
Some other interesting configurations to control use of EGPRS in the network
which lay outside OsmoPCU include:
- If `osmo-bts-trx` together with `osmo-trx` is used, remember to enable EGPRS
support (OsmoTRX VTY `egprs enable`).
- It is possible to improve EGPRS performance (in particular, the TBF
establishment timing) a bit by enabling 11-bit Access Burst support. This
allows EGPRS capable phones to indicate their EGPRS capability, establishment
cause, and multi-slot class directly in the Access Burst (OsmoTRX VTY
`ext-rach enable`, OsmoBSC VTY `gprs egprs-packet-channel-request`).
NOTE: If you enable MCS5-9 you will also need an 8-PSK capable OsmoBTS+PHY,
which means `osmo-bts-sysmo` or `osmo-bts-litecell15` with their associated PHY,
or `osmo-bts-trx` with `osmo-trx` properly configured.
==== GPRS+EGPRS multiplexing
Both EGPRS and GPRS-only capable MS can be driven concurrently in the same PDCH
timeslot by the PCU, hence no special configuration is required per timeslot
regarding this topic; OsmoPCU scheduler takes care of the specific requirements
when driving MS with different capabilities.
These specific requirements translate to some restrictions regarding which
Coding Schemes can be used at given frame numbers, and hence which kind of
RLCMAC blocks can be sent, which means serving a GPRS-only MS in a PDCH may end
up affecting slightly the downlink throughput of EGPRS capable MS.
Throughput loss based on MS capabilities with TBF attached to a certain PDCH
timeslot:
All UEs are EGPRS capable::
No throughput loss, since all data is sent using EGPRS, and EGPRS control
messages are used when appropriate.
All UEs are GPRS-only (doesn't support EGPRS)::
No throughput loss, since all data and control blocks use GPRS.
Some UEs are GPRS-only, some EGPRS::
In general EGPRS capable UEs will use EGPRS, and GPRS-only UEs will use GPRS,
with some restrictions affecting throughput of EGPRS capable UEs:
- Whenever a GPRS-only MS is to be polled to send uplink data to PCU, then a
downlink RLCMAC block modulated using GMSK must be sent, which means that if the
scheduler selects a EGPRS MS for downlink on that block it will force sending of
data with MCS1-4 (if it's new data, if it's a retransmission it cannot be
selected since MCS from original message cannot be changed). In the worst case
if no control block needs to be sent or no new data in MCS1-4 is available to
send, then an RLCMAC Dummy Block is sent.
- For synchronization purposes, each MS needs to receive an RLCMAC block which
it can fully decode at least every 360ms, which means the scheduler must enforce
a downlink block in CS1-4 every 360ms, that is, every 18th RLCMAC block. In
general this is not a big issue since anyway all control RLCMAC blocks are
encoded in CS1, so in case any control block is sent from time to time it's
accomplished and there's no penalty. However, if only EGPRS downlink data is sent
over that time frame, then the scheduler will force sending a RLCMAC Dummy
Block.
[[gsmtap]]
=== Configuring GSMTAP tracing
In addition to being able to obtain pcap protocol traces of the NS/BSSGP
communication and the text-based logging from the OsmoPCU software, there is
also the capability of tracing all communication on the radio interface related
to PS. To do so, OsmoPCU can encapsulate MAC blocks (23-155 byte messages at the
L2-L1 interface depending on coding scheme) into _GSMTAP_ and send them via
UDP/IP. At that point, they can be captured with utilities like *tcpdump* or
*tshark* for further analysis by the *wireshark* protocol analyzer.
In order to activate this feature, you first need to make sure to specify
the remote address of _GSMTAP_ host in the configuration file. In most
cases, using 127.0.0.1 for passing the messages over the loopback (`lo`)
device will be sufficient:
.Example: Enabling GSMTAP Um-frame logging to localhost
----
pcu
gsmtap-remote-host 127.0.0.1 <1>
----
<1> Destination address for _GSMTAP_ Um-frames
NOTE: Changing this parameter at run-time will not affect the existing
_GSMTAP_ connection, full program restart is required.
NOTE: Command line parameters `-i` and `--gsmtap-ip` have been deprecated.
OsmoPCU can selectively trace such messages based on different categories, for
both Ul and Dl. For a complete list of cateogry values, please refer to the
_OsmoPCU VTY reference manual_ <<vty-ref-osmopcu>>.
For example, to enable GSMTAP tracing for all DL EGPRS rlcmac data blocks, you
can use the `gsmtap-category dl-data-egprs` command at the `pcu` node of the
OsmoPCU VTY.
.Example: Enabling GSMTAP for for all DL EGPRS rlcmac data blocks
----
OsmoPCU> enable
OsmoPCU# configure terminal
OsmoPCU(config)# pcu
OsmoPCU(pcu)# gsmtap-category dl-data-egprs
OsmoPCU(trx)# write <1>
----
<1> the `write` command will make the configuration persistent in the
configuration file. This is not required if you wish to enable GSMTAP
only in the current session of OsmoPCU.
De-activation can be performed similarly by using the `no gsmtap-category
dl-data-egprs` command at the `pcu` node of the OsmoPCU VTY.
It may be useful to enable all categories with a few exceptions, or vice versa
disable everything using one command. For this purpose, the VTY provides
`gsmtap-category enable-all` and `gsmtap-category disable-all` commands.
.Example: Enabling all categoriess except _dl-dummy_
----
pcu
gsmtap-category enable-all <1>
no gsmtap-category dl-dummy <2>
----
<1> Enable all available SAPIs
<2> Exclude DL RLCMAC blocks
From the moment they are enabled via VTY, GSMTAP messages will be
generated and sent in UDP encapsulation to the IANA-registered UDP port
for GSMTAP (4729) of the specified remote address.

View File

@@ -0,0 +1,4 @@
[[counters]]
== Counters
include::./counters_generated.adoc[]

View File

@@ -0,0 +1,208 @@
// autogenerated by show asciidoc counters
These counters and their description are based on OsmoPCU 0.9.0.244-de96 (OsmoPCU).
=== Rate Counters
// generating tables for rate_ctr_group
// rate_ctr_group table NSVC Peer Statistics
.ns:nsvc - NSVC Peer Statistics
[options="header"]
|===
| Name | Reference | Description
| packets:in | <<ns:nsvc_packets:in>> | Packets at NS Level ( In)
| packets:out | <<ns:nsvc_packets:out>> | Packets at NS Level (Out)
| packets:out:drop | <<ns:nsvc_packets:out:drop>> | Dropped Packets (Out)
| bytes:in | <<ns:nsvc_bytes:in>> | Bytes at NS Level ( In)
| bytes:out | <<ns:nsvc_bytes:out>> | Bytes at NS Level (Out)
| bytes:out:drop | <<ns:nsvc_bytes:out:drop>> | Dropped Bytes (Out)
| blocked | <<ns:nsvc_blocked>> | NS-VC Block count
| unblocked | <<ns:nsvc_unblocked>> | NS-VC Unblock count
| dead | <<ns:nsvc_dead>> | NS-VC gone dead count
| replaced | <<ns:nsvc_replaced>> | NS-VC replaced other count
| nsei-chg | <<ns:nsvc_nsei-chg>> | NS-VC changed NSEI count
| inv-nsvci | <<ns:nsvc_inv-nsvci>> | NS-VCI was invalid count
| inv-nsei | <<ns:nsvc_inv-nsei>> | NSEI was invalid count
| lost:alive | <<ns:nsvc_lost:alive>> | ALIVE ACK missing count
| lost:reset | <<ns:nsvc_lost:reset>> | RESET ACK missing count
|===
// rate_ctr_group table NSE Peer Statistics
.ns:nse - NSE Peer Statistics
[options="header"]
|===
| Name | Reference | Description
| packets:in | <<ns:nse_packets:in>> | Packets at NS Level ( In)
| packets:out | <<ns:nse_packets:out>> | Packets at NS Level (Out)
| packets:out:drop | <<ns:nse_packets:out:drop>> | Dropped Packets (Out)
| bytes:in | <<ns:nse_bytes:in>> | Bytes at NS Level ( In)
| bytes:out | <<ns:nse_bytes:out>> | Bytes at NS Level (Out)
| bytes:out:drop | <<ns:nse_bytes:out:drop>> | Dropped Bytes (Out)
| blocked | <<ns:nse_blocked>> | NS-VC Block count
| unblocked | <<ns:nse_unblocked>> | NS-VC Unblock count
| dead | <<ns:nse_dead>> | NS-VC gone dead count
| replaced | <<ns:nse_replaced>> | NS-VC replaced other count
| nsei-chg | <<ns:nse_nsei-chg>> | NS-VC changed NSEI count
| inv-nsvci | <<ns:nse_inv-nsvci>> | NS-VCI was invalid count
| inv-nsei | <<ns:nse_inv-nsei>> | NSEI was invalid count
| lost:alive | <<ns:nse_lost:alive>> | ALIVE ACK missing count
| lost:reset | <<ns:nse_lost:reset>> | RESET ACK missing count
|===
// rate_ctr_group table SGSN Statistics
.pcu:sgsn - SGSN Statistics
[options="header"]
|===
| Name | Reference | Description
| rx_paging_cs | <<pcu:sgsn_rx_paging_cs>> | Amount of paging CS requests received
| rx_paging_ps | <<pcu:sgsn_rx_paging_ps>> | Amount of paging PS requests received
|===
// rate_ctr_group table BSSGP Peer Statistics
.bssgp:bss_ctx - BSSGP Peer Statistics
[options="header"]
|===
| Name | Reference | Description
| packets:in | <<bssgp:bss_ctx_packets:in>> | Packets at BSSGP Level ( In)
| packets:out | <<bssgp:bss_ctx_packets:out>> | Packets at BSSGP Level (Out)
| bytes:in | <<bssgp:bss_ctx_bytes:in>> | Bytes at BSSGP Level ( In)
| bytes:out | <<bssgp:bss_ctx_bytes:out>> | Bytes at BSSGP Level (Out)
| blocked | <<bssgp:bss_ctx_blocked>> | BVC Blocking count
| discarded | <<bssgp:bss_ctx_discarded>> | BVC LLC Discarded count
| status | <<bssgp:bss_ctx_status>> | BVC Status count
|===
// rate_ctr_group table BTS Statistics
.bts - BTS Statistics
[options="header"]
|===
| Name | Reference | Description
| tbf:dl:alloc | <<bts_tbf:dl:alloc>> | TBF DL Allocated
| tbf:dl:freed | <<bts_tbf:dl:freed>> | TBF DL Freed
| tbf:dl:aborted | <<bts_tbf:dl:aborted>> | TBF DL Aborted
| tbf:ul:alloc | <<bts_tbf:ul:alloc>> | TBF UL Allocated
| tbf:ul:freed | <<bts_tbf:ul:freed>> | TBF UL Freed
| tbf:ul:aborted | <<bts_tbf:ul:aborted>> | TBF UL Aborted
| tbf:reused | <<bts_tbf:reused>> | TBF Reused
| tbf:alloc:algo-a | <<bts_tbf:alloc:algo-a>> | TBF Alloc Algo A
| tbf:alloc:algo-b | <<bts_tbf:alloc:algo-b>> | TBF Alloc Algo B
| tbf:alloc:failed | <<bts_tbf:alloc:failed>> | TBF Alloc Failure (any reason)
| tbf:alloc:failed:no_tfi | <<bts_tbf:alloc:failed:no_tfi>> | TBF Alloc Failure (TFIs exhausted)
| tbf:alloc:failed:no_usf | <<bts_tbf:alloc:failed:no_usf>> | TBF Alloc Failure (USFs exhausted)
| tbf:alloc:failed:no_slot_combi | <<bts_tbf:alloc:failed:no_slot_combi>> | TBF Alloc Failure (No valid UL/DL slot combination found)
| tbf:alloc:failed:no_slot_avail | <<bts_tbf:alloc:failed:no_slot_avail>> | TBF Alloc Failure (No slot available)
| rlc:sent | <<bts_rlc:sent>> | RLC Sent
| rlc:resent | <<bts_rlc:resent>> | RLC Resent
| rlc:restarted | <<bts_rlc:restarted>> | RLC Restarted
| rlc:stalled | <<bts_rlc:stalled>> | RLC Stalled
| rlc:nacked | <<bts_rlc:nacked>> | RLC Nacked
| rlc:final_block_resent | <<bts_rlc:final_block_resent>> | RLC Final Blk resent
| rlc:ass:timedout | <<bts_rlc:ass:timedout>> | RLC Assign Timeout
| rlc:ass:failed | <<bts_rlc:ass:failed>> | RLC Assign Failed
| rlc:ack:timedout | <<bts_rlc:ack:timedout>> | RLC Ack Timeout
| rlc:ack:failed | <<bts_rlc:ack:failed>> | RLC Ack Failed
| rlc:rel:timedout | <<bts_rlc:rel:timedout>> | RLC Release Timeout
| rlc:late-block | <<bts_rlc:late-block>> | RLC Late Block
| rlc:sent-dummy | <<bts_rlc:sent-dummy>> | RLC Sent Dummy
| rlc:sent-control | <<bts_rlc:sent-control>> | RLC Sent Control
| rlc:dl_bytes | <<bts_rlc:dl_bytes>> | RLC DL Bytes
| rlc:dl_payload_bytes | <<bts_rlc:dl_payload_bytes>> | RLC DL Payload Bytes
| rlc:ul_bytes | <<bts_rlc:ul_bytes>> | RLC UL Bytes
| rlc:ul_payload_bytes | <<bts_rlc:ul_payload_bytes>> | RLC UL Payload Bytes
| decode:errors | <<bts_decode:errors>> | Decode Errors
| sba:allocated | <<bts_sba:allocated>> | SBA Allocated
| sba:freed | <<bts_sba:freed>> | SBA Freed
| sba:timedout | <<bts_sba:timedout>> | SBA Timeout
| llc:timeout | <<bts_llc:timeout>> | Timedout Frames
| llc:dropped | <<bts_llc:dropped>> | Dropped Frames
| llc:scheduled | <<bts_llc:scheduled>> | Scheduled Frames
| llc:dl_bytes | <<bts_llc:dl_bytes>> | RLC encapsulated PDUs
| llc:ul_bytes | <<bts_llc:ul_bytes>> | full PDUs received
| pch:requests | <<bts_pch:requests>> | PCH requests sent
| pch:requests:timeout | <<bts_pch:requests:timeout>> | PCH requests timeout
| rach:requests | <<bts_rach:requests>> | RACH requests received
| rach:requests:11bit | <<bts_rach:requests:11bit>> | 11BIT_RACH requests received
| rach:requests:one_phase | <<bts_rach:requests:one_phase>> | One phase packet access with request for single TS UL
| rach:requests:two_phase | <<bts_rach:requests:two_phase>> | Single block packet request for two phase packet access
| rach:requests:unexpected | <<bts_rach:requests:unexpected>> | RACH Request with unexpected content received
| spb:uplink_first_segment | <<bts_spb:uplink_first_segment>> | First seg of UL SPB
| spb:uplink_second_segment | <<bts_spb:uplink_second_segment>> | Second seg of UL SPB
| spb:downlink_first_segment | <<bts_spb:downlink_first_segment>> | First seg of DL SPB
| spb:downlink_second_segment | <<bts_spb:downlink_second_segment>> | Second seg of DL SPB
| immediate:assignment_UL | <<bts_immediate:assignment_UL>> | Immediate Assign UL
| immediate:assignment_ul:one_phase | <<bts_immediate:assignment_ul:one_phase>> | Immediate Assign UL (one phase packet access)
| immediate:assignment_ul:two_phase | <<bts_immediate:assignment_ul:two_phase>> | Immediate Assign UL (two phase packet access)
| immediate:assignment_ul:contention_resolution_success | <<bts_immediate:assignment_ul:contention_resolution_success>> | First RLC Block (PDU) on the PDTCH from the MS received
| immediate:assignment_rej | <<bts_immediate:assignment_rej>> | Immediate Assign Rej
| immediate:assignment_DL | <<bts_immediate:assignment_DL>> | Immediate Assign DL
| channel:request_description | <<bts_channel:request_description>> | Channel Request Desc
| pkt:ul_assignment | <<bts_pkt:ul_assignment>> | Packet UL Assignment
| pkt:access_reject | <<bts_pkt:access_reject>> | Packet Access Reject
| pkt:dl_assignment | <<bts_pkt:dl_assignment>> | Packet DL Assignment
| pkt:cell_chg_notification | <<bts_pkt:cell_chg_notification>> | Packet Cell Change Notification
| pkt:cell_chg_continue | <<bts_pkt:cell_chg_continue>> | Packet Cell Change Continue
| pkt:neigh_cell_data | <<bts_pkt:neigh_cell_data>> | Packet Neighbour Cell Data
| ul:control | <<bts_ul:control>> | UL control Block
| ul:assignment_poll_timeout | <<bts_ul:assignment_poll_timeout>> | UL Assign Timeout
| ul:assignment_failed | <<bts_ul:assignment_failed>> | UL Assign Failed
| dl:assignment_timeout | <<bts_dl:assignment_timeout>> | DL Assign Timeout
| dl:assignment_failed | <<bts_dl:assignment_failed>> | DL Assign Failed
| pkt:ul_ack_nack_timeout | <<bts_pkt:ul_ack_nack_timeout>> | PUAN Poll Timeout
| pkt:ul_ack_nack_failed | <<bts_pkt:ul_ack_nack_failed>> | PUAN poll Failed
| pkt:dl_ack_nack_timeout | <<bts_pkt:dl_ack_nack_timeout>> | PDAN poll Timeout
| pkt:dl_ack_nack_failed | <<bts_pkt:dl_ack_nack_failed>> | PDAN poll Failed
| gprs:downlink_cs1 | <<bts_gprs:downlink_cs1>> | CS1 downlink
| gprs:downlink_cs2 | <<bts_gprs:downlink_cs2>> | CS2 downlink
| gprs:downlink_cs3 | <<bts_gprs:downlink_cs3>> | CS3 downlink
| gprs:downlink_cs4 | <<bts_gprs:downlink_cs4>> | CS4 downlink
| egprs:downlink_mcs1 | <<bts_egprs:downlink_mcs1>> | MCS1 downlink
| egprs:downlink_mcs2 | <<bts_egprs:downlink_mcs2>> | MCS2 downlink
| egprs:downlink_mcs3 | <<bts_egprs:downlink_mcs3>> | MCS3 downlink
| egprs:downlink_mcs4 | <<bts_egprs:downlink_mcs4>> | MCS4 downlink
| egprs:downlink_mcs5 | <<bts_egprs:downlink_mcs5>> | MCS5 downlink
| egprs:downlink_mcs6 | <<bts_egprs:downlink_mcs6>> | MCS6 downlink
| egprs:downlink_mcs7 | <<bts_egprs:downlink_mcs7>> | MCS7 downlink
| egprs:downlink_mcs8 | <<bts_egprs:downlink_mcs8>> | MCS8 downlink
| egprs:downlink_mcs9 | <<bts_egprs:downlink_mcs9>> | MCS9 downlink
| gprs:uplink_cs1 | <<bts_gprs:uplink_cs1>> | CS1 Uplink
| gprs:uplink_cs2 | <<bts_gprs:uplink_cs2>> | CS2 Uplink
| gprs:uplink_cs3 | <<bts_gprs:uplink_cs3>> | CS3 Uplink
| gprs:uplink_cs4 | <<bts_gprs:uplink_cs4>> | CS4 Uplink
| egprs:uplink_mcs1 | <<bts_egprs:uplink_mcs1>> | MCS1 Uplink
| egprs:uplink_mcs2 | <<bts_egprs:uplink_mcs2>> | MCS2 Uplink
| egprs:uplink_mcs3 | <<bts_egprs:uplink_mcs3>> | MCS3 Uplink
| egprs:uplink_mcs4 | <<bts_egprs:uplink_mcs4>> | MCS4 Uplink
| egprs:uplink_mcs5 | <<bts_egprs:uplink_mcs5>> | MCS5 Uplink
| egprs:uplink_mcs6 | <<bts_egprs:uplink_mcs6>> | MCS6 Uplink
| egprs:uplink_mcs7 | <<bts_egprs:uplink_mcs7>> | MCS7 Uplink
| egprs:uplink_mcs8 | <<bts_egprs:uplink_mcs8>> | MCS8 Uplink
| egprs:uplink_mcs9 | <<bts_egprs:uplink_mcs9>> | MCS9 Uplink
|===
=== Osmo Stat Items
// generating tables for osmo_stat_items
NSVC Peer Statistics
// osmo_stat_item_group table NSVC Peer Statistics
.ns.nsvc - NSVC Peer Statistics
[options="header"]
|===
| Name | Reference | Description | Unit
| alive.delay | <<ns.nsvc_alive.delay>> | ALIVE response time | ms
|===
NS Bind Statistics
// osmo_stat_item_group table NS Bind Statistics
.ns.bind - NS Bind Statistics
[options="header"]
|===
| Name | Reference | Description | Unit
| tx_backlog_length | <<ns.bind_tx_backlog_length>> | Transmit backlog length | packets
|===
BTS Statistics
// osmo_stat_item_group table BTS Statistics
.bts - BTS Statistics
[options="header"]
|===
| Name | Reference | Description | Unit
| ms.present | <<bts_ms.present>> | MS Present |
| pdch.available | <<bts_pdch.available>> | PDCH available |
| pdch.occupied | <<bts_pdch.occupied>> | PDCH occupied (all) |
| pdch.occupied.gprs | <<bts_pdch.occupied.gprs>> | PDCH occupied (GPRS) |
| pdch.occupied.egprs | <<bts_pdch.occupied.egprs>> | PDCH occupied (EGPRS) |
|===
// there are no ungrouped osmo_counters

View File

@@ -0,0 +1,68 @@
== Overview
=== About OsmoPCU
OsmoPCU is the Osmocom implementation of the GPRS PCU (Packet Control
Unit) element inside the GPRS network.
The OsmoPCU is co-located within the BTS and connects to OsmoBTS via its
PCU socket interface.
On the other side, OsmoPCU is connected via the Gb interface to the
SGSN.
[[fig-gprs-pcubts]]
.GPRS network architecture with PCU in BTS
[graphviz]
----
digraph G {
rankdir=LR;
MS0 [label="MS"]
MS1 [label="MS"]
MS0->BTS [label="Um"]
MS1->BTS [label="Um"]
BTS->BSC [label="Abis"]
BSC->MSC [label="A"]
BTS->PCU [label="pcu_sock"]
PCU->SGSN [label="Gb"]
SGSN->GGSN [label="GTP"]
PCU [color=red]
}
----
=== Software Components
OsmoPCU consists of a variety of components, including
* Gb interface (NS/BSSGP protocol)
* `pcu_sock` interface towards OsmoBTS
* TBF management for uplink and downlink TBF
* RLC/MAC protocol implementation
* per-MS context for each MS currently served
* CSN.1 encoding/decoding routines
==== Gb Implementation
OsmoPCU implements the ETSI/3GPP specified Gb interface, including TS
08.16 (NS), TS 08.18 (BSSGP) protocols. As transport layer for NS, it
supports NS/IP (NS encapsulated in UDP/IP).
The actual Gb Implementation is part of the libosmogb library, which is
in turn part of the libosmocore software package. This allows the same
Gb implementation to be used from OsmoPCU, OsmoGbProxy as well as
OsmoSGSN.
==== `pcu_sock` Interface to OsmoBTS
The interface towards OsmoBTS is called 'pcu_sock' and implemented as a
set of non-standardized primitives over a unix domain socket. The
default file system path for this socket is `/tmp/pcu_bts`.
The PCU socket can be changed on both OsmoBTS and OsmoPCU to a different
file/path name, primarily to permit running multiple independent BTS+PCU
pairs on a single Linux machine without having to use filesystem
namespaces or other complex configurations.
NOTE: If you change the PCU socket path on OsmoBTS by means of the
`pcu-socket` VTY configuration command, you must ensure to make the
identical change on the OsmoPCU side.

View File

@@ -0,0 +1,44 @@
==== Full example of QoS for osmo-pcu uplink QoS
In the below example we will show the full set of configuration required
for both DSCP and PCP differentiation of uplink Gb traffic by osmo-pcu.
What we want to achieve in this example is the following configuration:
.DSCP and PCP assignments for osmo-bts uplink traffic in this example
[options="header",width="30%",cols="2,1,1"]
|===
|Traffic |DSCP|PCP
|Gb (NS) | 10| 1
|===
. configure the osmocom program to set the DSCP value
* osmo-pcu.cfg: `dscp 10` in `udp bind` vty node
. configure an egrees QoS map to map from priority to PCP
.Example Step 1: add related VTY configuration to `osmo-pcu.cfg`
----
...
pcu
gb ip-dscp 10
gb socket-priority 1
...
----
.Example Step 2: egress QoS map to map from DSCP values to priority values
----
$ sudo ip link set dev eth0.9<1> type vlan egress-qos-map 0:0 1:1 5:5 6:6 7:7 <2>
----
<1> make sure to specify your specific VLAN interface name here instead of `eth0.9`.
<2> create a egress QoS map that maps the priority value 1:1 to the PCP. We also
include the mappings for 5, 6, and 7 from the osmo-bts example here (see
<<userman-osmobts>>).
NOTE:: The settings of the `ip` command are volatile and only active until
the next reboot (or the network device or VLAN is removed). Please refer to
the documentation of your specific Linux distribution in order to find out how
to make such settings persistent by means of an `ifup` hook whenever the interface
comes up. For CentOS/RHEL 8 this can e.g. be achieved by means of an `/sbin/ifup-local
script` (when using `network-scripts` and not NetworkManager). For Debian or Ubuntu,
this typically involves adding `up` lines to `/etc/network/interfaces` or a `/etc/network/if-up.d`
script.

View File

@@ -0,0 +1,27 @@
== Running OsmoPCU
The OsmoPCU executable (`osmo-pcu`) offers the following command-line
options:
=== SYNOPSIS
*osmo-pcu* [-h|-V] [-D] [-c 'CONFIGFILE'] [-r 'PRIO'] [-m 'MCC'] [-n 'MNC'] [-i A.B.C.D]
=== OPTIONS
*-h, --help*::
Print a short help message about the supported options
*-V, --version*::
Print the compile-time version number of the program
*-D, --daemonize*::
Fork the process as a daemon into background.
*-c, --config-file 'CONFIGFILE'*::
Specify the file and path name of the configuration file to be
used. If none is specified, use `osmo-pcu.cfg` in the current
working directory.
*-m, --mcc 'MCC'*::
Use the given MCC instead of that provided by BTS via PCU socket
*-n, --mnc 'MNC'*::
Use the given MNC instead of that provided by BTS via PCU socket

501
doc/manuals/gb/bssgp.adoc Normal file
View File

@@ -0,0 +1,501 @@
[[bssgp]]
== BSS GPRS Protocol (BSSGP)
=== List of Messages
The following tables list the BSSGP messages used by OsmoPCU, grouped
by their level of compliance with 3GPP TS 48.018.
==== Messages Compliant With TS 48.018
.Messages compliant with TS 48.018
[options="header",cols="10%,10%,20%,35%,5%,20%"]
|===
| TS 48.018 § | type code (hex) | This document § | Message | <-/-> | Received/Sent by OsmoPCU
6+<| *RL and BSSGP SAP Messages:*
| 10.2.1 | 0x00 | <<dl_unit_data>> | DL-UNITDATA | <- | Received
| 10.2.2 | 0x01 | <<ul_unit_data>> | UL-UNITDATA | -> | Sent
| 10.2.3 | 0x02 | <<ra_capab>> | RA-CAPABILITY | <- | Received
6+<| *GMM SAP Messages:*
| 10.3.1 | 0x06 | <<paging_ps>> | PAGING PS | <- | Received
| 10.3.2 | 0x07 | <<paging_cs>> | PAGING CS | <- | Received
| 10.3.7 | 0x0c | <<susp_ack>> | SUSPEND-ACK | <- | Received
| 10.3.8 | 0x0d | <<susp_nack>> | SUSPEND-NACK | <- | Received
| 10.3.10 | 0x0f | <<res_ack>> | RESUME-ACK | <- | Received
| 10.3.11 | 0x10 | <<res_nack>> | RESUME-NACK | <- | Received
6+<| *NM SAP Messages:*
| 10.4.9 | 0x21 | <<block_ack>> | BVC-BLOCK-ACK | <- | Received
| 10.4.12 | 0x22 | <<bvc_reset>> | BVC-RESET | <-/-> | Received/Sent
| 10.4.13 | 0x23 | <<reset_ack>> | BVC-RESET-ACK | <- | Received
| 10.4.10 | 0x24 | <<bvc_unblock>> | BVC-UNBLOCK | -> | Sent
| 10.4.11 | 0x25 | <<unblock_ack>> | BVC-UNBLOCK-ACK | <- | Received
| 10.4.4 | 0x26 | <<flow_bvc>> | FLOW-CONTROL-BVC | -> | Sent
| 10.4.5 | 0x27 | <<flow_bvc_ack>> | FLOW-CONTROL-BVC-ACK | <- | Received
| 10.4.7 | 0x29 | <<flow_ms_ack>> | FLOW-CONTROL-MS-ACK | <- | Received
| 10.4.1 | 0x2a | <<flush_ll>> | FLUSH-LL | <- | Received
| 10.4.15 | 0x40 | <<invoke_trace>> | SGSN-INVOKE-TRACE | <- | Received
| 10.4.14 | 0x41 | <<bssgp_status>> | STATUS | <-/-> | Received/Sent
|===
==== Messages Specific to OsmoPCU
There are no OsmoPCU specific BSSGP messages.
[[not_impl]]
==== Messages Not Implemented by OsmoPCU
.3GPP TS 48.018 messages not implemented by OsmoPCU
[options="header",cols="10%,10%,80%"]
|===
| TS 48.018 § | type code (hex) | Message
3+<| *RL (relay) and BSSGP SAP Messages:*
| 10.2.4 | 0x03 | PTM-UNITDATA
3+<| *GMM (GPRS mobility management) SAP Messages:*
| 10.3.3 | 0x08 | RA-CAPABILITY-UPDATE
| 10.3.4 | 0x09 | RA-CAPABILITY-UPDATE-ACK
| 10.3.5 | 0x0a | RADIO-STATUS
| 10.3.6 | 0x0b | SUSPEND
| 10.3.9 | 0x0e | RESUME
3+<| *NM (network management) SAP Messages:*
| 10.4.8 | 0x20 | BVC-BLOCK
| 10.4.6 | 0x28 | FLOW-CONTROL-MS
| 10.4.2 | 0x2b | FLUSH-LL-ACK
| 10.4.3 | 0x2c | LLC-DISCARDED
3+<| *PFM (packet flow management) SAP Messages:*
| 10.4.16 | 0x50 | DOWNLOAD-BSS-PFC
| 10.4.17 | 0x51 | CREATE-BSS-PFC
| 10.4.18 | 0x52 | CREATE-BSS-PFC-ACK
| 10.4.19 | 0x53 | CREATE-BSS-PFC-NACK
| 10.4.20 | 0x54 | MODIFY-BSS-PFC
| 10.4.21 | 0x55 | MODIFY-BSS-PFC-ACK
| 10.4.22 | 0x56 | DELETE-BSS-PFC
| 10.4.23 | 0x57 | DELETE-BSS-PFC-ACK
|===
=== Details on Compliant BSSGP Messages
[[dl_unit_data]]
==== DL-UNITDATA
This message conforms to 3GPP TS 48.018 § 10.2.1, with the following
limitations:
* OsmoPCU does not support QoS
* all optional IEs except for IMSI and old TLLI are ignored.
._DL-UNITDATA_ IE limitations
[options="header",cols="10%,30%,60%"]
|===
| TS 48.018 § | IE Name | Handling
| 11.3.28 | QoS Profile | _ignored_
| 11.3.22 | MS Radio Access Capability | _ignored_
| 11.3.27 | Priority | _ignored_
| 11.3.11 | DRX Parameters | _ignored_
| 1.3.42 | PFI | _ignored_
| 11.3.19 | LSA Information | _ignored_
| 11.3.47 | Service UTRAN CCO | _ignored_
|===
[[ul_unit_data]]
==== UL-UNITDATA
This message conforms to 3GPP TS 48.018 § 10.2.2, with the following limitations:
* OsmoPCU does not send optional IEs - PFI (§ 12.3.42) and LSA
Identifier List (§ 11.3.18).
* QoS Profile (§ 11.3.28) IE is always set to 0x04.
[[ra_capab]]
==== RA-CAPABILITY
This message is received and logged but ignored by OsmoPCU at the moment.
[[paging_ps]]
==== PAGING PS
This message conforms to 3GPP TS 48.018 § 10.3.1, with the following
limitations:
* only IMSI and P-TMSI are parsed by OsmoPCU.
._DL-UNITDATA_ IE limitations
[options="header",cols="10%,30%,60%"]
|===
| TS 48.018 § | IE Name | Handling
| 11.3.11 | DRX Parameters | _ignored_
| 11.3.6 | BVCI | _ignored_
| 11.3.17 | Location Are | _ignored_
| 11.3.31 | Routeing Area | _ignored_
| 11.3.3 | BSS Area Indication | _ignored_
| 11.3.42 | PFI | _ignored_
| 11.3.43 | ABQP | _ignored_
| 11.3.28 | QoS Profile | _ignored_
| 11.3.36 | P-TMSI | treated as mandatory (in case of absence paging with 0-length P-TMSI will be sent)
|===
[[paging_cs]]
==== PAGING CS
This message is received and logged but ignored by OsmoPCU at the
moment.
[[susp_ack]]
==== SUSPEND-ACK
This message is received and logged but ignored by OsmoPCU at the
moment.
[[susp_nack]]
==== SUSPEND-NACK
This message is received and logged but ignored by OsmoPCU at the
moment.
[[res_ack]]
==== RESUME-ACK
This message is received and logged but ignored by OsmoPCU at the
moment.
[[res_nack]]
==== RESUME-NACK
This message is received and logged but ignored by OsmoPCU at the
moment.
[[block_ack]]
==== BVC-BLOCK-ACK
This message is received and logged but ignored by OsmoPCU at the
moment.
[[bvc_reset]]
==== BVC-RESET
OsmoPCU never transmits optional Feature bitmap (3GPP TS 48.018 §
11.3.40) IE.
Receiving BVC RESET will cause OsmoPCU to respond with "Unknown BVCI"
status message.
[[reset_ack]]
==== BVC-RESET-ACK
This message conforms to 3GPP TS 48.018 § 10.4.13.
After receiving it OsmoPCU completes the RESET procedure for BVC
according to 3GPP TS 48.018 § 8.4.
[[unblock_ack]]
==== BVC-UNBLOCK-ACK
This message conforms to 3GPP TS 48.018 § 10.4.11.
After receiving it OsmoPCU completes the RESET procedure for BVC
according to 3GPP TS 48.018 § 8.3.
[[bvc_unblock]]
==== BVC-UNBLOCK
This message conforms to 3GPP TS 48.018 § 10.4.10 and is send by
OsmoPCU as part of UNBLOCK procedure described in 3GPP TS 48.018 § 8.3.
[[flow_ms_ack]]
==== FLOW-CONTROL-MS-ACK
This message is received and logged but ignored by OsmoPCU at the
moment.
[[flow_bvc_ack]]
==== FLOW-CONTROL-BVC-ACK
This message is received and logged but ignored by OsmoPCU at the
moment.
[[flow_bvc]]
==== FLOW-CONTROL-BVC
This message conforms to 3GPP TS 48.018 § 10.4.4, with the following
limitations:
* OsmoPCU does not support Current Bucket Level (CBL) feature so
Bucket_Full Ratio (TS 48.018 § 11.3.46) IE is not transmitted as part
of this message.
[[flush_ll]]
==== FLUSH-LL
This message is received and logged but ignored by OsmoPCU at the
moment.
[[invoke_trace]]
==== SGSN-INVOKE-TRACE
This message is received and logged but ignored by OsmoPCU at the
moment.
[[bssgp_status]]
==== STATUS
This message conforms to 3GPP TS 48.018 § 10.4.14.
=== Information Elements Overview
All of the IEs handled by OsmoPCU are listed below, with limitations
and additions to 3GPP TS 48.018 specified in more detail.
==== IEs Conforming to 3GPP TS 48.018
The following Information Elements are accepted by OsmoPCU. Not all
IEs are actually evaluated.
.IEs conforming to 3GPP TS 48.018
[options="header",cols="5%,10%,40%,5%,40%"]
|===
| tag (hex) | TS 48.018 § | IE name | <-/-> | Received/Sent by OsmoPCU
| 0x00 | 11.3.1 | Alignment Octets | <-/-> | Received/Sent
| 0x01 | 11.3.2 | Bmax default MS | -> | Sent
| 0x02 | 11.3.3 | BSS Area Indication | <- | Received
| 0x03 | 11.3.4 | Bucket Leak Rate | -> | Sent
| 0x04 | 11.3.6 | BVCI | <-/-> | Received/Sent
| 0x05 | 11.3.5 | BVC Bucket Size | -> | Sent
| 0x06 | 11.3.7 | BVC Measurement | -> | Sent
| 0x07 | 11.3.8 | Cause | <-/-> | Received/Sent
| 0x08 | 11.3.9 | Cell Identifier | -> | Sent
| 0x09 | 11.3.10 | Channel needed | <- | Received
| 0x0a | 11.3.11 | DRX Parameters | <- | Received
| 0x0b | 11.3.12 | eMLPP-Priority | <- | Received
| 0x0c | 11.3.13 | Flush Action | <- | Received
| 0x0d | 11.3.14 | IMSI | <-/-> | Received/Sent
| 0x0e | 11.3.15 | LLC-PDU | <-/-> | Received/Sent
| 0x0f | 11.3.16 | LLC Frames Discarded | -> | Sent
| 0x10 | 11.3.17 | Location Area | <- | Received
| 0x11 | 11.3.20 | Mobile Id | <- | Received
| 0x12 | 11.3.21 | MS Bucket Size | -> | Sent
| 0x13 | 11.3.22 | MS Radio Access Capability | <- | Received
| 0x14 | 11.3.23 | OMC Id | <- | Received
| 0x15 | 11.3.24 | PDU In Error | <-/-> | Received/Sent
| 0x16 | 11.3.25 | PDU Lifetime | <- | Received
| 0x17 | 11.3.27 | Priority | <- | Received
| 0x19 | 11.3.29 | Radio Cause | -> | Sent
| 0x1a | 11.3.30 | RA-Cap-UPD-Cause | -> | Sent
| 0x1b | 11.3.31 | Routeing Area | <-/-> | Received/Sent
| 0x1c | 11.3.32 | R_default_MS | -> | Sent
| 0x1d | 11.3.33 | Suspend Reference Number | <-/-> | Received/Sent
| 0x1e | 11.3.34 | Tag | <-/-> | Received/Sent
| 0x1f | 11.3.35 | TLLI | <-/-> | Received/Sent
| 0x20 | 11.3.36 | TMSI | <-/-> | Received/Sent
| 0x21 | 11.3.37 | Trace Reference | <- | Received
| 0x22 | 11.3.38 | Trace Type | <- | Received
| 0x23 | 11.3.39 | TransactionId | <- | Received
| 0x24 | 11.3.40 | Trigger Id | <- | Received
| 0x25 | 11.3.41 | Number of octets affected | -> | Sent
| 0x26 | 11.3.18 | LSA Identifier List | -> | Sent
| 0x27 | 11.3.19 | LSA Information | <- | Received
| 0x28 | 11.3.42 | Packet Flow Identifier | <-/-> | Received/Sent
| 0x3a | 11.3.43 | Aggregate BSS QoS Profile (ABQP) | <-/-> | Received/Sent
| 0x3b | 11.3.45 | Feature Bitmap | <-/-> | Received/Sent
| 0x3c | 11.3.46 | Bucket_Full Ratio | -> | Sent
| 0x3d | 11.3.47 | Service UTRAN CCO (Cell Change Order) | <- | Received
|===
==== IEs Not Conforming to 3GPP TS 48.018
.IEs not conforming to 3GPP TS 48.018
[options="header",cols="5%,10%,30%,55%"]
|===
| tag (hex) | TS 48.018 § | IE name | Description
| 0x18 | 11.3.28 | QoS Profile | Received value is ignored. Sent value is hard-coded to 0x4 (3 octets).
|===
==== Additional Attributes and Parameters
There are no OsmoPCU specific additional Attributes and Parameters.
=== Details on IEs
==== BSS Area Indication
This IE is ignored by OsmoPCU.
==== Bucket Leak Rate
The value used by OsmoPCU for this IE can be set through configuration
file or vty via "flow-control force-ms-leak-rate <1-6553500>" command.
==== BVC Bucket Size
The value used by OsmoPCU for this IE can be set through configuration file or vty via
"flow-control force-bvc-bucket-size <1-6553500>" command.
==== Channel needed
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<paging_cs>> for details.
==== DRX Parameters
This IE is ignored by OsmoPCU.
==== eMLPP-Priority
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<paging_cs>> for details.
==== Flush Action
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<flush_ll>> for details.
==== LLC Frames Discarded
This IE is not available because entire message which contains it
(LLC-DISCARDED) is not implemented by OsmoPCU - see for <<not_impl>>
details.
==== Location Area
This IE is ignored by OsmoPCU.
==== Mobile Id
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<invoke_trace>> for details.
==== MS Bucket Size
The value used by OsmoPCU for this IE can be set through configuration
file or vty via "flow-control force-ms-bucket-size <1-6553500>"
command.
==== MS Radio Access Capability
This IE is ignored by OsmoPCU.
==== OMC Id
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<invoke_trace>> for details.
==== Priority
This IE is ignored by OsmoPCU.
==== QoS Profile
No QoS is supported by OsmoPCU so this IE is ignored or safe default
used when mandatory.
==== Radio Cause
This IE is not available because entire message which contains it
(RADIO-STATUS) is not implemented by OsmoPCU - see for <<not_impl>>
details.
==== RA-Cap-UPD-Cause
This IE is not available because entire message which contains it
(RA-CAPABILITY-UPDATE-ACK) is not implemented by OsmoPCU - see for
<<not_impl>> details.
==== Routeing Area
This IE is ignored by OsmoPCU upon receiving.
The messages which might require this IE to be send are not
implemented by OsmoPCU - see for <<not_impl>> details.
==== Suspend Reference Number
This IE is ignored by OsmoPCU upon receiving.
The messages which might require this IE to be send are not
implemented by OsmoPCU - see for <<not_impl>> details.
==== Tag
This IE currently only used by OsmoPCU for Flow Control procedure (TS
48.018 § 8.2). In other cases it's either ignored or unavailable.
==== Trace Reference
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<invoke_trace>> for details.
==== Trace Type
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<invoke_trace>> for details.
==== TransactionId
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<invoke_trace>> for details.
==== Trigger Id
This IE is ignored because entire message which contains it is ignored
by OsmoPCU - see <<invoke_trace>> for details.
==== Number of octets affected
This IE is not available because the messages which contains it
(FLUSH-LL-ACK and LLC-DISCARDE) are not implemented by OsmoPCU - see
for <<not_impl>> details.
==== LSA Information
This IE is ignored by OsmoPCU.
==== LSA Identifier List
This IE is not implemented by OsmoPCU.
==== Packet Flow Identifier
This IE is ignored by OsmoPCU upon receiving.
The messages which might require this IE to be send are not
implemented by OsmoPCU - see for <<not_impl>> details.
==== Aggregate BSS QoS Profile (ABQP)
This IE is ignored by OsmoPCU upon receiving.
The messages which might require this IE to be send are not
implemented by OsmoPCU - see for <<not_impl>> details.
==== Feature Bitmap
This IE is not implemented by OsmoPCU.
This IE is ignored by OsmoPCU when received.
Absence of Feature Bitmap automatically disables optional features for
Network Service Entity (NSE) communicating with OsmoPCU.
==== Bucket_Full Ratio
This IE is not implemented by OsmoPCU.
==== Service UTRAN CCO (Cell Change Order)
This IE is ignored by OsmoPCU.
=== Gb BSSGP Initialization / PCU bring-up
The BSSGP initialization directly follows NS connection establishment
described in <<ns_init>>.
OsmoPCU allocates a BVC context for the BVCI given by OsmoBTS, which
in turn receives it from OsmoBSC or OsmoNITB via OML procedures.
In addition to the BVCI identifying the OsmoPCU side of BSSGP
connection, there is also special BVCI which is accepted by OsmoPCU in
accordance with 3GPP TS 48.018 § 5.4.1: BVCI = 0 represents signaling data
between SGSN and PCU in contrast to PTP (Peer-To-Peer) user's data.
The mapping between BSSGP PDUs and signaling or PTP BVCIs is available
in 3GPP TS 48.018 Table 5.4.

View File

@@ -0,0 +1,27 @@
msc {
hscale="1.2";
bsc [label="BSC"], bts [label="BTS"], pcu [label="PCU"], sgsn [label="SGSN"];
|||;
bts box bsc [label="A-bis OML connection"];
bsc => bts [label="Set OML Attrbibutes (NSVC,CELL)"];
bts rbox pcu [label="PCU Unix Domain Socket"];
pcu => bts [label="connect to PCU socket"];
pcu <: bts [label="Config. parameters"];
pcu rbox pcu [label="bind/connect UDP socket"];
pcu note sgsn [label="NS-over-IP (UDP port 23000)"];
pcu => sgsn [label="NS RESET"];
pcu <= sgsn [label="NS RESET ACK"];
...;
pcu => sgsn [label="NS UNBLOCK"];
pcu <= sgsn [label="NS UNBLOCK ACK"];
pcu box sgsn [label="NS link established"];
...;
pcu => sgsn [label="BVC RESET"];
pcu <= sgsn [label="BVC RESET ACK"];
...;
pcu => sgsn [label="BVC UNBLOCK"];
pcu <= sgsn [label="BVC UNBLOCK ACK"];
pcu box sgsn [label="BSSGP link established"];
|||;
}

278
doc/manuals/gb/ns.adoc Normal file
View File

@@ -0,0 +1,278 @@
== Network Service (NS)
=== List of Messages
The following tables list the NS messages used by osmo-pcu and osmo-gbproxy, grouped by their level of
compliance with 3GPP TS 48.016.
==== Messages Compliant With 3GPP TS 48.016
The NS protocol is implemented inside libosmogb so none of the messages below are sent by OsmoPCU explicitly.
Instead corresponding functions from libosmogb are called which send and receive messages as necessary. See <<ns_init>> for details
on establishing NS connection.
.Messages compliant with 3GPP TS 48.016
[options="header",cols="10%,10%,20%,35%,5%,20%"]
|===
| TS 48.016 § | type code (hex) | This document § | Message | <-/-> | Received/Sent by OsmoPCU
| 9.2.1 | 0x0a | <<ns_alive>> | NS-ALIVE | <-/-> | Received/Sent
| 9.2.2 | 0x0b | <<ns_alive_ack>> | NS-ALIVE-ACK | <-/-> | Received/Sent
| 9.2.3 | 0x04 | <<ns_block>> | NS-BLOCK | <-/-> | Received/Sent
| 9.2.4 | 0x05 | <<ns_block_ack>> | NS-BLOCK-ACK | <-/-> | Received/Sent
| 9.2.5 | 0x02 | <<ns_reset>> | NS-RESET | <-/-> | Received/Sent
| 9.2.6 | 0x03 | <<ns_reset_ack>> | NS-RESET-ACK | <-/-> | Received/Sent
| 9.2.7 | 0x08 | <<ns_status>> | NS-STATUS | <-/-> | Received/Sent
| 9.2.8 | 0x06 | <<ns_unblock>> | NS-UNBLOCK | <-/-> | Received/Sent
| 9.2.9 | 0x07 | <<ns_unblock_ack>> | NS-UNBLOCK-ACK | <-/-> | Received/Sent
| 9.2.10 | 0x00 | <<ns_unit_data>> | NS-UNITDATA | <-/-> | Received/Sent
| 9.3.1 | 0x0c | <<sns_ack>> | SNS-ACK | <-/-> | Received/Sent
| 9.3.2 | 0x0d | <<sns_add>> | SNS-ADD | <-/-> | Received/Sent
| 9.3.3 | 0x0e | <<sns_changeweight>> | SNS-CHANGEWEIGHT | <-/-> | Received/Sent
| 9.3.4 | 0x0f | <<sns_config>> | SNS-CONFIG | <-/-> | Received/Sent
| 9.3.5 | 0x10 | <<sns_config_ack>> | SNS-CONFIG | <-/-> | Received/Sent
| 9.3.6 | 0x11 | <<sns_delete>> | SNS-DELETE | <-/-> | Received/Sent
| 9.3.7 | 0x12 | <<sns_size>> | SNS-SIZE | <-/-> | Received/Sent
| 9.3.8 | 0x13 | <<sns_size_ack>> | SNS-SIZE-ACK | <-/-> | Received/Sent
|===
==== Messages Specific to OsmoPCU
There are no OsmoPCU specific NS messages.
==== Messages Not Implemented by OsmoPCU
All the NS protocol messages from 3GPP TS 48.016 are implemented in OsmoPCU.
=== Details on Compliant NS Messages
[[ns_unit_data]]
==== NS-UNITDATA
This PDU transfers one NS SDU (specified in 3GPP TS 08.18) between
OsmoPCU and SGSN. Upon receiving it OsmoPCU passes it to BSSGP
implementation to handle. It is also sent by BSSGP as necessary - see
<<bssgp>> for details.
It contains BVCI (<<ie_bvci>>) and NS SDU (<<ie_nssdu>>) IEs.
[[ns_reset]]
==== NS-RESET
This message is send by OsmoPCU in order to initiate reset procedure
described in 3GPP TS 48.016 § 7.3. The expected reply is NS-RESET-ACK
(<<ns_reset_ack>>) message. If no expected reply is received in 3
seconds than the sending is retried up to 3 times. When this message
is received it is replied with NS-RESET-ACK (<<ns_reset_ack>>).
It might be ignored under conditions described in 3GPP TS 48.016 § 7.3.1.
The message conforms to 3GPP TS 48.016 § 9.2.5 specification.
It contains Cause (<<ie_cause>>), NSVCI (<<ie_nsvci>>) and NSEI (<<ie_nsei>>) IEs.
[[ns_reset_ack]]
==== NS-RESET-ACK
This message is sent as a response to proper NS-RESET (<<ns_reset>>)
message initiating reset procedure.
The message conforms to 3GPP TS 48.016 § 9.2.6 specification.
It contains NSVCI (<<ie_nsvci>>) and NSEI (<<ie_nsei>>) IEs.
[[ns_block]]
==== NS-BLOCK
Upon receiving this message corresponding NS-VC is marked as blocked
by OsmoPCU and NS-BLOCK-ACK (<<ns_block_ack>>) reply is transmitted.
When this message is sent by OsmoPCU corresponding NS-BLOCK-ACK
(<<ns_block_ack>>) reply is expected before NS-VC is actually marked
as blocked. This behavior follows the blocking procedure described in
3GPP TS 48.016 § 7.2.
The message conforms to 3GPP TS 48.016 § 9.2.3 specification.
It contains Cause (<<ie_cause>>) and NSVCI (<<ie_nsvci>>) IEs.
[[ns_block_ack]]
==== NS-BLOCK-ACK
This message is sent by OsmoPCU automatically upon reception of
correct NS-BLOCK (<<ns_block>>) message. It is expected as a reply
for NS-BLOCK (<<ns_block>>) message sent by OsmoPCU.
The message conforms to 3GPP TS 48.016 § 9.2.4 specification.
It contains NSVCI (<<ie_nsvci>>) IE.
[[ns_unblock]]
==== NS-UNBLOCK
Upon receiving this message corresponding NS-VC is unblocked by
OsmoPCU and NS-UNBLOCK-ACK (<<ns_unblock_ack>>) reply is sent. When
this message is sent by OsmoPCU corresponding NS-UNBLOCK-ACK
(<<ns_unblock_ack>>) reply is expected before NS-VC is actually marked
as unblocked. This behavior follows the blocking procedure described
in 3GPP TS 48.016 § 7.2.
The message conforms to 3GPP TS 48.016 § 9.2.8 specification.
[[ns_unblock_ack]]
==== NS-UNBLOCK-ACK
Receiving this message notifies OsmoPCU that NS-VC unblocking request
is confirmed and thus NS-VC is marked as unblocked. This message is
also sent as a reply to NS-UNBLOCK (<<ns_unblock>>) message.
The message conforms to 3GPP TS 48.016 § 9.2.9 specification.
[[ns_status]]
==== NS-STATUS
This message is sent to inform other party about error conditions as a
response to various unexpected PDUs or PDUs with unexpected/missing
data. If this message is received for unknown NS-VC it is ignored in
accordance with 3GPP TS 48.016 § 7.5.1, otherwise the error cause is
logged if present in NS-STATUS.
The message conforms to 3GPP TS 48.016 § 9.2.7 specification.
It contains Cause (<<ie_cause>>) and might (depending on actual error)
contain NSVCI (<<ie_nsvci>>), NS PDU (<<ie_nspdu>>) and BVCI
(<<ie_bvci>>) IEs.
[[ns_alive]]
==== NS-ALIVE
This message is sent periodically to test connectivity according to
3GPP TS 48.016 § 4.5.3. The expected response is NS-ALIVE-ACK
(<<ns_alive_ack>>). If no such response arrives within given amount of
time (3 seconds) than another NS-ALIVE message is sent and failed test
attempt is recorded. After 10 failed attempts NS connection is
considered dead and OsmoPCU tries to reconnect.
The message conforms to 3GPP TS 48.016 § 9.2.1 specification.
[[ns_alive_ack]]
==== NS-ALIVE-ACK
This message is sent automatically in reply to NS-ALIVE (<<ns_alive>>)
message.
The message conforms to 3GPP TS 48.016 § 9.2.2 specification.
[[sns_ack]]
==== SNS-ACK
[[sns_add]]
==== SNS-ADD
[[sns_changeweight]]
==== SNS-CHANGEWEIGHT
[[sns_config]]
==== SNS-CONFIG
[[sns_config_ack]]
==== SNS-CONFIG-ACK
[[sns_delete]]
==== SNS-DELETE
[[ssn_size]]
==== SNS-SIZE
[[sns_size_ack]]
==== SNS-SIZE-ACK
=== Information Elements Overview
All of the IEs handled by OsmoPCU are listed below, with limitations and
additions to 3GPP TS 48.016 specified in more detail.
==== IEs Conforming to 3GPP TS 48.016
The following Information Elements are accepted by OsmoPCU.
.IEs conforming to 3GPP TS 48.016
[options="header",cols="5%,10%,40%,5%,40%"]
|===
| tag (hex) | TS 48.016 § | IE name | <-/-> | Received/Sent by OsmoPCU
| 0x03 | 10.3.1 | BVCI | <-/-> | Received/Sent
| 0x00 | 10.3.2 | Cause | <-/-> | Received/Sent
| - | 10.3.2a | End Flag | <-/-> | Received/Sent
| 0x0b | 10.3.2b | IP Address | <-/-> | Received/Sent
| 0x05 | 10.3.2c | List of IP4 Elements | <-/-> | Received/Sent
| 0x06 | 10.3.2d | List of IP6 Elements | <-/-> | Received/Sent
| 0x07 | 10.3.2e | Maximum Number of NS-VCs | <-/-> | Received/Sent
| 0x08 | 10.3.2f | Number of IP4 Endpoints | <-/-> | Received/Sent
| 0x09 | 10.3.2g | Number of IP6 Endpoints | <-/-> | Received/Sent
| 0x02 | 10.3.3 | NS PDU | <-/-> | Received/Sent
| 0x01 | 10.3.5 | NSVCI | <-/-> | Received/Sent
| 0x04 | 10.3.6 | NSEI | <-/-> | Received/Sent
| - | 10.3.7 | PDU Type | <-/-> | Received/Sent
| 0x0a | 10.3.7a | Reset Flag | <-/-> | Received/Sent
| - | 10.3.8 | Spare Octet | <-/-> | Received/Sent
| - | 10.3.10 | Transaction ID | <-/-> | Received/Sent
|===
==== IEs Not Conforming to 3GPP TS 48.016
.IEs conforming to 3GPP TS 48.016
[options="header",cols="5%,10%,40%,5%,40%"]
|===
| tag (hex) | TS 48.016 § | IE name | <-/-> | Notice
| - | 10.3.9 | NS-SDU Control Bits | <-/-> | Not implemented yet
|===
All other IEs defined in 3GPP TS 48.016 § 10.3 are supported by OsmoPCU.
==== Additional Attributes and Parameters
There are no OsmoPCU specific additional Attributes and Parameters.
=== Details on IEs
[[ie_cause]]
==== Cause
This IE contains reason for a procedure or error as described in 3GPP TS 48.016 § 10.3.2.
[[ie_nsvci]]
==== NSVCI
This IE represents NSVCI identity described in <<ident>> and 3GPP TS 48.016 § 10.3.5.
[[ie_nspdu]]
==== NS PDU
This IE contains PDU (possibly truncated) which cause error described
in NS-STATUS message (<<ns_status>>) as described in 3GPP TS 48.016 §
10.3.3.
[[ie_nssdu]]
==== NS SDU
This IE contains BSSGP data - see <<bssgp>> for details.
[[ie_bvci]]
==== BVCI
This IE represents BSSGP identity described in <<ident>> and 3GPP TS 48.016
§ 10.3.1.
[[ie_nsei]]
==== NSEI
This IE represents NSEI identity described in <<ident>> and 3GPP TS 48.016 §
10.3.6.
[[ns_init]]
=== Gb NS Initialization / PCU bring-up
OsmoPCU binds and connects an UDP socket for NS using port numbers and IP
information given by OsmoBTS via the PCU socket. OsmoBTS in turn
receives this information from the BSC vi A-bis OML.
Following successful initialization of the UDP socket, the reset
procedure is initiated as described in <<ns_reset>>.

View File

@@ -0,0 +1,46 @@
<authorgroup>
<author>
<firstname>Max</firstname>
<surname>Suraev</surname>
<email>msuraev@sysmocom.de</email>
<authorinitials>MS</authorinitials>
<affiliation>
<shortaffil>sysmocom</shortaffil>
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
<jobtitle>Software Developer</jobtitle>
</affiliation>
</author>
<author>
<firstname>Harald</firstname>
<surname>Welte</surname>
<email>hwelte@sysmocom.de</email>
<authorinitials>HW</authorinitials>
<affiliation>
<shortaffil>sysmocom</shortaffil>
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
<jobtitle>Managing Director</jobtitle>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2015-2021</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, no Front-Cover Texts,
and no Back-Cover Texts. A copy of the license is included in
the section entitled "GNU Free Documentation License".
</para>
<para>
The Asciidoc source code of this manual can be found at
<ulink url="http://git.osmocom.org/osmo-gsm-manuals/">
http://git.osmocom.org/osmo-gsm-manuals/
</ulink>
</para>
</legalnotice>

View File

@@ -0,0 +1,95 @@
:gfdl-enabled:
OsmoPCU Gb Protocol Specification
=================================
Harald Welte <hwelte@sysmocom.de>
== Introduction
This document describes the Gb interface of *OsmoPCU*. Based on 3GPP TS
48.016 and 48.018, this document indicates which of the 3GPP specified Gb
messages and IEs are implemented according to 3GPP specifications, which of
these are not or not fully implemented, as well as OsmoPCU-specific extensions
to the Gb interface not specified by 3GPP.
Extensions to the Gb interface specific to OsmoPCU are detailed in this
document. For details on the messages and IEs that comply with above-mentioned
3GPP specifications, please refer to those documents.
.3GPP document versions referred to by this document
[cols="20%,80%"]
|===
|3GPP TS 08.56 | version 8.0.1 Release 1999
|3GPP TS 08.58 | version 8.6.0 Release 1999
|3GPP TS 08.60 | version 8.2.1 Release 1999
|3GPP TS 12.21 | version 8.0.0 Release 1999
|3GPP TS 48.016 | version 15.0.0 Release 15
|3GPP TS 48.018 | version 15.0.0 Release 15
|===
.IETF documents referred to by his document
[cols="20%,80%"]
|===
|IETF RFC 768 | User Datagram Protocol
|IETF RFC 791 | Internet Protocol
|===
== Overview
The OsmoPCU Gb interface consists of the NS (Network Services) and
BSSGP (Base Station Subsystem Gateway Protocol), encapsulated in UDP
(User Datagram Protocol) and IP (Internet Protocol) version 4.
Use of other underlying protocols (e. g. Frame Relay) is not supported.
.UDP port numbers used by OsmoPCU Gb/IP
[options="header",width="50%",cols="35%,65%"]
|===
|TCP Port Number|Usage
|23000|NS over UDP (default port)
|===
The NS-over-UDP link is established in the PCU -> SGSN direction, i.e.
the PCU is running as client while the SGSN is running as server.
Establishment of the NS-over-UDP link is only possible after OsmoPCU
has been configured via the *PCU socket* interface from OsmoBTS.
OsmoBTS in turn receives relevant configuration parameters from
OsmoBSC or the BSC component inside OsmoNITB.
.Overview of Gb link establishment
["mscgen"]
----
include::{srcdir}/gb/gb-startup.msc[]
----
[[ident]]
=== Identities
The Gb interface identities of the PCU are configured via BSC ->
OsmoBTS -> PCU Socket. They consist of
NSEI:: NS Equipment Identifier
NSVCI:: NS Virtual Connection Identifier
BVCI:: BSSGP Virtual Connection Identifier
For an explanation of those identifiers and their use in the NS and
BSSGP protocols, please see the relevant 3GPP specifications for NS (TS 48.016)
and BSSGP (TS 48.018).
In most cases, all above identities belong to different namespaces and
must be unique within their respective namespace and within the SGSN
they connect to.
This means that typically each OsmoPCU has one unique set of NSEI,
NSVCI and BVCI in your network.
include::{srcdir}/gb/ns.adoc[]
include::{srcdir}/gb/bssgp.adoc[]
include::./common/chapters/port_numbers.adoc[]
include::./common/chapters/glossary.adoc[]
include::./common/chapters/gfdl.adoc[]

View File

@@ -0,0 +1,35 @@
<authorgroup>
<author>
<firstname>Harald</firstname>
<surname>Welte</surname>
<email>hwelte@sysmocom.de</email>
<authorinitials>HW</authorinitials>
<affiliation>
<shortaffil>sysmocom</shortaffil>
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
<jobtitle>Managing Director</jobtitle>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2013-2021</year>
<holder>sysmocom - s.f.m.c. GmbH</holder>
</copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.3 or any later version published by the Free Software
Foundation; with no Invariant Sections, no Front-Cover Texts,
and no Back-Cover Texts. A copy of the license is included in
the section entitled "GNU Free Documentation License".
</para>
<para>
The Asciidoc source code of this manual can be found at
<ulink url="http://git.osmocom.org/osmo-gsm-manuals/">
http://git.osmocom.org/osmo-gsm-manuals/
</ulink>
</para>
</legalnotice>

View File

@@ -0,0 +1,34 @@
:gfdl-enabled:
OsmoPCU User Manual
===================
Harald Welte <hwelte@sysmocom.de>
include::./common/chapters/preface.adoc[]
include::{srcdir}/chapters/overview.adoc[]
include::{srcdir}/chapters/running.adoc[]
include::./common/chapters/vty.adoc[]
include::./common/chapters/logging.adoc[]
include::{srcdir}/chapters/configuration.adoc[]
include::{srcdir}/chapters/counters.adoc[]
include::./common/chapters/gb.adoc[]
include::./common/chapters/qos-dscp-pcp.adoc[]
include::./common/chapters/vty_cpu_sched.adoc[]
include::./common/chapters/port_numbers.adoc[]
include::./common/chapters/bibliography.adoc[]
include::./common/chapters/glossary.adoc[]
include::./common/chapters/gfdl.adoc[]

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
ex:ts=2:sw=42sts=2:et
-*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml">
<!ENTITY sections-vty SYSTEM "generated/docbook_vty.xml" >
]>
<book>
<info>
<title>OsmoPCU VTY Reference</title>
<copyright>
<year>2014-2021</year>
</copyright>
<legalnotice>
<para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
</para>
</legalnotice>
</info>
<!-- Main chapters-->
&chapter-vty;
</book>

17
doc/manuals/regen_doc.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh -x
if [ -z "$DOCKER_PLAYGROUND" ]; then
echo "You need to set DOCKER_PLAYGROUND"
exit 1
fi
SCRIPT=$(realpath "$0")
MANUAL_DIR=$(dirname "$SCRIPT")
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
OSMO_PCU_BRANCH=$COMMIT ./regen_doc.sh osmo-pcu 4240 \
"$MANUAL_DIR/chapters/counters_generated.adoc" \
"$MANUAL_DIR/vty/osmo-pcu_vty_reference.xml"

View File

@@ -0,0 +1,9 @@
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
<node id='14'>
<child_of id='4' />
<name>PCU Configuration Node</name>
<description>The main PCU configuration including the timeslot
assignment algorithm and other parameters.</description>
</node>
</vtydoc>

View File

@@ -14,16 +14,16 @@ Notes:
Queue of next frames to be transmitted.
States:
GPRS_RLCMAC_ASSIGN
TBF_ST_ASSIGN
After a downlink TBF is created, it resides in this state until the
block flow can start. This is required to give the mobile time to listen
to connect to downlink PDCH.
GPRS_RLCMAC_FLOW,
TBF_ST_FLOW,
During packet flow, this state indicates downlink and uplink TBF block
flow.
GPRS_RLCMAC_FINISHED,
TBF_ST_FINISHED,
Uplink TBF:
After final block is received AND all other blocks are completely
received, the state is entered. The PACKET CONTROL ACK is still not
@@ -33,11 +33,11 @@ States:
downlink blocks are acknowledged yet. (Counter N3015 is counted on each
poll request.)
GPRS_RLCMAC_WAIT_RELEASE,
TBF_ST_WAIT_RELEASE,
The all blocks on downlink TBF have been acked by mobile. The penalty
timer T3192 is running on mobile.
GPRS_RLCMAC_RELEASING,
TBF_ST_RELEASING,
Wait for TFI/USF to be re-used. This state is entered when a counter
reaches it's maximum and T3169 is running.
@@ -52,7 +52,7 @@ When downlink LLC PDU is received:
Attach PDU to LLC Frame of TBF.
Put TBF back into FLOW state.
Done.
If dowlink TBF does not exists for given TLLI, or in RELEASING state:
If downlink TBF does not exists for given TLLI, or in RELEASING state:
Create new downlink TBF.
Attach PDU to LLC Frame of TBF.
If uplink TBF exists for given TLLI, but not in RELEASING state:
@@ -117,13 +117,17 @@ Control TS:
Polling:
In order to poll uplink control block from MS, a special poll state and
frame number is stored at TBF. The scheduler reads that value and will not
assign uplink resource for other TBFs at that frame number.
frame number is stored at PDCH UL Controller. The scheduler reads that value
and will not assign uplink resource for other TBFs at that frame number.
When there is no uplink transmission received on the block, a timeout is
indicated by layer 1 interface. There are two ways of checking timeout:
- The received frame is bad (BFI).
- The GSM indicates that the block should have been already received.
On receipt of an Uplink RLCMAC block, it's the duty of each specific message
handler to release the expectancies previously stored in the PDCH UL
Controller. After the specific handler returns, the generic return path will
expire all reserved events up to the curent FN for that PDCH, eventually
calling timeout functions on TBFs and SBAs owning those reservations. Hence,
the layer 1 interface is expected to provide DATA.ind for each FN block,
containing data=0 if decoding failed, in order to keep the clock up-to-date in
upper layers.
Because polling requires uplink response from MS, the polling must be
performed at control TS.
@@ -131,13 +135,21 @@ Polling:
Data structures of TBFs and PDCHs:
There is a global structure for BTS.
There is a global structure for PCU (struct gprs_pcu the_pcu).
The BTS structure has 8 TRX structures.
A BTS is created and put into PCU's list for each PCUIF INFO_IND with a unique
bts_nr received.
Each BTS structure has 8 TRX structures.
Each TRX structure has 8 PDCH structures, one for each timeslot.
There are two linked lists of TBF instances:
Each BTS structure has a list of MS (struct GprsMs).
Each MS can have 1 UL TBF and 1 DL TBF, and 1 TBF is always assigned to an
existing GprsMS structure.
Each BTS also has two linked lists of TBF instances:
- uplink TBFs
- downlink TBFs
@@ -158,4 +170,6 @@ Data structures of TBFs and PDCHs:
On release of a TBF, the link to this PDCH is removed from all assigned
PDCHs. The TBF is removed from the list of TBFs. The TBF is destroyed.
GprsMs structures are kept alive for a while once they become unused, in order to
have a cache of MS related information it would otherwise need to acquire
again once it interacts with the PCU again.

View File

@@ -1,4 +0,0 @@
pcuconfdir = $(sysconfdir)/osmocom
pcuconf_DATA = osmo-pcu.cfg
EXTRA_DIST = osmo-pcu.cfg

2
include/Makefile.am Normal file
View File

@@ -0,0 +1,2 @@
noinst_HEADERS = \
osmocom/pcu/pcuif_proto.h

View File

@@ -0,0 +1,284 @@
#ifndef _PCUIF_PROTO_H
#define _PCUIF_PROTO_H
#include <osmocom/gsm/l1sap.h>
#include <arpa/inet.h>
#define PCU_SOCK_DEFAULT "/tmp/pcu_bts"
#define PCU_IF_VERSION 0x0a
#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_SUSP_REQ 0x03 /* BTS forwards GPRS SUSP REQ to PCU */
#define PCU_IF_MSG_APP_INFO_REQ 0x04 /* BTS asks PCU to transmit APP INFO via PACCH */
#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_INTERF_IND 0x53 /* interference report */
#define PCU_IF_MSG_PAG_REQ 0x60 /* paging request */
#define PCU_IF_MSG_TXT_IND 0x70 /* Text indication for BTS */
#define PCU_IF_MSG_CONTAINER 0x80 /* Transparent container message */
/* msg_type coming from BSC (inside PCU_IF_MSG_CONTAINER) */
#define PCU_IF_MSG_NEIGH_ADDR_REQ 0x81 /* Neighbor Address Resolution Request */
#define PCU_IF_MSG_NEIGH_ADDR_CNF 0x82 /* Neighbor Address Resolution Confirmation */
/* 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)
/* NSVC address type */
#define PCU_IF_ADDR_TYPE_UNSPEC 0x00 /* No address - empty entry */
#define PCU_IF_ADDR_TYPE_IPV4 0x04 /* IPv4 address */
#define PCU_IF_ADDR_TYPE_IPV6 0x29 /* IPv6 address */
#define PCU_IF_NUM_NSVC 2
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;
uint8_t trx_nr;
uint8_t ts_nr;
} __attribute__ ((packed));
struct gsm_pcu_if_info_ts {
uint8_t tsc;
uint8_t h;
uint8_t hsn;
uint8_t maio;
uint8_t ma_bit_len;
uint8_t ma[8];
} __attribute__ ((packed));
struct gsm_pcu_if_info_trx {
uint16_t arfcn;
uint8_t pdch_mask; /* PDCH timeslot mask */
uint8_t spare;
uint32_t hlayer1;
struct gsm_pcu_if_info_ts ts[8]; /* timeslots per TRX */
} __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[PCU_IF_NUM_NSVC];
uint16_t local_port[PCU_IF_NUM_NSVC];
uint16_t remote_port[PCU_IF_NUM_NSVC];
uint8_t address_type[PCU_IF_NUM_NSVC];
union {
struct in_addr v4;
struct in6_addr v6;
} remote_ip[PCU_IF_NUM_NSVC];
} __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));
/* BTS tells PCU to [once] send given application data via PACCH to all UE with active TBF */
struct gsm_pcu_if_app_info_req {
uint8_t application_type; /* 4bit field, see TS 44.060 11.2.47 */
uint8_t len; /* length of data */
uint8_t data[162]; /* random size choice; ETWS needs 56 bytes */
} __attribute__ ((packed));
/* BTS tells PCU about a GPRS SUSPENSION REQUEST received on DCCH */
struct gsm_pcu_if_susp_req {
uint32_t tlli;
uint8_t ra_id[6];
uint8_t cause;
} __attribute__ ((packed));
/* Interference measurements on PDCH timeslots */
struct gsm_pcu_if_interf_ind {
uint8_t trx_nr;
uint8_t spare[3];
uint32_t fn;
uint8_t interf[8];
} __attribute__ ((packed));
/* Contains messages transmitted BSC<->PCU, potentially forwarded by BTS via IPA/PCU */
struct gsm_pcu_if_container {
uint8_t msg_type;
uint8_t spare;
uint16_t length; /* network byte order */
uint8_t data[0];
} __attribute__ ((packed));
/*** Used inside container: NOTE: values must be network byte order here! ***/
/* Neighbor Address Resolution Request */
struct gsm_pcu_if_neigh_addr_req {
uint16_t local_lac;
uint16_t local_ci;
uint16_t tgt_arfcn;
uint8_t tgt_bsic;
} __attribute__ ((packed));
/* Neighbor Address Resolution Confirmation */
struct gsm_pcu_if_neigh_addr_cnf {
struct gsm_pcu_if_neigh_addr_req orig_req;
uint8_t err_code; /* 0 success, !0 failed & below unset */
/* RAI + CI (CGI-PS): */
struct __attribute__ ((packed)) {
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_3_digits;
uint16_t lac;
uint8_t rac;
uint16_t cell_identity;
} cgi_ps;
} __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_susp_req susp_req;
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;
struct gsm_pcu_if_app_info_req app_info_req;
struct gsm_pcu_if_interf_ind interf_ind;
struct gsm_pcu_if_container container;
} u;
} __attribute__ ((packed));
#endif /* _PCUIF_PROTO_H */

View File

@@ -15,12 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
app_configs = {
"osmo-pcu": ["examples/osmo-pcu.cfg"]
"osmo-pcu": ["doc/examples/osmo-pcu.cfg"]
}
apps = [(4240, "src/osmo-pcu", "Osmo-PCU", "osmo-pcu"),
apps = [(4240, "src/osmo-pcu", "OsmoPCU", "osmo-pcu"),
]
vty_command = ["src/osmo-pcu", "-c", "examples/osmo-pcu.cfg"]
vty_command = ["src/osmo-pcu", "-c", "doc/examples/osmo-pcu.cfg"]
vty_app = apps[0]

View File

@@ -18,107 +18,198 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS)
AUTOMAKE_OPTIONS = subdir-objects
AM_CPPFLAGS = -I$(top_srcdir)/include $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOGSM_CFLAGS)
if ENABLE_SYSMODSP
AM_CPPFLAGS += -DENABLE_SYSMODSP
AM_CPPFLAGS += -DENABLE_DIRECT_PHY
endif
if ENABLE_LC15BTS_PHY
AM_CPPFLAGS += -DENABLE_DIRECT_PHY
endif
if ENABLE_OC2GBTS_PHY
AM_CPPFLAGS += -DENABLE_DIRECT_PHY
endif
AM_CXXFLAGS = -Wall -ldl -pthread
AM_LDFLAGS = -lrt
noinst_LTLIBRARIES = libgprs.la
libgprs_la_SOURCES = \
gprs_debug.cpp \
csn1.cpp \
gsm_rlcmac.cpp \
gprs_bssgp_pcu.cpp \
csn1.c \
csn1_dec.c \
csn1_enc.c \
gsm_rlcmac.c \
gprs_bssgp_pcu.c \
gprs_bssgp_rim.c \
gprs_rlcmac.cpp \
gprs_rlcmac_sched.cpp \
gprs_rlcmac_meas.cpp \
gprs_rlcmac_ts_alloc.cpp \
gsm_timer.cpp \
bitvector.cpp \
gprs_ms.c \
gprs_ms_storage.cpp \
gprs_pcu.c \
pcu_l1_if.cpp \
pcu_vty.c \
pcu_vty_functions.cpp \
mslot_class.c \
nacc_fsm.c \
neigh_cache.c \
tbf.cpp \
tbf_fsm.c \
tbf_ul.cpp \
tbf_ul_ack_fsm.c \
tbf_ul_ass_fsm.c \
tbf_dl.cpp \
tbf_dl_ass_fsm.c \
bts.cpp \
poll_controller.cpp \
bts_pch_timer.c \
pdch.cpp \
pdch_ul_controller.c \
encoding.cpp \
ta.cpp \
sba.cpp \
sba.c \
decoding.cpp \
llc.cpp \
rlc.cpp
if ENABLE_SYSMOBTS
libgprs_la_SOURCES += \
sysmo_sock.cpp
else
libgprs_la_SOURCES += \
openbts_sock.cpp
endif
rlc.cpp \
osmobts_sock.c \
gprs_codel.c \
coding_scheme.c \
egprs_rlc_compression.cpp \
gprs_rlcmac_sched.cpp
bin_PROGRAMS = \
osmo-pcu
noinst_PROGRAMS =
if ENABLE_SYSMODSP
noinst_PROGRAMS += \
osmo-pcu-remote
endif
noinst_HEADERS = \
gprs_debug.h \
csn1.h \
gsm_rlcmac.h \
gprs_bssgp_pcu.h \
gprs_bssgp_rim.h \
gprs_rlcmac.h \
pcuif_proto.h \
gprs_ms.h \
gprs_ms_storage.h \
gprs_pcu.h \
pcu_l1_if.h \
gsm_timer.h \
bitvector.h \
pcu_vty.h \
sysmo_l1_if.h \
femtobts.h \
pcu_vty_functions.h \
mslot_class.h \
nacc_fsm.h \
neigh_cache.h \
tbf.h \
tbf_fsm.h \
tbf_ul.h \
tbf_ul_ack_fsm.h \
tbf_ul_ass_fsm.h \
tbf_dl.h \
tbf_dl_ass_fsm.h \
bts.h \
poll_controller.h \
bts_pch_timer.h \
pdch.h \
pdch_ul_controller.h \
encoding.h \
ta.h \
sba.h \
rlc.h \
decoding.h \
llc.h
llc.h \
pcu_utils.h \
cxx_linuxlist.h \
gprs_codel.h \
coding_scheme.h \
egprs_rlc_compression.h \
wireshark_compat.h
osmo_pcu_SOURCES = pcu_main.cpp
if ENABLE_SYSMODSP
osmo_pcu_SOURCES += sysmo_l1_if.c \
sysmo_l1_hw.c \
femtobts.c
AM_CPPFLAGS += -I$(srcdir)/osmo-bts-sysmo -I$(SYSMOBTS_INCDIR)
osmo_pcu_remote_SOURCES = pcu_main.cpp \
sysmo_l1_if.c \
sysmo_l1_fwd.c \
femtobts.c
EXTRA_DIST = \
osmo-bts-sysmo/sysmo_l1_if.c \
osmo-bts-sysmo/sysmo_l1_if.h \
osmo-bts-sysmo/sysmo_l1_hw.c \
osmo-bts-sysmo/femtobts.c \
osmo-bts-sysmo/femtobts.h
noinst_HEADERS += \
osmo-bts-sysmo/sysmo_l1_if.h \
osmo-bts-sysmo/femtobts.h
noinst_PROGRAMS += \
osmo-pcu-remote
osmo_pcu_SOURCES += \
osmo-bts-sysmo/sysmo_l1_if.c \
osmo-bts-sysmo/sysmo_l1_hw.c \
osmo-bts-sysmo/femtobts.c
osmo_pcu_remote_SOURCES = \
pcu_main.cpp \
osmo-bts-sysmo/sysmo_l1_if.c \
osmo-bts-sysmo/sysmo_l1_fwd.c \
osmo-bts-sysmo/femtobts.c
osmo_pcu_remote_LDADD = \
libgprs.la \
$(LIBOSMOGB_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(COMMON_LA)
endif
if ENABLE_LC15BTS_PHY
AM_CPPFLAGS += $(LITECELL15_CFLAGS) -I$(srcdir)/osmo-bts-litecell15
EXTRA_DIST = \
osmo-bts-litecell15/lc15_l1_if.c \
osmo-bts-litecell15/lc15_l1_if.h \
osmo-bts-litecell15/lc15_l1_hw.c \
osmo-bts-litecell15/lc15bts.c \
osmo-bts-litecell15/lc15bts.h
noinst_HEADERS += \
osmo-bts-litecell15/lc15_l1_if.h \
osmo-bts-litecell15/lc15bts.h
osmo_pcu_SOURCES += \
osmo-bts-litecell15/lc15_l1_if.c \
osmo-bts-litecell15/lc15_l1_hw.c \
osmo-bts-litecell15/lc15bts.c
endif
if ENABLE_OC2GBTS_PHY
AM_CPPFLAGS += -I$(OC2G_INCDIR) -I$(srcdir)/osmo-bts-oc2g
EXTRA_DIST = \
osmo-bts-oc2g/oc2g_l1_if.c \
osmo-bts-oc2g/oc2g_l1_if.h \
osmo-bts-oc2g/oc2g_l1_hw.c \
osmo-bts-oc2g/oc2gbts.c \
osmo-bts-oc2g/oc2gbts.h
noinst_HEADERS += \
osmo-bts-oc2g/oc2g_l1_if.h \
osmo-bts-oc2g/oc2gbts.h
osmo_pcu_SOURCES += \
osmo-bts-oc2g/oc2g_l1_if.c \
osmo-bts-oc2g/oc2g_l1_hw.c \
osmo-bts-oc2g/oc2gbts.c
endif
osmo_pcu_LDADD = \
libgprs.la \
$(LIBOSMOGB_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(COMMON_LA)
if ENABLE_SYSMODSP
osmo_pcu_remote_LDADD = \
libgprs.la \
$(LIBOSMOGB_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(COMMON_LA)
endif
#MOSTLYCLEANFILES += testSource testDestination

View File

@@ -1,119 +0,0 @@
/* bitvector.cpp
*
* Copyright (C) 2012 Ivan Klyuchnikov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*! \addtogroup bitvector
* @{
*/
/*! \file bitvector.cpp
* \brief Additional functions for Osmocom bit vector abstraction.
*/
#include <bitvector.h>
extern "C" {
#include <osmocom/core/talloc.h>
}
void *bv_tall_ctx;
struct bitvec *bitvec_alloc(unsigned size)
{
struct bitvec *bv = talloc_zero(bv_tall_ctx, struct bitvec);
bv->data_len = size;
bv->cur_bit = 0;
bv->data = talloc_zero_array(bv_tall_ctx, uint8_t, size);
return bv;
}
void bitvec_free(struct bitvec *bv)
{
talloc_free(bv->data);
talloc_free(bv);
}
unsigned int bitvec_pack(struct bitvec *bv, uint8_t *buffer)
{
unsigned int i = 0;
for (i = 0; i < bv->data_len; i++)
{
buffer[i] = bv->data[i];
}
return i;
}
unsigned int bitvec_unpack(struct bitvec *bv, uint8_t *buffer)
{
unsigned int i = 0;
for (i = 0; i < bv->data_len; i++)
{
bv->data[i] = buffer[i];
}
return i;
}
int bitvec_unhex(struct bitvec *bv, const char* src)
{
unsigned val;
unsigned write_index = 0;
unsigned digits = bv->data_len*2;
for (unsigned i=0; i<digits; i++) {
if (sscanf(src+i, "%1x", &val) < 1) {
return 1;
}
bitvec_write_field(bv, write_index,val, 4);
}
return 0;
}
uint64_t bitvec_read_field(struct bitvec *bv, unsigned& read_index, unsigned len)
{
unsigned int i;
uint64_t ui = 0;
bv->cur_bit = read_index;
for (i = 0; i < len; i++) {
int bit = bitvec_get_bit_pos((const struct bitvec *)bv, bv->cur_bit);
if (bit < 0)
return bit;
if (bit)
ui |= ((uint64_t)1 << (len - i - 1));
bv->cur_bit++;
}
read_index += len;
return ui;
}
int bitvec_write_field(struct bitvec *bv, unsigned& write_index, uint64_t val, unsigned len)
{
unsigned int i;
int rc;
bv->cur_bit = write_index;
for (i = 0; i < len; i++) {
int bit = 0;
if (val & ((uint64_t)1 << (len - i - 1)))
bit = 1;
rc = bitvec_set_bit(bv, (bit_value)bit);
if (rc)
return rc;
}
write_index += len;
return 0;
}

File diff suppressed because it is too large Load Diff

571
src/bts.h
View File

@@ -2,6 +2,7 @@
*
* Copyright (C) 2012 Ivan Klyuchnikov
* Copyright (C) 2013 by Holger Hans Peter Freyther
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -20,301 +21,371 @@
#pragma once
#include <pdch.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/stat_item.h>
#include <osmocom/core/tdef.h>
#include <osmocom/core/time_cc.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gsm/l1sap.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm48_rest_octets.h>
#include <osmocom/gsm/gsm48.h>
#include "mslot_class.h"
#include "gsm_rlcmac.h"
#include "gprs_pcu.h"
#ifdef __cplusplus
}
#endif
#include "poll_controller.h"
#include "sba.h"
#include "ta.h"
#include "tbf.h"
#endif
#include "coding_scheme.h"
#include <stdint.h>
struct BTS;
/*
* PDCH instance
*/
struct gprs_rlcmac_pdch {
#ifdef __cplusplus
struct gprs_rlcmac_paging *dequeue_paging();
struct msgb *packet_paging_request();
void add_paging(struct gprs_rlcmac_paging *pag);
void free_resources();
bool is_enabled() const;
void enable();
void disable();
/* dispatching of messages */
int rcv_block(uint8_t *data, uint8_t len, uint32_t fn, int8_t rssi);
gprs_rlcmac_bts *bts_data() const;
BTS *bts() const;
uint8_t trx_no() const;
#endif
uint8_t m_is_enabled; /* TS is enabled */
uint8_t tsc; /* TSC of this slot */
uint8_t next_ul_tfi; /* next uplink TBF/TFI to schedule (0..31) */
uint8_t next_dl_tfi; /* next downlink TBF/TFI to schedule (0..31) */
struct gprs_rlcmac_tbf *ul_tbf[32]; /* array of UL TBF, by UL TFI */
struct gprs_rlcmac_tbf *dl_tbf[32]; /* array of DL TBF, by DL TFI */
struct llist_head paging_list; /* list of paging messages */
uint32_t last_rts_fn; /* store last frame number of RTS */
/* back pointers */
struct gprs_rlcmac_trx *trx;
uint8_t ts_no;
#ifdef __cplusplus
private:
int rcv_data_block_acknowledged(uint8_t *data, uint8_t len, int8_t rssi);
int rcv_control_block(bitvec *rlc_block, uint32_t fn);
void rcv_control_ack(Packet_Control_Acknowledgement_t *, uint32_t fn);
void rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *, uint32_t fn);
void rcv_resource_request(Packet_Resource_Request_t *t, uint32_t fn);
void rcv_measurement_report(Packet_Measurement_Report_t *t, uint32_t fn);
#endif
};
struct GprsMs;
struct gprs_rlcmac_bts;
struct gprs_rlcmac_trx {
void *fl1h;
uint16_t arfcn;
struct gprs_rlcmac_pdch pdch[8];
struct gprs_rlcmac_tbf *ul_tbf[32]; /* array of UL TBF, by UL TFI */
struct gprs_rlcmac_tbf *dl_tbf[32]; /* array of DL TBF, by DL TFI */
/* back pointers */
struct BTS *bts;
struct gprs_rlcmac_bts *bts;
uint8_t trx_no;
};
/**
* This is the data from C. As soon as our minimal compiler is gcc 4.7
* we can start to compile pcu_vty.c with c++ and remove the split.
*/
struct gprs_rlcmac_bts {
uint8_t bsic;
uint8_t fc_interval;
uint8_t cs1;
uint8_t cs2;
uint8_t cs3;
uint8_t cs4;
uint8_t initial_cs_dl, initial_cs_ul;
uint8_t force_cs; /* 0=use from BTS 1=use from VTY */
uint16_t force_llc_lifetime; /* overrides lifetime from SGSN */
uint8_t t3142;
uint8_t t3169;
uint8_t t3191;
uint16_t t3193_msec;
uint8_t t3195;
uint8_t n3101;
uint8_t n3103;
uint8_t n3105;
struct gprs_rlcmac_trx trx[8];
int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
uint32_t alloc_algorithm_curst; /* options to customize algorithm */
uint8_t force_two_phase;
uint8_t alpha, gamma;
/* TBF handling, make private or move into TBFController */
/* list of uplink TBFs */
struct llist_head ul_tbfs;
struct llist_head ul_tbfs; /* list of gprs_rlcmac_tbf */
/* list of downlink TBFs */
struct llist_head dl_tbfs;
struct llist_head dl_tbfs; /* list of gprs_rlcmac_tbf */
/**
* Point back to the C++ object. This is used during the transition
* period.
*/
struct BTS *bts;
};
#ifdef __cplusplus
extern "C" {
#endif
void bts_trx_init(struct gprs_rlcmac_trx *trx, struct gprs_rlcmac_bts *bts, uint8_t trx_no);
void bts_trx_reserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir, uint8_t slots);
void bts_trx_unreserve_slots(struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir, uint8_t slots);
void bts_trx_free_all_tbf(struct gprs_rlcmac_trx *trx);
void bts_update_tbf_ta(struct gprs_rlcmac_bts *bts, const char *p, uint32_t fn,
uint8_t trx_no, uint8_t ts, int8_t ta, bool is_rach);
#ifdef __cplusplus
}
#endif
enum {
CTR_PDCH_ALL_ALLOCATED,
CTR_TBF_DL_ALLOCATED,
CTR_TBF_DL_FREED,
CTR_TBF_DL_ABORTED,
CTR_TBF_UL_ALLOCATED,
CTR_TBF_UL_FREED,
CTR_TBF_UL_ABORTED,
CTR_TBF_REUSED,
CTR_TBF_ALLOC_ALGO_A,
CTR_TBF_ALLOC_ALGO_B,
CTR_TBF_ALLOC_FAIL,
CTR_TBF_ALLOC_FAIL_NO_TFI,
CTR_TBF_ALLOC_FAIL_NO_USF,
CTR_TBF_ALLOC_FAIL_NO_SLOT_COMBI,
CTR_TBF_ALLOC_FAIL_NO_SLOT_AVAIL,
CTR_RLC_SENT,
CTR_RLC_RESENT,
CTR_RLC_RESTARTED,
CTR_RLC_STALLED,
CTR_RLC_NACKED,
CTR_RLC_FINAL_BLOCK_RESENT,
CTR_RLC_ASS_TIMEDOUT,
CTR_RLC_ASS_FAILED,
CTR_RLC_ACK_TIMEDOUT,
CTR_RLC_ACK_FAILED,
CTR_RLC_REL_TIMEDOUT,
CTR_RLC_LATE_BLOCK,
CTR_RLC_SENT_DUMMY,
CTR_RLC_SENT_CONTROL,
CTR_RLC_DL_BYTES,
CTR_RLC_DL_PAYLOAD_BYTES,
CTR_RLC_UL_BYTES,
CTR_RLC_UL_PAYLOAD_BYTES,
CTR_DECODE_ERRORS,
CTR_SBA_ALLOCATED,
CTR_SBA_FREED,
CTR_SBA_TIMEDOUT,
CTR_LLC_FRAME_TIMEDOUT,
CTR_LLC_FRAME_DROPPED,
CTR_LLC_FRAME_SCHED,
CTR_LLC_DL_BYTES,
CTR_LLC_UL_BYTES,
CTR_PCH_REQUESTS,
CTR_PCH_REQUESTS_ALREADY,
CTR_PCH_REQUESTS_TIMEDOUT,
CTR_RACH_REQUESTS,
CTR_RACH_REQUESTS_11BIT,
CTR_RACH_REQUESTS_ONE_PHASE,
CTR_RACH_REQUESTS_TWO_PHASE,
CTR_RACH_REQUESTS_UNEXPECTED,
CTR_SPB_UL_FIRST_SEGMENT,
CTR_SPB_UL_SECOND_SEGMENT,
CTR_SPB_DL_FIRST_SEGMENT,
CTR_SPB_DL_SECOND_SEGMENT,
CTR_IMMEDIATE_ASSIGN_UL_TBF,
CTR_IMMEDIATE_ASSIGN_UL_TBF_ONE_PHASE,
CTR_IMMEDIATE_ASSIGN_UL_TBF_TWO_PHASE,
CTR_IMMEDIATE_ASSIGN_UL_TBF_CONTENTION_RESOLUTION_SUCCESS,
CTR_IMMEDIATE_ASSIGN_REJ,
CTR_IMMEDIATE_ASSIGN_DL_TBF,
CTR_CHANNEL_REQUEST_DESCRIPTION,
CTR_PKT_UL_ASSIGNMENT,
CTR_PKT_ACCESS_REJ,
CTR_PKT_DL_ASSIGNMENT,
CTR_PKT_CELL_CHG_NOTIFICATION,
CTR_PKT_CELL_CHG_CONTINUE,
CTR_PKT_NEIGH_CELL_DATA,
CTR_RLC_RECV_CONTROL,
CTR_PUA_POLL_TIMEDOUT,
CTR_PUA_POLL_FAILED,
CTR_PDA_POLL_TIMEDOUT,
CTR_PDA_POLL_FAILED,
CTR_PUAN_POLL_TIMEDOUT,
CTR_PUAN_POLL_FAILED,
CTR_PDAN_POLL_TIMEDOUT,
CTR_PDAN_POLL_FAILED,
CTR_GPRS_DL_CS1,
CTR_GPRS_DL_CS2,
CTR_GPRS_DL_CS3,
CTR_GPRS_DL_CS4,
CTR_EGPRS_DL_MCS1,
CTR_EGPRS_DL_MCS2,
CTR_EGPRS_DL_MCS3,
CTR_EGPRS_DL_MCS4,
CTR_EGPRS_DL_MCS5,
CTR_EGPRS_DL_MCS6,
CTR_EGPRS_DL_MCS7,
CTR_EGPRS_DL_MCS8,
CTR_EGPRS_DL_MCS9,
CTR_GPRS_UL_CS1,
CTR_GPRS_UL_CS2,
CTR_GPRS_UL_CS3,
CTR_GPRS_UL_CS4,
CTR_EGPRS_UL_MCS1,
CTR_EGPRS_UL_MCS2,
CTR_EGPRS_UL_MCS3,
CTR_EGPRS_UL_MCS4,
CTR_EGPRS_UL_MCS5,
CTR_EGPRS_UL_MCS6,
CTR_EGPRS_UL_MCS7,
CTR_EGPRS_UL_MCS8,
CTR_EGPRS_UL_MCS9,
};
enum {
STAT_MS_PRESENT,
STAT_PDCH_AVAILABLE,
STAT_PDCH_OCCUPIED,
STAT_PDCH_OCCUPIED_GPRS,
STAT_PDCH_OCCUPIED_EGPRS,
};
/* RACH.ind parameters (to be parsed) */
struct rach_ind_params {
enum ph_burst_type burst_type;
bool is_11bit;
uint16_t ra;
uint8_t trx_nr;
uint8_t ts_nr;
uint32_t rfn;
int16_t qta;
};
/* [EGPRS Packet] Channel Request parameters (parsed) */
struct chan_req_params {
unsigned int egprs_mslot_class;
unsigned int priority;
bool single_block;
};
struct GprsMsStorage;
struct pcu_l1_meas;
/**
* I represent a GSM BTS. I have one or more TRX, I know the current
* GSM time and I have controllers that help with allocating resources
* on my TRXs.
*/
struct BTS {
public:
enum {
CTR_TBF_DL_ALLOCATED,
CTR_TBF_DL_FREED,
CTR_TBF_UL_ALLOCATED,
CTR_TBF_UL_FREED,
CTR_TBF_REUSED,
CTR_RLC_SENT,
CTR_RLC_RESENT,
CTR_RLC_RESTARTED,
CTR_RLC_STALLED,
CTR_RLC_NACKED,
CTR_DECODE_ERRORS,
CTR_SBA_ALLOCATED,
CTR_SBA_FREED,
CTR_SBA_TIMEDOUT,
CTR_LLC_FRAME_TIMEDOUT,
CTR_LLC_FRAME_DROPPED,
CTR_LLC_FRAME_SCHED,
CTR_RACH_REQUESTS,
};
struct gprs_rlcmac_bts {
uint8_t nr; /* bts_nr */
struct llist_head list; /* queued in pcu->bts_list */
bool active;
struct osmo_cell_global_id_ps cgi_ps;
uint8_t bsic;
uint8_t cs_mask; /* Allowed CS mask from BTS */
uint16_t mcs_mask; /* Allowed MCS mask from BTS */
struct { /* information stored from last received PCUIF info_ind message */
uint8_t initial_cs;
uint8_t initial_mcs;
} pcuif_info_ind;
uint8_t initial_cs_dl, initial_cs_ul;
uint8_t initial_mcs_dl, initial_mcs_ul;
/* Timer defintions */
struct osmo_tdef *T_defs_bts; /* timers controlled by BTS, received through PCUIF */
uint8_t n3101;
uint8_t n3103;
uint8_t n3105;
struct gprs_rlcmac_trx trx[8];
BTS();
~BTS();
uint8_t si1[GSM_MACBLOCK_LEN];
bool si1_is_set;
uint8_t si2[GSM_MACBLOCK_LEN];
bool si2_is_set;
struct gsm_sysinfo_freq si2_bcch_cell_list[1024];
uint8_t si3[GSM_MACBLOCK_LEN];
bool si3_is_set;
uint8_t si13[GSM_MACBLOCK_LEN];
struct osmo_gsm48_si13_info si13_ro_decoded;
bool si13_is_set;
static BTS* main_bts();
/* State for dynamic algorithm selection */
int multislot_disabled;
struct gprs_rlcmac_bts *bts_data();
SBAController *sba();
TimingAdvance *timing_advance();
/* Packet Application Information (3GPP TS 44.060 11.2.47, usually ETWS primary message). We don't need to store
* more than one message, because they get sent so rarely. */
struct msgb *app_info;
uint32_t app_info_pending; /* Count of MS with active TBF, to which we did not send app_info yet */
/** TODO: change the number to unsigned */
void set_current_frame_number(int frame_number);
int current_frame_number() const;
/* main nsei */
struct gprs_ns2_nse *nse;
/** add paging to paging queue(s) */
int add_paging(uint8_t chan_needed, uint8_t *identity_lv);
/* back pointer to PCU object */
struct gprs_pcu *pcu;
gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir);
gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts);
gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, enum gprs_rlcmac_tbf_direction dir);
uint32_t cur_fn;
int cur_blk_fn;
uint8_t max_cs_dl, max_cs_ul;
uint8_t max_mcs_dl, max_mcs_ul;
struct rate_ctr_group *ratectrs;
struct osmo_stat_item_group *statg;
int tfi_find_free(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx);
struct GprsMsStorage *ms_store;
int rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn);
int rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta);
/* List of struct bts_pch_timer for active PCH pagings */
struct llist_head pch_timer;
void trigger_dl_ass(gprs_rlcmac_tbf *tbf, gprs_rlcmac_tbf *old_tbf, const char *imsi);
void snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi);
/*
* Statistics
*/
void tbf_dl_created();
void tbf_dl_freed();
void tbf_ul_created();
void tbf_ul_freed();
void tbf_reused();
void rlc_sent();
void rlc_resent();
void rlc_restarted();
void rlc_stalled();
void rlc_nacked();
void decode_error();
void sba_allocated();
void sba_freed();
void sba_timedout();
void llc_timedout_frame();
void llc_dropped_frame();
void llc_frame_sched();
void rach_frame();
/*
* Below for C interface for the VTY
*/
struct rate_ctr_group *rate_counters() const;
private:
int m_cur_fn;
struct gprs_rlcmac_bts m_bts;
PollController m_pollController;
SBAController m_sba;
TimingAdvance m_ta;
struct rate_ctr_group *m_ratectrs;
private:
/* disable copying to avoid slicing */
BTS(const BTS&);
BTS& operator=(const BTS&);
struct osmo_time_cc all_allocated_pdch;
};
inline int BTS::current_frame_number() const
{
return m_cur_fn;
}
inline TimingAdvance *BTS::timing_advance()
{
return &m_ta;
}
inline SBAController *BTS::sba()
{
return &m_sba;
}
inline BTS *gprs_rlcmac_pdch::bts() const
{
return trx->bts;
}
inline struct rate_ctr_group *BTS::rate_counters() const
{
return m_ratectrs;
}
#define CREATE_COUNT_INLINE(func_name, ctr_name) \
inline void BTS::func_name() {\
rate_ctr_inc(&m_ratectrs->ctr[ctr_name]); \
}
CREATE_COUNT_INLINE(tbf_dl_created, CTR_TBF_DL_ALLOCATED)
CREATE_COUNT_INLINE(tbf_dl_freed, CTR_TBF_DL_FREED)
CREATE_COUNT_INLINE(tbf_ul_created, CTR_TBF_UL_ALLOCATED)
CREATE_COUNT_INLINE(tbf_ul_freed, CTR_TBF_UL_FREED)
CREATE_COUNT_INLINE(tbf_reused, CTR_TBF_REUSED)
CREATE_COUNT_INLINE(rlc_sent, CTR_RLC_SENT)
CREATE_COUNT_INLINE(rlc_resent, CTR_RLC_RESENT)
CREATE_COUNT_INLINE(rlc_restarted, CTR_RLC_RESTARTED)
CREATE_COUNT_INLINE(rlc_stalled, CTR_RLC_STALLED)
CREATE_COUNT_INLINE(rlc_nacked, CTR_RLC_NACKED)
CREATE_COUNT_INLINE(decode_error, CTR_DECODE_ERRORS)
CREATE_COUNT_INLINE(sba_allocated, CTR_SBA_ALLOCATED)
CREATE_COUNT_INLINE(sba_freed, CTR_SBA_FREED)
CREATE_COUNT_INLINE(sba_timedout, CTR_SBA_TIMEDOUT)
CREATE_COUNT_INLINE(llc_timedout_frame, CTR_LLC_FRAME_TIMEDOUT);
CREATE_COUNT_INLINE(llc_dropped_frame, CTR_LLC_FRAME_DROPPED);
CREATE_COUNT_INLINE(llc_frame_sched, CTR_LLC_FRAME_SCHED);
CREATE_COUNT_INLINE(rach_frame, CTR_RACH_REQUESTS);
#undef CREATE_COUNT_INLINE
inline gprs_rlcmac_bts *gprs_rlcmac_pdch::bts_data() const
{
return trx->bts->bts_data();
}
inline uint8_t gprs_rlcmac_pdch::trx_no() const
{
return trx->trx_no;
}
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct gprs_rlcmac_bts *bts_main_data();
struct rate_ctr_group *bts_main_data_stats();
#ifdef __cplusplus
struct paging_req_cs {
uint8_t chan_needed;
uint32_t tlli; /* GSM_RESERVED_TMSI if not present */
bool mi_tmsi_present;
struct osmo_mobile_identity mi_tmsi;
bool mi_imsi_present;
struct osmo_mobile_identity mi_imsi;
};
struct GprsMs *bts_alloc_ms(struct gprs_rlcmac_bts *bts, uint8_t ms_class, uint8_t egprs_ms_class);
int bts_add_paging(struct gprs_rlcmac_bts *bts, const struct paging_req_cs *req, struct GprsMs *ms);
uint32_t bts_rfn_to_fn(const struct gprs_rlcmac_bts *bts, int32_t rfn);
struct gprs_rlcmac_dl_tbf *bts_dl_tbf_by_tfi(struct gprs_rlcmac_bts *bts, uint8_t tfi, uint8_t trx, uint8_t ts);
struct gprs_rlcmac_ul_tbf *bts_ul_tbf_by_tfi(struct gprs_rlcmac_bts *bts, uint8_t tfi, uint8_t trx, uint8_t ts);
void bts_snd_dl_ass(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf);
void bts_set_current_frame_number(struct gprs_rlcmac_bts *bts, uint32_t frame_number);
void bts_set_current_block_frame_number(struct gprs_rlcmac_bts *bts, int frame_number);
static inline uint32_t bts_current_frame_number(const struct gprs_rlcmac_bts *bts)
{
return bts->cur_fn;
}
inline bool gprs_rlcmac_pdch::is_enabled() const
int bts_tfi_find_free(const struct gprs_rlcmac_bts *bts, enum gprs_rlcmac_tbf_direction dir,
uint8_t *_trx, int8_t use_trx);
int bts_rcv_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip);
int bts_rcv_ptcch_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip);
int bts_rcv_imm_ass_cnf(struct gprs_rlcmac_bts *bts, const uint8_t *data, uint32_t fn);
void bts_send_gsmtap(struct gprs_rlcmac_bts *bts,
enum pcu_gsmtap_category categ, bool uplink, uint8_t trx_no,
uint8_t ts_no, uint8_t channel, uint32_t fn,
const uint8_t *data, unsigned int len);
void bts_send_gsmtap_meas(struct gprs_rlcmac_bts *bts,
enum pcu_gsmtap_category categ, bool uplink, uint8_t trx_no,
uint8_t ts_no, uint8_t channel, uint32_t fn,
const uint8_t *data, unsigned int len, struct pcu_l1_meas *meas);
void bts_send_gsmtap_rach(struct gprs_rlcmac_bts *bts,
enum pcu_gsmtap_category categ, uint8_t channel,
const struct rach_ind_params *rip);
struct GprsMsStorage *bts_ms_store(const struct gprs_rlcmac_bts *bts);
struct GprsMs *bts_ms_by_tlli(struct gprs_rlcmac_bts *bts, uint32_t tlli, uint32_t old_tlli);
static inline struct rate_ctr_group *bts_rate_counters(struct gprs_rlcmac_bts *bts)
{
return m_is_enabled;
return bts->ratectrs;
}
static inline struct osmo_stat_item_group *bts_stat_items(struct gprs_rlcmac_bts *bts)
{
return bts->statg;
}
static inline void bts_do_rate_ctr_inc(const struct gprs_rlcmac_bts *bts, unsigned int ctr_id) {
rate_ctr_inc(rate_ctr_group_get_ctr(bts->ratectrs, ctr_id));
}
static inline void bts_do_rate_ctr_add(const struct gprs_rlcmac_bts *bts, unsigned int ctr_id, int inc) {
rate_ctr_add(rate_ctr_group_get_ctr(bts->ratectrs, ctr_id), inc);
}
static inline void bts_stat_item_add(struct gprs_rlcmac_bts *bts, unsigned int stat_id, int inc) {
struct osmo_stat_item *item = osmo_stat_item_group_get_item(bts->statg, stat_id);
int32_t val = osmo_stat_item_get_last(item);
osmo_stat_item_set(item, val + inc);
}
#define bts_stat_item_inc(bts, stat_id) bts_stat_item_add(bts, stat_id, 1)
#define bts_stat_item_dec(bts, stat_id) bts_stat_item_add(bts, stat_id, -1)
struct gprs_rlcmac_bts *bts_alloc(struct gprs_pcu *pcu, uint8_t bts_nr);
struct gprs_rlcmac_sba *bts_alloc_sba(struct gprs_rlcmac_bts *bts, uint8_t ta);
void bts_recalc_initial_cs(struct gprs_rlcmac_bts *bts);
void bts_recalc_initial_mcs(struct gprs_rlcmac_bts *bts);
void bts_recalc_max_cs(struct gprs_rlcmac_bts *bts);
void bts_recalc_max_mcs(struct gprs_rlcmac_bts *bts);
struct GprsMs *bts_ms_by_imsi(struct gprs_rlcmac_bts *bts, const char *imsi);
uint8_t bts_max_cs_dl(const struct gprs_rlcmac_bts *bts);
uint8_t bts_max_cs_ul(const struct gprs_rlcmac_bts *bts);
uint8_t bts_max_mcs_dl(const struct gprs_rlcmac_bts *bts);
uint8_t bts_max_mcs_ul(const struct gprs_rlcmac_bts *bts);
void bts_set_max_cs_dl(struct gprs_rlcmac_bts *bts, uint8_t cs_dl);
void bts_set_max_cs_ul(struct gprs_rlcmac_bts *bts, uint8_t cs_ul);
void bts_set_max_mcs_dl(struct gprs_rlcmac_bts *bts, uint8_t mcs_dl);
void bts_set_max_mcs_ul(struct gprs_rlcmac_bts *bts, uint8_t mcs_ul);
bool bts_cs_dl_is_supported(const struct gprs_rlcmac_bts *bts, enum CodingScheme cs);
const struct llist_head* bts_ms_list(struct gprs_rlcmac_bts *bts);
uint8_t bts_get_ms_pwr_alpha(const struct gprs_rlcmac_bts *bts);
bool bts_all_pdch_allocated(const struct gprs_rlcmac_bts *bts);
#ifdef __cplusplus
}
#endif

121
src/bts_pch_timer.c Normal file
View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Oliver Smith
*
* 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 <string.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/tdef.h>
#include <osmocom/core/utils.h>
#include <gprs_debug.h>
#include <gprs_pcu.h>
#include <bts_pch_timer.h>
#include <gprs_ms.h>
static struct bts_pch_timer *bts_pch_timer_get_by_ptmsi(struct gprs_rlcmac_bts *bts, uint32_t ptmsi)
{
struct bts_pch_timer *p;
OSMO_ASSERT(ptmsi != GSM_RESERVED_TMSI);
llist_for_each_entry(p, &bts->pch_timer, entry) {
if (p->ptmsi != GSM_RESERVED_TMSI && p->ptmsi == ptmsi)
return p;
}
return NULL;
}
struct bts_pch_timer *bts_pch_timer_get_by_imsi(struct gprs_rlcmac_bts *bts, const char *imsi)
{
struct bts_pch_timer *p;
llist_for_each_entry(p, &bts->pch_timer, entry) {
if (strcmp(p->imsi, imsi) == 0)
return p;
}
return NULL;
}
static void bts_pch_timer_remove(struct bts_pch_timer *p)
{
osmo_timer_del(&p->T3113);
llist_del(&p->entry);
LOGP(DPCU, LOGL_DEBUG, "PCH paging timer stopped for IMSI=%s\n", p->imsi);
talloc_free(p);
}
static void T3113_callback(void *data)
{
struct bts_pch_timer *p = data;
LOGP(DPCU, LOGL_INFO, "PCH paging timeout for IMSI=%s\n", p->imsi);
bts_do_rate_ctr_inc(p->bts, CTR_PCH_REQUESTS_TIMEDOUT);
bts_pch_timer_remove(p);
}
void bts_pch_timer_start(struct gprs_rlcmac_bts *bts, const struct osmo_mobile_identity *mi_paging,
const char *imsi)
{
struct bts_pch_timer *p;
struct osmo_tdef *tdef;
p = talloc_zero(bts, struct bts_pch_timer);
llist_add_tail(&p->entry, &bts->pch_timer);
p->bts = bts;
OSMO_STRLCPY_ARRAY(p->imsi, imsi);
p->ptmsi = (mi_paging->type == GSM_MI_TYPE_TMSI) ? mi_paging->tmsi : GSM_RESERVED_TMSI;
tdef = osmo_tdef_get_entry(the_pcu->T_defs, 3113);
OSMO_ASSERT(tdef);
osmo_timer_setup(&p->T3113, T3113_callback, p);
osmo_timer_schedule(&p->T3113, tdef->val, 0);
if (log_check_level(DPCU, LOGL_DEBUG)) {
char str[64];
osmo_mobile_identity_to_str_buf(str, sizeof(str), mi_paging);
LOGP(DPCU, LOGL_DEBUG, "PCH paging timer started for MI=%s IMSI=%s\n", str, p->imsi);
}
}
void bts_pch_timer_stop(struct gprs_rlcmac_bts *bts, const struct GprsMs *ms)
{
struct bts_pch_timer *p = NULL;
uint32_t tlli = ms_tlli(ms);
const char *imsi = ms_imsi(ms);
/* First try matching by TMSI if available in MS */
if (tlli != GSM_RESERVED_TMSI)
p = bts_pch_timer_get_by_ptmsi(bts, tlli);
/* Otherwise try matching by IMSI if available in MS */
if (!p && imsi[0] != '\0')
p = bts_pch_timer_get_by_imsi(bts, imsi);
if (p)
bts_pch_timer_remove(p);
}
void bts_pch_timer_stop_all(struct gprs_rlcmac_bts *bts)
{
struct bts_pch_timer *p, *n;
llist_for_each_entry_safe(p, n, &bts->pch_timer, entry) {
bts_pch_timer_remove(p);
}
}

49
src/bts_pch_timer.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Oliver Smith
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <bts.h>
#ifdef __cplusplus
extern "C" {
#endif
struct bts_pch_timer {
struct llist_head entry;
struct gprs_rlcmac_bts *bts;
struct osmo_timer_list T3113;
uint32_t ptmsi; /* GSM_RESERVED_TMSI if not available */
char imsi[OSMO_IMSI_BUF_SIZE];
};
struct GprsMs;
void bts_pch_timer_start(struct gprs_rlcmac_bts *bts, const struct osmo_mobile_identity *mi_paging,
const char *imsi);
void bts_pch_timer_stop(struct gprs_rlcmac_bts *bts, const struct GprsMs *ms);
void bts_pch_timer_stop_all(struct gprs_rlcmac_bts *bts);
struct bts_pch_timer *bts_pch_timer_get_by_imsi(struct gprs_rlcmac_bts *bts, const char *imsi);
#ifdef __cplusplus
}
#endif

408
src/coding_scheme.c Normal file
View File

@@ -0,0 +1,408 @@
/* coding_scheme.c
*
* Copyright (C) 2019 by sysmocom s.f.m.c. GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/utils.h>
#include "coding_scheme.h"
const struct value_string mcs_names[] = {
{ UNKNOWN, "UNKNOWN" },
{ CS1, "CS-1" },
{ CS2, "CS-2" },
{ CS3, "CS-3" },
{ CS4, "CS-4" },
{ MCS1, "MCS-1" },
{ MCS2, "MCS-2" },
{ MCS3, "MCS-3" },
{ MCS4, "MCS-4" },
{ MCS5, "MCS-5" },
{ MCS6, "MCS-6" },
{ MCS7, "MCS-7" },
{ MCS8, "MCS-8" },
{ MCS9, "MCS-9" },
{ 0, NULL }
};
enum Family {
FAMILY_INVALID,
FAMILY_A,
FAMILY_B,
FAMILY_C,
};
static struct {
struct {
uint8_t bytes;
uint8_t ext_bits;
uint8_t data_header_bits;
} uplink, downlink;
uint8_t data_bytes;
uint8_t optional_padding_bits;
enum HeaderType data_hdr;
enum Family family;
} mcs_info[NUM_SCHEMES] = {
{{0, 0}, {0, 0}, 0, 0,
HEADER_INVALID, FAMILY_INVALID},
{{23, 0}, {23, 0}, 20, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{33, 7}, {33, 7}, 30, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{39, 3}, {39, 3}, 36, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{53, 7}, {53, 7}, 50, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{26, 1}, {26, 1}, 22, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_C},
{{32, 1}, {32, 1}, 28, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_B},
{{41, 1}, {41, 1}, 37, 48,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_A},
{{48, 1}, {48, 1}, 44, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_C},
{{60, 7}, {59, 6}, 56, 0,
HEADER_EGPRS_DATA_TYPE_2, FAMILY_B},
{{78, 7}, {77, 6}, 74, 48,
HEADER_EGPRS_DATA_TYPE_2, FAMILY_A},
{{118, 2}, {117, 4}, 56, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_B},
{{142, 2}, {141, 4}, 68, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_A},
{{154, 2}, {153, 4}, 74, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_A},
};
const char *mcs_name(enum CodingScheme val) {
return get_value_string(mcs_names, val);
}
bool mcs_is_gprs(enum CodingScheme cs)
{
return CS1 <= cs && cs <= CS4;
}
bool mcs_is_edge(enum CodingScheme cs)
{
return MCS1 <= cs && cs <= MCS9;
}
bool mcs_is_edge_gmsk(enum CodingScheme cs)
{
if (mcs_is_edge(cs))
return cs <= MCS4;
return false;
}
/* Return 3GPP TS 44.060 §12.10d (EDGE) or Table 11.2.28.2 (GPRS) Channel Coding Command value */
uint8_t mcs_chan_code(enum CodingScheme cs)
{
if (mcs_is_gprs(cs))
return cs - CS1;
if (mcs_is_edge(cs))
return cs - MCS1;
/* Defaults to (M)CS1 */
return 0;
}
enum CodingScheme mcs_get_by_size_ul(unsigned size)
{
switch (size) {
case 23: return CS1;
case 27: return MCS1;
case 33: return MCS2;
case 34: return CS2;
case 40: return CS3;
case 42: return MCS3;
case 49: return MCS4;
case 54: return CS4;
case 61: return MCS5;
case 79: return MCS6;
case 119: return MCS7;
case 143: return MCS8;
case 155: return MCS9;
default: return UNKNOWN;
}
}
enum CodingScheme mcs_get_gprs_by_num(unsigned num)
{
if (num < 1 || num > 4)
return UNKNOWN;
return CS1 + (num - 1);
}
enum CodingScheme mcs_get_egprs_by_num(unsigned num)
{
if (num < 1 || num > 9)
return UNKNOWN;
return MCS1 + (num - 1);
}
bool mcs_is_valid(enum CodingScheme cs)
{
return UNKNOWN < cs && cs <= MCS9;
}
bool mcs_is_compat_kind(enum CodingScheme cs, enum mcs_kind mode)
{
switch (mode) {
case GPRS: return mcs_is_gprs(cs);
case EGPRS_GMSK: return mcs_is_edge_gmsk(cs);
case EGPRS: return mcs_is_edge(cs);
}
return false;
}
bool mcs_is_compat(enum CodingScheme cs, enum CodingScheme o)
{
return (mcs_is_gprs(cs) && mcs_is_gprs(o)) || (mcs_is_edge(cs) && mcs_is_edge(o));
}
uint8_t mcs_size_ul(enum CodingScheme cs)
{
return mcs_info[cs].uplink.bytes + (mcs_spare_bits_ul(cs) ? 1 : 0);
}
uint8_t mcs_size_dl(enum CodingScheme cs)
{
return mcs_info[cs].downlink.bytes + (mcs_spare_bits_dl(cs) ? 1 : 0);
}
uint8_t mcs_used_size_ul(enum CodingScheme cs)
{
if (mcs_info[cs].data_hdr == HEADER_GPRS_DATA)
return mcs_info[cs].uplink.bytes;
else
return mcs_size_ul(cs);
}
uint8_t mcs_used_size_dl(enum CodingScheme cs)
{
if (mcs_info[cs].data_hdr == HEADER_GPRS_DATA)
return mcs_info[cs].downlink.bytes;
else
return mcs_size_dl(cs);
}
uint8_t mcs_max_bytes_ul(enum CodingScheme cs)
{
return mcs_info[cs].uplink.bytes;
}
uint8_t mcs_max_bytes_dl(enum CodingScheme cs)
{
return mcs_info[cs].downlink.bytes;
}
uint8_t mcs_spare_bits_ul(enum CodingScheme cs)
{
return mcs_info[cs].uplink.ext_bits;
}
uint8_t mcs_spare_bits_dl(enum CodingScheme cs)
{
return mcs_info[cs].downlink.ext_bits;
}
uint8_t mcs_max_data_block_bytes(enum CodingScheme cs)
{
return mcs_info[cs].data_bytes;
}
uint8_t mcs_opt_padding_bits(enum CodingScheme cs)
{
return mcs_info[cs].optional_padding_bits;
}
void mcs_inc_kind(enum CodingScheme *cs, enum mcs_kind mode)
{
if (!mcs_is_compat_kind(*cs, mode))
/* This should not happen. TODO: Use assert? */
return;
enum CodingScheme new_cs = *cs + 1;
if (!mcs_is_compat_kind(new_cs, mode))
/* Clipping, do not change the value */
return;
*cs = new_cs;
}
void mcs_dec_kind(enum CodingScheme *cs, enum mcs_kind mode)
{
if (!mcs_is_compat_kind(*cs, mode))
/* This should not happen. TODO: Use assert? */
return;
enum CodingScheme new_cs = *cs - 1;
if (!mcs_is_compat_kind(new_cs, mode))
/* Clipping, do not change the value */
return;
*cs = new_cs;
}
void mcs_inc(enum CodingScheme *cs)
{
if (mcs_is_gprs(*cs) && *cs == CS4)
return;
if (mcs_is_edge(*cs) && *cs == MCS9)
return;
if (!mcs_is_valid(*cs))
return;
*cs = *cs + 1;
}
void mcs_dec(enum CodingScheme *cs)
{
if (mcs_is_gprs(*cs) && *cs == CS1)
return;
if (mcs_is_edge(*cs) && *cs == MCS1)
return;
if (!mcs_is_valid(*cs))
return;
*cs = *cs - 1;
}
bool mcs_is_family_compat(enum CodingScheme cs, enum CodingScheme o)
{
if (cs == o)
return true;
if (mcs_info[cs].family == FAMILY_INVALID)
return false;
return mcs_info[cs].family == mcs_info[o].family;
}
void mcs_dec_to_single_block(enum CodingScheme *cs, bool *need_stuffing)
{
switch (*cs) {
case MCS7: *need_stuffing = false; *cs = MCS5; break;
case MCS8: *need_stuffing = true; *cs = MCS6; break;
case MCS9: *need_stuffing = false; *cs = MCS6; break;
default: *need_stuffing = false; break;
}
}
static struct {
struct {
uint8_t data_header_bits;
} uplink, downlink;
uint8_t data_block_header_bits;
uint8_t num_blocks;
const char *name;
} hdr_type_info[NUM_HEADER_TYPES] = {
{ { 0 }, { 0 }, 0, 0, "INVALID" },
{ { 1 * 8 + 0 }, { 1 * 8 + 0 }, 0, 0, "CONTROL" },
{ { 3 * 8 + 0 }, { 3 * 8 + 0 }, 0, 1, "GPRS_DATA" },
{ { 5 * 8 + 6 }, { 5 * 8 + 0 }, 2, 2, "EGPRS_DATA_TYPE1" },
{ { 4 * 8 + 5 }, { 3 * 8 + 4 }, 2, 1, "EGPRS_DATA_TYPE2" },
{ { 3 * 8 + 7 }, { 3 * 8 + 7 }, 2, 1, "EGPRS_DATA_TYPE3" },
};
enum HeaderType mcs_header_type(enum CodingScheme mcs)
{
return mcs_info[mcs].data_hdr;
}
uint8_t num_data_blocks(enum HeaderType ht)
{
OSMO_ASSERT(ht < NUM_HEADER_TYPES);
return hdr_type_info[ht].num_blocks;
}
uint8_t num_data_header_bits_UL(enum HeaderType ht)
{
OSMO_ASSERT(ht < NUM_HEADER_TYPES);
return hdr_type_info[ht].uplink.data_header_bits;
}
uint8_t num_data_header_bits_DL(enum HeaderType ht)
{
OSMO_ASSERT(ht < NUM_HEADER_TYPES);
return hdr_type_info[ht].downlink.data_header_bits;
}
uint8_t num_data_block_header_bits(enum HeaderType ht)
{
OSMO_ASSERT(ht < NUM_HEADER_TYPES);
return hdr_type_info[ht].data_block_header_bits;
}
const struct value_string mode_names[] = {
{ GPRS, "GPRS" },
{ EGPRS_GMSK, "EGPRS_GMSK-only"},
{ EGPRS, "EGPRS"},
{ 0, NULL }
};
const char *mode_name(enum mcs_kind val) {
return get_value_string(mode_names, val);
}
/* FIXME: take into account padding and special cases of commanded MCS (MCS-6-9 and MCS-5-7) */
enum CodingScheme get_retx_mcs(enum CodingScheme initial_mcs, enum CodingScheme commanded_mcs, bool resegment_bit)
{
OSMO_ASSERT(mcs_is_edge(initial_mcs));
OSMO_ASSERT(mcs_is_edge(commanded_mcs));
OSMO_ASSERT(NUM_SCHEMES - MCS1 == 9);
if (resegment_bit) { /* 3GPP TS 44.060 Table 8.1.1.1, reflected over antidiagonal */
enum CodingScheme egprs_reseg[NUM_SCHEMES - MCS1][NUM_SCHEMES - MCS1] = {
{ MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1 },
{ MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2 },
{ MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3 },
{ MCS1, MCS1, MCS1, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4 },
{ MCS2, MCS2, MCS2, MCS2, MCS5, MCS5, MCS7, MCS7, MCS7 },
{ MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS6, MCS9 },
{ MCS2, MCS2, MCS2, MCS2, MCS5, MCS5, MCS7, MCS7, MCS7 },
{ MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS8, MCS8 },
{ MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS6, MCS9 },
};
return egprs_reseg[mcs_chan_code(initial_mcs)][mcs_chan_code(commanded_mcs)];
} else { /* 3GPP TS 44.060 Table 8.1.1.2, reflected over antidiagonal */
enum CodingScheme egprs_no_reseg[NUM_SCHEMES - MCS1][NUM_SCHEMES - MCS1] = {
{ MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1 },
{ MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2 },
{ MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3 },
{ MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4 },
{ MCS5, MCS5, MCS5, MCS5, MCS5, MCS5, MCS7, MCS7, MCS7 },
{ MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS9 },
{ MCS5, MCS5, MCS5, MCS5, MCS5, MCS5, MCS7, MCS7, MCS7 },
{ MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS8, MCS8 },
{ MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS9 },
};
return egprs_no_reseg[mcs_chan_code(initial_mcs)][mcs_chan_code(commanded_mcs)];
}
}

99
src/coding_scheme.h Normal file
View File

@@ -0,0 +1,99 @@
/* coding_scheme.h
*
* Copyright (C) 2015-2019 by sysmocom s.f.m.c. GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include <osmocom/core/utils.h>
#include <stdbool.h>
enum CodingScheme {
UNKNOWN,
/* GPRS Coding Schemes: */
CS1, CS2, CS3, CS4,
/* EDGE/EGPRS Modulation and Coding Schemes: */
MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9,
NUM_SCHEMES
};
enum mcs_kind {
GPRS,
EGPRS_GMSK,
EGPRS,
};
enum egprs_arq_type {
EGPRS_ARQ1 = 0,
EGPRS_ARQ2 = 1
};
extern const struct value_string mcs_names[];
const char *mcs_name(enum CodingScheme val);
enum CodingScheme get_retx_mcs(enum CodingScheme initial_mcs, enum CodingScheme commanded_mcs, bool resegment_bit);
bool mcs_is_gprs(enum CodingScheme cs);
bool mcs_is_edge(enum CodingScheme cs);
bool mcs_is_edge_gmsk(enum CodingScheme cs);
uint8_t mcs_chan_code(enum CodingScheme cs);
enum CodingScheme mcs_get_by_size_ul(unsigned size);
enum CodingScheme mcs_get_gprs_by_num(unsigned num);
enum CodingScheme mcs_get_egprs_by_num(unsigned num);
bool mcs_is_valid(enum CodingScheme cs);
bool mcs_is_compat(enum CodingScheme cs, enum CodingScheme o);
bool mcs_is_compat_kind(enum CodingScheme cs, enum mcs_kind mode);
uint8_t mcs_size_ul(enum CodingScheme cs);
uint8_t mcs_size_dl(enum CodingScheme cs);
uint8_t mcs_used_size_ul(enum CodingScheme cs);
uint8_t mcs_used_size_dl(enum CodingScheme cs);
uint8_t mcs_max_bytes_ul(enum CodingScheme cs);
uint8_t mcs_max_bytes_dl(enum CodingScheme cs);
uint8_t mcs_spare_bits_ul(enum CodingScheme cs);
uint8_t mcs_spare_bits_dl(enum CodingScheme cs);
uint8_t mcs_max_data_block_bytes(enum CodingScheme cs);
uint8_t mcs_opt_padding_bits(enum CodingScheme cs);
void mcs_inc_kind(enum CodingScheme *cs, enum mcs_kind mode);
void mcs_dec_kind(enum CodingScheme *cs, enum mcs_kind mode);
void mcs_inc(enum CodingScheme *cs);
void mcs_dec(enum CodingScheme *cs);
bool mcs_is_family_compat(enum CodingScheme cs, enum CodingScheme o);
void mcs_dec_to_single_block(enum CodingScheme *cs, bool *need_stuffing);
enum HeaderType {
HEADER_INVALID,
HEADER_GPRS_CONTROL,
HEADER_GPRS_DATA,
HEADER_EGPRS_DATA_TYPE_1,
HEADER_EGPRS_DATA_TYPE_2,
HEADER_EGPRS_DATA_TYPE_3,
NUM_HEADER_TYPES
};
enum HeaderType mcs_header_type(enum CodingScheme mcs);
uint8_t num_data_blocks(enum HeaderType ht);
uint8_t num_data_header_bits_UL(enum HeaderType ht);
uint8_t num_data_header_bits_DL(enum HeaderType ht);
uint8_t num_data_block_header_bits(enum HeaderType ht);
const char *mode_name(enum mcs_kind val);

107
src/csn1.c Normal file
View File

@@ -0,0 +1,107 @@
/* csn1_enc.c
* Routines for CSN1 dissection in wireshark.
*
* Copyright (C) 2011 Ivan Klyuchnikov
*
* By Vincent Helfre, based on original code by Jari Sassi
* with the gracious authorization of STE
* Copyright (c) 2011 ST-Ericsson
*
* $Id: packet-csn1.c 39140 2011-09-25 22:01:50Z wmeier $
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <assert.h>
#include <string.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include "csn1.h"
#include <gprs_debug.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
const unsigned char ixBitsTab[] = {0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5};
/* Returns no_of_bits (up to 8) masked with 0x2B */
guint8
get_masked_bits8(struct bitvec *vector, unsigned *readIndex, gint bit_offset, const gint no_of_bits)
{
static const guint8 maskBits[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF};
//gint byte_offset = bit_offset >> 3; /* divide by 8 */
gint relative_bit_offset = bit_offset & 0x07; /* modulo 8 */
guint8 result;
gint bit_shift = 8 - relative_bit_offset - (gint) no_of_bits;
*readIndex -= relative_bit_offset;
if (bit_shift >= 0)
{
result = (0x2B ^ ((guint8)bitvec_read_field(vector, readIndex, 8))) >> bit_shift;
*readIndex-= bit_shift;
result &= maskBits[no_of_bits];
}
else
{
guint8 hight_part = (0x2B ^ ((guint8)bitvec_read_field(vector, readIndex, 8))) & maskBits[8 - relative_bit_offset];
hight_part = (guint8) (hight_part << (-bit_shift));
result = (0x2B ^ ((guint8)bitvec_read_field(vector, readIndex, 8))) >> (8 + bit_shift);
*readIndex = *readIndex - (8 - (-bit_shift));
result |= hight_part;
}
return result;
}
/**
* ================================================================================================
* set initial/start values in help data structure used for packing/unpacking operation
* ================================================================================================
*/
void
csnStreamInit(csnStream_t* ar, gint bit_offset, gint remaining_bits_len)
{
ar->remaining_bits_len = remaining_bits_len;
ar->bit_offset = bit_offset;
ar->direction = 0;
}
static const struct value_string csn1_error_names[] = {
{ CSN_OK, "General 0" },
{ CSN_ERROR_GENERAL, "General -1" },
{ CSN_ERROR_DATA_NOT_VALID, "DATA_NOT VALID" },
{ CSN_ERROR_IN_SCRIPT, "IN SCRIPT" },
{ CSN_ERROR_INVALID_UNION_INDEX, "INVALID UNION INDEX" },
{ CSN_ERROR_NEED_MORE_BITS_TO_UNPACK, "NEED_MORE BITS TO UNPACK" },
{ CSN_ERROR_ILLEGAL_BIT_VALUE, "ILLEGAL BIT VALUE" },
{ CSN_ERROR_INTERNAL, "INTERNAL" },
{ CSN_ERROR_STREAM_NOT_SUPPORTED, "STREAM_NOT_SUPPORTED" },
{ CSN_ERROR_MESSAGE_TOO_LONG, "MESSAGE_TOO_LONG" },
{ 0, NULL }
};
gint16 ProcessError_impl(const char *file, int line, unsigned *readIndex,
const char* sz, gint16 err, const CSN_DESCR* pDescr)
{
/* Don't add trailing newline, top caller is responsible for appending it */
if (err != CSN_OK)
LOGPSRC(DCSN1, LOGL_ERROR, file, line, "%s: error %s (%d) at %s (idx %u)",
sz, get_value_string(csn1_error_names, err), err,
pDescr ? pDescr->sz : "-", *readIndex);
return err;
}

File diff suppressed because it is too large Load Diff

View File

@@ -25,15 +25,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <bitvector.h>
#include <iostream>
#include <cstdlib>
#ifndef _PACKET_CSN1_H_
#define _PACKET_CSN1_H_
#define MIN(a,b) (((a)<(b))?(a):(b))
//#define max(a,b) (((a)>(b))?(a):(b))
#include <osmocom/core/bitvec.h>
#include "wireshark_compat.h"
/* Error codes */
#define CSN_OK 0
@@ -48,16 +44,6 @@
#define CSN_ERROR_MESSAGE_TOO_LONG -9
#define CSN_ERROR_ -10
#define FALSE (0)
#define TRUE (1)
typedef signed int gint32;
typedef signed short gint16;
typedef int gint;
typedef gint gboolean;
typedef unsigned char guint8;
typedef unsigned short guint16;
typedef unsigned int guint32;
typedef unsigned long guint64;
/* CallBack return status */
typedef gint16 CSN_CallBackStatus_t;
@@ -74,6 +60,7 @@ typedef gint16 CSN_CallBackStatus_t;
#ifndef ElementsOf
#define ElementsOf(array) (sizeof(array) / sizeof(array[0]))
#endif
typedef void(*void_fn_t)(void);
/* Context holding CSN1 parameters */
typedef struct
@@ -83,7 +70,9 @@ typedef struct
gint direction; /* 0 - decode; 1 - encode */
} csnStream_t;
typedef gint16 (*StreamSerializeFcn_t)(csnStream_t* ar, bitvec *vector, unsigned& readIndex, void* data);
typedef gint16 (*StreamSerializeFcn_t)(csnStream_t* ar, struct bitvec *vector, unsigned *readIndex, void* data);
typedef CSN_CallBackStatus_t (*DissectorCallbackFcn_t)(struct bitvec *vector, unsigned *readIndex, void* param1, void* param2);
typedef enum
{
CSN_END = 0,
@@ -191,24 +180,21 @@ typedef struct
gint16 i;
union
{
void* ptr;
const void* ptr;
guint32 value;
} descr;
unsigned offset;
gboolean may_be_null;
const char* sz;
union
{
StreamSerializeFcn_t fcn;
guint32 value;
int* hf_ptr;
} serialize;
guint32 value;
void_fn_t aux_fn;
} CSN_DESCR;
typedef struct
{
guint8 bits;
guint8 value;
gboolean keep_bits;
CSN_DESCR descr;
} CSN_ChoiceElement_t;
@@ -231,16 +217,16 @@ void csnStreamInit(csnStream_t* ar,gint BitOffset,gint BitCount);
* RETURNS: int Number of bits left to be unpacked. Negative Error code if failed to unpack all bits
******************************************************************************/
gint16 csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector, unsigned& readIndex, void* data);
gint16 csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, struct bitvec *vector, unsigned *readIndex, void* data);
gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector, unsigned& readIndex, void* data);
gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, struct bitvec *vector, unsigned *writeIndex, void* data);
/* CSN struct macro's */
#define CSN_DESCR_BEGIN(_STRUCT)\
CSN_DESCR CSNDESCR_##_STRUCT[] = {
#define CSN_DESCR_END(_STRUCT)\
{CSN_END, 0, {0}, 0, FALSE, "", {(StreamSerializeFcn_t)0}} };
{CSN_END, 0, {0}, 0, FALSE, "", 0, NULL} };
/******************************************************************************
* CSN_ERROR(Par1, Par2, Par3)
@@ -251,7 +237,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par3: Error code
*****************************************************************************/
#define CSN_ERROR(_STRUCT, _Text, _ERRCODE)\
{CSN_TRAP_ERROR, _ERRCODE, {(void*)_Text}, 0, FALSE, _Text, {(StreamSerializeFcn_t)0}}
{CSN_TRAP_ERROR, _ERRCODE, {_Text}, 0, FALSE, _Text, 0, NULL}
/******************************************************************************
* M_BIT(Par1, Par2)
@@ -260,7 +246,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par2: C structure element name
*****************************************************************************/
#define M_BIT(_STRUCT, _MEMBER)\
{CSN_BIT, 0, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_BIT, 0, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_BIT_OR_NULL(Par1, Par2)
@@ -270,11 +256,11 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Covers the case {null | 0 | 1}
*****************************************************************************/
#define M_BIT_OR_NULL(_STRUCT, _MEMBER)\
{CSN_BIT, 0, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_BIT, 0, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_NEXT_EXIST(Par1, Par2, Par3)
* Indicates whether the next element or a group of elements defined in the
* Indicates whether the next element or a group of elements defined in the
* structure is present or not.
* Par1: C structure name
* Par2: C structure element name
@@ -282,37 +268,37 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* element(s) does not exist
*****************************************************************************/
#define M_NEXT_EXIST(_STRUCT, _MEMBER, _NoOfExisting)\
{CSN_NEXT_EXIST, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_NEXT_EXIST, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_NEXT_EXIST_LH(Par1, Par2, Par3)
* similar to the M_NEXT_EXIST except that instead of bit 0/1 which is fetched
* from the message in order to find out whether the next element/elements are
* present in the message, the logical operation XOR with the background
* present in the message, the logical operation XOR with the background
* pattern 0x2B is performed on the read bit before the decision is made.
*****************************************************************************/
#define M_NEXT_EXIST_LH(_STRUCT, _MEMBER, _NoOfExisting)\
{CSN_NEXT_EXIST_LH, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_NEXT_EXIST_LH, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_NEXT_EXIST_OR_NULL(Par1, Par2, Par3)
* Similar to the M_NEXT_EXIST except that not only bit 0 or 1 but also the end
* of the message may be encountered when looking for the next element in the
* of the message may be encountered when looking for the next element in the
* message.
* Covers the case {null | 0 | 1 < IE >}
* Covers the case {null | 0 | 1 < IE >}
*****************************************************************************/
#define M_NEXT_EXIST_OR_NULL(_STRUCT, _MEMBER, _NoOfExisting)\
{CSN_NEXT_EXIST, _NoOfExisting, {(void*)1}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_NEXT_EXIST, _NoOfExisting, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_NEXT_EXIST_OR_NULL_LH(Par1, Par2, Par3)
* Similar to the M_NEXT_EXIST_LH except that not only bit 0 or 1 but also the
* end of the message may be encountered when looking for the next element in
* the message.
* Covers the case {null | L | H < IE >}
* Covers the case {null | L | H < IE >}
*****************************************************************************/
#define M_NEXT_EXIST_OR_NULL_LH(_STRUCT, _MEMBER, _NoOfExisting)\
{CSN_NEXT_EXIST_LH, _NoOfExisting, {(void*)1}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_NEXT_EXIST_LH, _NoOfExisting, {(void*)1}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_UINT(Par1, Par2, Par3)
@@ -322,7 +308,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par3: number of bits used to code the element (between 1 and 32)
*****************************************************************************/
#define M_UINT(_STRUCT, _MEMBER, _BITS)\
{CSN_UINT, _BITS, {(void*)1}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_UINT, _BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_UINT_OR_NULL(Par1, Par2, Par3)
@@ -332,17 +318,17 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Covers the case {null | 0 | 1 < IE >}
*****************************************************************************/
#define M_UINT_OR_NULL(_STRUCT, _MEMBER, _BITS)\
{CSN_UINT, _BITS, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_UINT, _BITS, {0}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_UINT(Par1, Par2, Par3)
* This macro has the same functionality as M_UINT except that in addition the
* logical "exclusive or" operation with the background value "0x2B" is
* performed before the final value of the integer number is delivered from the
* logical "exclusive or" operation with the background value "0x2B" is
* performed before the final value of the integer number is delivered from the
* received CSN.1 message
*****************************************************************************/
#define M_UINT_LH(_STRUCT, _MEMBER, _BITS)\
{CSN_UINT_LH, _BITS, {(void*)1}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_UINT_LH, _BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_UINT_OFFSET(Par1, Par2, Par3, Par4)
@@ -353,7 +339,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par4: value added to the returned integer (offset)
*****************************************************************************/
#define M_UINT_OFFSET(_STRUCT, _MEMBER, _BITS, _OFFSET)\
{CSN_UINT_OFFSET, _BITS, {(void*)_OFFSET}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_UINT_OFFSET, _BITS, {(void*)_OFFSET}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_UINT_ARRAY(Par1, Par2, Par3, Par4)
@@ -364,7 +350,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par4: number of elements in the array (fixed integer value)
*****************************************************************************/
#define M_UINT_ARRAY(_STRUCT, _MEMBER, _BITS, _ElementCount)\
{CSN_UINT_ARRAY, _BITS, {(void*)_ElementCount}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_UINT_ARRAY, _BITS, {(void*)_ElementCount}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_VAR_UINT_ARRAY(Par1, Par2, Par3, Par4)
@@ -376,7 +362,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* structure member holding the length value
*****************************************************************************/
#define M_VAR_UINT_ARRAY(_STRUCT, _MEMBER, _BITS, _ElementCountField)\
{CSN_UINT_ARRAY, _BITS, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)1}}
{CSN_UINT_ARRAY, _BITS, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 1, NULL}
/******************************************************************************
* M_VAR_ARRAY(Par1, Par2, Par3, Par4)
@@ -387,7 +373,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par4: offset that is added to the Par3 to get the actual size of the array
*****************************************************************************/
#define M_VAR_ARRAY(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
{CSN_VARIABLE_ARRAY, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_VARIABLE_ARRAY, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_VAR_TARRAY(Par1, Par2, Par3, Par4)
@@ -398,32 +384,32 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par4: name of the structure member holding the size of the array
*****************************************************************************/
#define M_VAR_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
{CSN_VARIABLE_TARRAY, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}
{CSN_VARIABLE_TARRAY, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), NULL}
/******************************************************************************
* M_VAR_TARRAY_OFFSET(Par1, Par2, Par3, Par4)
* Same as M_VAR_TARRAY with offset
*****************************************************************************/
#define M_VAR_TARRAY_OFFSET(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
{CSN_VARIABLE_TARRAY_OFFSET, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}
{CSN_VARIABLE_TARRAY_OFFSET, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), NULL}
/******************************************************************************
* M_REC_ARRAY(Par1, Par2, Par3, Par4)
* similar to the M_VAR_ARRAY. The difference is that the size of the array is
* similar to the M_VAR_ARRAY. The difference is that the size of the array is
* not known in advance and it has to be calculated during unpacking. Its value
* is stored in a variable which belongs to the same structure as the array.
* A zero element terminates the array. The CSN.1 syntax describes it
* is stored in a variable which belongs to the same structure as the array.
* A zero element terminates the array. The CSN.1 syntax describes it
* recursively as:
* <array> ::={1 <element> <array>| 0}
* <array> ::={1 <element> <array>| 0}
*
* Par1: C structure name
* Par2: C structure element name
* Par3: name of the structure member where the calculated the size of the
* Par3: name of the structure member where the calculated the size of the
* array will be stored
* Par4: length of each element in bits
*****************************************************************************/
#define M_REC_ARRAY(_STRUCT, _MEMBER, _ElementCountField, _BITS)\
{CSN_RECURSIVE_ARRAY, _BITS, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_RECURSIVE_ARRAY, _BITS, {(const void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_VAR_TYPE_ARRAY(Par1, Par2, Par3, Par4)
@@ -434,7 +420,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par4: number of elements in the array (fixed integer value)
*****************************************************************************/
#define M_TYPE_ARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCount)\
{CSN_TYPE_ARRAY, _ElementCount, {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}
{CSN_TYPE_ARRAY, _ElementCount, {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), NULL}
/******************************************************************************
* M_REC_TARRAY(Par1, Par2, Par3, Par4)
@@ -446,7 +432,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par4: will hold the number of element in the array after unpacking
*****************************************************************************/
#define M_REC_TARRAY(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
{CSN_RECURSIVE_TARRAY, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}
{CSN_RECURSIVE_TARRAY, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)}
/******************************************************************************
* M_REC_TARRAY1(Par1, Par2, Par3, Par4)
@@ -454,7 +440,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* <list> ::= <type> {1 <type>} ** 0 ;
*****************************************************************************/
#define M_REC_TARRAY_1(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
{CSN_RECURSIVE_TARRAY_1, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}
{CSN_RECURSIVE_TARRAY_1, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)}
/******************************************************************************
* M_REC_TARRAY2(Par1, Par2, Par3, Par4)
@@ -462,7 +448,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* <lists> ::= <type> { 0 <type> } ** 1 ;
*****************************************************************************/
#define M_REC_TARRAY_2(_STRUCT, _MEMBER, _MEMBER_TYPE, _ElementCountField)\
{CSN_RECURSIVE_TARRAY_2, offsetof(_STRUCT, _ElementCountField), {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)sizeof(_MEMBER_TYPE)}}
{CSN_RECURSIVE_TARRAY_2, offsetof(_STRUCT, _ElementCountField), {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, sizeof(_MEMBER_TYPE), (void_fn_t)ElementsOf(((_STRUCT*)0)->_MEMBER)}
/******************************************************************************
* M_TYPE(Par1, Par2, Par3)
@@ -473,134 +459,161 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
* Par3: type of member
*****************************************************************************/
#define M_TYPE(_STRUCT, _MEMBER, _MEMBER_TYPE)\
{CSN_TYPE, 0, {(void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_TYPE, 0, {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_TYPE_OR_NULL(Par1, Par2, Par3)
* Similar to the M_TYPE except that not only the request set of bits but also the
* end of the message may be encountered when looking for the next element in
* the message.
* Covers the case {null | 0 | 1 < IE >}
*****************************************************************************/
#define M_TYPE_OR_NULL(_STRUCT, _MEMBER, _MEMBER_TYPE)\
{CSN_TYPE, 0, {(const void*)CSNDESCR_##_MEMBER_TYPE}, offsetof(_STRUCT, _MEMBER), TRUE, #_MEMBER, 0, NULL}
/******************************************************************************
* M_UNION(Par1, Par2)
* Informs the CSN.1 library that a union follows and how many possible choices
* there are in the union. The actual value of the choice, which points out the
* chosen element of the union is stored in the uint8 variable and is usually
* called UnionType. The elements of the union have to be listed directly after
* chosen element of the union is stored in the uint8 variable and is usually
* called UnionType. The elements of the union have to be listed directly after
* the M_UNION statement.
* Par1: C structure name
* Par2: number of possible choice in the union
*****************************************************************************/
#define M_UNION(_STRUCT, _COUNT)\
{CSN_UNION, _COUNT, {0}, offsetof(_STRUCT, UnionType), FALSE, "UnionType", {(StreamSerializeFcn_t)0}}
{CSN_UNION, _COUNT, {0}, offsetof(_STRUCT, UnionType), FALSE, "UnionType", 0, NULL}
/******************************************************************************
* M_UNION_LH(Par1, Par2)
* Same as M_UNION but masked with background value 0x2B
*****************************************************************************/
#define M_UNION_LH(_STRUCT, _COUNT)\
{CSN_UNION_LH, _COUNT, {0}, offsetof(_STRUCT, UnionType), FALSE, "UnionType", {(StreamSerializeFcn_t)0}}
{CSN_UNION_LH, _COUNT, {0}, offsetof(_STRUCT, UnionType), FALSE, "UnionType", 0, NULL}
/******************************************************************************
* M_CHOICE(Par1, Par2, Par3, Par4)
* Similar to the M_UNION. In the M_UNION the selected element of all possible
* choices in the union is referred as a sequential numbers, i.e., the first
* choice is addressed as choice 0 the second as choice 1, the third as choice
* Similar to the M_UNION. In the M_UNION the selected element of all possible
* choices in the union is referred as a sequential numbers, i.e., the first
* choice is addressed as choice 0 the second as choice 1, the third as choice
* 2 and so on, both in the encoded message and in the variable UnionType which
* is the part of the message. In the CSN_CHOICE case, this rule does not
* apply. There is free but predefined mapping of the element of the union and
* is the part of the message. In the CSN_CHOICE case, this rule does not
* apply. There is free but predefined mapping of the element of the union and
* the value which addresses this element.
* The value of the address is called a selector.
* The value of the address is called a selector. Up to 256 (UCHAR_MAX) unique
* selectors can be handled, longer choice list would cause CSN_ERROR_IN_SCRIPT.
* After unpacking, this value is then converted to the sequential number of the
* element in the union and stored in the UnionType variable.
* element in the union and stored in the UnionType variable (Par2).
* Par1: C structure name
* Par2: C structure element name
* Par2: C structure field name holding sequential number of the chosen element.
* BEWARE! Never use an enumerated type here, because its length is
* compiler/machine dependent, while decoder would cast it to guint8.
* Par3: address of an array of type CSN_ChoiceElement_t where all possible
* values of the selector are provided, together with the selector
* length expressed in bits and the address of the CSN_DESCR type
* where the element is defined. For every element in the union
* there is one line in the Choice variable. These lines have to
* appear in the _CHOICE in the same order as the elements in the
* union. The element of the union selected in the message through
* the _CHOICE parameter is after unpacking translated to the
* corresponding sequential number of this element and stored in
* values of the selector are provided, together with the selector
* length expressed in bits and the address of the CSN_DESCR type
* where the element is defined. For every element in the union
* there is one line in the Choice variable. These lines have to
* appear in the _CHOICE in the same order as the elements in the
* union. The element of the union selected in the message through
* the _CHOICE parameter is after unpacking translated to the
* corresponding sequential number of this element and stored in
* the variable pointed out by the _MEMBER
* Par4: number of possible choices in the union
*****************************************************************************/
#define M_CHOICE(_STRUCT, _MEMBER, _CHOICE, _ElementCount)\
{CSN_CHOICE, _ElementCount, {(void*)_CHOICE}, offsetof(_STRUCT, _MEMBER), FALSE, #_CHOICE, {(StreamSerializeFcn_t)0}}
{CSN_CHOICE, _ElementCount, {(const void*)_CHOICE}, offsetof(_STRUCT, _MEMBER), FALSE, #_CHOICE, 0, NULL}
/******************************************************************************
* M_FIXED(Par1, Par2, Par3)
* Defines a fixed value of type integer which should be fetched from or stored
* Defines a fixed value of type integer which should be fetched from or stored
* in the message
* Par1: C structure name
* Par2: gives the length of the fixed number in bits.
* Par3: the value of the number. If the expected value is not present in
* Par3: the value of the number. If the expected value is not present in
* the message the unpacking procedure is aborted
*****************************************************************************/
#define M_FIXED(_STRUCT, _BITS, _BITVALUE)\
{CSN_FIXED, _BITS, {0}, _BITVALUE, FALSE, #_BITVALUE, {(StreamSerializeFcn_t)0}}
{CSN_FIXED, _BITS, {0}, _BITVALUE, FALSE, #_BITVALUE, 0, NULL}
/******************************************************************************
* M_SERIALIZE(Par1, Par2, Par3)
* Allows using a complete free format of data being encoded or decoded.
* Allows using a complete free format of data being encoded or decoded.
* When the M_SERIALIZE is encounted during encoding or decoding of a message
* the CSNstream program passes the control over to the specified function
* together with all necessary parameters about the current position within
* the message being unpacked or packed. When transferring of "serialized"
* data to or from the message is finished by the function the CSNstream gets
* the CSNstream program passes the control over to the specified function
* together with all necessary parameters about the current position within
* the message being unpacked or packed. When transferring of "serialized"
* data to or from the message is finished by the function the CSNstream gets
* back control over the data stream and continues to work with the message.
*****************************************************************************/
#define M_SERIALIZE(_STRUCT, _MEMBER, _LENGTH_LEN, _SERIALIZEFCN)\
{CSN_SERIALIZE, _LENGTH_LEN, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {_SERIALIZEFCN}}
{CSN_SERIALIZE, _LENGTH_LEN, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, (void_fn_t)_SERIALIZEFCN}
#define M_CALLBACK(_STRUCT, _CSNCALLBACKFCN, _PARAM1, _PARAM2)\
{CSN_CALLBACK, offsetof(_STRUCT, _PARAM1), {_CSNCALLBACKFCN}, offsetof(_STRUCT, _PARAM2), FALSE, "CallBack_"#_CSNCALLBACKFCN, {(StreamSerializeFcn_t)0}}
{CSN_CALLBACK, offsetof(_STRUCT, _PARAM1), {0}, offsetof(_STRUCT, _PARAM2), FALSE, "CallBack_"#_CSNCALLBACKFCN, 0, (void_fn_t)_CSNCALLBACKFCN}
/******************************************************************************
* M_BITMAP(Par1, Par2, Par3)
* Defines a type which consists of a bitmap. The size of the bitmap in bits
* Defines a type which consists of a bitmap. The size of the bitmap in bits
* is fixed and provided by the parameter Par3
* Par1: C structure name
* Par2: C structure element name
* Par3: length of the bitmap expressed in bits
*****************************************************************************/
#define M_BITMAP(_STRUCT, _MEMBER, _BITS)\
{CSN_BITMAP, _BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_BITMAP, _BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/* variable length, right aligned bitmap i.e. _ElementCountField = 11 => 00000111 11111111 */
#define M_VAR_BITMAP(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
{CSN_VARIABLE_BITMAP, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_VARIABLE_BITMAP, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/* variable length, right aligned bitmap filling the rest of message
* - when unpacking the _ElementCountField will be set in runtime
* - when packing _ElementCountField contains the size of bitmap
*/
#define M_VAR_BITMAP_1(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
{CSN_VARIABLE_BITMAP_1, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_VARIABLE_BITMAP_1, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/* variable length, left aligned bitmap i.e. _ElementCountField = 11 => 11111111 11100000 */
#define M_LEFT_VAR_BMP(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
{CSN_LEFT_ALIGNED_VAR_BMP, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_LEFT_ALIGNED_VAR_BMP, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/* variable length, left aligned bitmap filling the rest of message
*- when unpacking the _ElementCountField will be set in runtime
* - when packing _ElementCountField contains the size of bitmap
*/
#define M_LEFT_VAR_BMP_1(_STRUCT, _MEMBER, _ElementCountField, _OFFSET)\
{CSN_LEFT_ALIGNED_VAR_BMP_1, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
{CSN_LEFT_ALIGNED_VAR_BMP_1, _OFFSET, {(void*)offsetof(_STRUCT, _ElementCountField)}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
/* todo: dissect padding bits looking for unexpected extensions */
#define M_PADDING_BITS(_STRUCT)\
{CSN_PADDING_BITS, 0, {0}, 0, TRUE, "Padding", {(StreamSerializeFcn_t)0}}
{CSN_PADDING_BITS, 0, {0}, 0, TRUE, "Padding", 0, NULL}
#define M_NULL(_STRUCT, _MEMBER)\
{CSN_NULL, 0, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, {(StreamSerializeFcn_t)0}}
#define M_NULL(_STRUCT, _MEMBER, _SKIP_BITS)\
{CSN_NULL, _SKIP_BITS, {0}, offsetof(_STRUCT, _MEMBER), FALSE, #_MEMBER, 0, NULL}
#define M_THIS_EXIST(_STRUCT)\
{CSN_EXIST, 0, {0}, offsetof(_STRUCT, Exist), FALSE, "Exist", {(StreamSerializeFcn_t)0}}
{CSN_EXIST, 0, {0}, offsetof(_STRUCT, Exist), FALSE, "Exist", 0, NULL}
#define M_THIS_EXIST_LH(_STRUCT)\
{CSN_EXIST_LH, 0, {0}, offsetof(_STRUCT, Exist), FALSE, "Exist", {(StreamSerializeFcn_t)0}}
{CSN_EXIST_LH, 0, {0}, offsetof(_STRUCT, Exist), FALSE, "Exist", 0, NULL}
/* return value 0 if ok else discontionue the unpacking */
typedef gint16 (*CsnCallBackFcn_t)(void* pv ,...);
#define CSNDESCR(_FuncType) CSNDESCR_##_FuncType
#define pvDATA(_pv, _offset) ((void*) ((unsigned char*)_pv + _offset))
#define pui8DATA(_pv, _offset) ((guint8*) pvDATA(_pv, _offset))
#define pui16DATA(_pv, _offset) ((guint16*) pvDATA(_pv, _offset))
#define pui32DATA(_pv, _offset) ((guint32*) pvDATA(_pv, _offset))
#define pui64DATA(_pv, _offset) ((guint64*) pvDATA(_pv, _offset))
/* used to tag existence of next element in variable length lists */
#define STANDARD_TAG 1
#define REVERSED_TAG 0
gint16 ProcessError_impl(const char *file, int line, unsigned *readIndex,
const char* sz, gint16 err, const CSN_DESCR* pDescr);
#define ProcessError(readIndex, sz, err, pDescr) \
ProcessError_impl(__FILE__, __LINE__, readIndex, sz, err, pDescr)
#endif /*_PACKET_CSN1_H_*/

1428
src/csn1_dec.c Normal file

File diff suppressed because it is too large Load Diff

1305
src/csn1_enc.c Normal file

File diff suppressed because it is too large Load Diff

133
src/cxx_linuxlist.h Normal file
View File

@@ -0,0 +1,133 @@
/* cxx_linuxlist.h
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
extern "C" {
#include <osmocom/core/linuxlist.h>
}
template <typename T>
struct LListHead {
typedef T entry_t;
/* This must match the declaration of struct llist_head */
LListHead<T> *next;
LListHead<T> *prev;
LListHead() : m_back(0) { INIT_LLIST_HEAD(this); }
LListHead(T* entry) : m_back(entry) {
next = (LListHead<T> *)LLIST_POISON1;
prev = (LListHead<T> *)LLIST_POISON2;
}
T *entry() {return m_back;}
const T *entry() const {return m_back;}
llist_head &llist() {
return *static_cast<llist_head *>(static_cast<void *>(this));
}
const llist_head &llist() const {
return *static_cast<const llist_head *>(static_cast<const void *>(this));
}
private:
T *const m_back;
};
/* Define a family of casting functions */
template <typename T>
llist_head &llist(LListHead<T> &l)
{
return l->llist();
}
template <typename T>
const llist_head &llist(const LListHead<T> &l)
{
return l->llist();
}
template <typename T>
llist_head *llptr(LListHead<T> *l)
{
return &(l->llist());
}
template <typename T>
const llist_head *llptr(const LListHead<T> *l)
{
return &(l->llist());
}
/* Define type-safe wrapper for the existing linux_list.h functions */
template <typename T>
inline void llist_add(LListHead<T> *new_, LListHead<T> *head)
{
llist_add(llptr(new_), llptr(head));
}
template <typename T>
inline void llist_add_tail(LListHead<T> *new_, LListHead<T> *head)
{
llist_add_tail(llptr(new_), llptr(head));
}
template <typename T>
inline void llist_del(LListHead<T> *entry)
{
llist_del(llptr(entry));
}
template <typename T>
inline void llist_del_init(LListHead<T> *entry)
{
llist_del_init(llptr(entry));
}
template <typename T>
inline void llist_move(LListHead<T> *list, LListHead<T> *head)
{
llist_move(llptr(list), llptr(head));
}
template <typename T>
inline void llist_move_tail(LListHead<T> *list, LListHead<T> *head)
{
llist_move_tail(llptr(list), llptr(head));
}
template <typename T>
inline int llist_empty(const LListHead<T> *head)
{
return llist_empty(llptr(head));
}
template <typename T>
inline void llist_splice(LListHead<T> *list, LListHead<T> *head)
{
llist_splice(llptr(list), llptr(head));
}
template <typename T>
inline void llist_splice_init(LListHead<T> *list, LListHead<T> *head)
{
llist_splice_init(llptr(list), llptr(head));
}

View File

@@ -20,55 +20,278 @@
#include <decoding.h>
#include <rlc.h>
#include <gprs_debug.h>
#include <egprs_rlc_compression.h>
extern "C" {
#include <osmocom/core/utils.h>
#include <osmocom/core/bitcomp.h>
#include <osmocom/gprs/protocol/gsm_04_60.h>
}
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
int Decoding::tlli_from_ul_data(const uint8_t *data, uint8_t len,
uint32_t *tlli)
#define LENGTH_TO_END 255
/*!
* \returns num extensions fields (num frames == offset) on success,
* -errno otherwise.
*/
static int parse_extensions_egprs(const uint8_t *data, unsigned int data_len,
unsigned int *offs,
bool is_last_block,
Decoding::RlcData *chunks, unsigned int chunks_size)
{
struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
struct rlc_li_field *li;
const struct rlc_li_field_egprs *li;
uint8_t e;
uint32_t _tlli;
unsigned int num_chunks = 0;
if (!rh->ti)
return -EINVAL;
data += 3;
len -= 3;
e = rh->e;
/* if E is not set (LI follows) */
e = 0;
while (!e) {
if (!len) {
if (*offs > data_len) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
"but no more data\n");
return -EINVAL;
}
/* get new E */
li = (struct rlc_li_field *)data;
if (li->e == 0) /* if LI==0, E is interpreted as '1' */
e = 1;
else
e = li->e;
data++;
len--;
}
if (len < 4) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of frame "
"border\n");
return -EINVAL;
}
memcpy(&_tlli, data, 4);
*tlli = ntohl(_tlli);
return 0;
/* get new E */
li = (struct rlc_li_field_egprs *)&data[*offs];
e = li->e;
*offs += 1;
if (!chunks)
continue;
if (num_chunks == chunks_size) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
"but no more chunks possible\n");
return -ENOSPC;
}
if (li->li == 0 && num_chunks == 0) {
/* TS 44.060, table 10.4.14a.1, row 2a */
/* TS 44.060, table 10.4.14a.1, row 4 */
chunks[num_chunks].length = 0;
chunks[num_chunks].is_complete = true;
} else if (li->li == 127 && li->e == 1) {
/* TS 44.060, table 10.4.14a.1, row 3 & 5 */
/* only filling bytes left */
LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA LI contains "
"only filling bytes with extension octet: LI=%d, E=%d, count=%d\n",
li->li, li->e, num_chunks);
break;
} else if (li->li > 0) {
/* TS 44.060, table 10.4.14a.1, row 1 & 2b */
chunks[num_chunks].length = li->li;
chunks[num_chunks].is_complete = true;
} else {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI contains "
"invalid extension octet: LI=%d, E=%d, count=%d\n",
li->li, li->e, num_chunks);
return -EINVAL;
}
LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA LI contains "
"extension octet: LI=%d, E=%d, count=%d\n",
li->li, li->e, num_chunks);
num_chunks += 1;
if (e == 1) {
/* There is space after the last chunk, add a final one */
if (num_chunks == chunks_size) {
LOGP(DRLCMACUL, LOGL_NOTICE,
"UL DATA LI possibly extended, "
"but no more chunks possible\n");
return -ENOSPC;
}
chunks[num_chunks].length = LENGTH_TO_END;
chunks[num_chunks].is_complete = is_last_block;
num_chunks += 1;
}
}
return num_chunks;
}
uint8_t Decoding::get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len,
unsigned int *offs,
bool is_last_block,
Decoding::RlcData *chunks, unsigned int chunks_size)
{
const struct rlc_li_field *li;
uint8_t m, e;
unsigned int num_chunks = 0;
e = 0;
while (!e) {
if (*offs > data_len) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
"but no more data\n");
return -EINVAL;
}
/* get new E */
li = (const struct rlc_li_field *)&data[*offs];
e = li->e;
m = li->m;
*offs += 1;
if (li->li == 0) {
/* TS 44.060, 10.4.14, par 6 */
e = 1;
m = 0;
}
/* TS 44.060, table 10.4.13.1 */
if (m == 0 && e == 0) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA "
"ignored, because M='0' and E='0'.\n");
return 0;
}
if (!chunks)
continue;
if (num_chunks == chunks_size) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
"but no more chunks possible\n");
return -ENOSPC;
}
if (li->li == 0)
/* e is 1 here */
chunks[num_chunks].length = LENGTH_TO_END;
else
chunks[num_chunks].length = li->li;
chunks[num_chunks].is_complete = li->li || is_last_block;
LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA LI contains "
"extension octet: LI=%d, M=%d, E=%d, count=%d\n",
li->li, li->m, li->e, num_chunks);
num_chunks += 1;
if (e == 1 && m == 1) {
if (num_chunks == chunks_size) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
"but no more chunks possible\n");
return -ENOSPC;
}
/* TS 44.060, 10.4.13.1, row 4 */
chunks[num_chunks].length = LENGTH_TO_END;
chunks[num_chunks].is_complete = is_last_block;
num_chunks += 1;
}
}
return num_chunks;
}
int Decoding::rlc_data_from_ul_data(
const struct gprs_rlc_data_block_info *rdbi, enum CodingScheme cs,
const uint8_t *data, RlcData *chunks, unsigned int chunks_size,
uint32_t *tlli)
{
uint8_t e;
unsigned int data_len = rdbi->data_len;
int num_chunks = 0, i;
unsigned int offs = 0;
bool is_last_block = (rdbi->cv == 0);
if (!chunks)
chunks_size = 0;
e = rdbi->e;
if (e) {
if (chunks_size > 0) {
/* Block without LI means it only contains data of one LLC PDU */
chunks[num_chunks].offset = offs;
chunks[num_chunks].length = LENGTH_TO_END;
chunks[num_chunks].is_complete = is_last_block;
num_chunks += 1;
} else if (chunks) {
LOGP(DRLCMACUL, LOGL_NOTICE, "No extension, "
"but no more chunks possible\n");
return -ENOSPC;
}
} else if (mcs_is_edge(cs)) {
/* if E is not set (LI follows), EGPRS */
num_chunks = parse_extensions_egprs(data, data_len, &offs,
is_last_block,
chunks, chunks_size);
} else {
/* if E is not set (LI follows), GPRS */
num_chunks = parse_extensions_gprs(data, data_len, &offs,
is_last_block,
chunks, chunks_size);
}
if (num_chunks < 0)
return num_chunks;
/* TLLI */
if (rdbi->ti) {
uint32_t tlli_enc;
if (offs + 4 > data_len) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of block "
"border\n");
return -EINVAL;
}
memcpy(&tlli_enc, data + offs, sizeof(tlli_enc));
if (mcs_is_gprs(cs))
/* The TLLI is encoded in big endian for GPRS (see
* TS 44.060, figure 10.2.2.1, note) */
*tlli = be32toh(tlli_enc);
else
/* The TLLI is encoded in little endian for EGPRS (see
* TS 44.060, figure 10.3a.2.1, note 2) */
*tlli = le32toh(tlli_enc);
offs += sizeof(tlli_enc);
} else {
*tlli = 0;
}
/* PFI */
if (rdbi->pi) {
LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, "
"please disable in SYSTEM INFORMATION\n");
return -ENOTSUP;
/* TODO: Skip all extensions with E=0 (see TS 44.060, 10.4.11 */
}
if (chunks_size == 0)
return num_chunks;
/* LLC */
for (i = 0; i < num_chunks; i++) {
chunks[i].offset = offs;
if (chunks[i].length == LENGTH_TO_END) {
if (offs == data_len) {
/* There is no place for an additional chunk,
* so drop it (this may happen with EGPRS since
* there is no M flag. */
num_chunks -= 1;
break;
}
chunks[i].length = data_len - offs;
}
offs += chunks[i].length;
if (offs > data_len) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA out of block "
"border, chunk idx: %d, offset: %u, size: %d, data_len: %u\n",
i, offs, chunks[i].length, data_len);
return -EINVAL;
}
}
return num_chunks;
}
uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
{
int i;
@@ -83,17 +306,482 @@ uint8_t Decoding::get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
return 0;
}
/**
* show_rbb needs to be an array with 65 elements
*/
void Decoding::extract_rbb(const uint8_t *rbb, char *show_rbb)
uint8_t get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
{
for (int i = 63; i >= 0; i--) {
uint8_t bit;
int i;
bit = (rbb[i >> 3] >> (7 - (i&7))) & 1;
show_rbb[i] = bit ? '1' : 'o';
for (i = 0; i < cap->Count_MS_RA_capability_value; i++) {
if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability)
continue;
if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_EGPRS_multislot_class)
continue;
return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.EGPRS_multislot_class;
}
show_rbb[64] = '\0';
return 0;
}
/**
* show_rbb needs to be an array with 65 elements
* The index of the array is the bit position in the rbb
* (show_rbb[63] relates to BSN ssn-1)
*/
void Decoding::extract_rbb(const struct bitvec *rbb, char *show_rbb)
{
unsigned int i;
for (i = 0; i < rbb->cur_bit; i++) {
uint8_t bit;
bit = bitvec_get_bit_pos(rbb, i);
show_rbb[i] = bit == 1 ? 'R' : 'I';
}
show_rbb[i] = '\0';
}
int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
const uint8_t *data, enum CodingScheme cs)
{
unsigned int cur_bit = 0;
switch(mcs_header_type(cs)) {
case HEADER_GPRS_DATA :
cur_bit = rlc_parse_ul_data_header_gprs(rlc, data, cs);
break;
case HEADER_EGPRS_DATA_TYPE_3 :
cur_bit = rlc_parse_ul_data_header_egprs_type_3(rlc, data, cs);
break;
case HEADER_EGPRS_DATA_TYPE_2 :
cur_bit = rlc_parse_ul_data_header_egprs_type_2(rlc, data, cs);
break;
case HEADER_EGPRS_DATA_TYPE_1 :
cur_bit = rlc_parse_ul_data_header_egprs_type_1(rlc, data, cs);
break;
default:
LOGP(DRLCMACDL, LOGL_ERROR,
"Decoding of uplink %s data blocks not yet supported.\n",
mcs_name(cs));
return -ENOTSUP;
};
return cur_bit;
}
int Decoding::rlc_parse_ul_data_header_egprs_type_3(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const enum CodingScheme &cs)
{
int punct, punct2, with_padding, cps;
unsigned int e_ti_header, offs, cur_bit = 0;
const struct gprs_rlc_ul_header_egprs_3 *egprs3;
egprs3 = static_cast < struct gprs_rlc_ul_header_egprs_3 * >
((void *)data);
cps = (egprs3->cps_hi << 0) | (egprs3->cps_lo << 2);
gprs_rlc_mcs_cps_decode(cps, cs, &punct, &punct2, &with_padding);
gprs_rlc_data_info_init_ul(rlc, cs, with_padding);
rlc->r = egprs3->r;
rlc->si = egprs3->si;
rlc->tfi = (egprs3->tfi_hi << 0) | (egprs3->tfi_lo << 2);
rlc->cps = cps;
rlc->rsb = egprs3->rsb;
rlc->num_data_blocks = 1;
rlc->block_info[0].cv = egprs3->cv;
rlc->block_info[0].pi = egprs3->pi;
rlc->block_info[0].spb = egprs3->spb;
rlc->block_info[0].bsn =
(egprs3->bsn1_hi << 0) | (egprs3->bsn1_lo << 5);
cur_bit += rlc->data_offs_bits[0] - 2;
offs = rlc->data_offs_bits[0] / 8;
OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 1);
e_ti_header = (data[offs-1] + (data[offs] << 8)) >> 7;
rlc->block_info[0].e = !!(e_ti_header & 0x01);
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
cur_bit += 2;
/* skip data area */
cur_bit += mcs_max_data_block_bytes(cs) * 8;
return cur_bit;
}
int Decoding::rlc_parse_ul_data_header_egprs_type_2(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const enum CodingScheme &cs)
{
const struct gprs_rlc_ul_header_egprs_2 *egprs2;
unsigned int e_ti_header, offs, cur_bit = 0;
int punct, punct2, with_padding, cps;
egprs2 = static_cast < struct gprs_rlc_ul_header_egprs_2 * >
((void *)data);
cps = (egprs2->cps_hi << 0) | (egprs2->cps_lo << 2);
gprs_rlc_mcs_cps_decode(cps, cs, &punct, &punct2, &with_padding);
gprs_rlc_data_info_init_ul(rlc, cs, with_padding);
rlc->r = egprs2->r;
rlc->si = egprs2->si;
rlc->tfi = (egprs2->tfi_hi << 0) | (egprs2->tfi_lo << 2);
rlc->cps = cps;
rlc->rsb = egprs2->rsb;
rlc->num_data_blocks = 1;
rlc->block_info[0].cv = egprs2->cv;
rlc->block_info[0].pi = egprs2->pi;
rlc->block_info[0].bsn =
(egprs2->bsn1_hi << 0) | (egprs2->bsn1_lo << 5);
cur_bit += rlc->data_offs_bits[0] - 2;
offs = rlc->data_offs_bits[0] / 8;
OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 7);
e_ti_header = (data[offs] & 0x60) >> 5;
rlc->block_info[0].e = !!(e_ti_header & 0x01);
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
cur_bit += 2;
/* skip data area */
cur_bit += mcs_max_data_block_bytes(cs) * 8;
return cur_bit;
}
int Decoding::rlc_parse_ul_data_header_egprs_type_1(
struct gprs_rlc_data_info *rlc,
const uint8_t *data, const enum CodingScheme &cs)
{
struct gprs_rlc_ul_header_egprs_1 *egprs1;
unsigned int e_ti_header, cur_bit = 0, offs;
int punct, punct2, with_padding;
egprs1 = static_cast < struct gprs_rlc_ul_header_egprs_1 * >
((void *)data);
gprs_rlc_mcs_cps_decode(egprs1->cps, cs, &punct, &punct2,
&with_padding);
gprs_rlc_data_info_init_ul(rlc, cs, with_padding);
rlc->r = egprs1->r;
rlc->si = egprs1->si;
rlc->tfi = (egprs1->tfi_hi << 0) | (egprs1->tfi_lo << 2);
rlc->cps = egprs1->cps;
rlc->rsb = egprs1->rsb;
rlc->num_data_blocks = 2;
rlc->block_info[0].cv = egprs1->cv;
rlc->block_info[0].pi = egprs1->pi;
rlc->block_info[0].bsn =
(egprs1->bsn1_hi << 0) | (egprs1->bsn1_lo << 5);
cur_bit += rlc->data_offs_bits[0] - 2;
offs = rlc->data_offs_bits[0] / 8;
OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 0);
e_ti_header = data[offs - 1] >> 6;
rlc->block_info[0].e = (e_ti_header & 0x01);
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
cur_bit += 2;
rlc->block_info[1].cv = egprs1->cv;
rlc->block_info[1].pi = egprs1->pi;
rlc->block_info[1].bsn = rlc->block_info[0].bsn +
((egprs1->bsn2_hi << 0) | (egprs1->bsn2_lo << 2));
rlc->block_info[1].bsn = rlc->block_info[1].bsn & (RLC_EGPRS_SNS - 1);
if ((rlc->block_info[1].bsn != rlc->block_info[0].bsn) &&
(rlc->block_info[0].cv == 0))
rlc->block_info[0].cv = 1;
cur_bit = rlc->data_offs_bits[1] - 2;
offs = rlc->data_offs_bits[1] / 8;
OSMO_ASSERT(rlc->data_offs_bits[1] % 8 == 2);
e_ti_header = (data[offs] & (0x03));
rlc->block_info[1].e = (e_ti_header & 0x01);
rlc->block_info[1].ti = !!(e_ti_header & 0x02);
cur_bit += 2;
/* skip data area */
cur_bit += mcs_max_data_block_bytes(cs) * 8;
return cur_bit;
}
int Decoding::rlc_parse_ul_data_header_gprs(struct gprs_rlc_data_info *rlc,
const uint8_t *data, const enum CodingScheme &cs)
{
const struct rlc_ul_header *gprs;
unsigned int cur_bit = 0;
gprs = static_cast < struct rlc_ul_header * >
((void *)data);
gprs_rlc_data_info_init_ul(rlc, cs, false);
rlc->r = gprs->r;
rlc->si = gprs->si;
rlc->tfi = gprs->tfi;
rlc->cps = 0;
rlc->rsb = 0;
rlc->num_data_blocks = 1;
rlc->block_info[0].cv = gprs->cv;
rlc->block_info[0].pi = gprs->pi;
rlc->block_info[0].bsn = gprs->bsn;
rlc->block_info[0].e = gprs->e;
rlc->block_info[0].ti = gprs->ti;
rlc->block_info[0].spb = 0;
cur_bit += rlc->data_offs_bits[0];
/* skip data area */
cur_bit += mcs_max_data_block_bytes(cs) * 8;
return cur_bit;
}
/**
* \brief Copy LSB bitstream RLC data block to byte aligned buffer.
*
* Note that the bitstream is encoded in LSB first order, so the two octets
* 654321xx xxxxxx87 contain the octet 87654321 starting at bit position 3
* (LSB has bit position 1). This is a different order than the one used by
* CSN.1.
*
* \param data_block_idx The block index, 0..1 for header type 1, 0 otherwise
* \param src A pointer to the start of the RLC block (incl. the header)
* \param buffer A data area of a least the size of the RLC block
* \returns the number of bytes copied
*/
unsigned int Decoding::rlc_copy_to_aligned_buffer(
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer)
{
unsigned int hdr_bytes;
unsigned int extra_bits;
unsigned int i;
uint8_t c, last_c;
uint8_t *dst;
const struct gprs_rlc_data_block_info *rdbi;
OSMO_ASSERT(data_block_idx < rlc->num_data_blocks);
rdbi = &rlc->block_info[data_block_idx];
hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3;
extra_bits = (rlc->data_offs_bits[data_block_idx] & 7);
if (extra_bits == 0) {
/* It is aligned already */
memmove(buffer, src + hdr_bytes, rdbi->data_len);
return rdbi->data_len;
}
dst = buffer;
src = src + hdr_bytes;
last_c = *(src++);
for (i = 0; i < rdbi->data_len; i++) {
c = src[i];
*(dst++) = (last_c >> extra_bits) | (c << (8 - extra_bits));
last_c = c;
}
return rdbi->data_len;
}
/**
* \brief Get a pointer to byte aligned RLC data.
*
* Since the RLC data may not be byte aligned to the RLC block data such that a
* single RLC data byte is spread over two RLC block bytes, this function
* eventually uses the provided buffer as data storage.
*
* \param src A pointer to the start of the RLC block (incl. the header)
* \param buffer A data area of a least the size of the RLC block
* \returns A pointer to the RLC data start within src if it is aligned, and
* buffer otherwise.
*/
const uint8_t *Decoding::rlc_get_data_aligned(
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer)
{
unsigned int hdr_bytes;
unsigned int extra_bits;
OSMO_ASSERT(data_block_idx < ARRAY_SIZE(rlc->data_offs_bits));
hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3;
extra_bits = (rlc->data_offs_bits[data_block_idx] & 7);
if (extra_bits == 0)
/* It is aligned already, return a pointer that refers to the
* original data. */
return src + hdr_bytes;
Decoding::rlc_copy_to_aligned_buffer(rlc, data_block_idx, src, buffer);
return buffer;
}
static int handle_final_ack(bitvec *bits, int *bsn_begin, int *bsn_end,
gprs_rlc_dl_window *window)
{
int num_blocks, i;
num_blocks = window->mod_sns(window->v_s() - window->v_a());
for (i = 0; i < num_blocks; i++)
bitvec_set_bit(bits, ONE);
*bsn_begin = window->v_a();
*bsn_end = window->mod_sns(*bsn_begin + num_blocks);
return num_blocks;
}
int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc,
bitvec *bits, int *bsn_begin, int *bsn_end, gprs_rlc_dl_window *window)
{
int urbb_len = desc->URBB_LENGTH;
int crbb_len = 0;
int num_blocks = 0;
struct bitvec urbb;
int i;
bool have_bitmap;
int implicitly_acked_blocks;
int ssn = desc->STARTING_SEQUENCE_NUMBER;
int rc;
if (desc->FINAL_ACK_INDICATION)
return handle_final_ack(bits, bsn_begin, bsn_end, window);
if (desc->Exist_CRBB)
crbb_len = desc->CRBB_LENGTH;
have_bitmap = (urbb_len + crbb_len) > 0;
/*
* bow & bitmap present:
* V(A)-> [ 11111...11111 0 SSN-> BBBBB...BBBBB ] (SSN+Nbits) .... V(S)
* bow & not bitmap present:
* V(A)-> [ 11111...11111 ] . SSN .... V(S)
* not bow & bitmap present:
* V(A)-> ... [ 0 SSN-> BBBBB...BBBBB ](SSN+N) .... V(S)
* not bow & not bitmap present:
* V(A)-> ... [] . SSN .... V(S)
*/
if (desc->BEGINNING_OF_WINDOW) {
implicitly_acked_blocks = window->mod_sns(ssn - 1 - window->v_a());
for (i = 0; i < implicitly_acked_blocks; i++)
bitvec_set_bit(bits, ONE);
num_blocks += implicitly_acked_blocks;
}
if (!have_bitmap)
goto aborted;
/* next bit refers to V(Q) and thus is always zero (and not
* transmitted) */
bitvec_set_bit(bits, ZERO);
num_blocks += 1;
if (crbb_len > 0) {
int old_len = bits->cur_bit;
LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exists, "
"CRBB LEN = %d and Starting color code = %d",
desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE);
rc = egprs_compress::decompress_crbb(desc->CRBB_LENGTH,
desc->CRBB_STARTING_COLOR_CODE, desc->CRBB, bits);
if (rc < 0) {
LOGP(DRLCMACUL, LOGL_NOTICE,
"Failed to decode CRBB: length %d, data '%s'\n",
desc->CRBB_LENGTH, osmo_hexdump(
desc->CRBB, (desc->CRBB_LENGTH + 7)/8));
/* We don't know the SSN offset for the URBB,
* return what we have so far and assume the
* bitmap has stopped here */
goto aborted;
}
LOGP(DRLCMACDL, LOGL_DEBUG,
"CRBB len: %d, decoded len: %d, cc: %d, crbb: '%s'\n",
desc->CRBB_LENGTH, bits->cur_bit - old_len,
desc->CRBB_STARTING_COLOR_CODE,
osmo_hexdump(
desc->CRBB, (desc->CRBB_LENGTH + 7)/8)
);
num_blocks += (bits->cur_bit - old_len);
}
urbb.cur_bit = 0;
urbb.data = (uint8_t *)desc->URBB;
urbb.data_len = sizeof(desc->URBB);
for (i = urbb_len; i > 0; i--) {
/*
* Set bit at the appropriate position (see 3GPP TS
* 44.060 12.3.1)
*/
int is_ack = bitvec_get_bit_pos(&urbb, i-1);
bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO);
}
num_blocks += urbb_len;
aborted:
*bsn_begin = window->v_a();
*bsn_end = window->mod_sns(*bsn_begin + num_blocks);
return num_blocks;
}
int Decoding::decode_gprs_acknack_bits(const Ack_Nack_Description_t *desc,
bitvec *bits, int *bsn_begin, int *bsn_end, gprs_rlc_dl_window *window)
{
int urbb_len = RLC_GPRS_WS;
int num_blocks;
struct bitvec urbb;
if (desc->FINAL_ACK_INDICATION)
return handle_final_ack(bits, bsn_begin, bsn_end, window);
*bsn_begin = window->v_a();
*bsn_end = desc->STARTING_SEQUENCE_NUMBER;
num_blocks = window->mod_sns(*bsn_end - *bsn_begin);
if (num_blocks < 0 || num_blocks > urbb_len) {
*bsn_end = *bsn_begin;
LOGP(DRLCMACUL, LOGL_NOTICE,
"Invalid GPRS Ack/Nack window %d:%d (length %d)\n",
*bsn_begin, *bsn_end, num_blocks);
return -EINVAL;
}
urbb.cur_bit = 0;
urbb.data = (uint8_t *)desc->RECEIVED_BLOCK_BITMAP;
urbb.data_len = sizeof(desc->RECEIVED_BLOCK_BITMAP);
/*
* TS 44.060, 12.3:
* BSN = (SSN - bit_number) modulo 128, for bit_number = 1 to 64.
* The BSN values represented range from (SSN - 1) mod 128 to (SSN - 64) mod 128.
*
* We are only interested in the range from V(A) to SSN-1 which is
* num_blocks large. The RBB is laid out as
* [SSN-1] [SSN-2] ... [V(A)] ... [SSN-64]
* so we want to start with [V(A)] and go backwards until we reach
* [SSN-1] to get the needed BSNs in an increasing order. Note that
* the bit numbers are counted from the end of the buffer.
*/
for (int i = num_blocks; i > 0; i--) {
int is_ack = bitvec_get_bit_pos(&urbb, urbb_len - i);
bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO);
}
return num_blocks;
}

View File

@@ -19,15 +19,83 @@
*/
#pragma once
#include <gsm_rlcmac.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "gsm_rlcmac.h"
#include "coding_scheme.h"
#ifdef __cplusplus
}
#endif
#include <stdint.h>
struct bitvec;
#ifdef __cplusplus
class Decoding {
public:
static int tlli_from_ul_data(const uint8_t *data, uint8_t len,
uint32_t *tlli);
static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
/* represents (parts) LLC PDUs within one RLC Data block */
struct RlcData {
uint8_t offset;
uint8_t length;
bool is_complete; /* if this PDU ends in this block */
};
static void extract_rbb(const uint8_t *rbb, char *extracted_rbb);
static int rlc_data_from_ul_data(
const struct gprs_rlc_data_block_info *rdbi,
enum CodingScheme cs, const uint8_t *data, RlcData *chunks,
unsigned int chunks_size, uint32_t *tlli);
static void extract_rbb(const struct bitvec *rbb, char *show_rbb);
static int rlc_parse_ul_data_header_egprs_type_3(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const enum CodingScheme &cs);
static int rlc_parse_ul_data_header_egprs_type_2(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const enum CodingScheme &cs);
static int rlc_parse_ul_data_header_egprs_type_1(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const enum CodingScheme &cs);
static int rlc_parse_ul_data_header_gprs(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const enum CodingScheme &cs);
static int rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
const uint8_t *data, enum CodingScheme cs);
static unsigned int rlc_copy_to_aligned_buffer(
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer);
static const uint8_t *rlc_get_data_aligned(
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer);
static int decode_egprs_acknack_bits(
const EGPRS_AckNack_Desc_t *desc,
struct bitvec *bits, int *bsn_begin, int *bsn_end,
struct gprs_rlc_dl_window *window);
static int decode_gprs_acknack_bits(
const Ack_Nack_Description_t *desc,
bitvec *bits, int *bsn_begin, int *bsn_end,
gprs_rlc_dl_window *window);
};
#endif /* #ifdef __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif
uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
uint8_t get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,696 @@
/* egprs_rlc_compression.h
* Routines for EGPRS RLC bitmap compression handling
*/
#include <errno.h>
#include <decoding.h>
#include <arpa/inet.h>
#include <string.h>
#include <gprs_debug.h>
#include <gprs_rlcmac.h>
#include <egprs_rlc_compression.h>
extern "C" {
#include <osmocom/core/talloc.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/stats.h>
}
#define EGPRS_CODEWORDS 79 /* total number of codewords */
struct egprs_compress_node{
struct egprs_compress_node *left;
struct egprs_compress_node *right;
int run_length;
};
extern void *tall_pcu_ctx;
egprs_compress *egprs_compress::s_instance = 0;
egprs_compress_node *egprs_compress::create_tree_node(void *parent)
{
egprs_compress_node *new_node;
new_node = talloc_zero(parent, egprs_compress_node);
new_node->left = NULL;
new_node->right = NULL;
new_node->run_length = -1;
return new_node;
}
egprs_compress *egprs_compress::instance()
{
if (!egprs_compress::s_instance)
egprs_compress::s_instance = new egprs_compress;
return egprs_compress::s_instance;
}
/* Expands the given tree by incorporating
* the given codewords.
* \param root[in] Root of ones or zeros tree
* \param cdwd[in] Array of code words
* number of codewords is EGPRS_CODEWORDS
*/
void egprs_compress::build_codewords(egprs_compress_node *root, const char *cdwd[])
{
egprs_compress_node *iter;
int len;
int i;
int idx;
for (idx = 0; idx < EGPRS_CODEWORDS; idx++) {
len = strlen((const char *)cdwd[idx]);
iter = root;
for (i = 0; i < len; i++) {
if (cdwd[idx][i] == '0') {
if (!iter->left)
iter->left = create_tree_node(root);
iter = iter->left;
} else {
if (!iter->right)
iter->right = create_tree_node(root);
iter = iter->right;
}
}
if (iter) {
/* The first 64 run lengths are 0, 1, 2, ..., 63
* and the following ones are 64, 128, 192 described in
* section 9.1.10 of 3gpp 44.060 */
if (idx < 64)
iter->run_length = idx;
else
iter->run_length = (idx - 63) * 64;
}
}
}
/*
* Terminating codes for uninterrupted sequences of 0 and 1 up to 64 bit length
* according to TS 44.060 9.1.10
*/
static const unsigned t4_term[2][64] = {
{
0b0000110111,
0b10,
0b11,
0b010,
0b011,
0b0011,
0b0010,
0b00011,
0b000101,
0b000100,
0b0000100,
0b0000101,
0b0000111,
0b00000100,
0b00000111,
0b000011000,
0b0000010111,
0b0000011000,
0b0000001000,
0b00001100111,
0b00001101000,
0b00001101100,
0b00000110111,
0b00000101000,
0b00000010111,
0b00000011000,
0b000011001010,
0b000011001011,
0b000011001100,
0b000011001101,
0b000001101000,
0b000001101001,
0b000001101010,
0b000001101011,
0b000011010010,
0b000011010011,
0b000011010100,
0b000011010101,
0b000011010110,
0b000011010111,
0b000001101100,
0b000001101101,
0b000011011010,
0b000011011011,
0b000001010100,
0b000001010101,
0b000001010110,
0b000001010111,
0b000001100100,
0b000001100101,
0b000001010010,
0b000001010011,
0b000000100100,
0b000000110111,
0b000000111000,
0b000000100111,
0b000000101000,
0b000001011000,
0b000001011001,
0b000000101011,
0b000000101100,
0b000001011010,
0b000001100110,
0b000001100111
},
{
0b00110101,
0b000111,
0b0111,
0b1000,
0b1011,
0b1100,
0b1110,
0b1111,
0b10011,
0b10100,
0b00111,
0b01000,
0b001000,
0b000011,
0b110100,
0b110101,
0b101010,
0b101011,
0b0100111,
0b0001100,
0b0001000,
0b0010111,
0b0000011,
0b0000100,
0b0101000,
0b0101011,
0b0010011,
0b0100100,
0b0011000,
0b00000010,
0b00000011,
0b00011010,
0b00011011,
0b00010010,
0b00010011,
0b00010100,
0b00010101,
0b00010110,
0b00010111,
0b00101000,
0b00101001,
0b00101010,
0b00101011,
0b00101100,
0b00101101,
0b00000100,
0b00000101,
0b00001010,
0b00001011,
0b01010010,
0b01010011,
0b01010100,
0b01010101,
0b00100100,
0b00100101,
0b01011000,
0b01011001,
0b01011010,
0b01011011,
0b01001010,
0b01001011,
0b00110010,
0b00110011,
0b00110100
}
};
static const unsigned t4_term_length[2][64] = {
{10, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12},
{8, 6, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
};
static const unsigned t4_min_term_length[] = {2, 4};
static const unsigned t4_min_make_up_length[] = {10, 5};
static const unsigned t4_max_term_length[] = {12, 8};
static const unsigned t4_max_make_up_length[] = {13, 9};
static const unsigned t4_make_up_length[2][15] = {
{10, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13},
{5, 5, 6, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9}
};
static const unsigned t4_make_up_ind[15] = {64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960};
static const unsigned t4_make_up[2][15] = {
{
0b0000001111,
0b000011001000,
0b000011001001,
0b000001011011,
0b000000110011,
0b000000110100,
0b000000110101,
0b0000001101100,
0b0000001101101,
0b0000001001010,
0b0000001001011,
0b0000001001100,
0b0000001001101,
0b0000001110010,
0b0000001110011
},
{
0b11011,
0b10010,
0b010111,
0b0110111,
0b00110110,
0b00110111,
0b01100100,
0b01100101,
0b01101000,
0b01100111,
0b011001100,
0b011001101,
0b011010010,
0b011010011,
0b011010100
}
};
/* The code words for one run length and zero
* run length are described in table 9.1.10.1
* of 3gpp 44.060
*/
const char *one_run_len_code_list[EGPRS_CODEWORDS] = {
"00110101",
"000111",
"0111",
"1000",
"1011",
"1100",
"1110",
"1111",
"10011",
"10100",
"00111",
"01000",
"001000",
"000011",
"110100",
"110101",
"101010",
"101011",
"0100111",
"0001100",
"0001000",
"0010111",
"0000011",
"0000100",
"0101000",
"0101011",
"0010011",
"0100100",
"0011000",
"00000010",
"00000011",
"00011010",
"00011011",
"00010010",
"00010011",
"00010100",
"00010101",
"00010110",
"00010111",
"00101000",
"00101001",
"00101010",
"00101011",
"00101100",
"00101101",
"00000100",
"00000101",
"00001010",
"00001011",
"01010010",
"01010011",
"01010100",
"01010101",
"00100100",
"00100101",
"01011000",
"01011001",
"01011010",
"01011011",
"01001010",
"01001011",
"00110010",
"00110011",
"00110100",
"11011",
"10010",
"010111",
"0110111",
"00110110",
"00110111",
"01100100",
"01100101",
"01101000",
"01100111",
"011001100",
"011001101",
"011010010",
"011010011",
"011010100"
};
const char *zero_run_len_code_list[EGPRS_CODEWORDS] = {
"0000110111",
"10",
"11",
"010",
"011",
"0011",
"0010",
"00011",
"000101",
"000100",
"0000100",
"0000101",
"0000111",
"00000100",
"00000111",
"000011000",
"0000010111",
"0000011000",
"0000001000",
"00001100111",
"00001101000",
"00001101100",
"00000110111",
"00000101000",
"00000010111",
"00000011000",
"000011001010",
"000011001011",
"000011001100",
"000011001101",
"000001101000",
"000001101001",
"000001101010",
"000001101011",
"000011010010",
"000011010011",
"000011010100",
"000011010101",
"000011010110",
"000011010111",
"000001101100",
"000001101101",
"000011011010",
"000011011011",
"000001010100",
"000001010101",
"000001010110",
"000001010111",
"000001100100",
"000001100101",
"000001010010",
"000001010011",
"000000100100",
"000000110111",
"000000111000",
"000000100111",
"000000101000",
"000001011000",
"000001011001",
"000000101011",
"000000101100",
"000001011010",
"000001100110",
"000001100111",
"0000001111",
"000011001000",
"000011001001",
"000001011011",
"000000110011",
"000000110100",
"000000110101",
"0000001101100",
"0000001101101",
"0000001001010",
"0000001001011",
"0000001001100",
"0000001001101",
"0000001110010",
"0000001110011"
};
/* Calculate runlength of a codeword
* \param root[in] Root of Ones or Zeros tree
* \param bmbuf[in] Received compressed bitmap buf
* \param length[in] Length of bitmap buf in bits
* \param bit_pos[in] The start bit pos to read codeword
* \param len_codewd[in] Length of code word
* \param rlen[out] Calculated run length
*/
static int search_runlen(
egprs_compress_node *root,
const uint8_t *bmbuf,
uint8_t length,
uint8_t bit_pos,
uint8_t *len_codewd,
uint16_t *rlen)
{
egprs_compress_node *iter;
uint8_t dir;
iter = root;
*len_codewd = 0;
while (iter->run_length == -1) {
if ((!iter->left) && (!iter->right))
return -1;
if (bit_pos >= length)
return -1;
/* get the bit value at the bitpos and put it in right most of dir */
dir = (bmbuf[bit_pos/8] >> (7 - (bit_pos & 0x07))) & 0x01;
bit_pos++;
(*len_codewd)++;
if (!dir && (iter->left != NULL))
iter = iter->left;
else if (dir && (iter->right != NULL))
iter = iter->right;
else
return -1;
}
LOGP(DRLCMACUL, LOGL_DEBUG, "Run_length = %d\n", iter->run_length);
*rlen = iter->run_length;
return 1;
}
/* Decompress received block bitmap
* \param compress_bmap_len[in] Compressed bitmap length
* \param start[in] Starting Color Code, true if bitmap starts with a run
* length of ones, false if zeros; see 9.1.10, 3GPP 44.060.
* \param orig_crbb_buf[in] Received block crbb bitmap
* \param dest[out] Uncompressed bitvector
*/
int egprs_compress::decompress_crbb(
int8_t compress_bmap_len,
bool start,
const uint8_t *orig_crbb_buf,
bitvec *dest)
{
int8_t remaining_bmap_len = compress_bmap_len;
uint8_t bit_pos = 0;
uint8_t data;
egprs_compress_node *list = NULL;
uint8_t nbits = 0; /* number of bits of codeword */
uint16_t run_length = 0;
uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */
unsigned wp = dest->cur_bit;
int rc = 0;
egprs_compress *compress = instance();
while (remaining_bmap_len > 0) {
if (start) {
data = 0xff;
list = compress->ones_list;
} else {
data = 0x00;
list = compress->zeros_list;
}
rc = search_runlen(list, orig_crbb_buf, compress_bmap_len,
bit_pos, &nbits, &run_length);
if (rc == -1)
return -1;
/* If run length > 64, need makeup and terminating code */
if (run_length < 64)
start = !start;
cbmaplen = cbmaplen + run_length;
/* put run length of Ones in uncompressed bitmap */
while (run_length != 0) {
if (run_length > 8) {
bitvec_write_field(dest, &wp, data, 8);
run_length = run_length - 8;
} else {
bitvec_write_field(dest, &wp, data, run_length);
run_length = 0;
}
}
bit_pos = bit_pos + nbits;
remaining_bmap_len = remaining_bmap_len - nbits;
}
return 0;
}
void egprs_compress::decode_tree_init()
{
ones_list = create_tree_node(tall_pcu_ctx);
zeros_list = create_tree_node(tall_pcu_ctx);
build_codewords(ones_list, one_run_len_code_list);
build_codewords(zeros_list, zero_run_len_code_list);
}
egprs_compress::egprs_compress()
{
decode_tree_init();
}
/* Compress received block bitmap
* \param run_len_cnt[in] Count of number of 1's and 0's
* \param codewrd_bitmap[in] Code word for coresponding run length.
* \param crbb_vec[out] compressed bitvector.
*/
static void compress_bitmap(
uint16_t *run_len_cnt, /* cnt: run length count */
uint16_t *codewrd_bitmap, /* code word */
int16_t *codewrd_len, /* number of bits in the code word */
bitvec *crbb_vec, /* bitmap buffer to put code word in */
bool start)
{
int i = 0;
unsigned writeIndex = crbb_vec->cur_bit;
*codewrd_bitmap = 0;
*codewrd_len = 0;
if (*run_len_cnt >= 64) {
for (i = 0; i < 15; i++) {
if (t4_make_up_ind[i] == *run_len_cnt) {
*codewrd_bitmap = t4_make_up[start][i];
*codewrd_len = t4_make_up_length[start][i];
}
}
} else {
*codewrd_bitmap = t4_term[start][*run_len_cnt];
*codewrd_len = t4_term_length[start][*run_len_cnt];
}
bitvec_write_field(crbb_vec, &writeIndex, *codewrd_bitmap, *codewrd_len);
}
/* Compress received block bitmap */
int egprs_compress::osmo_t4_compress(struct bitvec *bv)
{
uint8_t crbb_len = 0;
uint8_t uclen_crbb = 0;
uint8_t crbb_bitmap[127] = {'\0'};
bool start = (bv->data[0] & 0x80)>>7;
struct bitvec crbb_vec;
crbb_vec.data = crbb_bitmap;
crbb_vec.cur_bit = 0;
crbb_vec.data_len = 127;
bv->data_len = bv->cur_bit;
bv->cur_bit = 0;
if (egprs_compress::compress_rbb(bv, &crbb_vec, &uclen_crbb, 23*8)) {
memcpy(bv->data, crbb_bitmap, (crbb_len+7)/8);
bv->cur_bit = crbb_len;
bv->data_len = (crbb_len+7)/8;
return start;
}
else
printf("Encode failed\n");
return -1;
}
/*! \brief compression algorithm using T4 encoding
* the compressed bitmap's are copied in crbb_bitmap
* \param[in] rbb_vec bit vector to be encoded
* \return 1 if compression is success or 0 for failure
*/
int egprs_compress::compress_rbb(
struct bitvec *urbb_vec,
struct bitvec *crbb_vec,
uint8_t *uclen_crbb, /* Uncompressed bitmap len in CRBB */
uint8_t max_bits) /* max remaining bits */
{
bool run_len_bit;
int buflen = urbb_vec->cur_bit;
int total_bits = urbb_vec->cur_bit;
uint16_t rlen;
uint16_t temprl = 0;
uint16_t cbmap = 0; /* Compressed code word */
int16_t nbits; /* Length of code word */
uint16_t uclen = 0;
int16_t clen = 0;
bool start; /* Starting color code see 9.1.10, 3GPP 44.060 */
urbb_vec->cur_bit = 0;
run_len_bit = (urbb_vec->data[0] & 0x80)>>7;
while (buflen > 0) {
temprl = 0;
/* Find Run length */
if (run_len_bit == 1)
rlen = bitvec_rl_curbit(urbb_vec, true, total_bits);
else
rlen = bitvec_rl_curbit(urbb_vec, false, total_bits);
buflen = buflen - rlen;
/* if rlen > 64 need Makeup code word */
/*Compress the bits */
if (run_len_bit == 0) {
start = 0;
if (rlen >= 64) {
temprl = (rlen/64)*64;
compress_bitmap(&temprl, &cbmap, &nbits,
crbb_vec, start);
clen = clen + nbits;
}
temprl = MOD64(rlen);
compress_bitmap(&temprl, &cbmap, &nbits,
crbb_vec, start);
/* next time the run length will be Ones */
run_len_bit = 1;
} else {
start = 1;
if (rlen >= 64) {
temprl = (rlen/64)*64;
compress_bitmap(&temprl, &cbmap, &nbits,
crbb_vec, start);
clen = clen + nbits;
}
temprl = MOD64(rlen);
compress_bitmap(&temprl, &cbmap, &nbits,
crbb_vec, start);
/* next time the run length will be Zeros */
run_len_bit = 0;
}
uclen = uclen + rlen;
clen = clen + nbits;
/*compressed bitmap exceeds the buffer space */
if (clen > max_bits) {
uclen = uclen - rlen;
clen = clen - nbits;
break;
}
}
crbb_vec->cur_bit = clen;
*uclen_crbb = uclen;
if (clen >= uclen)
/* No Gain is observed, So no need to compress */
return 0;
LOGP(DRLCMACUL, LOGL_DEBUG, "CRBB bitmap = %s\n", osmo_hexdump(crbb_vec->data, (crbb_vec->cur_bit+7)/8));
/* Add compressed bitmap to final buffer */
return 1;
}

View File

@@ -0,0 +1,33 @@
/* egprs_rlc_compression.h
* Routines for EGPRS RLC bitmap compression handling
*/
#pragma once
struct egprs_compress_node;
#define MOD64(X) (((X) + 64) & 0x3F)
/* Singleton to manage the EGPRS compression algorithm. */
class egprs_compress
{
public:
static int decompress_crbb(int8_t compress_bmap_len,
bool start, const uint8_t *orig_buf,
bitvec *dest);
egprs_compress();
int osmo_t4_compress(struct bitvec *bv);
static int compress_rbb(struct bitvec *urbb_vec, struct bitvec *crbb_vec,
uint8_t *uclen_crbb, uint8_t max_bits);
private:
egprs_compress_node *ones_list;
egprs_compress_node *zeros_list;
void decode_tree_init(void);
static egprs_compress *s_instance;
static egprs_compress*instance();
egprs_compress_node *create_tree_node(void *);
void build_codewords(egprs_compress_node *root, const char *cdwd[]);
/* singleton class, so this private destructor is left unimplemented. */
~egprs_compress();
};

File diff suppressed because it is too large Load Diff

View File

@@ -21,12 +21,23 @@
#pragma once
#include <stdint.h>
#include <gsm_rlcmac.h>
struct gprs_rlcmac_bts;
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/gsm/l1sap.h>
#include "coding_scheme.h"
#include "gsm_rlcmac.h"
#ifdef __cplusplus
}
#endif
struct gprs_rlcmac_tbf;
struct bitvec;
struct gprs_llc;
struct gprs_rlc_data_block_info;
#ifdef __cplusplus
/**
* I help with encoding data into CSN1 messages.
* TODO: Nobody can remember a function signature like this. One should
@@ -36,31 +47,85 @@ struct bitvec;
class Encoding {
public:
static int write_immediate_assignment(
struct gprs_rlcmac_bts *bts,
bitvec * dest, uint8_t downlink, uint8_t ra,
uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling,
uint32_t fn, uint8_t single_block, uint8_t alpha, uint8_t gamma,
int8_t ta_idx);
const struct gprs_rlcmac_pdch *pdch,
struct gprs_rlcmac_tbf *tbf,
bitvec * dest, bool downlink, uint16_t ra,
uint32_t ref_fn, uint8_t ta,
uint8_t usf, bool polling,
uint32_t fn, uint8_t alpha, uint8_t gamma,
int8_t ta_idx,
enum ph_burst_type burst_type);
static void write_packet_uplink_assignment(
struct gprs_rlcmac_bts *bts,
bitvec * dest, uint8_t old_tfi,
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
struct gprs_rlcmac_tbf *tbf, uint8_t poll, uint8_t alpha,
uint8_t gamma, int8_t ta_idx);
static int write_immediate_assignment_reject(
bitvec *dest, uint16_t ra,
uint32_t ref_fn,
enum ph_burst_type burst_type,
uint8_t t3142
);
static void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi,
uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll,
uint8_t alpha, uint8_t gamma, int8_t ta_idx, uint8_t ta_ts);
static void encode_rbb(const char *show_rbb, bitvec *rbb);
static void write_packet_uplink_ack(struct gprs_rlcmac_bts *bts, RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *tbf,
uint8_t final);
static int write_paging_request(bitvec * dest, uint8_t *ptmsi, uint16_t ptmsi_len);
static int write_paging_request(bitvec * dest, const struct osmo_mobile_identity *mi);
static unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len,
uint8_t *identity, uint8_t chan_needed);
static unsigned write_packet_paging_request(bitvec * dest);
static int rlc_write_dl_data_header(
const struct gprs_rlc_data_info *rlc,
uint8_t *data);
static unsigned int rlc_copy_from_aligned_buffer(
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,
uint8_t *dst, const uint8_t *buffer);
enum AppendResult {
AR_NEED_MORE_BLOCKS,
AR_COMPLETED_SPACE_LEFT,
AR_COMPLETED_BLOCK_FILLED,
};
static AppendResult rlc_data_to_dl_append(
struct gprs_rlc_data_block_info *rdbi, enum CodingScheme cs,
gprs_llc *llc, int *offset, int *num_chunks,
uint8_t *data, bool is_final, int *count_payload);
static void rlc_data_to_dl_append_egprs_li_padding(
const struct gprs_rlc_data_block_info *rdbi,
int *offset, int *num_chunks, uint8_t *data_block);
};
#endif /* ifdef __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif
void write_packet_access_reject(struct bitvec *dest, uint32_t tlli, unsigned long t3172_ms);
void write_packet_uplink_assignment(RlcMacDownlink_t *block, uint8_t old_tfi,
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
const struct gprs_rlcmac_ul_tbf *tbf, uint8_t poll,
uint8_t rrbp, uint8_t alpha, uint8_t gamma, int8_t ta_idx,
bool use_egprs);
void write_packet_downlink_assignment(RlcMacDownlink_t * block, bool old_tfi_is_valid,
uint8_t old_tfi, uint8_t old_downlink,
const struct gprs_rlcmac_dl_tbf *tbf, uint8_t poll,
uint8_t rrbp, uint8_t alpha, uint8_t gamma,
int8_t ta_idx, uint8_t ta_ts, bool use_egprs,
uint8_t control_ack);
void write_packet_uplink_ack(struct bitvec *dest, struct gprs_rlcmac_ul_tbf *tbf,
bool is_final, uint8_t rrbp);
void write_packet_neighbour_cell_data(RlcMacDownlink_t *block,
bool tfi_is_dl, uint8_t tfi, uint8_t container_id,
uint8_t container_idx, PNCDContainer_t *container);
void write_packet_cell_change_continue(RlcMacDownlink_t *block, uint8_t poll, uint8_t rrbp,
bool tfi_is_dl, uint8_t tfi, bool exist_id,
uint16_t arfcn, uint8_t bsic, uint8_t container_id);
#ifdef __cplusplus
}
#endif

View File

@@ -1,57 +0,0 @@
#ifndef FEMTOBTS_H
#define FEMTOBTS_H
#include <stdlib.h>
#include <osmocom/core/utils.h>
#include <sysmocom/femtobts/superfemto.h>
#include <sysmocom/femtobts/gsml1const.h>
#ifdef L1_HAS_RTP_MODE
/* This is temporarily disabled, as AMR has some bugs in RTP mode */
//#define USE_L1_RTP_MODE /* Tell L1 to use RTP mode */
#endif
enum l1prim_type {
L1P_T_REQ,
L1P_T_CONF,
L1P_T_IND,
};
const enum l1prim_type femtobts_l1prim_type[GsmL1_PrimId_NUM];
const struct value_string femtobts_l1prim_names[GsmL1_PrimId_NUM+1];
const GsmL1_PrimId_t femtobts_l1prim_req2conf[GsmL1_PrimId_NUM];
const enum l1prim_type femtobts_sysprim_type[SuperFemto_PrimId_NUM];
const struct value_string femtobts_sysprim_names[SuperFemto_PrimId_NUM+1];
const SuperFemto_PrimId_t femtobts_sysprim_req2conf[SuperFemto_PrimId_NUM];
const struct value_string femtobts_l1sapi_names[GsmL1_Sapi_NUM+1];
const struct value_string femtobts_l1status_names[GSML1_STATUS_NUM+1];
const struct value_string femtobts_tracef_names[29];
const struct value_string femtobts_tch_pl_names[15];
const struct value_string femtobts_dir_names[6];
enum pdch_cs {
PDCH_CS_1,
PDCH_CS_2,
PDCH_CS_3,
PDCH_CS_4,
PDCH_MCS_1,
PDCH_MCS_2,
PDCH_MCS_3,
PDCH_MCS_4,
PDCH_MCS_5,
PDCH_MCS_6,
PDCH_MCS_7,
PDCH_MCS_8,
PDCH_MCS_9,
_NUM_PDCH_CS
};
const uint8_t pdch_msu_size[_NUM_PDCH_CS];
#endif /* FEMTOBTS_H */

1362
src/gprs_bssgp_pcu.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,576 +0,0 @@
/* gprs_bssgp_pcu.cpp
*
* Copyright (C) 2012 Ivan Klyuchnikov
* Copyright (C) 2013 by Holger Hans Peter Freyther
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <gprs_rlcmac.h>
#include <gprs_bssgp_pcu.h>
#include <pcu_l1_if.h>
#include <bts.h>
#include <tbf.h>
static struct gprs_bssgp_pcu the_pcu = { 0, };
extern void *tall_pcu_ctx;
extern uint16_t spoof_mcc, spoof_mnc;
static void bvc_timeout(void *_priv);
static int parse_imsi(struct tlv_parsed *tp, char *imsi)
{
uint8_t imsi_len;
uint8_t *bcd_imsi;
int i, j;
if (!TLVP_PRESENT(tp, BSSGP_IE_IMSI))
return -EINVAL;
imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
bcd_imsi = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_IMSI);
if ((bcd_imsi[0] & 0x08))
imsi_len = imsi_len * 2 - 1;
else
imsi_len = (imsi_len - 1) * 2;
for (i = 0, j = 0; j < imsi_len && j < 15; j++)
{
if (!(j & 1)) {
imsi[j] = (bcd_imsi[i] >> 4) + '0';
i++;
} else
imsi[j] = (bcd_imsi[i] & 0xf) + '0';
}
imsi[j] = '\0';
return 0;
}
static int parse_ra_cap_ms_class(struct tlv_parsed *tp)
{
bitvec *block;
unsigned rp = 0;
uint8_t ms_class = 0;
uint8_t cap_len;
uint8_t *cap;
if (!TLVP_PRESENT(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP))
return ms_class;
cap_len = TLVP_LEN(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP);
cap = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_MS_RADIO_ACCESS_CAP);
block = bitvec_alloc(cap_len);
bitvec_unpack(block, cap);
bitvec_read_field(block, rp, 4); // Access Technology Type
bitvec_read_field(block, rp, 7); // Length of Access Capabilities
bitvec_read_field(block, rp, 3); // RF Power Capability
if (bitvec_read_field(block, rp, 1)) // A5 Bits Present
bitvec_read_field(block, rp, 7); // A5 Bits
bitvec_read_field(block, rp, 1); // ES IND
bitvec_read_field(block, rp, 1); // PS
bitvec_read_field(block, rp, 1); // VGCS
bitvec_read_field(block, rp, 1); // VBS
if (bitvec_read_field(block, rp, 1)) { // Multislot Cap Present
if (bitvec_read_field(block, rp, 1)) // HSCSD Present
bitvec_read_field(block, rp, 5); // Class
if (bitvec_read_field(block, rp, 1)) { // GPRS Present
ms_class = bitvec_read_field(block, rp, 5); // Class
bitvec_read_field(block, rp, 1); // Ext.
}
if (bitvec_read_field(block, rp, 1)) // SMS Present
bitvec_read_field(block, rp, 4); // SMS Value
}
bitvec_free(block);
return ms_class;
}
static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
{
struct bssgp_ud_hdr *budh;
uint32_t tlli;
uint8_t *data;
uint16_t len;
char imsi[16] = "000";
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg);
tlli = ntohl(budh->tlli);
/* LLC_PDU is mandatory IE */
if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU))
{
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tlli);
return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
}
data = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
if (len > sizeof(gprs_llc::frame))
{
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP TLLI=0x%08x Rx UL-UD IE_LLC_PDU too large\n", tlli);
return bssgp_tx_status(BSSGP_CAUSE_COND_IE_ERR, NULL, msg);
}
/* read IMSI. if no IMSI exists, use first paging block (any paging),
* because during attachment the IMSI might not be known, so the MS
* will listen to all paging blocks. */
parse_imsi(tp, imsi);
/* parse ms radio access capability */
uint8_t ms_class = parse_ra_cap_ms_class(tp);
/* get lifetime */
uint16_t delay_csec = 0xffff;
if (TLVP_PRESENT(tp, BSSGP_IE_PDU_LIFETIME))
{
uint8_t lt_len = TLVP_LEN(tp, BSSGP_IE_PDU_LIFETIME);
uint16_t *lt = (uint16_t *) TLVP_VAL(tp, BSSGP_IE_PDU_LIFETIME);
if (lt_len == 2)
delay_csec = ntohs(*lt);
else
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP invalid length of "
"PDU_LIFETIME IE\n");
} else
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP missing mandatory "
"PDU_LIFETIME IE\n");
LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, imsi, len);
return gprs_rlcmac_tbf::handle(the_pcu.bts, tlli, imsi, ms_class, delay_csec, data, len);
}
int gprs_bssgp_pcu_rx_paging_ps(struct msgb *msg, struct tlv_parsed *tp)
{
char imsi[16];
uint8_t *ptmsi = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_TMSI);
uint16_t ptmsi_len = TLVP_LEN(tp, BSSGP_IE_TMSI);
LOGP(DBSSGP, LOGL_NOTICE, " P-TMSI = ");
for (int i = 0; i < ptmsi_len; i++)
{
LOGPC(DBSSGP, LOGL_NOTICE, "%02x", ptmsi[i]);
}
LOGPC(DBSSGP, LOGL_NOTICE, "\n");
if (parse_imsi(tp, imsi))
{
LOGP(DBSSGP, LOGL_ERROR, "No IMSI\n");
return -EINVAL;
}
return gprs_rlcmac_paging_request(ptmsi, ptmsi_len, imsi);
}
/* Receive a BSSGP PDU from a BSS on a PTP BVCI */
static int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx)
{
struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
uint8_t pdu_type = bgph->pdu_type;
unsigned rc = 0;
if (!bctx)
return -EINVAL;
/* If traffic is received on a BVC that is marked as blocked, the
* received PDU shall not be accepted and a STATUS PDU (Cause value:
* BVC Blocked) shall be sent to the peer entity on the signalling BVC */
if (bctx->state & BVC_S_BLOCKED && pdu_type != BSSGP_PDUT_STATUS)
{
uint16_t bvci = msgb_bvci(msg);
LOGP(DBSSGP, LOGL_NOTICE, "rx BVC_S_BLOCKED\n");
return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &bvci, msg);
}
switch (pdu_type) {
case BSSGP_PDUT_DL_UNITDATA:
LOGP(DBSSGP, LOGL_DEBUG, "RX: [SGSN->PCU] BSSGP_PDUT_DL_UNITDATA\n");
if (the_pcu.on_dl_unit_data)
the_pcu.on_dl_unit_data(&the_pcu, msg, tp);
gprs_bssgp_pcu_rx_dl_ud(msg, tp);
break;
case BSSGP_PDUT_PAGING_PS:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_PS\n");
break;
case BSSGP_PDUT_PAGING_CS:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_CS\n");
break;
case BSSGP_PDUT_RA_CAPA_UPDATE_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RA_CAPA_UPDATE_ACK\n");
break;
case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_FLOW_CONTROL_BVC_ACK\n");
break;
case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_FLOW_CONTROL_MS_ACK\n");
break;
default:
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u PDU type 0x%02x unknown\n", bctx->bvci, pdu_type);
rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
break;
}
return rc;
}
/* Receive a BSSGP PDU from a SGSN on a SIGNALLING BVCI */
static int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx)
{
struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
int rc = 0;
switch (bgph->pdu_type) {
case BSSGP_PDUT_STATUS:
/* Some exception has occurred */
DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC STATUS\n", bctx->bvci);
/* FIXME: send NM_STATUS.ind to NM */
break;
case BSSGP_PDUT_SUSPEND_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_ACK\n");
break;
case BSSGP_PDUT_SUSPEND_NACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_NACK\n");
break;
case BSSGP_PDUT_BVC_RESET_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_RESET_ACK\n");
if (!the_pcu.bvc_sig_reset)
the_pcu.bvc_sig_reset = 1;
else
the_pcu.bvc_reset = 1;
bvc_timeout(NULL);
break;
case BSSGP_PDUT_PAGING_PS:
LOGP(DBSSGP, LOGL_NOTICE, "RX: [SGSN->PCU] BSSGP_PDUT_PAGING_PS\n");
gprs_bssgp_pcu_rx_paging_ps(msg, tp);
break;
case BSSGP_PDUT_PAGING_CS:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_CS\n");
break;
case BSSGP_PDUT_RESUME_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RESUME_ACK\n");
break;
case BSSGP_PDUT_RESUME_NACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RESUME_NACK\n");
break;
case BSSGP_PDUT_FLUSH_LL:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_FLUSH_LL\n");
break;
case BSSGP_PDUT_BVC_BLOCK_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_ACK\n");
break;
case BSSGP_PDUT_BVC_UNBLOCK_ACK:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n");
the_pcu.bvc_unblocked = 1;
if (the_pcu.on_unblock_ack)
the_pcu.on_unblock_ack(&the_pcu);
bvc_timeout(NULL);
break;
case BSSGP_PDUT_SGSN_INVOKE_TRACE:
LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SGSN_INVOKE_TRACE\n");
break;
default:
LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n", bctx->bvci, bgph->pdu_type);
rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
break;
}
return rc;
}
static int gprs_bssgp_pcu_rcvmsg(struct msgb *msg)
{
struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
struct tlv_parsed tp;
uint8_t pdu_type = bgph->pdu_type;
uint16_t ns_bvci = msgb_bvci(msg);
int data_len;
int rc = 0;
struct bssgp_bvc_ctx *bctx;
if (pdu_type == BSSGP_PDUT_STATUS) {
LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u received STATUS\n",
msgb_nsei(msg), ns_bvci);
return 0;
}
/* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */
/* UNITDATA BSSGP headers have TLLI in front */
if (pdu_type != BSSGP_PDUT_UL_UNITDATA && pdu_type != BSSGP_PDUT_DL_UNITDATA)
{
data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
}
else
{
data_len = msgb_bssgp_len(msg) - sizeof(*budh);
rc = bssgp_tlv_parse(&tp, budh->data, data_len);
}
/* look-up or create the BTS context for this BVC */
bctx = btsctx_by_bvci_nsei(ns_bvci, msgb_nsei(msg));
if (!bctx
&& pdu_type != BSSGP_PDUT_BVC_RESET_ACK
&& pdu_type != BSSGP_PDUT_BVC_UNBLOCK_ACK
&& pdu_type != BSSGP_PDUT_PAGING_PS)
{
LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU "
"type %u for unknown BVCI\n", msgb_nsei(msg), ns_bvci,
pdu_type);
return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg);
}
if (bctx)
{
log_set_context(BSC_CTX_BVC, bctx);
rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_IN]);
rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_IN], msgb_bssgp_len(msg));
}
if (ns_bvci == BVCI_SIGNALLING)
{
LOGP(DBSSGP, LOGL_DEBUG, "rx BVCI_SIGNALLING gprs_bssgp_rx_sign\n");
rc = gprs_bssgp_pcu_rx_sign(msg, &tp, bctx);
}
else if (ns_bvci == BVCI_PTM)
{
LOGP(DBSSGP, LOGL_DEBUG, "rx BVCI_PTM bssgp_tx_status\n");
rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg);
}
else
{
LOGP(DBSSGP, LOGL_DEBUG, "rx BVCI_PTP gprs_bssgp_rx_ptp\n");
rc = gprs_bssgp_pcu_rx_ptp(msg, &tp, bctx);
}
return rc;
}
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
return 0;
}
static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, struct msgb *msg, uint16_t bvci)
{
int rc = 0;
switch (event) {
case GPRS_NS_EVT_UNIT_DATA:
/* hand the message into the BSSGP implementation */
rc = gprs_bssgp_pcu_rcvmsg(msg);
break;
default:
LOGP(DPCU, LOGL_NOTICE, "RLCMAC: Unknown event %u from NS\n", event);
rc = -EIO;
break;
}
return rc;
}
static int nsvc_signal_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct ns_signal_data *nssd;
if (subsys != SS_L_NS)
return -EINVAL;
nssd = (struct ns_signal_data *)signal_data;
if (nssd->nsvc != the_pcu.nsvc) {
LOGP(DPCU, LOGL_ERROR, "Signal received of unknown NSVC\n");
return -EINVAL;
}
switch (signal) {
case S_NS_UNBLOCK:
if (!the_pcu.nsvc_unblocked) {
the_pcu.nsvc_unblocked = 1;
LOGP(DPCU, LOGL_NOTICE, "NS-VC %d is unblocked.\n",
the_pcu.nsvc->nsvci);
the_pcu.bvc_sig_reset = 0;
the_pcu.bvc_reset = 0;
the_pcu.bvc_unblocked = 0;
bvc_timeout(NULL);
}
break;
case S_NS_BLOCK:
if (the_pcu.nsvc_unblocked) {
the_pcu.nsvc_unblocked = 0;
osmo_timer_del(&the_pcu.bvc_timer);
the_pcu.bvc_sig_reset = 0;
the_pcu.bvc_reset = 0;
the_pcu.bvc_unblocked = 0;
LOGP(DPCU, LOGL_NOTICE, "NS-VC is blocked.\n");
}
break;
}
return 0;
}
int gprs_bssgp_tx_fc_bvc(void)
{
if (!the_pcu.bctx) {
LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
return -EIO;
}
/* FIXME: use real values */
return bssgp_tx_fc_bvc(the_pcu.bctx, 1, 6553500, 819100, 50000, 50000,
NULL, NULL);
}
static void bvc_timeout(void *_priv)
{
if (!the_pcu.bvc_sig_reset) {
LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI 0\n");
bssgp_tx_bvc_reset(the_pcu.bctx, 0, BSSGP_CAUSE_OML_INTERV);
osmo_timer_schedule(&the_pcu.bvc_timer, 1, 0);
return;
}
if (!the_pcu.bvc_reset) {
LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI %d\n",
the_pcu.bctx->bvci);
bssgp_tx_bvc_reset(the_pcu.bctx, the_pcu.bctx->bvci, BSSGP_CAUSE_OML_INTERV);
osmo_timer_schedule(&the_pcu.bvc_timer, 1, 0);
return;
}
if (!the_pcu.bvc_unblocked) {
LOGP(DBSSGP, LOGL_INFO, "Sending unblock on BVCI %d\n",
the_pcu.bctx->bvci);
bssgp_tx_bvc_unblock(the_pcu.bctx);
osmo_timer_schedule(&the_pcu.bvc_timer, 1, 0);
return;
}
LOGP(DBSSGP, LOGL_DEBUG, "Sending flow control info on BVCI %d\n",
the_pcu.bctx->bvci);
gprs_bssgp_tx_fc_bvc();
osmo_timer_schedule(&the_pcu.bvc_timer, the_pcu.bts->fc_interval, 0);
}
/* create BSSGP/NS layer instances */
struct gprs_bssgp_pcu *gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts,
uint16_t local_port, uint32_t sgsn_ip,
uint16_t sgsn_port, uint16_t nsei, uint16_t nsvci, uint16_t bvci,
uint16_t mcc, uint16_t mnc, uint16_t lac, uint16_t rac,
uint16_t cell_id)
{
struct sockaddr_in dest;
int rc;
mcc = ((mcc & 0xf00) >> 8) * 100 + ((mcc & 0x0f0) >> 4) * 10 + (mcc & 0x00f);
mnc = ((mnc & 0xf00) >> 8) * 100 + ((mnc & 0x0f0) >> 4) * 10 + (mnc & 0x00f);
cell_id = ntohs(cell_id);
/* if already created... return the current address */
if (the_pcu.bctx)
return &the_pcu;
the_pcu.bts = bts;
bssgp_nsi = gprs_ns_instantiate(&sgsn_ns_cb, tall_pcu_ctx);
if (!bssgp_nsi) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create NS instance\n");
return NULL;
}
gprs_ns_vty_init(bssgp_nsi);
bssgp_nsi->nsip.local_port = local_port;
rc = gprs_ns_nsip_listen(bssgp_nsi);
if (rc < 0) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create socket\n");
gprs_ns_destroy(bssgp_nsi);
bssgp_nsi = NULL;
return NULL;
}
dest.sin_family = AF_INET;
dest.sin_port = htons(sgsn_port);
dest.sin_addr.s_addr = htonl(sgsn_ip);
the_pcu.nsvc = gprs_ns_nsip_connect(bssgp_nsi, &dest, nsei, nsvci);
if (!the_pcu.nsvc) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create NSVCt\n");
gprs_ns_destroy(bssgp_nsi);
bssgp_nsi = NULL;
return NULL;
}
the_pcu.bctx = btsctx_alloc(bvci, nsei);
if (!the_pcu.bctx) {
LOGP(DBSSGP, LOGL_ERROR, "Failed to create BSSGP context\n");
the_pcu.nsvc = NULL;
gprs_ns_destroy(bssgp_nsi);
bssgp_nsi = NULL;
return NULL;
}
the_pcu.bctx->ra_id.mcc = spoof_mcc ? : mcc;
the_pcu.bctx->ra_id.mnc = spoof_mnc ? : mnc;
the_pcu.bctx->ra_id.lac = lac;
the_pcu.bctx->ra_id.rac = rac;
the_pcu.bctx->cell_id = cell_id;
osmo_signal_register_handler(SS_L_NS, nsvc_signal_cb, NULL);
the_pcu.bvc_timer.cb = bvc_timeout;
return &the_pcu;
}
void gprs_bssgp_destroy_or_exit(void)
{
if (the_pcu.exit_on_destroy) {
LOGP(DBSSGP, LOGL_NOTICE, "Exiting on BSSGP destruction.\n");
exit(0);
}
if (!bssgp_nsi)
return;
osmo_timer_del(&the_pcu.bvc_timer);
osmo_signal_unregister_handler(SS_L_NS, nsvc_signal_cb, NULL);
the_pcu.nsvc = NULL;
/* FIXME: move this to libgb: btsctx_free() */
llist_del(&the_pcu.bctx->list);
talloc_free(the_pcu.bctx);
the_pcu.bctx = NULL;
/* FIXME: blocking... */
the_pcu.nsvc_unblocked = 0;
the_pcu.bvc_sig_reset = 0;
the_pcu.bvc_reset = 0;
the_pcu.bvc_unblocked = 0;
gprs_ns_destroy(bssgp_nsi);
bssgp_nsi = NULL;
}
void gprs_bssgp_exit_on_destroy(void)
{
LOGP(DBSSGP, LOGL_NOTICE, "Going to quit on BSSGP destruction\n");
the_pcu.exit_on_destroy = 1;
}
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void)
{
return the_pcu.bctx;
}

View File

@@ -21,43 +21,62 @@
#ifndef GPRS_BSSGP_PCU_H
#define GPRS_BSSGP_PCU_H
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/talloc.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/signal.h>
#include <osmocom/core/application.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_bssgp_bss.h>
#include <osmocom/gprs/gprs_msgb.h>
struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei);
}
#include <gprs_debug.h>
#include <time.h>
#include <unistd.h>
#define QOS_PROFILE 4
#define BSSGP_HDR_LEN 53
#define NS_HDR_LEN 4
#define IE_LLC_PDU 14
struct gprs_rlcmac_bts;
enum sgsn_counter_id {
SGSN_CTR_RX_PAGING_CS,
SGSN_CTR_RX_PAGING_PS,
};
struct gprs_bssgp_pcu {
struct gprs_nsvc *nsvc;
struct bssgp_bvc_ctx *bctx;
struct gprs_rlcmac_bts *bts;
struct osmo_timer_list bvc_timer;
struct rate_ctr_group *ctrs;
/* state: is the NSVC unblocked? */
int nsvc_unblocked;
/* state: true if bvc signalling needs to be reseted or waiting for reset ack */
int bvc_sig_reset;
/* state: true if bvc ptp needs to be reseted or waiting for reset ack */
int bvc_reset;
/* state: true if bvc ptp is unblocked */
int bvc_unblocked;
int exit_on_destroy;
/* Flow control */
struct timespec queue_delay_sum;
unsigned queue_delay_count;
uint8_t fc_tag;
unsigned queue_frames_sent;
unsigned queue_bytes_recv;
unsigned queue_frames_recv;
/** callbacks below */
@@ -69,15 +88,28 @@ struct gprs_bssgp_pcu {
struct tlv_parsed *tp);
};
struct gprs_bssgp_pcu *gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts,
uint16_t local_port,
uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei,
uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc,
int gprs_gp_send_cb(void *ctx, struct msgb *msg);
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
void gprs_bssgp_update_queue_delay(const struct timespec *tv_recv,
const struct timespec *tv_now);
void gprs_bssgp_update_frames_sent();
void gprs_bssgp_update_bytes_received(unsigned bytes_recv, unsigned frames_recv);
struct gprs_bssgp_pcu *gprs_bssgp_init(
struct gprs_rlcmac_bts *bts,
uint16_t nsei, uint16_t bvci,
uint16_t mcc, uint16_t mnc, bool mnc_3_digits,
uint16_t lac, uint16_t rac, uint16_t cell_id);
void gprs_bssgp_exit_on_destroy(void);
void gprs_bssgp_destroy_or_exit(void);
int gprs_ns_update_config(struct gprs_rlcmac_bts *bts, uint16_t nsei,
const struct osmo_sockaddr *local,
const struct osmo_sockaddr *remote,
uint16_t *nsvci, uint16_t valid);
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void);
void gprs_bssgp_destroy(struct gprs_rlcmac_bts *bts);
#ifdef __cplusplus
}
#endif
#endif // GPRS_BSSGP_PCU_H

289
src/gprs_bssgp_rim.c Normal file
View File

@@ -0,0 +1,289 @@
/* gprs_bssgp_pcu.cpp
*
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_bssgp_rim.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/core/prim.h>
#include <pcu_l1_if.h>
#include <gprs_rlcmac.h>
#include <bts.h>
#include "gprs_debug.h"
#include "gprs_pcu.h"
#include "bts.h"
#include "gprs_ms.h"
#include "nacc_fsm.h"
#define LOGPRIM(nsei, level, fmt, args...) \
LOGP(DRIM, level, "(NSEI=%u) " fmt, nsei, ## args)
static inline void gprs_ra_id_ci_to_cgi_ps(struct osmo_cell_global_id_ps *cgi_ps,
const struct gprs_ra_id *raid, uint16_t cid)
{
*cgi_ps = (struct osmo_cell_global_id_ps) {
.rai.lac.plmn.mcc = raid->mcc,
.rai.lac.plmn.mnc = raid->mnc,
.rai.lac.plmn.mnc_3_digits = raid->mnc_3_digits,
.rai.lac.lac = raid->lac,
.rai.rac = raid->rac,
.cell_identity = cid,
};
}
/* Mirror RIM routing information of a given PDU, see also 3GPP TS 48.018, section 8c.1.4.3 */
static void mirror_rim_routing_info(struct bssgp_ran_information_pdu *to_pdu,
const struct bssgp_ran_information_pdu *from_pdu)
{
memcpy(&to_pdu->routing_info_dest, &from_pdu->routing_info_src, sizeof(to_pdu->routing_info_dest));
memcpy(&to_pdu->routing_info_src, &from_pdu->routing_info_dest, sizeof(to_pdu->routing_info_src));
}
/* Fill NACC application container with data (cell identifier, sysinfo) */
#define SI_HDR_LEN 2
static void fill_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *app_cont, const struct gprs_rlcmac_bts *bts)
{
struct bssgp_bvc_ctx *bctx = the_pcu->bssgp.bctx;
gprs_ra_id_ci_to_cgi_ps(&app_cont->reprt_cell, &bctx->ra_id, bctx->cell_id);
app_cont->num_si = 0;
/* Note: The BTS struct stores the system information including its pseudo header. The RIM application
* container defines the system information without pseudo header, so we need to chop it off. */
if (bts->si1_is_set) {
app_cont->si[app_cont->num_si] = bts->si1 + SI_HDR_LEN;
app_cont->num_si++;
}
if (bts->si3_is_set) {
app_cont->si[app_cont->num_si] = bts->si3 + SI_HDR_LEN;
app_cont->num_si++;
}
if (bts->si13_is_set) {
app_cont->si[app_cont->num_si] = bts->si13 + SI_HDR_LEN;
app_cont->num_si++;
}
/* Note: It is possible that the resulting PDU will not contain any system information, even if this is
* an unlikely case since the BTS immediately updates the system information after startup. The
* specification permits to send zero system information, see also: 3GPP TS 48.018 section 11.3.63.2.1 */
if (!bts->si1_is_set || !bts->si3_is_set || !bts->si13_is_set)
LOGP(DNACC, LOGL_INFO, "TX RAN INFO RESPONSE (NACC) %s: Some SI are missing:%s%s%s\n",
osmo_cgi_ps_name(&app_cont->reprt_cell),
bts->si1_is_set ? "" : " SI1",
bts->si3_is_set ? "" : " SI3",
bts->si13_is_set ? "" : " SI13");
}
/* Format a RAN INFORMATION PDU that contains the requested system information */
static void format_response_pdu(struct bssgp_ran_information_pdu *resp_pdu,
const struct bssgp_ran_information_pdu *req_pdu,
const struct gprs_rlcmac_bts *bts)
{
memset(resp_pdu, 0, sizeof(*resp_pdu));
mirror_rim_routing_info(resp_pdu, req_pdu);
resp_pdu->decoded.rim_cont = (struct bssgp_ran_inf_rim_cont) {
.app_id = BSSGP_RAN_INF_APP_ID_NACC,
.seq_num = 1, /* single report has only one message in response */
.pdu_ind = {
.pdu_type_ext = RIM_PDU_TYPE_SING_REP,
},
.prot_ver = 1,
};
fill_app_cont_nacc(&resp_pdu->decoded.rim_cont.u.app_cont_nacc, bts);
resp_pdu->decoded_present = true;
resp_pdu->rim_cont_iei = BSSGP_IE_RI_RIM_CONTAINER;
}
/* Format a RAN INFORMATION ERROR PDU */
static void format_response_pdu_err(struct bssgp_ran_information_pdu *resp_pdu,
const struct bssgp_ran_information_pdu *req_pdu)
{
memset(resp_pdu, 0, sizeof(*resp_pdu));
mirror_rim_routing_info(resp_pdu, req_pdu);
resp_pdu->decoded.err_rim_cont = (struct bssgp_ran_inf_err_rim_cont) {
.app_id = BSSGP_RAN_INF_APP_ID_NACC,
.prot_ver = 1,
.err_pdu = req_pdu->rim_cont,
.err_pdu_len = req_pdu->rim_cont_len,
};
resp_pdu->decoded_present = true;
resp_pdu->rim_cont_iei = BSSGP_IE_RI_ERROR_RIM_COINTAINER;
}
static int handle_ran_info_response_nacc(const struct bssgp_ran_inf_app_cont_nacc *nacc, struct gprs_rlcmac_bts *bts)
{
struct si_cache_value val;
struct si_cache_entry *entry;
struct llist_head *tmp;
int i;
LOGP(DRIM, LOGL_INFO, "Rx RAN-INFO cell=%s type=%sBCCH num_si=%d\n",
osmo_cgi_ps_name(&nacc->reprt_cell),
nacc->type_psi ? "P" : "", nacc->num_si);
val.type_psi = nacc->type_psi;
val.si_len = 0;
for (i = 0; i < nacc->num_si; i++) {
size_t len = val.type_psi ? BSSGP_RIM_PSI_LEN : BSSGP_RIM_SI_LEN;
memcpy(&val.si_buf[val.si_len], nacc->si[i], len);
val.si_len += len;
}
entry = si_cache_add(bts->pcu->si_cache, &nacc->reprt_cell, &val);
llist_for_each(tmp, bts_ms_list(bts)) {
struct GprsMs *ms = llist_entry(tmp, typeof(*ms), list);
if (ms->nacc && nacc_fsm_is_waiting_si_resolution(ms->nacc, &nacc->reprt_cell))
osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_RX_SI, entry);
}
return 0;
}
static int handle_ran_info_request(const struct bssgp_ran_information_pdu *pdu,
struct gprs_rlcmac_bts *bts, uint16_t nsei)
{
const struct bssgp_ran_inf_req_rim_cont *ri_req = &pdu->decoded.req_rim_cont;
const struct bssgp_ran_inf_req_app_cont_nacc *nacc_req;
struct bssgp_ran_information_pdu resp_pdu;
int rc;
/* Check if we support the application ID */
if (ri_req->app_id != BSSGP_RAN_INF_APP_ID_NACC) {
LOGPRIM(nsei, LOGL_ERROR,
"Rx RAN-INFO-REQ for cell %s with unknown/wrong application ID %s -- reject.\n",
osmo_cgi_ps_name(&bts->cgi_ps), bssgp_ran_inf_app_id_str(ri_req->app_id));
format_response_pdu_err(&resp_pdu, pdu);
rc = -ENOTSUP;
goto tx_ret;
}
nacc_req = &ri_req->u.app_cont_nacc;
rc = osmo_cgi_ps_cmp(&bts->cgi_ps, &nacc_req->reprt_cell);
if (rc != 0) {
LOGPRIM(nsei, LOGL_ERROR, "reporting cell in RIM application container %s "
"does not match destination cell in RIM routing info %s -- rejected.\n",
osmo_cgi_ps_name(&nacc_req->reprt_cell),
osmo_cgi_ps_name2(&bts->cgi_ps));
format_response_pdu_err(&resp_pdu, pdu);
} else {
LOGPRIM(nsei, LOGL_INFO, "Responding to RAN INFORMATION REQUEST %s ...\n",
osmo_cgi_ps_name(&nacc_req->reprt_cell));
format_response_pdu(&resp_pdu, pdu, bts);
}
tx_ret:
bssgp_tx_rim(&resp_pdu, nsei);
return rc;
}
static int handle_ran_info_response(const struct bssgp_ran_information_pdu *pdu, struct gprs_rlcmac_bts *bts)
{
const struct bssgp_ran_inf_rim_cont *ran_info = &pdu->decoded.rim_cont;
char ri_src_str[64];
/* Check if we support the application ID */
if (ran_info->app_id != BSSGP_RAN_INF_APP_ID_NACC) {
LOGP(DRIM, LOGL_ERROR,
"Rx RAN-INFO for cell %s with unknown/wrong application ID %s received -- reject.\n",
osmo_cgi_ps_name(&bts->cgi_ps), bssgp_ran_inf_app_id_str(ran_info->app_id));
return -1;
}
if (ran_info->app_err) {
LOGP(DRIM, LOGL_ERROR,
"%s Rx RAN-INFO with an app error! cause: %s\n",
bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &pdu->routing_info_src),
bssgp_nacc_cause_str(ran_info->u.app_err_cont_nacc.nacc_cause));
return -1;
}
handle_ran_info_response_nacc(&ran_info->u.app_cont_nacc, bts);
return 0;
}
int handle_rim(struct osmo_bssgp_prim *bp)
{
struct msgb *msg = bp->oph.msg;
uint16_t nsei = msgb_nsei(msg);
struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
struct bssgp_ran_information_pdu resp_pdu;
struct osmo_cell_global_id_ps dst_addr;
struct gprs_rlcmac_bts *bts;
OSMO_ASSERT (bp->oph.sap == SAP_BSSGP_RIM);
/* At the moment we only support GERAN, so we block all other network
* types here. */
if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGPRIM(nsei, LOGL_ERROR,
"Only GERAN supported, destination cell is not a GERAN cell -- rejected.\n");
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
}
/* Check if the RIM pdu is really addressed to this PCU. In case we
* receive a RIM PDU for a cell that is not parented by this PCU we
* are supposed to reject it with a BSSGP STATUS.
* see also: 3GPP TS 48.018, section 8c.3.1.2 */
gprs_ra_id_ci_to_cgi_ps(&dst_addr, &pdu->routing_info_dest.geran.raid,
pdu->routing_info_dest.geran.cid);
bts = gprs_pcu_get_bts_by_cgi_ps(the_pcu, &dst_addr);
if (!bts) {
LOGPRIM(nsei, LOGL_ERROR, "Destination cell %s unknown to this pcu\n",
osmo_cgi_ps_name(&dst_addr));
return bssgp_tx_status(BSSGP_CAUSE_UNKN_DST, NULL, msg);
}
/* Check if the incoming RIM PDU is parseable, if not we must report
* an error to the controlling BSS 3GPP TS 48.018, 8c.3.4 and 8c.3.4.2 */
if (!pdu->decoded_present) {
LOGPRIM(nsei, LOGL_ERROR, "Erroneous RIM PDU received for cell %s -- reject.\n",
osmo_cgi_ps_name(&dst_addr));
format_response_pdu_err(&resp_pdu, pdu);
return 0;
}
/* Handle incoming RIM container */
switch (pdu->rim_cont_iei) {
case BSSGP_IE_RI_REQ_RIM_CONTAINER:
return handle_ran_info_request(pdu, bts, nsei);
case BSSGP_IE_RI_RIM_CONTAINER:
return handle_ran_info_response(pdu, bts);
case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
case BSSGP_IE_RI_ACK_RIM_CONTAINER:
case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
LOGPRIM(nsei, LOGL_ERROR, "RIM PDU not handled by this application\n");
return -EINVAL;
default:
/* This should never happen. If the RIM PDU is parsed correctly, then the rim_cont_iei will
* be set to one of the cases above and if parsing fails this switch statement is guarded
* by the check on decoded_present above */
OSMO_ASSERT(false);
}
return 0;
}

View File

@@ -1,7 +1,6 @@
/*
* Copyright (C) 2012 Ivan Klyuchnikov
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2013 by Holger Hans Peter Freyther
/* gprs_bssgp_rim.h
*
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -17,24 +16,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
extern "C" {
#include <osmocom/core/linuxlist.h>
}
struct osmo_bssgp_prim;
#include <stdint.h>
class TimingAdvance {
public:
TimingAdvance();
int update(uint32_t old_tlli, uint32_t new_tlli, uint8_t ta);
int remember(uint32_t tlli, uint8_t ta);
int recall(uint32_t tlli);
int flush();
private:
size_t m_ta_len;
llist_head m_ta_list;
};
int handle_rim(struct osmo_bssgp_prim *bp);

180
src/gprs_codel.c Normal file
View File

@@ -0,0 +1,180 @@
/* gprs_codel.cpp
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gprs_codel.h"
#include "gprs_debug.h"
#include <osmocom/core/utils.h>
#include <osmocom/core/timer_compat.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
static void control_law(struct gprs_codel *state, struct timespec *delta)
{
/* 256 / sqrt(x), limited to 255 */
static uint8_t inv_sqrt_tab[] = {255,
255, 181, 147, 128, 114, 104, 96, 90, 85, 80, 77, 73, 71, 68,
66, 64, 62, 60, 58, 57, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
45, 45, 44, 43, 43, 42, 42, 41, 40, 40, 39, 39, 39, 38, 38, 37,
37, 36, 36, 36, 35, 35, 35, 34, 34, 34, 33, 33, 33, 33, 32, 32,
32, 32, 31, 31, 31, 31, 30, 30, 30, 30, 29, 29, 29, 29, 29, 28,
28, 28, 28, 28, 28, 27, 27, 27, 27, 27, 27, 26, 26, 26, 26, 26,
26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 24, 24, 24, 24, 24, 24,
24, 24, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17
};
uint_fast32_t delta_usecs;
uint_fast32_t inv_sqrt;
div_t q;
if (state->count >= ARRAY_SIZE(inv_sqrt_tab))
inv_sqrt = 16;
else
inv_sqrt = inv_sqrt_tab[state->count];
/* delta = state->interval / sqrt(count) */
delta_usecs = state->interval.tv_sec * 1000000 + state->interval.tv_nsec/1000;
delta_usecs = delta_usecs * inv_sqrt / 256;
q = div(delta_usecs, 1000000);
delta->tv_sec = q.quot;
delta->tv_nsec = q.rem * 1000;
}
void gprs_codel_init(struct gprs_codel *state)
{
static const struct gprs_codel init_state = {0};
*state = init_state;
gprs_codel_set_interval(state, -1);
gprs_codel_set_maxpacket(state, -1);
}
void gprs_codel_set_interval(struct gprs_codel *state, int interval_ms)
{
div_t q;
if (interval_ms <= 0)
interval_ms = GPRS_CODEL_DEFAULT_INTERVAL_MS;
q = div(interval_ms, 1000);
state->interval.tv_sec = q.quot;
state->interval.tv_nsec = q.rem * 1000000;
/* target ~ 5% of interval */
q = div(interval_ms * 13 / 256, 1000);
state->target.tv_sec = q.quot;
state->target.tv_nsec = q.rem * 1000000;
}
void gprs_codel_set_maxpacket(struct gprs_codel *state, int maxpacket)
{
if (maxpacket < 0)
maxpacket = GPRS_CODEL_DEFAULT_MAXPACKET;
state->maxpacket = maxpacket;
}
/*
* This is an broken up variant of the algorithm being described in
* http://queue.acm.org/appendices/codel.html
*/
int gprs_codel_control(struct gprs_codel *state, const struct timespec *recv,
const struct timespec *now, int bytes)
{
struct timespec sojourn_time;
struct timespec delta;
if (recv == NULL)
goto stop_dropping;
timespecsub(now, recv, &sojourn_time);
if (timespeccmp(&sojourn_time, &state->target, <))
goto stop_dropping;
if (bytes >= 0 && (unsigned)bytes <= state->maxpacket)
goto stop_dropping;
if (!timespecisset(&state->first_above_time)) {
timespecadd(now, &state->interval, &state->first_above_time);
goto not_ok_to_drop;
}
if (timespeccmp(now, &state->first_above_time, <))
goto not_ok_to_drop;
/* Ok to drop */
if (!state->dropping) {
int recently = 0;
int in_drop_cycle = 0;
if (timespecisset(&state->drop_next)) {
timespecsub(now, &state->drop_next, &delta);
in_drop_cycle = timespeccmp(&delta, &state->interval, <);
recently = in_drop_cycle;
}
if (!recently) {
timespecsub(now, &state->first_above_time, &delta);
recently = !timespeccmp(&delta, &state->interval, <);
};
if (!recently)
return 0;
state->dropping = 1;
if (in_drop_cycle && state->count > 2)
state->count -= 2;
else
state->count = 1;
state->drop_next = *now;
} else {
if (timespeccmp(now, &state->drop_next, <))
return 0;
state->count += 1;
}
control_law(state, &delta);
timespecadd(&state->drop_next, &delta, &state->drop_next);
#if 1
LOGP(DRLCMAC, LOGL_INFO,
"CoDel decided to drop packet, window = %d.%03dms, count = %d\n",
(int)delta.tv_sec, (int)(delta.tv_nsec / 1000000), state->count);
#endif
return 1;
stop_dropping:
timespecclear(&state->first_above_time);
not_ok_to_drop:
state->dropping = 0;
return 0;
}

108
src/gprs_codel.h Normal file
View File

@@ -0,0 +1,108 @@
/* gprs_codel.h
*
* This is an implementation of the CoDel algorithm based on the reference
* pseudocode (see http://queue.acm.org/appendices/codel.html).
* Instead of abstracting the queue itself, the following implementation
* provides a time stamp based automaton. The main work is done by a single
* decision function which updates the state and tells whether to pass or to
* drop a packet after it has been taken from the queue.
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include <time.h>
/* Spec default values */
#define GPRS_CODEL_DEFAULT_INTERVAL_MS 100
#define GPRS_CODEL_DEFAULT_MAXPACKET 512
#ifdef __cplusplus
extern "C" {
#endif
struct gprs_codel {
int dropping;
unsigned count;
struct timespec first_above_time;
struct timespec drop_next;
struct timespec target;
struct timespec interval;
unsigned maxpacket;
};
/*!
* \brief Decide about packet drop and update CoDel state
*
* This function takes timing information and decides whether the packet in
* question should be dropped in order to keep related queue in a 'good' state.
* The function is meant to be called when the packet is dequeued.
*
* The CoDel state is updated by this function.
*
* \param state A pointer to the CoDel state of this queue
* \param recv The time when the packet has entered the queue,
* use NULL if dequeueing was not possible because the queue is
* empty
* \param now The current (dequeueing) time
* \param bytes The number of bytes currently stored in the queue (-1 if
* unknown)
*
* \return != 0 if the packet should be dropped, 0 otherwise
*/
int gprs_codel_control(struct gprs_codel *state, const struct timespec *recv,
const struct timespec *now, int bytes);
/*!
* \brief Initialise CoDel state
*
* This function initialises the CoDel state object. It sets the interval time
* to the default value (GPRS_CODEL_DEFAULT_INTERVAL_MS).
*
* \param state A pointer to the CoDel state of this queue
*/
void gprs_codel_init(struct gprs_codel *state);
/*!
* \brief Set interval time
*
* This function changes the interval time.
* The target time is derived from the interval time as proposed in the spec
* (5% of interval time).
*
* \param state A pointer to the CoDel state of this queue
* \param interval_ms The initial interval in ms to be used (<= 0 selects the
* default value)
*/
void gprs_codel_set_interval(struct gprs_codel *state, int interval_ms);
/*!
* \brief Set max packet size
*
* This function changes the maxpacket value. If no more than this number of
* bytes are still stored in the queue, no dropping will be done.
*
* \param state A pointer to the CoDel state of this queue
* \param maxpacket The value in bytes
*/
void gprs_codel_set_maxpacket(struct gprs_codel *state, int maxpacket);
#ifdef __cplusplus
}
#endif

View File

@@ -1,6 +1,7 @@
/* gprs_debug.cpp
*
* Copyright (C) 2012 Ivan Klyuchnikov
* Copyright (C) 2019 Harald Welte <laforge@gnumonks.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -16,56 +17,138 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <errno.h>
#include <osmocom/core/talloc.h>
extern "C" {
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
}
#include <gprs_debug.h>
/* default categories */
static const struct log_info_cat default_categories[] = {
{"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0},
{"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_INFO, 1},
{"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_NOTICE, 1},
{"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1},
{"DBSSGP","\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO , 1},
{"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1},
};
enum {
_FLT_ALL = LOG_FILTER_ALL, /* libosmocore */
FLT_IMSI = 1,
FLT_NSVC = 2,
FLT_BVC = 3,
[DCSN1] = {
.name = "DCSN1",
.color = "\033[1;31m",
.description = "Concrete Syntax Notation One (CSN1)",
.loglevel = LOGL_NOTICE,
.enabled = 0,
},
[DL1IF] = {
.name = "DL1IF",
.color = "\033[1;32m",
.description = "GPRS PCU L1 interface (L1IF)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DRLCMAC] = {
.name = "DRLCMAC",
.color = "\033[0;33m",
.description = "GPRS RLC/MAC layer (RLCMAC)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DRLCMACDATA] = {
.name = "DRLCMACDATA",
.color = "\033[0;33m",
.description = "GPRS RLC/MAC layer Data (RLCMAC)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DRLCMACDL] = {
.name = "DRLCMACDL",
.color = "\033[1;33m",
.description = "GPRS RLC/MAC layer Downlink (RLCMAC)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DRLCMACUL] = {
.name = "DRLCMACUL",
.color = "\033[1;36m",
.description = "GPRS RLC/MAC layer Uplink (RLCMAC)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DRLCMACSCHED] = {
.name = "DRLCMACSCHED",
.color = "\033[0;36m",
.description = "GPRS RLC/MAC layer Scheduling (RLCMAC)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DRLCMACMEAS] = {
.name = "DRLCMACMEAS",
.color = "\033[1;31m",
.description = "GPRS RLC/MAC layer Measurements (RLCMAC)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DTBF] = {
.name = "DTBF",
.color = "\033[1;34m",
.description = "Temporary Block Flow (TBF)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DTBFDL] = {
.name = "DTBFDL",
.color = "\033[1;34m",
.description = "Temporary Block Flow (TBF) Downlink",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DTBFUL] = {
.name = "DTBFUL",
.color = "\033[1;34m",
.description = "Temporary Block Flow (TBF) Uplink",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DNS] = {
.name = "DNS",
.color = "\033[1;34m",
.description = "GPRS Network Service Protocol (NS)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DPCU] = {
.name = "DPCU",
.color = "\033[1;35m",
.description = "GPRS Packet Control Unit (PCU)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DNACC] = {
.name = "DNACC",
.color = "\033[1;37m",
.description = "Network Assisted Cell Change (NACC)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
[DRIM] = {
.name = "DRIM",
.color = "\033[1;38m",
.description = "RAN Information Management (RIM)",
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
};
static int filter_fn(const struct log_context *ctx,
struct log_target *tar)
{
const struct gprs_nsvc *nsvc = (const struct gprs_nsvc*)ctx->ctx[BSC_CTX_NSVC];
const struct gprs_nsvc *bvc = (const struct gprs_nsvc*)ctx->ctx[BSC_CTX_BVC];
const struct gprs_nsvc *nsvc = (const struct gprs_nsvc*)ctx->ctx[LOG_CTX_GB_NSVC];
const struct gprs_nsvc *bvc = (const struct gprs_nsvc*)ctx->ctx[LOG_CTX_GB_BVC];
/* Filter on the NS Virtual Connection */
if ((tar->filter_map & (1 << FLT_NSVC)) != 0
&& nsvc && (nsvc == tar->filter_data[FLT_NSVC]))
if ((tar->filter_map & (1 << LOG_FLT_GB_NSVC)) != 0
&& nsvc && (nsvc == tar->filter_data[LOG_FLT_GB_NSVC]))
return 1;
/* Filter on the BVC */
if ((tar->filter_map & (1 << FLT_BVC)) != 0
&& bvc && (bvc == tar->filter_data[FLT_BVC]))
if ((tar->filter_map & (1 << LOG_FLT_GB_BVC)) != 0
&& bvc && (bvc == tar->filter_data[LOG_FLT_GB_BVC]))
return 1;
return 0;

View File

@@ -16,19 +16,21 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef GPRS_DEBUG_H
#define GPRS_DEBUG_H
#include <stdio.h>
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/logging.h>
#ifdef __cplusplus
};
#endif
/* we used to have DBSSGP definded in each application, and applications telling
* libosmogb which sub-system to use. That creates problems and has been deprecated */
#define DBSSGP DLBSSGP
/* Debug Areas of the code */
enum {
DCSN1,
@@ -39,38 +41,14 @@ enum {
DRLCMACUL,
DRLCMACSCHED,
DRLCMACMEAS,
DBSSGP,
DTBF,
DTBFDL,
DTBFUL,
DNS,
DPCU,
DNACC,
DRIM,
aDebug_LastEntry
};
/* context */
#define BSC_CTX_SUBSCR 1
#define BSC_CTX_NSVC 4
#define BSC_CTX_BVC 5
/* target */
enum {
//DEBUG_FILTER_ALL = 1 << 0,
LOG_FILTER_IMSI = 1 << 1,
LOG_FILTER_NSVC = 1 << 2,
LOG_FILTER_BVC = 1 << 3,
};
/* we don't need a header dependency for this... */
struct gprs_nsvc;
struct bssgp_bvc_ctx;
void log_set_imsi_filter(struct log_target *target, const char *imsi);
void log_set_nsvc_filter(struct log_target *target,
struct gprs_nsvc *nsvc);
void log_set_bvc_filter(struct log_target *target,
struct bssgp_bvc_ctx *bctx);
extern const struct log_info gprs_log_info;
#endif // GPRS_DEBUG_H

988
src/gprs_ms.c Normal file
View File

@@ -0,0 +1,988 @@
/* gprs_ms.c
*
* Copyright (C) 2015-2020 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gprs_ms.h"
#include "bts.h"
#include "tbf.h"
#include "tbf_ul.h"
#include "gprs_debug.h"
#include "gprs_codel.h"
#include "pcu_utils.h"
#include "nacc_fsm.h"
#include <time.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/stats.h>
#include "coding_scheme.h"
#define GPRS_CODEL_SLOW_INTERVAL_MS 4000
extern void *tall_pcu_ctx;
static unsigned int next_ms_ctr_group_id;
static const struct rate_ctr_desc ms_ctr_description[] = {
[MS_CTR_DL_CTRL_MSG_SCHED] = { "ms:dl_ctrl_msg_sched", "Amount of DL CTRL messages scheduled" },
};
static const struct rate_ctr_group_desc ms_ctrg_desc = {
.group_name_prefix = "pcu:ms",
.group_description = "MS Statistics",
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
.num_ctr = ARRAY_SIZE(ms_ctr_description),
.ctr_desc = ms_ctr_description,
};
static int64_t now_msec()
{
struct timespec ts;
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
return (int64_t)(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
}
void gprs_default_cb_ms_idle(struct GprsMs *ms)
{
talloc_free(ms);
}
void gprs_default_cb_ms_active(struct GprsMs *ms)
{
/* do nothing */
}
static struct gpr_ms_callback gprs_default_cb = {
.ms_idle = gprs_default_cb_ms_idle,
.ms_active = gprs_default_cb_ms_active,
};
static void ms_release_timer_cb(void *data)
{
struct GprsMs *ms = (struct GprsMs *) data;
LOGPMS(ms, DRLCMAC, LOGL_INFO, "Release timer expired\n");
if (ms->timer.data) {
ms->timer.data = NULL;
ms_unref(ms);
}
}
static int ms_talloc_destructor(struct GprsMs *ms);
struct GprsMs *ms_alloc(struct gprs_rlcmac_bts *bts, uint32_t tlli)
{
struct GprsMs *ms = talloc_zero(tall_pcu_ctx, struct GprsMs);
talloc_set_destructor(ms, ms_talloc_destructor);
ms->bts = bts;
ms->cb = gprs_default_cb;
ms->tlli = tlli;
ms->new_ul_tlli = GSM_RESERVED_TMSI;
ms->new_dl_tlli = GSM_RESERVED_TMSI;
ms->ta = GSM48_TA_INVALID;
ms->current_cs_ul = UNKNOWN;
ms->current_cs_dl = UNKNOWN;
ms->is_idle = true;
INIT_LLIST_HEAD(&ms->list);
INIT_LLIST_HEAD(&ms->old_tbfs);
int codel_interval = LLC_CODEL_USE_DEFAULT;
LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
ms->imsi[0] = '\0';
memset(&ms->timer, 0, sizeof(ms->timer));
ms->timer.cb = ms_release_timer_cb;
llc_queue_init(&ms->llc_queue);
ms_set_mode(ms, GPRS);
if (ms->bts)
codel_interval = the_pcu->vty.llc_codel_interval_msec;
if (codel_interval) {
if (codel_interval == LLC_CODEL_USE_DEFAULT)
codel_interval = GPRS_CODEL_SLOW_INTERVAL_MS;
ms->codel_state = talloc(ms, struct gprs_codel);
gprs_codel_init(ms->codel_state);
gprs_codel_set_interval(ms->codel_state, codel_interval);
}
ms->last_cs_not_low = now_msec();
ms->app_info_pending = false;
ms->ctrs = rate_ctr_group_alloc(ms, &ms_ctrg_desc, next_ms_ctr_group_id++);
if (!ms->ctrs)
goto free_ret;
return ms;
free_ret:
talloc_free(ms);
return NULL;
}
static int ms_talloc_destructor(struct GprsMs *ms)
{
struct llist_item *pos, *tmp;
LOGPMS(ms, DRLCMAC, LOGL_INFO, "Destroying MS object\n");
ms_set_reserved_slots(ms, NULL, 0, 0);
if (osmo_timer_pending(&ms->timer))
osmo_timer_del(&ms->timer);
if (ms->ul_tbf) {
tbf_set_ms((struct gprs_rlcmac_tbf *)ms->ul_tbf, NULL);
ms->ul_tbf = NULL;
}
if (ms->dl_tbf) {
tbf_set_ms((struct gprs_rlcmac_tbf *)ms->dl_tbf, NULL);
ms->dl_tbf = NULL;
}
llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {
struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)pos->entry;
tbf_set_ms(tbf, NULL);
}
llc_queue_clear(&ms->llc_queue, ms->bts);
if (ms->ctrs)
rate_ctr_group_free(ms->ctrs);
return 0;
}
void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb)
{
if (cb)
ms->cb = *cb;
else
ms->cb = gprs_default_cb;
}
static void ms_update_status(struct GprsMs *ms)
{
if (ms->ref > 0)
return;
if (ms_is_idle(ms) && !ms->is_idle) {
ms->is_idle = true;
ms->cb.ms_idle(ms);
/* this can be deleted by now, do not access it */
return;
}
if (!ms_is_idle(ms) && ms->is_idle) {
ms->is_idle = false;
ms->cb.ms_active(ms);
}
}
struct GprsMs *ms_ref(struct GprsMs *ms)
{
ms->ref += 1;
return ms;
}
void ms_unref(struct GprsMs *ms)
{
OSMO_ASSERT(ms->ref >= 0);
ms->ref -= 1;
if (ms->ref == 0)
ms_update_status(ms);
}
static void ms_release_timer_start(struct GprsMs *ms)
{
if (ms->delay == 0)
return;
LOGPMS(ms, DRLCMAC, LOGL_DEBUG, "Schedule MS release in %u secs\n", ms->delay);
if (!ms->timer.data)
ms->timer.data = ms_ref(ms);
osmo_timer_schedule(&ms->timer, ms->delay, 0);
}
static void ms_release_timer_stop(struct GprsMs *ms)
{
if (!ms->timer.data)
return;
LOGPMS(ms, DRLCMAC, LOGL_DEBUG, "Cancel scheduled MS release\n");
osmo_timer_del(&ms->timer);
ms->timer.data = NULL;
ms_unref(ms);
}
void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode)
{
ms->mode = mode;
switch (ms->mode) {
case GPRS:
if (!mcs_is_gprs(ms->current_cs_ul)) {
ms->current_cs_ul = mcs_get_gprs_by_num(
ms->bts->initial_cs_ul);
if (!mcs_is_valid(ms->current_cs_ul))
ms->current_cs_ul = CS1;
}
if (!mcs_is_gprs(ms->current_cs_dl)) {
ms->current_cs_dl = mcs_get_gprs_by_num(
ms->bts->initial_cs_dl);
if (!mcs_is_valid(ms->current_cs_dl))
ms->current_cs_dl = CS1;
}
break;
case EGPRS_GMSK:
if (!mcs_is_edge_gmsk(ms->current_cs_ul)) {
ms->current_cs_ul = mcs_get_egprs_by_num(
ms->bts->initial_mcs_ul);
if (!mcs_is_valid(ms->current_cs_ul))
ms->current_cs_ul = MCS1;
}
if (!mcs_is_edge_gmsk(ms->current_cs_dl)) {
ms->current_cs_dl = mcs_get_egprs_by_num(
ms->bts->initial_mcs_dl);
if (!mcs_is_valid(ms->current_cs_dl))
ms->current_cs_dl = MCS1;
}
break;
case EGPRS:
if (!mcs_is_edge(ms->current_cs_ul)) {
ms->current_cs_ul = mcs_get_egprs_by_num(
ms->bts->initial_mcs_ul);
if (!mcs_is_valid(ms->current_cs_ul))
ms->current_cs_ul = MCS1;
}
if (!mcs_is_edge(ms->current_cs_dl)) {
ms->current_cs_dl = mcs_get_egprs_by_num(
ms->bts->initial_mcs_dl);
if (!mcs_is_valid(ms->current_cs_dl))
ms->current_cs_dl = MCS1;
}
break;
}
}
static void ms_attach_ul_tbf(struct GprsMs *ms, struct gprs_rlcmac_ul_tbf *tbf)
{
if (ms->ul_tbf == tbf)
return;
LOGPMS(ms, DRLCMAC, LOGL_INFO, "Attaching UL TBF: %s\n", tbf_name((struct gprs_rlcmac_tbf *)tbf));
ms_ref(ms);
if (ms->ul_tbf)
llist_add_tail(tbf_ms_list((struct gprs_rlcmac_tbf *)ms->ul_tbf), &ms->old_tbfs);
ms->ul_tbf = tbf;
if (tbf)
ms_release_timer_stop(ms);
ms_unref(ms);
}
static void ms_attach_dl_tbf(struct GprsMs *ms, struct gprs_rlcmac_dl_tbf *tbf)
{
if (ms->dl_tbf == tbf)
return;
LOGPMS(ms, DRLCMAC, LOGL_INFO, "Attaching DL TBF: %s\n", tbf_name((struct gprs_rlcmac_tbf *)tbf));
ms_ref(ms);
if (ms->dl_tbf)
llist_add_tail(tbf_ms_list((struct gprs_rlcmac_tbf *)ms->dl_tbf), &ms->old_tbfs);
ms->dl_tbf = tbf;
if (tbf)
ms_release_timer_stop(ms);
ms_unref(ms);
}
void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
{
if (tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF)
ms_attach_dl_tbf(ms, as_dl_tbf(tbf));
else
ms_attach_ul_tbf(ms, as_ul_tbf(tbf));
}
void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
{
if (tbf == (struct gprs_rlcmac_tbf *)(ms->ul_tbf)) {
ms->ul_tbf = NULL;
} else if (tbf == (struct gprs_rlcmac_tbf *)(ms->dl_tbf)) {
ms->dl_tbf = NULL;
} else {
bool found = false;
struct llist_item *pos, *tmp;
llist_for_each_entry_safe(pos, tmp, &ms->old_tbfs, list) {
struct gprs_rlcmac_tbf *tmp_tbf = (struct gprs_rlcmac_tbf *)pos->entry;
if (tmp_tbf == tbf) {
llist_del(&pos->list);
found = true;
break;
}
}
/* Protect against recursive calls via set_ms() */
if (!found)
return;
}
LOGPMS(ms, DRLCMAC, LOGL_INFO, "Detaching TBF: %s\n",
tbf_name(tbf));
if (tbf_ms(tbf) == ms)
tbf_set_ms(tbf, NULL);
if (!ms->dl_tbf && !ms->ul_tbf) {
ms_set_reserved_slots(ms, NULL, 0, 0);
if (ms_tlli(ms) != 0)
ms_release_timer_start(ms);
}
ms_update_status(ms);
}
void ms_reset(struct GprsMs *ms)
{
LOGPMS(ms, DRLCMAC, LOGL_INFO, "Clearing MS object\n");
ms_release_timer_stop(ms);
ms->tlli = GSM_RESERVED_TMSI;
ms->new_dl_tlli = ms->tlli;
ms->new_ul_tlli = ms->tlli;
ms->imsi[0] = '\0';
}
static void ms_merge_old_ms(struct GprsMs *ms, struct GprsMs *old_ms)
{
OSMO_ASSERT(old_ms != ms);
if (strlen(ms_imsi(ms)) == 0 && strlen(ms_imsi(old_ms)) != 0)
osmo_strlcpy(ms->imsi, ms_imsi(old_ms), sizeof(ms->imsi));
if (!ms_ms_class(ms) && ms_ms_class(old_ms))
ms_set_ms_class(ms, ms_ms_class(old_ms));
if (!ms_egprs_ms_class(ms) && ms_egprs_ms_class(old_ms))
ms_set_egprs_ms_class(ms, ms_egprs_ms_class(old_ms));
llc_queue_move_and_merge(&ms->llc_queue, &old_ms->llc_queue);
ms_reset(old_ms);
}
void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms)
{
OSMO_ASSERT(old_ms != ms);
ms_ref(old_ms);
/* Clean up the old MS object */
/* TODO: Use timer? */
if (ms_ul_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms), T_MAX))
tbf_free((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms));
if (ms_dl_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms), T_MAX))
tbf_free((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms));
ms_merge_old_ms(ms, old_ms);
ms_unref(old_ms);
}
void ms_set_tlli(struct GprsMs *ms, uint32_t tlli)
{
if (tlli == ms->tlli || tlli == ms->new_ul_tlli)
return;
if (tlli != ms->new_dl_tlli) {
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
"not yet confirmed\n",
ms_tlli(ms), tlli);
ms->new_ul_tlli = tlli;
return;
}
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
"already confirmed partly\n",
ms->tlli, tlli);
ms->tlli = tlli;
ms->new_dl_tlli = GSM_RESERVED_TMSI;
ms->new_ul_tlli = GSM_RESERVED_TMSI;
}
bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli)
{
if (tlli == ms->tlli || tlli == ms->new_dl_tlli)
return false;
if (tlli != ms->new_ul_tlli) {
/* The MS has not sent a message with the new TLLI, which may
* happen according to the spec [TODO: add reference]. */
LOGP(DRLCMAC, LOGL_INFO,
"The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
"partly confirmed\n", tlli);
/* Use the network's idea of TLLI as candidate, this does not
* change the result value of tlli() */
ms->new_dl_tlli = tlli;
return false;
}
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
ms->tlli = tlli;
ms->new_dl_tlli = GSM_RESERVED_TMSI;
ms->new_ul_tlli = GSM_RESERVED_TMSI;
return true;
}
void ms_set_imsi(struct GprsMs *ms, const char *imsi)
{
if (!imsi) {
LOGP(DRLCMAC, LOGL_ERROR, "Expected IMSI!\n");
return;
}
if (imsi[0] && strlen(imsi) < 3) {
LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI '%s'!\n",
imsi);
return;
}
if (strcmp(imsi, ms->imsi) == 0)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, IMSI '%s' -> '%s'\n",
ms_tlli(ms), ms->imsi, imsi);
struct GprsMs *old_ms = bts_ms_by_imsi(ms->bts, imsi);
/* Check if we are going to store a different MS object with already
existing IMSI. This is probably a bug in code calling this function,
since it should take care of this explicitly */
if (old_ms) {
/* We cannot find ms->ms by IMSI since we know that it has a
* different IMSI */
OSMO_ASSERT(old_ms != ms);
LOGPMS(ms, DRLCMAC, LOGL_NOTICE,
"IMSI '%s' was already assigned to another "
"MS object: TLLI = 0x%08x, that IMSI will be removed\n",
imsi, ms_tlli(old_ms));
ms_merge_and_clear_ms(ms, old_ms);
}
osmo_strlcpy(ms->imsi, imsi, sizeof(ms->imsi));
}
uint16_t ms_paging_group(struct GprsMs *ms)
{
uint16_t pgroup;
if (!ms_imsi_is_valid(ms))
return 0; /* 000 is the special "all paging" group */
if ((pgroup = imsi2paging_group(ms_imsi(ms))) > 999) {
LOGPMS(ms, DRLCMAC, LOGL_ERROR, "IMSI to paging group failed!\n");
return 0;
}
return pgroup;
}
void ms_set_ta(struct GprsMs *ms, uint8_t ta_)
{
if (ta_ == ms->ta)
return;
if (gsm48_ta_is_valid(ta_)) {
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
ms_tlli(ms), ms->ta, ta_);
ms->ta = ta_;
} else
LOGP(DRLCMAC, LOGL_NOTICE,
"MS object, TLLI = 0x%08x, invalid TA %d rejected (old "
"value %d kept)\n", ms_tlli(ms), ta_, ms->ta);
}
void ms_set_ms_class(struct GprsMs *ms, uint8_t ms_class_)
{
if (ms_class_ == ms->ms_class)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, MS class %d -> %d\n",
ms_tlli(ms), ms->ms_class, ms_class_);
ms->ms_class = ms_class_;
}
void ms_set_egprs_ms_class(struct GprsMs *ms, uint8_t ms_class_)
{
if (ms_class_ == ms->egprs_ms_class)
return;
LOGP(DRLCMAC, LOGL_INFO,
"Modifying MS object, TLLI = 0x%08x, EGPRS MS class %d -> %d\n",
ms_tlli(ms), ms->egprs_ms_class, ms_class_);
ms->egprs_ms_class = ms_class_;
if (!bts_max_mcs_ul(ms->bts) || !bts_max_mcs_dl(ms->bts)) {
LOGPMS(ms, DRLCMAC, LOGL_DEBUG,
"Avoid enabling EGPRS because use of MCS is disabled: ul=%u dl=%u\n",
bts_max_mcs_ul(ms->bts), bts_max_mcs_dl(ms->bts));
return;
}
if (mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts))) &&
mcs_is_edge_gmsk(mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts))) &&
ms_mode(ms) != EGPRS)
{
ms_set_mode(ms, EGPRS_GMSK);
} else {
ms_set_mode(ms, EGPRS);
}
LOGPMS(ms, DRLCMAC, LOGL_INFO, "Enabled EGPRS, mode %s\n", mode_name(ms_mode(ms)));
}
void ms_update_error_rate(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, int error_rate)
{
int64_t now;
enum CodingScheme max_cs_dl = ms_max_cs_dl(ms);
OSMO_ASSERT(max_cs_dl);
if (error_rate < 0)
return;
now = now_msec();
/* TODO: Check for TBF direction */
/* TODO: Support different CS values for UL and DL */
ms->nack_rate_dl = error_rate;
if (error_rate > the_pcu->vty.cs_adj_upper_limit) {
if (mcs_chan_code(ms->current_cs_dl) > 0) {
mcs_dec_kind(&ms->current_cs_dl, ms_mode(ms));
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): High error rate %d%%, "
"reducing CS level to %s\n",
ms_imsi(ms), error_rate, mcs_name(ms->current_cs_dl));
ms->last_cs_not_low = now;
}
} else if (error_rate < the_pcu->vty.cs_adj_lower_limit) {
if (ms->current_cs_dl < max_cs_dl) {
if (now - ms->last_cs_not_low > 1000) {
mcs_inc_kind(&ms->current_cs_dl, ms_mode(ms));
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): Low error rate %d%%, "
"increasing DL CS level to %s\n",
ms_imsi(ms), error_rate,
mcs_name(ms->current_cs_dl));
ms->last_cs_not_low = now;
} else {
LOGP(DRLCMACDL, LOGL_DEBUG,
"MS (IMSI %s): Low error rate %d%%, "
"ignored (within blocking period)\n",
ms_imsi(ms), error_rate);
}
}
} else {
LOGP(DRLCMACDL, LOGL_DEBUG,
"MS (IMSI %s): Medium error rate %d%%, ignored\n",
ms_imsi(ms), error_rate);
ms->last_cs_not_low = now;
}
}
enum CodingScheme ms_max_cs_ul(const struct GprsMs *ms)
{
enum CodingScheme cs;
OSMO_ASSERT(ms->bts != NULL);
if (mcs_is_gprs(ms->current_cs_ul)) {
if (!bts_max_cs_ul(ms->bts)) {
return CS4;
}
return mcs_get_gprs_by_num(bts_max_cs_ul(ms->bts));
}
cs = mcs_get_egprs_by_num(bts_max_mcs_ul(ms->bts));
if (ms_mode(ms) == EGPRS_GMSK && cs > MCS4)
cs = MCS4;
return cs;
}
void ms_set_current_cs_dl(struct GprsMs *ms, enum CodingScheme scheme)
{
ms->current_cs_dl = scheme;
}
enum CodingScheme ms_max_cs_dl(const struct GprsMs *ms)
{
enum CodingScheme cs;
OSMO_ASSERT(ms->bts != NULL);
if (mcs_is_gprs(ms->current_cs_dl)) {
if (!bts_max_cs_dl(ms->bts)) {
return CS4;
}
return mcs_get_gprs_by_num(bts_max_cs_dl(ms->bts));
}
cs = mcs_get_egprs_by_num(bts_max_mcs_dl(ms->bts));
if (ms_mode(ms) == EGPRS_GMSK && cs > MCS4)
cs = MCS4;
return cs;
}
void ms_update_cs_ul(struct GprsMs *ms, const struct pcu_l1_meas *meas)
{
enum CodingScheme max_cs_ul = ms_max_cs_ul(ms);
int old_link_qual;
int low;
int high;
enum CodingScheme new_cs_ul = ms->current_cs_ul;
uint8_t current_cs = mcs_chan_code(ms->current_cs_ul);
if (!max_cs_ul) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"max_cs_ul cannot be derived (current UL CS: %s)\n",
mcs_name(ms->current_cs_ul));
return;
}
if (!ms->current_cs_ul) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS because it's not set: %s\n",
mcs_name(ms->current_cs_ul));
return;
}
if (!meas->have_link_qual) {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS %s because we don't have link quality measurements.\n",
mcs_name(ms->current_cs_ul));
return;
}
if (mcs_is_gprs(ms->current_cs_ul)) {
if (current_cs >= MAX_GPRS_CS)
current_cs = MAX_GPRS_CS - 1;
low = the_pcu->vty.cs_lqual_ranges[current_cs].low;
high = the_pcu->vty.cs_lqual_ranges[current_cs].high;
} else if (mcs_is_edge(ms->current_cs_ul)) {
if (current_cs >= MAX_EDGE_MCS)
current_cs = MAX_EDGE_MCS - 1;
low = the_pcu->vty.mcs_lqual_ranges[current_cs].low;
high = the_pcu->vty.mcs_lqual_ranges[current_cs].high;
} else {
LOGP(DRLCMACMEAS, LOGL_ERROR,
"Unable to update UL (M)CS because it's neither GPRS nor EDGE: %s\n",
mcs_name(ms->current_cs_ul));
return;
}
/* To avoid rapid changes of the coding scheme, we also take
* the old link quality value into account (if present). */
if (ms->l1_meas.have_link_qual)
old_link_qual = ms->l1_meas.link_qual;
else
old_link_qual = meas->link_qual;
if (meas->link_qual < low && old_link_qual < low)
mcs_dec_kind(&new_cs_ul, ms_mode(ms));
else if (meas->link_qual > high && old_link_qual > high &&
ms->current_cs_ul < max_cs_ul)
mcs_inc_kind(&new_cs_ul, ms_mode(ms));
if (ms->current_cs_ul != new_cs_ul) {
LOGPMS(ms, DRLCMACMEAS, LOGL_INFO,
"Link quality %ddB (old %ddB) left window [%d, %d], "
"modifying uplink CS level: %s -> %s\n",
meas->link_qual, old_link_qual,
low, high,
mcs_name(ms->current_cs_ul), mcs_name(new_cs_ul));
ms->current_cs_ul = new_cs_ul;
}
}
void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas)
{
unsigned i;
ms_update_cs_ul(ms, meas);
if (meas->have_rssi)
pcu_l1_meas_set_rssi(&ms->l1_meas, meas->rssi);
if (meas->have_bto)
pcu_l1_meas_set_bto(&ms->l1_meas, meas->bto);
if (meas->have_ber)
pcu_l1_meas_set_ber(&ms->l1_meas, meas->ber);
if (meas->have_link_qual)
pcu_l1_meas_set_link_qual(&ms->l1_meas, meas->link_qual);
if (meas->have_ms_rx_qual)
pcu_l1_meas_set_ms_rx_qual(&ms->l1_meas, meas->ms_rx_qual);
if (meas->have_ms_c_value)
pcu_l1_meas_set_ms_c_value(&ms->l1_meas, meas->ms_c_value);
if (meas->have_ms_sign_var)
pcu_l1_meas_set_ms_sign_var(&ms->l1_meas, meas->ms_sign_var);
if (meas->have_ms_i_level) {
for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
if (meas->ts[i].have_ms_i_level)
pcu_l1_meas_set_ms_i_level(&ms->l1_meas, i, meas->ts[i].ms_i_level);
else
ms->l1_meas.ts[i].have_ms_i_level = 0;
}
}
}
/* req_mcs_kind acts as a set filter, where EGPRS means any and GPRS is the most restrictive */
enum CodingScheme ms_current_cs_dl(const struct GprsMs *ms, enum mcs_kind req_mcs_kind)
{
enum CodingScheme orig_cs = ms->current_cs_dl;
struct gprs_rlcmac_bts *bts = ms->bts;
size_t unencoded_octets;
enum CodingScheme cs;
/* It could be that a TBF requests a GPRS CS despite the MS currently
being upgraded to EGPRS (hence reporting MCS). That could happen
because the TBF was created early in the process where we didn't have
yet enough information about the MS, and only AFTER it was created we
upgraded the MS to be EGPRS capable.
As a result, when the MS is queried for the target CS here, we could be
returning an MCS despite the current TBF being established as GPRS,
but we rather stick to the TBF type we assigned to the MS rather than
magically sending EGPRS data blocks to a GPRS TBF.
It could also be that the caller requests specific MCS kind
explicitly too due to scheduling restrictions (GPRS+EGPRS multiplexing). */
if (req_mcs_kind == EGPRS_GMSK && mcs_is_edge(orig_cs) && orig_cs > MCS4) {
cs = bts_cs_dl_is_supported(bts, MCS4) ? MCS4 :
bts_cs_dl_is_supported(bts, MCS3) ? MCS3 :
bts_cs_dl_is_supported(bts, MCS2) ? MCS2 :
MCS1;
} else if (req_mcs_kind == GPRS && mcs_is_edge(orig_cs)) { /* GPRS */
int i;
cs = orig_cs > MCS4 ? MCS4 : orig_cs;
cs -= (MCS1 - CS1); /* MCSx -> CSx */
/* Find suitable CS starting from equivalent MCS which is supported by BTS: */
for (i = mcs_chan_code(cs); !bts_cs_dl_is_supported(bts, CS1 + i); i--);
OSMO_ASSERT(i >= 0 && i <= 3); /* CS1 is always supported */
cs = CS1 + i;
} else {
cs = orig_cs;
}
if (orig_cs != cs)
LOGPMS(ms, DRLCMACDL, LOGL_INFO, "MS (mode=%s) suggests transmitting "
"DL %s, downgrade to %s in order to match TBF & scheduler requirements\n",
mode_name(ms_mode(ms)), mcs_name(orig_cs), mcs_name(cs));
unencoded_octets = llc_queue_octets(&ms->llc_queue);
/* If the DL TBF is active, add number of unencoded chunk octets */
if (ms->dl_tbf)
unencoded_octets += llc_chunk_size(tbf_llc((struct gprs_rlcmac_tbf *)ms->dl_tbf));
/* There are many unencoded octets, don't reduce */
if (unencoded_octets >= the_pcu->vty.cs_downgrade_threshold)
return cs;
/* RF conditions are good, don't reduce */
if (ms->nack_rate_dl < the_pcu->vty.cs_adj_lower_limit)
return cs;
/* The throughput would probably be better if the CS level was reduced */
mcs_dec_kind(&cs, ms_mode(ms));
/* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
if (cs == CS2)
mcs_dec_kind(&cs, ms_mode(ms));
return cs;
}
int ms_first_common_ts(const struct GprsMs *ms)
{
if (ms->dl_tbf)
return tbf_first_common_ts((struct gprs_rlcmac_tbf *)ms->dl_tbf);
if (ms->ul_tbf)
return tbf_first_common_ts((struct gprs_rlcmac_tbf *)ms->ul_tbf);
return -1;
}
uint8_t ms_dl_slots(const struct GprsMs *ms)
{
uint8_t slots = 0;
if (ms->dl_tbf)
slots |= tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
if (ms->ul_tbf)
slots |= tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
return slots;
}
uint8_t ms_ul_slots(const struct GprsMs *ms)
{
uint8_t slots = 0;
if (ms->dl_tbf)
slots |= tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
if (ms->ul_tbf)
slots |= tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
return slots;
}
uint8_t ms_current_pacch_slots(const struct GprsMs *ms)
{
uint8_t slots = 0;
bool is_dl_active = ms->dl_tbf && tbf_is_tfi_assigned((struct gprs_rlcmac_tbf *)ms->dl_tbf);
bool is_ul_active = ms->ul_tbf && tbf_is_tfi_assigned((struct gprs_rlcmac_tbf *)ms->ul_tbf);
if (!is_dl_active && !is_ul_active)
return 0;
/* see TS 44.060, 8.1.1.2.2 */
if (is_dl_active && !is_ul_active)
slots = tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
else if (!is_dl_active && is_ul_active)
slots = tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf);
else
slots = tbf_ul_slots((struct gprs_rlcmac_tbf *)ms->ul_tbf) &
tbf_dl_slots((struct gprs_rlcmac_tbf *)ms->dl_tbf);
/* Assume a multislot class 1 device */
/* TODO: For class 2 devices, this could be removed */
slots = pcu_lsb(slots);
return slots;
}
void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,
uint8_t ul_slots, uint8_t dl_slots)
{
if (ms->current_trx) {
bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,
ms->reserved_dl_slots);
bts_trx_unreserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,
ms->reserved_ul_slots);
ms->reserved_dl_slots = 0;
ms->reserved_ul_slots = 0;
}
ms->current_trx = trx;
if (trx) {
ms->reserved_dl_slots = dl_slots;
ms->reserved_ul_slots = ul_slots;
bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_DL_TBF,
ms->reserved_dl_slots);
bts_trx_reserve_slots(ms->current_trx, GPRS_RLCMAC_UL_TBF,
ms->reserved_ul_slots);
}
}
struct gprs_rlcmac_tbf *ms_tbf(const struct GprsMs *ms, enum gprs_rlcmac_tbf_direction dir)
{
switch (dir) {
case GPRS_RLCMAC_DL_TBF: return (struct gprs_rlcmac_tbf *)ms->dl_tbf;
case GPRS_RLCMAC_UL_TBF: return (struct gprs_rlcmac_tbf *)ms->ul_tbf;
}
return NULL;
}
int ms_nacc_start(struct GprsMs *ms, Packet_Cell_Change_Notification_t *notif)
{
if (!ms->nacc)
ms->nacc = nacc_fsm_alloc(ms);
if (!ms->nacc)
return -EINVAL;
return osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_RX_CELL_CHG_NOTIFICATION, notif);
}
bool ms_nacc_rts(const struct GprsMs *ms)
{
if (!ms->nacc)
return false;
if (ms->nacc->fi->state == NACC_ST_TX_NEIGHBOUR_DATA ||
ms->nacc->fi->state == NACC_ST_TX_CELL_CHG_CONTINUE)
return true;
return false;
}
struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts)
{
int rc;
struct nacc_ev_create_rlcmac_msg_ctx data_ctx;
data_ctx = (struct nacc_ev_create_rlcmac_msg_ctx) {
.tbf = tbf,
.fn = fn,
.ts = ts,
.msg = NULL,
};
rc = osmo_fsm_inst_dispatch(ms->nacc->fi, NACC_EV_CREATE_RLCMAC_MSG, &data_ctx);
if (rc != 0 || !data_ctx.msg)
return NULL;
return data_ctx.msg;
}

259
src/gprs_ms.h Normal file
View File

@@ -0,0 +1,259 @@
/* gprs_ms.h
*
* Copyright (C) 2015-2020 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
struct gprs_codel;
#include "llc.h"
#include "tbf.h"
#include "tbf_ul.h"
#include "tbf_dl.h"
#include "pcu_l1_if.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/timer.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/gsm/gsm48.h>
#include "coding_scheme.h"
#include <gsm_rlcmac.h>
#include <stdint.h>
#include <stddef.h>
#include <inttypes.h>
enum ms_counter_id {
MS_CTR_DL_CTRL_MSG_SCHED,
};
struct gprs_rlcmac_bts;
struct gprs_rlcmac_trx;
struct GprsMs;
struct gpr_ms_callback {
void (*ms_idle)(struct GprsMs *);
void (*ms_active)(struct GprsMs *);
};
struct GprsMs {
struct llist_head list; /* list of all GprsMs */
struct gpr_ms_callback cb;
bool app_info_pending;
struct gprs_rlcmac_bts *bts;
struct gprs_rlcmac_ul_tbf *ul_tbf;
struct gprs_rlcmac_dl_tbf *dl_tbf;
struct llist_head old_tbfs; /* list of gprs_rlcmac_tbf */
uint32_t tlli;
uint32_t new_ul_tlli;
uint32_t new_dl_tlli;
/* store IMSI for look-up and PCH retransmission */
char imsi[OSMO_IMSI_BUF_SIZE];
uint8_t ta;
uint8_t ms_class;
uint8_t egprs_ms_class;
/* current coding scheme */
enum CodingScheme current_cs_ul;
enum CodingScheme current_cs_dl;
struct gprs_llc_queue llc_queue;
bool is_idle;
int ref;
struct osmo_timer_list timer;
unsigned delay;
int64_t last_cs_not_low;
struct pcu_l1_meas l1_meas;
unsigned nack_rate_dl;
uint8_t reserved_dl_slots;
uint8_t reserved_ul_slots;
struct gprs_rlcmac_trx *current_trx;
struct gprs_codel *codel_state;
enum mcs_kind mode;
struct rate_ctr_group *ctrs;
struct nacc_fsm_ctx *nacc;
};
struct GprsMs *ms_alloc(struct gprs_rlcmac_bts *bts, uint32_t tlli);
int ms_first_common_ts(const struct GprsMs *ms);
void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,
uint8_t ul_slots, uint8_t dl_slots);
struct GprsMs *ms_ref(struct GprsMs *ms);
void ms_unref(struct GprsMs *ms);
void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode);
void ms_set_ms_class(struct GprsMs *ms, uint8_t ms_class_);
void ms_set_egprs_ms_class(struct GprsMs *ms, uint8_t ms_class_);
void ms_set_ta(struct GprsMs *ms, uint8_t ta_);
enum CodingScheme ms_current_cs_dl(const struct GprsMs *ms, enum mcs_kind req_mcs_kind);
enum CodingScheme ms_max_cs_ul(const struct GprsMs *ms);
enum CodingScheme ms_max_cs_dl(const struct GprsMs *ms);
void ms_set_current_cs_dl(struct GprsMs *ms, enum CodingScheme scheme);
void ms_update_error_rate(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, int error_rate);
uint8_t ms_current_pacch_slots(const struct GprsMs *ms);
void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms);
void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);
void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf);
void ms_set_tlli(struct GprsMs *ms, uint32_t tlli);
bool ms_confirm_tlli(struct GprsMs *ms, uint32_t tlli);
void ms_set_imsi(struct GprsMs *ms, const char *imsi);
uint16_t ms_paging_group(struct GprsMs *ms);
void ms_update_l1_meas(struct GprsMs *ms, const struct pcu_l1_meas *meas);
struct gprs_rlcmac_tbf *ms_tbf(const struct GprsMs *ms, enum gprs_rlcmac_tbf_direction dir);
static inline struct gprs_rlcmac_ul_tbf *ms_ul_tbf(const struct GprsMs *ms) {return ms->ul_tbf;}
static inline struct gprs_rlcmac_dl_tbf *ms_dl_tbf(const struct GprsMs *ms) {return ms->dl_tbf;}
void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb);
int ms_nacc_start(struct GprsMs *ms, Packet_Cell_Change_Notification_t *notif);
bool ms_nacc_rts(const struct GprsMs *ms);
struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts);
static inline bool ms_is_idle(const struct GprsMs *ms)
{
return !ms->ul_tbf && !ms->dl_tbf && !ms->ref && llist_empty(&ms->old_tbfs);
}
static inline struct gprs_llc_queue *ms_llc_queue(struct GprsMs *ms)
{
return &ms->llc_queue;
}
static inline bool ms_need_dl_tbf(struct GprsMs *ms)
{
if (ms_dl_tbf(ms) != NULL &&
tbf_state((const struct gprs_rlcmac_tbf *)ms_dl_tbf(ms)) != TBF_ST_WAIT_RELEASE)
return false;
return llc_queue_size(ms_llc_queue(ms)) > 0;
}
static inline uint32_t ms_tlli(const struct GprsMs *ms)
{
if (ms->new_ul_tlli != GSM_RESERVED_TMSI)
return ms->new_ul_tlli;
if (ms->tlli != GSM_RESERVED_TMSI)
return ms->tlli;
return ms->new_dl_tlli;
}
static inline bool ms_check_tlli(struct GprsMs *ms, uint32_t tlli)
{
return tlli != GSM_RESERVED_TMSI &&
(tlli == ms->tlli || tlli == ms->new_ul_tlli || tlli == ms->new_dl_tlli);
}
static inline const char *ms_imsi(const struct GprsMs *ms)
{
return ms->imsi;
}
static inline bool ms_imsi_is_valid(const struct GprsMs *ms)
{
return ms->imsi[0] != '\0';
}
static inline uint8_t ms_ta(const struct GprsMs *ms)
{
return ms->ta;
}
static inline uint8_t ms_ms_class(const struct GprsMs *ms)
{
return ms->ms_class;
}
static inline uint8_t ms_egprs_ms_class(const struct GprsMs *ms)
{
return ms->egprs_ms_class;
}
static inline enum CodingScheme ms_current_cs_ul(const struct GprsMs *ms)
{
return ms->current_cs_ul;
}
static inline enum mcs_kind ms_mode(const struct GprsMs *ms)
{
return ms->mode;
}
static inline void ms_set_timeout(struct GprsMs *ms, unsigned secs)
{
ms->delay = secs;
}
static inline struct gprs_codel *ms_codel_state(const struct GprsMs *ms)
{
return ms->codel_state;
}
static inline unsigned ms_nack_rate_dl(const struct GprsMs *ms)
{
return ms->nack_rate_dl;
}
static inline uint8_t ms_reserved_dl_slots(const struct GprsMs *ms)
{
return ms->reserved_dl_slots;
}
static inline uint8_t ms_reserved_ul_slots(const struct GprsMs *ms)
{
return ms->reserved_ul_slots;
}
static inline struct gprs_rlcmac_trx *ms_current_trx(const struct GprsMs *ms)
{
return ms->current_trx;
}
#define LOGPMS(ms, category, level, fmt, args...) \
LOGP(category, level, "MS(TLLI=0x%08x, IMSI=%s, TA=%" PRIu8 ", %" PRIu8 "/%" PRIu8 ",%s%s) " fmt, \
ms_tlli(ms), ms_imsi(ms), ms_ta(ms), ms_ms_class(ms), ms_egprs_ms_class(ms), \
ms_ul_tbf(ms) ? " UL": "", \
ms_dl_tbf(ms) ? " DL": "", \
## args)
#ifdef __cplusplus
}
#endif

113
src/gprs_ms_storage.cpp Normal file
View File

@@ -0,0 +1,113 @@
/* gprs_ms_storage.cpp
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "gprs_ms_storage.h"
#include "tbf.h"
#include "bts.h"
extern "C" {
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsm48.h>
}
static void ms_storage_ms_idle_cb(struct GprsMs *ms)
{
llist_del(&ms->list);
if (ms->bts)
bts_stat_item_add(ms->bts, STAT_MS_PRESENT, -1);
if (ms_is_idle(ms))
talloc_free(ms);
}
static void ms_storage_ms_active_cb(struct GprsMs *ms)
{
/* Nothing to do */
}
static struct gpr_ms_callback ms_storage_ms_cb = {
.ms_idle = ms_storage_ms_idle_cb,
.ms_active = ms_storage_ms_active_cb,
};
GprsMsStorage::GprsMsStorage(struct gprs_rlcmac_bts *bts) :
m_bts(bts)
{
INIT_LLIST_HEAD(&m_list);
}
GprsMsStorage::~GprsMsStorage()
{
cleanup();
}
void GprsMsStorage::cleanup()
{
struct llist_head *pos, *tmp;
llist_for_each_safe(pos, tmp, &m_list) {
struct GprsMs *ms = llist_entry(pos, typeof(*ms), list);
ms_set_callback(ms, NULL);
ms_storage_ms_idle_cb(ms);
}
}
GprsMs *GprsMsStorage::get_ms(uint32_t tlli, uint32_t old_tlli, const char *imsi) const
{
struct llist_head *tmp;
GprsMs *ms;
if (tlli != GSM_RESERVED_TMSI || old_tlli != GSM_RESERVED_TMSI) {
llist_for_each(tmp, &m_list) {
ms = llist_entry(tmp, typeof(*ms), list);
if (ms_check_tlli(ms, tlli))
return ms;
if (ms_check_tlli(ms, old_tlli))
return ms;
}
}
/* not found by TLLI */
if (imsi && imsi[0] != '\0') {
llist_for_each(tmp, &m_list) {
ms = llist_entry(tmp, typeof(*ms), list);
if (ms_imsi_is_valid(ms) && strcmp(imsi, ms_imsi(ms)) == 0)
return ms;
}
}
return NULL;
}
GprsMs *GprsMsStorage::create_ms()
{
GprsMs *ms;
ms = ms_alloc(m_bts, GSM_RESERVED_TMSI);
ms_set_callback(ms, &ms_storage_ms_cb);
llist_add(&ms->list, &m_list);
if (m_bts)
bts_stat_item_add(m_bts, STAT_MS_PRESENT, 1);
return ms;
}

44
src/gprs_ms_storage.h Normal file
View File

@@ -0,0 +1,44 @@
/* gprs_ms_storage.h
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include "gprs_ms.h"
#include "tbf.h"
#include <stdint.h>
#include <stddef.h>
struct gprs_rlcmac_bts;
struct GprsMsStorage {
public:
GprsMsStorage(struct gprs_rlcmac_bts *bts);
~GprsMsStorage();
void cleanup();
GprsMs *get_ms(uint32_t tlli, uint32_t old_tlli = GSM_RESERVED_TMSI, const char *imsi = NULL) const;
GprsMs *create_ms();
const struct llist_head* ms_list() const {return &m_list;}
private:
struct gprs_rlcmac_bts *m_bts;
struct llist_head m_list; /* list of struct GprsMs */
};

212
src/gprs_pcu.c Normal file
View File

@@ -0,0 +1,212 @@
/*
* Copyright (C) 2013 by Holger Hans Peter Freyther
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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/utils.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/ctrl/ports.h>
#include "gprs_pcu.h"
#include "bts.h"
struct gprs_pcu *the_pcu;
static struct osmo_tdef T_defs_pcu[] = {
{ .T=3113, .default_val=7, .unit=OSMO_TDEF_S, .desc="Timeout for paging", .val=0 },
{ .T=3190, .default_val=5, .unit=OSMO_TDEF_S, .desc="Return to packet idle mode after Packet DL Assignment on CCCH (s)", .val=0},
{ .T=3141, .default_val=10, .unit=OSMO_TDEF_S, .desc="Timeout for contention resolution procedure (s)", .val=0 },
{ .T=3172, .default_val=5000, .unit=OSMO_TDEF_MS, .desc="Wait Indication used in Imm Ass Reject during TBF Establishment (PACCH)", .val=0, .min_val = 0, .max_val = 255000 }, /* TS 44.060 7.1.3.2.1 */
{ .T=PCU_TDEF_NEIGH_RESOLVE_TO, .default_val=1000, .unit=OSMO_TDEF_MS, .desc="[ARFCN+BSIC]->[RAC+CI] resolution timeout (ms)", .val=0 },
{ .T=PCU_TDEF_SI_RESOLVE_TO, .default_val=1000, .unit=OSMO_TDEF_MS, .desc="RIM RAN-INFO response timeout (ms)", .val=0 },
{ .T=PCU_TDEF_NEIGH_CACHE_ALIVE, .default_val=5, .unit=OSMO_TDEF_S, .desc="[ARFCN+BSIC]->[RAC+CI] resolution cache entry storage timeout (s)", .val=0 },
{ .T=PCU_TDEF_SI_CACHE_ALIVE, .default_val=5, .unit=OSMO_TDEF_S, .desc="[RAC+CI]->[SI] resolution cache entry storage timeout (s)", .val=0 },
{ .T=-101, .default_val=30, .unit=OSMO_TDEF_S, .desc="BSSGP (un)blocking procedures timer (s)", .val=0 },
{ .T=-102, .default_val=30, .unit=OSMO_TDEF_S, .desc="BSSGP reset procedure timer (s)", .val=0 },
{ .T=-2000, .default_val=0, .unit=OSMO_TDEF_MS, .desc="Delay release of UL TBF after tx Packet Access Reject (PACCH) (ms)", .val=0 },
{ .T=-2001, .default_val=2, .unit=OSMO_TDEF_S, .desc="PACCH assignment timeout (s)", .val=0 },
{ .T=-2002, .default_val=200, .unit=OSMO_TDEF_MS, .desc="Waiting after IMM.ASS confirm timer (ms)", .val=0 },
{ .T=-2030, .default_val=60, .unit=OSMO_TDEF_S, .desc="Time to keep an idle MS object alive (s)", .val=0 }, /* slightly above T3314 (default 44s, 24.008, 11.2.2) */
{ .T=-2031, .default_val=2000, .unit=OSMO_TDEF_MS, .desc="Time to keep an idle DL TBF alive (ms)", .val=0 },
{ .T=0, .default_val=0, .unit=OSMO_TDEF_S, .desc=NULL, .val=0 } /* empty item at the end */
};
static void _update_stats_timer_cb(void *data)
{
struct gprs_pcu *pcu = (struct gprs_pcu *)data;
struct gprs_rlcmac_bts *bts;
llist_for_each_entry(bts, &pcu->bts_list, list)
osmo_time_cc_set_flag(&bts->all_allocated_pdch, bts_all_pdch_allocated(bts));
osmo_timer_schedule(&pcu->update_stats_timer, 1, 0);
}
static int gprs_pcu_talloc_destructor(struct gprs_pcu *pcu)
{
if (osmo_timer_pending(&pcu->update_stats_timer))
osmo_timer_del(&pcu->update_stats_timer);
neigh_cache_free(pcu->neigh_cache);
si_cache_free(pcu->si_cache);
return 0;
}
struct gprs_pcu *gprs_pcu_alloc(void *ctx)
{
struct gprs_pcu *pcu;
pcu = (struct gprs_pcu *)talloc_zero(ctx, struct gprs_pcu);
OSMO_ASSERT(pcu);
talloc_set_destructor(pcu, gprs_pcu_talloc_destructor);
pcu->vty.fc_interval = 1;
pcu->vty.max_cs_ul = MAX_GPRS_CS;
pcu->vty.max_cs_dl = MAX_GPRS_CS;
pcu->vty.max_mcs_ul = MAX_EDGE_MCS;
pcu->vty.max_mcs_dl = MAX_EDGE_MCS;
pcu->vty.force_alpha = (uint8_t)-1; /* don't force by default, use BTS SI13 provided value */
pcu->vty.dl_tbf_preemptive_retransmission = true;
/* By default resegmentation is supported in DL can also be configured
* through VTY */
pcu->vty.dl_arq_type = EGPRS_ARQ1;
pcu->vty.cs_adj_enabled = true;
pcu->vty.cs_adj_upper_limit = 33; /* Decrease CS if the error rate is above */
pcu->vty.cs_adj_lower_limit = 10; /* Increase CS if the error rate is below */
pcu->vty.cs_downgrade_threshold = 200;
/* CS-1 to CS-4 */
pcu->vty.cs_lqual_ranges[0].low = -256;
pcu->vty.cs_lqual_ranges[0].high = 6;
pcu->vty.cs_lqual_ranges[1].low = 5;
pcu->vty.cs_lqual_ranges[1].high = 8;
pcu->vty.cs_lqual_ranges[2].low = 7;
pcu->vty.cs_lqual_ranges[2].high = 13;
pcu->vty.cs_lqual_ranges[3].low = 12;
pcu->vty.cs_lqual_ranges[3].high = 256;
/* MCS-1 to MCS-9 */
/* Default thresholds are referenced from literature */
/* Fig. 2.3, Chapter 2, Optimizing Wireless Communication Systems, Springer (2009) */
pcu->vty.mcs_lqual_ranges[0].low = -256;
pcu->vty.mcs_lqual_ranges[0].high = 6;
pcu->vty.mcs_lqual_ranges[1].low = 5;
pcu->vty.mcs_lqual_ranges[1].high = 8;
pcu->vty.mcs_lqual_ranges[2].low = 7;
pcu->vty.mcs_lqual_ranges[2].high = 13;
pcu->vty.mcs_lqual_ranges[3].low = 12;
pcu->vty.mcs_lqual_ranges[3].high = 15;
pcu->vty.mcs_lqual_ranges[4].low = 14;
pcu->vty.mcs_lqual_ranges[4].high = 17;
pcu->vty.mcs_lqual_ranges[5].low = 16;
pcu->vty.mcs_lqual_ranges[5].high = 18;
pcu->vty.mcs_lqual_ranges[6].low = 17;
pcu->vty.mcs_lqual_ranges[6].high = 20;
pcu->vty.mcs_lqual_ranges[7].low = 19;
pcu->vty.mcs_lqual_ranges[7].high = 24;
pcu->vty.mcs_lqual_ranges[8].low = 23;
pcu->vty.mcs_lqual_ranges[8].high = 256;
pcu->vty.ns_dialect = GPRS_NS2_DIALECT_IPACCESS;
pcu->vty.ns_ip_dscp = -1;
pcu->vty.ns_priority = -1;
/* TODO: increase them when CRBB decoding is implemented */
pcu->vty.ws_base = 64;
pcu->vty.ws_pdch = 0;
pcu->vty.llc_codel_interval_msec = LLC_CODEL_USE_DEFAULT;
pcu->vty.llc_idle_ack_csec = 10;
pcu->vty.neigh_ctrl_addr = NULL; /* don't use CTRL iface for Neigh Addr Resolution */
pcu->vty.neigh_ctrl_port = OSMO_CTRL_PORT_BSC_NEIGH;
pcu->T_defs = T_defs_pcu;
osmo_tdefs_reset(pcu->T_defs);
INIT_LLIST_HEAD(&pcu->bts_list);
pcu->neigh_cache = neigh_cache_alloc(pcu, osmo_tdef_get(pcu->T_defs, PCU_TDEF_NEIGH_CACHE_ALIVE, OSMO_TDEF_S, -1));
pcu->si_cache = si_cache_alloc(pcu, osmo_tdef_get(pcu->T_defs, PCU_TDEF_SI_CACHE_ALIVE, OSMO_TDEF_S, -1));
osmo_timer_setup(&pcu->update_stats_timer, _update_stats_timer_cb, pcu);
osmo_timer_schedule(&pcu->update_stats_timer, 1, 0);
return pcu;
}
struct gprs_rlcmac_bts *gprs_pcu_get_bts_by_nr(struct gprs_pcu *pcu, uint8_t bts_nr)
{
struct gprs_rlcmac_bts *pos;
llist_for_each_entry(pos, &pcu->bts_list, list) {
if (pos->nr == bts_nr)
return pos;
}
return NULL;
}
struct gprs_rlcmac_bts *gprs_pcu_get_bts_by_cgi_ps(struct gprs_pcu *pcu, struct osmo_cell_global_id_ps *cgi_ps)
{
struct gprs_rlcmac_bts *pos;
llist_for_each_entry(pos, &pcu->bts_list, list) {
if (osmo_cgi_ps_cmp(&pos->cgi_ps, cgi_ps) == 0)
return pos;
}
return NULL;
}
void gprs_pcu_set_initial_cs(struct gprs_pcu *pcu, uint8_t cs_dl, uint8_t cs_ul)
{
struct gprs_rlcmac_bts *bts;
the_pcu->vty.initial_cs_dl = cs_dl;
the_pcu->vty.initial_cs_ul = cs_ul;
llist_for_each_entry(bts, &pcu->bts_list, list) {
bts_recalc_initial_cs(bts);
}
}
void gprs_pcu_set_initial_mcs(struct gprs_pcu *pcu, uint8_t mcs_dl, uint8_t mcs_ul)
{
struct gprs_rlcmac_bts *bts;
the_pcu->vty.initial_mcs_dl = mcs_dl;
the_pcu->vty.initial_mcs_ul = mcs_ul;
llist_for_each_entry(bts, &pcu->bts_list, list) {
bts_recalc_initial_mcs(bts);
}
}
void gprs_pcu_set_max_cs(struct gprs_pcu *pcu, uint8_t cs_dl, uint8_t cs_ul)
{
struct gprs_rlcmac_bts *bts;
the_pcu->vty.max_cs_dl = cs_dl;
the_pcu->vty.max_cs_ul = cs_ul;
llist_for_each_entry(bts, &pcu->bts_list, list) {
bts_recalc_max_cs(bts);
}
}
void gprs_pcu_set_max_mcs(struct gprs_pcu *pcu, uint8_t mcs_dl, uint8_t mcs_ul)
{
struct gprs_rlcmac_bts *bts;
the_pcu->vty.max_mcs_dl = mcs_dl;
the_pcu->vty.max_mcs_ul = mcs_ul;
llist_for_each_entry(bts, &pcu->bts_list, list) {
bts_recalc_max_mcs(bts);
}
}

150
src/gprs_pcu.h Normal file
View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2013 by Holger Hans Peter Freyther
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* 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/>.
*
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/gsmtap_util.h>
#include <osmocom/core/timer.h>
#include "gprs_bssgp_pcu.h"
#include "coding_scheme.h"
#include "neigh_cache.h"
#define LLC_CODEL_DISABLE 0
#define LLC_CODEL_USE_DEFAULT (-1)
#define MAX_EDGE_MCS 9
#define MAX_GPRS_CS 4
#define PCU_TDEF_NEIGH_RESOLVE_TO (-1)
#define PCU_TDEF_SI_RESOLVE_TO (-2)
#define PCU_TDEF_NEIGH_CACHE_ALIVE (-10)
#define PCU_TDEF_SI_CACHE_ALIVE (-11)
/* see bts->gsmtap_categ_mask */
enum pcu_gsmtap_category {
PCU_GSMTAP_C_DL_UNKNOWN = 0, /* unknown or undecodable downlink blocks */
PCU_GSMTAP_C_DL_DUMMY = 1, /* downlink dummy blocks */
PCU_GSMTAP_C_DL_CTRL = 2, /* downlink control blocks */
PCU_GSMTAP_C_DL_DATA_GPRS = 3, /* downlink GPRS data blocks */
PCU_GSMTAP_C_DL_DATA_EGPRS = 4, /* downlink EGPRS data blocks */
PCU_GSMTAP_C_DL_PTCCH = 5, /* downlink PTCCH blocks */
PCU_GSMTAP_C_DL_AGCH = 6, /* downlink AGCH blocks */
PCU_GSMTAP_C_DL_PCH = 7, /* downlink PCH blocks */
PCU_GSMTAP_C_UL_UNKNOWN = 15, /* unknown or undecodable uplink blocks */
PCU_GSMTAP_C_UL_DUMMY = 16, /* uplink dummy blocks */
PCU_GSMTAP_C_UL_CTRL = 17, /* uplink control blocks */
PCU_GSMTAP_C_UL_DATA_GPRS = 18, /* uplink GPRS data blocks */
PCU_GSMTAP_C_UL_DATA_EGPRS = 19, /* uplink EGPRS data blocks */
PCU_GSMTAP_C_UL_RACH = 20, /* uplink RACH bursts */
PCU_GSMTAP_C_UL_PTCCH = 21, /* uplink PTCCH bursts */
};
struct gprs_rlcmac_bts;
struct GprsMs;
struct gprs_rlcmac_tbf;
typedef int (*alloc_algorithm_func_t)(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *tbf,
bool single, int8_t use_tbf);
struct gprs_pcu {
/* Path to be used for the pcu-bts socket */
char *pcu_sock_path;
struct { /* Config Values set by VTY */
uint8_t fc_interval;
uint16_t fc_bucket_time;
uint32_t fc_bvc_bucket_size;
uint32_t fc_bvc_leak_rate;
uint32_t fc_ms_bucket_size;
uint32_t fc_ms_leak_rate;
bool force_initial_cs; /* false=use from BTS true=use from VTY */
bool force_initial_mcs; /* false=use from BTS true=use from VTY */
uint8_t initial_cs_dl, initial_cs_ul;
uint8_t initial_mcs_dl, initial_mcs_ul;
uint8_t max_cs_dl, max_cs_ul;
uint8_t max_mcs_dl, max_mcs_ul;
uint8_t force_two_phase;
uint8_t force_alpha, gamma;
bool dl_tbf_preemptive_retransmission;
enum egprs_arq_type dl_arq_type; /* EGPRS_ARQ1 to support resegmentation in DL, EGPRS_ARQ2 for no reseg */
bool cs_adj_enabled; /* whether cs_adj_{upper,lower}_limit are used to adjust DL CS */
uint8_t cs_adj_upper_limit; /* downgrade DL CS if error rate above its value */
uint8_t cs_adj_lower_limit; /* upgrade DL CS if error rate below its value */
/* downgrade DL CS when less than specified octets are left in tx queue. Optimization, see paper:
"Theoretical Analysis of GPRS Throughput and Delay" */
uint16_t cs_downgrade_threshold;
/* Link quality range for each UL (M)CS. Below or above, next/prev (M)CS is selected. */
struct {int16_t low; int16_t high; } cs_lqual_ranges[MAX_GPRS_CS];
struct {int16_t low; int16_t high; } mcs_lqual_ranges[MAX_EDGE_MCS];
enum gprs_ns2_dialect ns_dialect; /* Are we talking Gb with IP-SNS (true) or classic Gb? */
int ns_ip_dscp;
int ns_priority;
uint16_t ws_base;
uint16_t ws_pdch; /* increase WS by this value per PDCH */
uint16_t force_llc_lifetime; /* overrides lifetime from SGSN */
uint32_t llc_discard_csec;
uint32_t llc_idle_ack_csec;
uint32_t llc_codel_interval_msec; /* 0=disabled, -1=use default interval */
/* Remote BSS resolution sevice (CTRL iface) */
char *neigh_ctrl_addr;
uint16_t neigh_ctrl_port;
} vty;
struct gsmtap_inst *gsmtap;
uint32_t gsmtap_categ_mask;
char *gsmtap_remote_host;
struct llist_head bts_list; /* list of gprs_rlcmac_bts */
struct gprs_ns2_inst *nsi;
alloc_algorithm_func_t alloc_algorithm;
struct gprs_bssgp_pcu bssgp;
struct osmo_tdef *T_defs; /* timers controlled by PCU */
struct neigh_cache *neigh_cache; /* ARFC+BSIC -> CGI PS cache */
struct si_cache *si_cache; /* ARFC+BSIC -> CGI PS cache */
struct osmo_timer_list update_stats_timer; /* Used to update some time_cc stats periodically */
};
extern struct gprs_pcu *the_pcu;
struct gprs_pcu *gprs_pcu_alloc(void *ctx);
struct gprs_rlcmac_bts *gprs_pcu_get_bts_by_nr(struct gprs_pcu *pcu, uint8_t bts_nr);
struct gprs_rlcmac_bts *gprs_pcu_get_bts_by_cgi_ps(struct gprs_pcu *pcu, struct osmo_cell_global_id_ps *cgi_ps);
void gprs_pcu_set_initial_cs(struct gprs_pcu *pcu, uint8_t cs_dl, uint8_t cs_ul);
void gprs_pcu_set_initial_mcs(struct gprs_pcu *pcu, uint8_t mcs_dl, uint8_t mcs_ul);
void gprs_pcu_set_max_cs(struct gprs_pcu *pcu, uint8_t cs_dl, uint8_t cs_ul);
void gprs_pcu_set_max_mcs(struct gprs_pcu *pcu, uint8_t mcs_dl, uint8_t mcs_ul);

View File

@@ -18,28 +18,61 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <gprs_bssgp_pcu.h>
extern "C" {
#include <osmocom/gsm/gsm48.h>
}
#include <pcu_l1_if.h>
#include <gprs_rlcmac.h>
#include <bts.h>
#include <encoding.h>
#include <tbf.h>
#include <gprs_debug.h>
extern void *tall_pcu_ctx;
int gprs_rlcmac_paging_request(uint8_t *ptmsi, uint16_t ptmsi_len,
const char *imsi)
int gprs_rlcmac_paging_request(struct gprs_rlcmac_bts *bts, const struct osmo_mobile_identity *mi,
uint16_t pgroup)
{
LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] Paging Request (CCCH)\n");
bitvec *paging_request = bitvec_alloc(23);
bitvec_unhex(paging_request, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
int plen = Encoding::write_paging_request(paging_request, ptmsi, ptmsi_len);
pcu_l1if_tx_pch(paging_request, plen, (char *)imsi);
if (log_check_level(DRLCMAC, LOGL_NOTICE)) {
char str[64];
osmo_mobile_identity_to_str_buf(str, sizeof(str), mi);
LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] Paging Request (CCCH) MI=%s\n", str);
}
bitvec *paging_request = bitvec_alloc(22, tall_pcu_ctx);
bitvec_unhex(paging_request, DUMMY_VEC);
int plen = Encoding::write_paging_request(paging_request, mi);
if (plen <= 0) {
LOGP(DRLCMAC, LOGL_ERROR, "TX: [PCU -> BTS] Failed to encode Paging Request\n");
return -1;
}
bts_do_rate_ctr_inc(bts, CTR_PCH_REQUESTS);
pcu_l1if_tx_pch(bts, paging_request, plen, pgroup);
bitvec_free(paging_request);
return 0;
}
/* Encode Application Information Request to Packet Application Information (3GPP TS 44.060 11.2.47) */
struct msgb *gprs_rlcmac_app_info_msg(const struct gsm_pcu_if_app_info_req *req) {
struct msgb *msg;
uint16_t msgb_len = req->len + 1;
struct bitvec bv = {0, msgb_len, NULL};
const enum bit_value page_mode[] = {ZERO, ZERO}; /* Normal Paging (3GPP TS 44.060 12.20) */
if (!req->len) {
LOGP(DRLCMAC, LOGL_ERROR, "Application Information Request with zero length received!\n");
return NULL;
}
msg = msgb_alloc(msgb_len, "app_info_msg");
if (!msg)
return NULL;
bv.data = msgb_put(msg, msgb_len);
bitvec_set_bits(&bv, page_mode, 2);
bitvec_set_uint(&bv, req->application_type, 4);
bitvec_set_bytes(&bv, req->data, req->len);
return msg;
}

View File

@@ -17,18 +17,25 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef GPRS_RLCMAC_H
#define GPRS_RLCMAC_H
#ifdef __cplusplus
#include <bitvector.h>
#include <gsm_rlcmac.h>
#include <gsm_timer.h>
#include <stdbool.h>
#include <stdint.h>
#include <pcu_l1_if.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/bitvec.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/pcu/pcuif_proto.h>
#include "gsm_rlcmac.h"
#ifdef __cplusplus
}
#endif
@@ -38,10 +45,11 @@ extern "C" {
*/
//#define DEBUG_DL_ASS_IDLE
#define DUMMY_VEC "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"
struct gprs_rlcmac_tbf;
struct gprs_rlcmac_bts;
struct BTS;
struct GprsMs;
#ifdef __cplusplus
/*
@@ -62,47 +70,54 @@ struct gprs_rlcmac_cs {
uint8_t block_payload;
};
int gprs_rlcmac_received_lost(struct gprs_rlcmac_tbf *tbf, uint16_t received,
/* TS allocation internal functions */
int find_multi_slots(struct gprs_rlcmac_trx *trx, uint8_t mslot_class, uint8_t *ul_slots, uint8_t *dl_slots);
int gprs_rlcmac_received_lost(struct gprs_rlcmac_dl_tbf *tbf, uint16_t received,
uint16_t lost);
int gprs_rlcmac_lost_rep(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_lost_rep(struct gprs_rlcmac_dl_tbf *tbf);
int gprs_rlcmac_meas_rep(Packet_Measurement_Report_t *pmr);
int gprs_rlcmac_meas_rep(GprsMs *ms, Packet_Measurement_Report_t *pmr);
int gprs_rlcmac_rssi(struct gprs_rlcmac_tbf *tbf, int8_t rssi);
int gprs_rlcmac_rssi_rep(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_dl_bw(struct gprs_rlcmac_tbf *tbf, uint16_t octets);
int gprs_rlcmac_dl_bw(struct gprs_rlcmac_dl_tbf *tbf, uint16_t octets);
/* TS 44.060 Section 10.4.7 Table 10.4.7.1: Payload Type field */
enum gprs_rlcmac_block_type {
GPRS_RLCMAC_DATA_BLOCK = 0x0,
GPRS_RLCMAC_CONTROL_BLOCK = 0x1,
GPRS_RLCMAC_CONTROL_BLOCK = 0x1,
GPRS_RLCMAC_CONTROL_BLOCK_OPT = 0x2,
GPRS_RLCMAC_RESERVED = 0x3
};
int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_paging_request(uint8_t *ptmsi, uint16_t ptmsi_len,
const char *imsi);
struct msgb *gprs_rlcmac_app_info_msg(const struct gsm_pcu_if_app_info_req *req);
int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint16_t arfcn,
uint8_t trx, uint8_t ts,
uint32_t fn, uint8_t block_nr);
extern "C" {
#endif
int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf, bool single,
int8_t use_trx);
int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf,
struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf, bool single,
int8_t use_trx);
int alloc_algorithm_dynamic(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf, bool single,
int8_t use_trx);
int gprs_rlcmac_paging_request(struct gprs_rlcmac_bts *bts, const struct osmo_mobile_identity *mi, uint16_t pgroup);
int gprs_alloc_max_dl_slots_per_ms(const struct gprs_rlcmac_bts *bts, uint8_t ms_class);
#ifdef __cplusplus
}
#endif
#endif // GPRS_RLCMAC_H

View File

@@ -16,11 +16,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
extern "C" {
#include <osmocom/core/timer_compat.h>
}
#include <gprs_rlcmac.h>
#include <gprs_debug.h>
#include <pcu_l1_if.h>
#include <tbf.h>
#include <tbf_dl.h>
#include <gprs_ms.h>
#include <string.h>
#include <errno.h>
@@ -28,17 +34,16 @@
/*
* downlink measurement
*/
#warning "TODO: trigger the measurement report from the pollcontroller and use it for flow control"
/* TODO: trigger the measurement report from the pollcontroller and use it for flow control */
/* received Measurement Report */
int gprs_rlcmac_meas_rep(Packet_Measurement_Report_t *pmr)
int gprs_rlcmac_meas_rep(GprsMs *ms, Packet_Measurement_Report_t *pmr)
{
NC_Measurement_Report_t *ncr;
NC_Measurements_t *nc;
int i;
LOGP(DRLCMACMEAS, LOGL_INFO, "Measuement Report of TLLI=0x%08x:",
pmr->TLLI);
LOGPMS(ms, DRLCMACMEAS, LOGL_INFO, "Rx Measurement Report:");
switch (pmr->UnionType) {
case 0:
@@ -71,22 +76,22 @@ int gprs_rlcmac_meas_rep(Packet_Measurement_Report_t *pmr)
/* RSSI values received from MS */
int gprs_rlcmac_rssi(struct gprs_rlcmac_tbf *tbf, int8_t rssi)
{
struct timeval now_tv, *rssi_tv = &tbf->meas.rssi_tv;
uint32_t elapsed;
struct timespec now_tv, *rssi_tv = &tbf->meas.rssi_tv;
struct timespec elapsed;
tbf->meas.rssi_sum += rssi;
tbf->meas.rssi_num++;
gettimeofday(&now_tv, NULL);
elapsed = ((now_tv.tv_sec - rssi_tv->tv_sec) << 7)
+ ((now_tv.tv_usec - rssi_tv->tv_usec) << 7) / 1000000;
if (elapsed < 128)
osmo_clock_gettime(CLOCK_MONOTONIC, &now_tv);
timespecsub(&now_tv, rssi_tv, &elapsed);
if (elapsed.tv_sec < 1)
return 0;
gprs_rlcmac_rssi_rep(tbf);
/* reset rssi values and timestamp */
memcpy(rssi_tv, &now_tv, sizeof(struct timeval));
memcpy(rssi_tv, &now_tv, sizeof(*rssi_tv));
tbf->meas.rssi_sum = 0;
tbf->meas.rssi_num = 0;
@@ -100,8 +105,8 @@ int gprs_rlcmac_rssi_rep(struct gprs_rlcmac_tbf *tbf)
if (!tbf->meas.rssi_num)
return -EINVAL;
LOGP(DRLCMACMEAS, LOGL_INFO, "UL RSSI of TLLI=0x%08x: %d dBm\n",
tbf->tlli(), tbf->meas.rssi_sum / tbf->meas.rssi_num);
LOGPMS(tbf->ms(), DRLCMACMEAS, LOGL_INFO, "UL RSSI: %d dBm\n",
tbf->meas.rssi_sum / tbf->meas.rssi_num);
return 0;
}
@@ -112,11 +117,11 @@ int gprs_rlcmac_rssi_rep(struct gprs_rlcmac_tbf *tbf)
*/
/* Lost frames reported from RLCMAC layer */
int gprs_rlcmac_received_lost(struct gprs_rlcmac_tbf *tbf, uint16_t received,
int gprs_rlcmac_received_lost(struct gprs_rlcmac_dl_tbf *tbf, uint16_t received,
uint16_t lost)
{
struct timeval now_tv, *loss_tv = &tbf->meas.dl_loss_tv;
uint32_t elapsed;
struct timespec now_tv, *loss_tv = &tbf->m_bw.dl_loss_tv;
struct timespec elapsed;
uint16_t sum = received + lost;
/* No measurement values */
@@ -126,37 +131,36 @@ int gprs_rlcmac_received_lost(struct gprs_rlcmac_tbf *tbf, uint16_t received,
LOGP(DRLCMACMEAS, LOGL_DEBUG, "DL Loss of TLLI 0x%08x: Received: %4d "
"Lost: %4d Sum: %4d\n", tbf->tlli(), received, lost, sum);
tbf->meas.dl_loss_received += received;
tbf->meas.dl_loss_lost += lost;
tbf->m_bw.dl_loss_received += received;
tbf->m_bw.dl_loss_lost += lost;
gettimeofday(&now_tv, NULL);
elapsed = ((now_tv.tv_sec - loss_tv->tv_sec) << 7)
+ ((now_tv.tv_usec - loss_tv->tv_usec) << 7) / 1000000;
if (elapsed < 128)
osmo_clock_gettime(CLOCK_MONOTONIC, &now_tv);
timespecsub(&now_tv, loss_tv, &elapsed);
if (elapsed.tv_sec < 1)
return 0;
gprs_rlcmac_lost_rep(tbf);
/* reset lost values and timestamp */
memcpy(loss_tv, &now_tv, sizeof(struct timeval));
tbf->meas.dl_loss_received = 0;
tbf->meas.dl_loss_lost = 0;
memcpy(loss_tv, &now_tv, sizeof(*loss_tv));
tbf->m_bw.dl_loss_received = 0;
tbf->m_bw.dl_loss_lost = 0;
return 0;
}
/* Give Lost report */
int gprs_rlcmac_lost_rep(struct gprs_rlcmac_tbf *tbf)
int gprs_rlcmac_lost_rep(struct gprs_rlcmac_dl_tbf *tbf)
{
uint16_t sum = tbf->meas.dl_loss_lost + tbf->meas.dl_loss_received;
uint16_t sum = tbf->m_bw.dl_loss_lost + tbf->m_bw.dl_loss_received;
/* No measurement values */
if (!sum)
return -EINVAL;
LOGP(DRLCMACMEAS, LOGL_INFO, "DL packet loss of IMSI=%s / TLLI=0x%08x: "
LOGP(DRLCMACMEAS, LOGL_DEBUG, "DL packet loss of IMSI=%s / TLLI=0x%08x: "
"%d%%\n", tbf->imsi(), tbf->tlli(),
tbf->meas.dl_loss_lost * 100 / sum);
tbf->m_bw.dl_loss_lost * 100 / sum);
return 0;
}
@@ -166,27 +170,25 @@ int gprs_rlcmac_lost_rep(struct gprs_rlcmac_tbf *tbf)
* downlink bandwidth
*/
int gprs_rlcmac_dl_bw(struct gprs_rlcmac_tbf *tbf, uint16_t octets)
int gprs_rlcmac_dl_bw(struct gprs_rlcmac_dl_tbf *tbf, uint16_t octets)
{
struct timeval now_tv, *bw_tv = &tbf->meas.dl_bw_tv;
uint32_t elapsed;
struct timespec now_tv, *bw_tv = &tbf->m_bw.dl_bw_tv;
struct timespec elapsed;
tbf->meas.dl_bw_octets += octets;
tbf->m_bw.dl_bw_octets += octets;
gettimeofday(&now_tv, NULL);
elapsed = ((now_tv.tv_sec - bw_tv->tv_sec) << 7)
+ ((now_tv.tv_usec - bw_tv->tv_usec) << 7) / 1000000;
if (elapsed < 128)
osmo_clock_gettime(CLOCK_MONOTONIC, &now_tv);
timespecsub(&now_tv, bw_tv, &elapsed);
if (elapsed.tv_sec < 1)
return 0;
tbf->m_bw.dl_throughput = (tbf->m_bw.dl_bw_octets << 10) / ((elapsed.tv_sec << 10) + (elapsed.tv_nsec >> 20));
LOGP(DRLCMACMEAS, LOGL_INFO, "DL Bandwitdh of IMSI=%s / TLLI=0x%08x: "
"%d KBits/s\n", tbf->imsi(), tbf->tlli(),
tbf->meas.dl_bw_octets / elapsed);
"%d KBits/s\n", tbf->imsi(), tbf->tlli(), tbf->m_bw.dl_throughput);
/* reset bandwidth values timestamp */
memcpy(bw_tv, &now_tv, sizeof(struct timeval));
tbf->meas.dl_bw_octets = 0;
memcpy(bw_tv, &now_tv, sizeof(*bw_tv));
tbf->m_bw.dl_bw_octets = 0;
return 0;
}

View File

@@ -16,72 +16,81 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <gprs_bssgp_pcu.h>
#include <gprs_rlcmac.h>
#include <pcu_l1_if.h>
#include <bts.h>
#include <tbf.h>
#include <tbf_ul.h>
#include <gprs_debug.h>
#include <gprs_ms.h>
#include <rlc.h>
#include <sba.h>
#include <pdch.h>
#include "pcu_utils.h"
static uint32_t sched_poll(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr,
struct gprs_rlcmac_tbf **poll_tbf,
struct gprs_rlcmac_tbf **ul_ass_tbf,
struct gprs_rlcmac_tbf **dl_ass_tbf,
struct gprs_rlcmac_tbf **ul_ack_tbf)
{
struct gprs_rlcmac_tbf *tbf;
uint32_t poll_fn;
/* check special TBF for events */
poll_fn = fn + 4;
if ((block_nr % 3) == 2)
poll_fn ++;
poll_fn = poll_fn % 2715648;
llist_for_each_entry(tbf, &bts->ul_tbfs, list) {
/* this trx, this ts */
if (tbf->trx->trx_no != trx || tbf->control_ts != ts)
continue;
/* polling for next uplink block */
if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
&& tbf->poll_fn == poll_fn)
*poll_tbf = tbf;
if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK)
*ul_ack_tbf = tbf;
if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS)
*dl_ass_tbf = tbf;
if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS)
*ul_ass_tbf = tbf;
#warning "Is this supposed to be fair? The last TBF for each wins? Maybe use llist_add_tail and skip once we have all states?"
}
llist_for_each_entry(tbf, &bts->dl_tbfs, list) {
/* this trx, this ts */
if (tbf->trx->trx_no != trx || tbf->control_ts != ts)
continue;
/* polling for next uplink block */
if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
&& tbf->poll_fn == poll_fn)
*poll_tbf = tbf;
if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS)
*dl_ass_tbf = tbf;
if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS)
*ul_ass_tbf = tbf;
}
return poll_fn;
extern "C" {
#include <osmocom/core/gsmtap.h>
}
static uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,
uint8_t block_nr, struct gprs_rlcmac_pdch *pdch)
struct tbf_sched_candidates {
struct gprs_rlcmac_tbf *ul_ass;
struct gprs_rlcmac_tbf *dl_ass;
struct gprs_rlcmac_tbf *nacc;
struct gprs_rlcmac_ul_tbf *ul_ack;
};
static void get_ctrl_msg_tbf_candidates(const struct gprs_rlcmac_pdch *pdch,
struct tbf_sched_candidates *tbf_cand)
{
struct gprs_rlcmac_tbf *tbf;
uint8_t usf = 0x07;
struct gprs_rlcmac_ul_tbf *ul_tbf;
struct gprs_rlcmac_dl_tbf *dl_tbf;
struct llist_item *pos;
llist_for_each_entry(pos, &pdch->trx->ul_tbfs, list) {
ul_tbf = as_ul_tbf((struct gprs_rlcmac_tbf *)pos->entry);
OSMO_ASSERT(ul_tbf);
/* this trx, this ts */
if (!ul_tbf->is_control_ts(pdch->ts_no))
continue;
if (tbf_ul_ack_rts(ul_tbf))
tbf_cand->ul_ack = ul_tbf;
if (tbf_dl_ass_rts(ul_tbf))
tbf_cand->dl_ass = ul_tbf;
if (tbf_ul_ass_rts(ul_tbf))
tbf_cand->ul_ass = ul_tbf;
/* NACC ready to send. TFI assigned is needed to send messages */
if (ul_tbf->is_tfi_assigned() && ms_nacc_rts(ul_tbf->ms()))
tbf_cand->nacc = ul_tbf;
/* FIXME: Is this supposed to be fair? The last TBF for each wins? Maybe use llist_add_tail and skip once we have all
states? */
}
llist_for_each_entry(pos, &pdch->trx->dl_tbfs, list) {
dl_tbf = as_dl_tbf((struct gprs_rlcmac_tbf *)pos->entry);
OSMO_ASSERT(dl_tbf);
/* this trx, this ts */
if (!dl_tbf->is_control_ts(pdch->ts_no))
continue;
if (tbf_dl_ass_rts(dl_tbf))
tbf_cand->dl_ass = dl_tbf;
if (tbf_ul_ass_rts(dl_tbf))
tbf_cand->ul_ass = dl_tbf;
/* NACC ready to send. TFI assigned is needed to send messages */
if (dl_tbf->is_tfi_assigned() && ms_nacc_rts(dl_tbf->ms()))
tbf_cand->nacc = dl_tbf;
}
}
static struct gprs_rlcmac_ul_tbf *sched_select_uplink(struct gprs_rlcmac_pdch *pdch, bool require_gprs_only)
{
struct gprs_rlcmac_ul_tbf *tbf;
uint8_t i, tfi;
/* select uplink resource */
for (i = 0, tfi = pdch->next_ul_tfi; i < 32;
i++, tfi = (tfi + 1) & 31) {
tbf = pdch->ul_tbf[tfi];
tbf = pdch->ul_tbf_by_tfi(tfi);
/* no TBF for this tfi, go next */
if (!tbf)
continue;
@@ -89,79 +98,206 @@ static uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,
/* we don't need to give resources in FINISHED state,
* because we have received all blocks and only poll
* for packet control ack. */
if (tbf->state_is_not(GPRS_RLCMAC_FLOW))
if (tbf->state_is_not(TBF_ST_FLOW))
continue;
/* use this USF */
usf = tbf->dir.ul.usf[ts];
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
"TS=%d FN=%d block_nr=%d scheduling USF=%d for "
"required uplink resource of UL TFI=%d\n", trx, ts, fn,
block_nr, usf, tfi);
if (require_gprs_only && tbf->is_egprs_enabled())
continue;
/* use this USF (tbf) */
/* next TBF to handle resource is the next one */
pdch->next_ul_tfi = (tfi + 1) & 31;
break;
return tbf;
}
return usf;
return NULL;
}
static struct msgb *sched_select_ctrl_msg(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint32_t fn,
uint8_t block_nr, struct gprs_rlcmac_pdch *pdch,
struct gprs_rlcmac_tbf *ul_ass_tbf,
struct gprs_rlcmac_tbf *dl_ass_tbf,
struct gprs_rlcmac_tbf *ul_ack_tbf)
struct msgb *sched_app_info(struct gprs_rlcmac_tbf *tbf) {
struct gprs_rlcmac_bts *bts;
struct msgb *msg = NULL;
if (!tbf || !tbf->ms()->app_info_pending)
return NULL;
bts = tbf->bts;
if (bts->app_info) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Sending Packet Application Information message\n");
msg = msgb_copy(bts->app_info, "app_info_msg_sched");
} else
LOGP(DRLCMACSCHED, LOGL_ERROR, "MS has app_info_pending flag set, but no Packet Application Information"
" message stored in BTS!\n");
tbf->ms()->app_info_pending = false;
bts->app_info_pending--;
if (!bts->app_info_pending) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Packet Application Information successfully sent to all MS with active"
" TBF\n");
msgb_free(bts->app_info);
bts->app_info = NULL;
}
return msg;
}
static struct msgb *sched_select_ctrl_msg(struct gprs_rlcmac_pdch *pdch, uint32_t fn,
uint8_t block_nr, struct tbf_sched_candidates *tbfs)
{
struct msgb *msg = NULL;
struct gprs_rlcmac_tbf *tbf = NULL;
struct gprs_rlcmac_tbf *next_list[] = { tbfs->ul_ass,
tbfs->dl_ass,
tbfs->ul_ack,
tbfs->nacc };
uint8_t ts = pdch->ts_no;
/* schedule PACKET UPLINK ASSIGNMENT (1st priority) */
if (ul_ass_tbf) {
tbf = ul_ass_tbf;
msg = tbf->create_ul_ass(fn);
/* Send Packet Application Information first (ETWS primary notifications) */
msg = sched_app_info(tbfs->dl_ass);
if (!msg) {
for (size_t i = 0; i < ARRAY_SIZE(next_list); ++i) {
tbf = next_list[(pdch->next_ctrl_prio + i) % ARRAY_SIZE(next_list)];
if (!tbf)
continue;
/*
* Assignments for the same direction have lower precedence,
* because they may kill the TBF when the CONTROL ACK is
* received, thus preventing the others from being processed.
*/
if (tbf == tbfs->ul_ass && tbf->ul_ass_state_is(TBF_UL_ASS_SEND_ASS_REJ))
msg = tbf_ul_ass_create_rlcmac_msg(tbfs->ul_ass, fn, ts);
else if (tbf == tbfs->ul_ass && tbf->direction == GPRS_RLCMAC_DL_TBF)
msg = tbf_ul_ass_create_rlcmac_msg(tbfs->ul_ass, fn, ts);
else if (tbf == tbfs->dl_ass && tbf->direction == GPRS_RLCMAC_UL_TBF)
msg = tbf_dl_ass_create_rlcmac_msg(tbfs->dl_ass, fn, ts);
else if (tbf == tbfs->ul_ack)
msg = tbf_ul_ack_create_rlcmac_msg(tbfs->ul_ack, fn, ts);
else if (tbf == tbfs->nacc) {
msg = ms_nacc_create_rlcmac_msg(tbf->ms(), tbf, fn, ts);
}
if (!msg) {
tbf = NULL;
continue;
}
pdch->next_ctrl_prio = (pdch->next_ctrl_prio + 1) % ARRAY_SIZE(next_list);
break;
}
}
/* schedule PACKET DOWNLINK ASSIGNMENT (2nd priotiry) */
if (!msg && dl_ass_tbf) {
tbf = dl_ass_tbf;
msg = tbf->create_dl_ass(fn);
}
/* schedule PACKET UPLINK ACK (3rd priority) */
if (!msg && ul_ack_tbf) {
tbf = ul_ack_tbf;
msg = tbf->create_ul_ack(fn);
if (!msg) {
/*
* If one of these is left, the response (CONTROL ACK) from the
* MS will kill the current TBF, only one of them can be
* non-NULL
*/
if (tbfs->dl_ass) {
tbf = tbfs->dl_ass;
msg = tbf_dl_ass_create_rlcmac_msg(tbfs->dl_ass, fn, ts);
} else if (tbfs->ul_ass) {
tbf = tbfs->ul_ass;
msg = tbf_ul_ass_create_rlcmac_msg(tbfs->ul_ass, fn, ts);
}
}
/* any message */
if (msg) {
if (!tbf) {
LOGPDCH(pdch, DRLCMACSCHED, LOGL_ERROR, "FN=%" PRIu32
" Control message to be scheduled, but no TBF\n", fn);
msgb_free(msg);
return NULL;
}
tbf->rotate_in_list();
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control "
"message at RTS for %s (TRX=%d, TS=%d)\n",
tbf_name(tbf), trx, ts);
LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "FN=%" PRIu32
" Scheduling control message at RTS for %s\n",
fn, tbf_name(tbf));
rate_ctr_inc(rate_ctr_group_get_ctr(tbf->ms()->ctrs, MS_CTR_DL_CTRL_MSG_SCHED));
return msg;
}
/* schedule PACKET PAGING REQUEST */
/* schedule PACKET PAGING REQUEST, if any are pending */
msg = pdch->packet_paging_request();
if (msg) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging request "
"message at RTS for (TRX=%d, TS=%d)\n", trx, ts);
LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "FN=%" PRIu32
" Scheduling paging request message at RTS\n", fn);
return msg;
}
return NULL;
}
static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint32_t fn,
uint8_t block_nr, struct gprs_rlcmac_pdch *pdch)
static inline enum tbf_dl_prio tbf_compute_priority(const struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_dl_tbf *tbf,
uint8_t ts, uint32_t fn, int age)
{
const gprs_rlc_dl_window *w = static_cast<gprs_rlc_dl_window *>(tbf->window());
unsigned long msecs_t3190 = osmo_tdef_get(the_pcu->T_defs, 3190, OSMO_TDEF_MS, -1);
unsigned long dl_tbf_idle_msec = osmo_tdef_get(the_pcu->T_defs, -2031, OSMO_TDEF_MS, -1);
int age_thresh1 = msecs_to_frames(200);
int age_thresh2 = msecs_to_frames(OSMO_MIN(msecs_t3190/2, dl_tbf_idle_msec));
if (tbf->is_control_ts(ts) && tbf->need_poll_for_dl_ack_nack())
return DL_PRIO_CONTROL;
if (tbf->is_control_ts(ts) && age > age_thresh2 && age_thresh2 > 0)
return DL_PRIO_HIGH_AGE;
if ((tbf->state_is(TBF_ST_FLOW) && tbf->have_data()) || w->resend_needed() >= 0)
return DL_PRIO_NEW_DATA;
if (tbf->is_control_ts(ts) && age > age_thresh1 && tbf->keep_open(fn))
return DL_PRIO_LOW_AGE;
if (!w->window_empty())
return DL_PRIO_SENT_DATA;
return DL_PRIO_NONE;
}
/* Check if next data block of a TBF can be encoded in GMSK [(M)CS1-4]. */
static bool can_produce_gmsk_data_block_next(struct gprs_rlcmac_dl_tbf *tbf, enum tbf_dl_prio prio)
{
const gprs_rlc_dl_window *w;
/* GPRS TBFs can always send GMSK */
if (!tbf->is_egprs_enabled())
return true;
switch (prio) {
case DL_PRIO_CONTROL:
/* Control blocks are always CS-1 */
return true;
case DL_PRIO_NEW_DATA:
/* We can send any new data (no block generated yet) using any
* MCS. However, we don't (yet) support resegmenting already
* sent blocks (NACKed blocks in this case) into lower MCS of
* the same family. See OS#4966 */
w = static_cast<gprs_rlc_dl_window *>(tbf->window());
return w->resend_needed() < 0;
default:
return false;
}
}
static struct msgb *sched_select_dl_data_msg(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_pdch *pdch,
uint32_t fn, uint8_t block_nr, enum mcs_kind req_mcs_kind,
bool *is_egprs)
{
struct msgb *msg = NULL;
struct gprs_rlcmac_tbf *tbf = NULL;
uint8_t i, tfi;
struct gprs_rlcmac_dl_tbf *tbf, *prio_tbf = NULL;
enum tbf_dl_prio prio, max_prio = DL_PRIO_NONE;
uint8_t ts = pdch->ts_no;
uint8_t i, tfi, prio_tfi;
int age;
/* select downlink resource */
for (i = 0, tfi = pdch->next_dl_tfi; i < 32;
i++, tfi = (tfi + 1) & 31) {
tbf = pdch->dl_tbf[tfi];
tbf = pdch->dl_tbf_by_tfi(tfi);
/* no TBF for this tfi, go next */
if (!tbf)
continue;
@@ -169,21 +305,48 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
if (tbf->direction != GPRS_RLCMAC_DL_TBF)
continue;
/* no DL resources needed, go next */
if (tbf->state_is_not(GPRS_RLCMAC_FLOW)
&& tbf->state_is_not(GPRS_RLCMAC_FINISHED))
if (tbf->state_is_not(TBF_ST_FLOW)
&& tbf->state_is_not(TBF_ST_FINISHED))
continue;
/* waiting for CCCH IMM.ASS confirm */
if (tbf->dir.dl.wait_confirm)
/* If a GPRS (CS1-4) Dl block is required, skip EGPRS(_GSMK) tbfs: */
if (req_mcs_kind == GPRS && tbf->is_egprs_enabled())
continue;
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data message at "
"RTS for DL TFI=%d (TRX=%d, TS=%d)\n", tfi, trx, ts);
age = tbf->frames_since_last_poll(fn);
/* compute priority */
prio = tbf_compute_priority(bts, tbf, ts, fn, age);
if (prio == DL_PRIO_NONE)
continue;
/* If a GPRS (CS1-4/MCS1-4) Dl block is required, downgrade MCS
* below instead of skipping. However, downgrade can only be
* done on new data BSNs (not yet sent) and control blocks. */
if (req_mcs_kind == EGPRS_GMSK && !can_produce_gmsk_data_block_next(tbf, prio)) {
LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "FN=%" PRIu32
" Cannot downgrade EGPRS TBF with prio %d for %s\n",
fn, prio, tbf_name(tbf));
continue;
}
/* get the TBF with the highest priority */
if (prio > max_prio) {
prio_tfi = tfi;
prio_tbf = tbf;
max_prio = prio;
}
}
if (prio_tbf) {
LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "FN=%" PRIu32
" Scheduling data message at RTS for DL TFI=%d prio=%d mcs_mode_restrict=%s\n",
fn, prio_tfi, max_prio, mode_name(req_mcs_kind));
/* next TBF to handle resource is the next one */
pdch->next_dl_tfi = (tfi + 1) & 31;
pdch->next_dl_tfi = (prio_tfi + 1) & 31;
/* generate DL data block */
msg = tbf->create_dl_acked_block(fn, ts);
break;
msg = prio_tbf->create_dl_acked_block(fn, ts, req_mcs_kind);
*is_egprs = prio_tbf->is_egprs_enabled();
}
return msg;
@@ -209,74 +372,171 @@ static struct msgb *sched_dummy(void)
return msg;
}
static inline void tap_n_acc(const struct msgb *msg, struct gprs_rlcmac_bts *bts, uint8_t trx, uint8_t ts,
uint32_t fn, enum pcu_gsmtap_category cat)
{
if (!msg)
return;
switch(cat) {
case PCU_GSMTAP_C_DL_CTRL:
bts_do_rate_ctr_inc(bts, CTR_RLC_SENT_CONTROL);
bts_send_gsmtap(bts, PCU_GSMTAP_C_DL_CTRL, false, trx, ts, GSMTAP_CHANNEL_PACCH, fn, msg->data,
msg->len);
break;
case PCU_GSMTAP_C_DL_DATA_GPRS:
case PCU_GSMTAP_C_DL_DATA_EGPRS:
bts_do_rate_ctr_inc(bts, CTR_RLC_SENT);
bts_send_gsmtap(bts, cat, false, trx, ts, GSMTAP_CHANNEL_PDTCH, fn, msg->data,
msg->len);
break;
case PCU_GSMTAP_C_DL_DUMMY:
bts_do_rate_ctr_inc(bts, CTR_RLC_SENT_DUMMY);
bts_send_gsmtap(bts, PCU_GSMTAP_C_DL_DUMMY, false, trx, ts, GSMTAP_CHANNEL_PACCH, fn, msg->data,
msg->len);
break;
default:
break;
}
}
int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint16_t arfcn,
uint8_t trx, uint8_t ts,
uint32_t fn, uint8_t block_nr)
{
struct gprs_rlcmac_pdch *pdch;
struct gprs_rlcmac_tbf *poll_tbf = NULL, *dl_ass_tbf = NULL,
*ul_ass_tbf = NULL, *ul_ack_tbf = NULL;
uint8_t usf = 0x7;
struct tbf_sched_candidates tbf_cand = {0};
struct gprs_rlcmac_tbf *poll_tbf;
struct gprs_rlcmac_ul_tbf *usf_tbf = NULL;
struct gprs_rlcmac_sba *sba;
uint8_t usf;
struct msgb *msg = NULL;
uint32_t poll_fn, sba_fn;
#warning "ARFCN... it is already in the TRX..... is it consistent with it?"
uint32_t poll_fn;
enum pcu_gsmtap_category gsmtap_cat = PCU_GSMTAP_C_DL_DUMMY; /* init: make gcc happy */
bool tx_is_egprs = false;
bool require_gprs_only;
enum mcs_kind req_mcs_kind; /* Restrict CS/MCS if DL Data block is to be sent */
if (trx >= 8 || ts >= 8)
return -EINVAL;
pdch = &bts->trx[trx].pdch[ts];
if (!pdch->is_enabled()) {
LOGP(DRLCMACSCHED, LOGL_ERROR, "Received RTS on disabled PDCH: "
"TRX=%d TS=%d\n", trx, ts);
LOGPDCH(pdch, DRLCMACSCHED, LOGL_INFO, "Received RTS on disabled TS\n");
return -EIO;
}
/* store last frame number of RTS */
pdch->last_rts_fn = fn;
poll_fn = sched_poll(bts, trx, ts, fn, block_nr, &poll_tbf, &ul_ass_tbf,
&dl_ass_tbf, &ul_ack_tbf);
/* check uplink resource for polling */
if (poll_tbf)
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
"TS=%d FN=%d block_nr=%d scheduling free USF for "
"polling at FN=%d of %s\n", trx, ts, fn,
block_nr, poll_fn,
tbf_name(poll_tbf));
/* use free USF */
/* else. check for sba */
else if ((sba_fn = bts->bts->sba()->sched(trx, ts, fn, block_nr) != 0xffffffff))
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
"TS=%d FN=%d block_nr=%d scheduling free USF for "
"single block allocation at FN=%d\n", trx, ts, fn,
block_nr, sba_fn);
/* use free USF */
/* else, we search for uplink resource */
else
usf = sched_select_uplink(trx, ts, fn, block_nr, pdch);
/* require_gprs_only: Prioritize USF for GPRS-only MS here,
* since anyway we'll need to tx a Dl block with CS1-4 due to
* synchronization requirements. See 3GPP TS 03.64 version
* 8.12.0
*/
require_gprs_only = (pdch->fn_without_cs14 == MS_RESYNC_NUM_FRAMES - 1);
if (require_gprs_only) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "TRX=%d TS=%d FN=%d "
"synchronization frame (every 18 frames), only CS1-4 allowed",
trx, ts, fn);
req_mcs_kind = GPRS; /* only GPRS CS1-4 allowed, all MS need to be able to decode it */
} else {
req_mcs_kind = EGPRS; /* all kinds are fine */
}
/* polling for next uplink block */
poll_fn = rts_next_fn(fn, block_nr);
/* check for sba */
if ((sba = pdch_ulc_get_sba(pdch->ulc, poll_fn))) {
LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: "
"FN=%d block_nr=%d scheduling free USF for "
"single block allocation at FN=%d\n", fn, block_nr, sba->fn);
/* else, check uplink resource for polling */
} else if ((poll_tbf = pdch_ulc_get_tbf_poll(pdch->ulc, poll_fn))) {
LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: FN=%d "
"block_nr=%d scheduling free USF for polling at FN=%d of %s\n",
fn, block_nr, poll_fn, tbf_name(poll_tbf));
/* If POLL TBF is UL and already has a USF assigned on this TS,
* let's set its USF in the DL msg. This is not really needed,
* but it helps understand better the flow when looking at
* pcaps. */
if (poll_tbf->direction == GPRS_RLCMAC_UL_TBF && as_ul_tbf(poll_tbf)->m_usf[ts] != USF_INVALID)
usf_tbf = as_ul_tbf(poll_tbf);
/* else, search for uplink tbf */
} else if ((usf_tbf = sched_select_uplink(pdch, require_gprs_only))) {
LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: FN=%d "
"block_nr=%d scheduling USF=%d for %s, expect answer on UL FN=%d\n",
fn, block_nr, usf_tbf->m_usf[pdch->ts_no], tbf_name(usf_tbf), poll_fn);
pdch_ulc_reserve_tbf_usf(pdch->ulc, poll_fn, usf_tbf);
}
/* If MS selected for USF is GPRS-only, then it will only be
* able to read USF if dl block uses GMSK (CS1-4, MCS1-4) */
if (usf_tbf && req_mcs_kind == EGPRS && ms_mode(usf_tbf->ms()) != EGPRS)
req_mcs_kind = EGPRS_GMSK;
get_ctrl_msg_tbf_candidates(pdch, &tbf_cand);
/* Prio 1: select control message */
msg = sched_select_ctrl_msg(bts, trx, ts, fn, block_nr, pdch, ul_ass_tbf,
dl_ass_tbf, ul_ack_tbf);
if ((msg = sched_select_ctrl_msg(pdch, fn, block_nr, &tbf_cand))) {
gsmtap_cat = PCU_GSMTAP_C_DL_CTRL;
}
/* Prio 2: select data message for downlink */
if (!msg)
msg = sched_select_downlink(bts, trx, ts, fn, block_nr, pdch);
else if((msg = sched_select_dl_data_msg(bts, pdch, fn, block_nr, req_mcs_kind, &tx_is_egprs))) {
gsmtap_cat = tx_is_egprs ? PCU_GSMTAP_C_DL_DATA_EGPRS :
PCU_GSMTAP_C_DL_DATA_GPRS;
}
/* Prio 3: send dummy control message if need to poll or USF */
else {
/* If there's no TBF attached to this PDCH, we can submit an empty
* data_req since there's nothing to transmit nor to poll/USF. This
* way we help BTS energy saving (on TRX!=C0) by sending nothing
* instead of a dummy block. The early return is done here and
* not at the start of the function because the condition below
* (num_tbfs==0) may not be enough, because temporary dummy TBFs
* created to send Imm Ass Rej (see handle_tbf_reject()) don't
* have a TFI assigned and hence are not attached to the PDCH
* TS, so they don't show up in the count below.
*/
const unsigned num_tbfs = pdch->num_tbfs(GPRS_RLCMAC_DL_TBF)
+ pdch->num_tbfs(GPRS_RLCMAC_UL_TBF);
bool skip_idle = (num_tbfs == 0);
#ifdef ENABLE_DIRECT_PHY
/* In DIRECT_PHY mode we want to always submit something to L1 in
* TRX0, since BTS is not preparing dummy bursts on idle TS for us */
skip_idle = skip_idle && trx != 0;
#endif
if (!skip_idle && (msg = sched_dummy())) {
/* increase counter */
gsmtap_cat = PCU_GSMTAP_C_DL_DUMMY;
} else {
msg = NULL; /* submit empty frame */
}
}
/* Prio 3: send dummy contol message */
if (!msg)
msg = sched_dummy();
if (tx_is_egprs && pdch->has_gprs_only_tbf_attached()) {
pdch->fn_without_cs14 += 1;
} else {
pdch->fn_without_cs14 = 0;
}
if (!msg)
return -ENOMEM;
/* msg is now available */
/* Used to measure the leak rate, count all blocks */
gprs_bssgp_update_frames_sent();
/* set USF */
msg->data[0] = (msg->data[0] & 0xf8) | usf;
if (msg) {
/* msg is now available */
bts_do_rate_ctr_add(bts, CTR_RLC_DL_BYTES, msgb_length(msg));
/* send PDTCH/PACCH to L1 */
pcu_l1if_tx_pdtch(msg, trx, ts, arfcn, fn, block_nr);
/* set USF */
OSMO_ASSERT(msgb_length(msg) > 0);
usf = usf_tbf ? usf_tbf->m_usf[ts] : USF_UNUSED;
msg->data[0] = (msg->data[0] & 0xf8) | usf;
/* Send to GSMTAP */
tap_n_acc(msg, bts, trx, ts, fn, gsmtap_cat);
}
/* send PDTCH/PACCH to L1. msg=NULL accepted too (idle block) */
pcu_l1if_tx_pdtch(msg, bts, trx, ts, bts->trx[trx].arfcn, fn, block_nr);
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,238 +0,0 @@
/* gsm_timer.cpp
*
* Copyright (C) 2012 Ivan Klyuchnikov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* These store the amount of frame number that we wait until next timer expires. */
static int nearest;
static int *nearest_p;
/*! \addtogroup gsm_timer
* @{
*/
/*! \file gsm_timer.cpp
*/
#include <assert.h>
#include <string.h>
#include <limits.h>
#include <gsm_timer.h>
#include <pcu_l1_if.h>
#include <bts.h>
static struct rb_root timer_root = RB_ROOT;
/*
* TODO: make this depend on the BTS. This means that
* all time functions schedule based on the BTS they
* are scheduled on.
*/
static int get_current_fn()
{
return BTS::main_bts()->current_frame_number();
}
static void __add_gsm_timer(struct osmo_gsm_timer_list *timer)
{
struct rb_node **new_node = &(timer_root.rb_node);
struct rb_node *parent = NULL;
while (*new_node) {
struct osmo_gsm_timer_list *this_timer;
this_timer = container_of(*new_node, struct osmo_gsm_timer_list, node);
parent = *new_node;
if (timer->fn < this_timer->fn)
new_node = &((*new_node)->rb_left);
else
new_node = &((*new_node)->rb_right);
}
rb_link_node(&timer->node, parent, new_node);
rb_insert_color(&timer->node, &timer_root);
}
/*! \brief add a new timer to the timer management
* \param[in] timer the timer that should be added
*/
void osmo_gsm_timer_add(struct osmo_gsm_timer_list *timer)
{
osmo_gsm_timer_del(timer);
timer->active = 1;
INIT_LLIST_HEAD(&timer->list);
__add_gsm_timer(timer);
}
/*! \brief schedule a gsm timer at a given future relative time
* \param[in] timer the to-be-added timer
* \param[in] number of frames from now
*
* This function can be used to (re-)schedule a given timer at a
* specified number of frames in the future. It will
* internally add it to the timer management data structures, thus
* osmo_timer_add() is automatically called.
*/
void
osmo_gsm_timer_schedule(struct osmo_gsm_timer_list *timer, int fn)
{
int current_fn;
current_fn = get_current_fn();
timer->fn = current_fn + fn;
osmo_gsm_timer_add(timer);
}
/*! \brief delete a gsm timer from timer management
* \param[in] timer the to-be-deleted timer
*
* This function can be used to delete a previously added/scheduled
* timer from the timer management code.
*/
void osmo_gsm_timer_del(struct osmo_gsm_timer_list *timer)
{
if (timer->active) {
timer->active = 0;
rb_erase(&timer->node, &timer_root);
/* make sure this is not already scheduled for removal. */
if (!llist_empty(&timer->list))
llist_del_init(&timer->list);
}
}
/*! \brief check if given timer is still pending
* \param[in] timer the to-be-checked timer
* \return 1 if pending, 0 otherwise
*
* This function can be used to determine whether a given timer
* has alredy expired (returns 0) or is still pending (returns 1)
*/
int osmo_gsm_timer_pending(struct osmo_gsm_timer_list *timer)
{
return timer->active;
}
/*
* if we have a nearest frame number return the delta between the current
* FN and the FN of the nearest timer.
* If the nearest timer timed out return NULL and then we will
* dispatch everything after the select
*/
int *osmo_gsm_timers_nearest(void)
{
/* nearest_p is exactly what we need already: NULL if nothing is
* waiting, {0,0} if we must dispatch immediately, and the correct
* delay if we need to wait */
return nearest_p;
}
static void update_nearest(int *cand, int *current)
{
if (*cand != LONG_MAX) {
if (*cand > *current)
nearest = *cand - *current;
else {
/* loop again inmediately */
nearest = 0;
}
nearest_p = &nearest;
} else {
nearest_p = NULL;
}
}
/*
* Find the nearest FN and update s_nearest_time
*/
void osmo_gsm_timers_prepare(void)
{
struct rb_node *node;
int current_fn;
current_fn = get_current_fn();
node = rb_first(&timer_root);
if (node) {
struct osmo_gsm_timer_list *this_timer;
this_timer = container_of(node, struct osmo_gsm_timer_list, node);
update_nearest(&this_timer->fn, &current_fn);
} else {
nearest_p = NULL;
}
}
/*
* fire all timers... and remove them
*/
int osmo_gsm_timers_update(void)
{
int current_fn;
struct rb_node *node;
struct llist_head timer_eviction_list;
struct osmo_gsm_timer_list *this_timer;
int work = 0;
current_fn = get_current_fn();
INIT_LLIST_HEAD(&timer_eviction_list);
for (node = rb_first(&timer_root); node; node = rb_next(node)) {
this_timer = container_of(node, struct osmo_gsm_timer_list, node);
if (this_timer->fn > current_fn)
break;
llist_add(&this_timer->list, &timer_eviction_list);
}
/*
* The callbacks might mess with our list and in this case
* even llist_for_each_entry_safe is not safe to use. To allow
* osmo_gsm_timer_del to be called from within the callback we need
* to restart the iteration for each element scheduled for removal.
*
* The problematic scenario is the following: Given two timers A
* and B that have expired at the same time. Thus, they are both
* in the eviction list in this order: A, then B. If we remove
* timer B from the A's callback, we continue with B in the next
* iteration step, leading to an access-after-release.
*/
restart:
llist_for_each_entry(this_timer, &timer_eviction_list, list) {
osmo_gsm_timer_del(this_timer);
this_timer->cb(this_timer->data);
work = 1;
goto restart;
}
return work;
}
int osmo_gsm_timers_check(void)
{
struct rb_node *node;
int i = 0;
for (node = rb_first(&timer_root); node; node = rb_next(node)) {
i++;
}
return i;
}
/*! }@ */

View File

@@ -1,84 +0,0 @@
/* gsm_timer.h
*
* Copyright (C) 2012 Ivan Klyuchnikov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*! \defgroup timer GSM timers
* @{
*/
/*! \file gsm_timer.h
* \brief GSM timer handling routines
*/
#ifndef GSM_TIMER_H
#define GSM_TIMER_H
extern "C" {
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/linuxrbtree.h>
}
/**
* Timer management:
* - Create a struct osmo_gsm_timer_list
* - Fill out timeout and use add_gsm_timer or
* use schedule_gsm_timer to schedule a timer in
* x frames from now...
* - Use del_gsm_timer to remove the timer
*
* Internally:
* - We hook into select.c to give a frame number of the
* nearest timer. On already passed timers we give
* it a 0 to immediately fire after the select.
* - update_gsm_timers will call the callbacks and remove
* the timers.
*
*/
/*! \brief A structure representing a single instance of a gsm timer */
struct osmo_gsm_timer_list {
struct rb_node node; /*!< \brief rb-tree node header */
struct llist_head list; /*!< \brief internal list header */
int fn; /*!< \brief expiration frame number */
unsigned int active : 1; /*!< \brief is it active? */
void (*cb)(void*); /*!< \brief call-back called at timeout */
void *data; /*!< \brief user data for callback */
};
/**
* timer management
*/
void osmo_gsm_timer_add(struct osmo_gsm_timer_list *timer);
void osmo_gsm_timer_schedule(struct osmo_gsm_timer_list *timer, int fn);
void osmo_gsm_timer_del(struct osmo_gsm_timer_list *timer);
int osmo_gsm_timer_pending(struct osmo_gsm_timer_list *timer);
/*
* internal timer list management
*/
int *osmo_gsm_timers_nearest(void);
void osmo_gsm_timers_prepare(void);
int osmo_gsm_timers_update(void);
int osmo_gsm_timers_check(void);
/*! }@ */
#endif // GSM_TIMER_H

View File

@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <tbf.h>
#include <bts.h>
#include <stdio.h>
@@ -28,11 +27,15 @@ extern "C" {
#include <osmocom/core/msgb.h>
}
#include "pcu_utils.h"
/* reset LLC frame */
void gprs_llc::reset()
{
m_index = 0;
m_length = 0;
memset(frame, 0x42, sizeof(frame));
}
void gprs_llc::reset_frame_space()
@@ -40,9 +43,26 @@ void gprs_llc::reset_frame_space()
m_index = 0;
}
void gprs_llc::enqueue(struct msgb *llc_msg)
/* Put an Unconfirmed Information (UI) Dummy command, see GSM 44.064, 6.4.2.2 */
void gprs_llc::put_dummy_frame(size_t req_len)
{
msgb_enqueue(&queue, llc_msg);
/* The shortest dummy command (the spec requests at least 6 octets) */
static const uint8_t llc_dummy_command[] = {
0x43, 0xc0, 0x01, 0x2b, 0x2b, 0x2b
};
static const size_t max_dummy_command_len = 79;
put_frame(llc_dummy_command, sizeof(llc_dummy_command));
if (req_len > max_dummy_command_len)
req_len = max_dummy_command_len;
/* Add further stuffing, if the requested length exceeds the minimum
* dummy command length */
if (m_length < req_len) {
memset(&frame[m_length], 0x2b, req_len - m_length);
m_length = req_len;
}
}
void gprs_llc::put_frame(const uint8_t *data, size_t len)
@@ -59,33 +79,155 @@ void gprs_llc::append_frame(const uint8_t *data, size_t len)
m_length += len;
}
void gprs_llc::clear(BTS *bts)
{
struct msgb *msg;
while ((msg = msgb_dequeue(&queue))) {
bts->llc_dropped_frame();
msgb_free(msg);
}
}
void gprs_llc::init()
{
INIT_LLIST_HEAD(&queue);
reset();
}
struct msgb *gprs_llc::dequeue()
bool gprs_llc::is_user_data_frame(uint8_t *data, size_t len)
{
return msgb_dequeue(&queue);
if (len < 2)
return false;
if ((data[0] & 0x0f) == 1 /* GPRS_SAPI_GMM */)
return false;
if ((data[0] & 0xe0) != 0xc0 /* LLC UI */)
/* It is not an LLC UI frame, see TS 44.064, 6.3 */
return false;
return true;
}
void llc_queue_init(struct gprs_llc_queue *q)
{
INIT_LLIST_HEAD(&q->m_queue);
q->m_queue_size = 0;
q->m_queue_octets = 0;
q->m_avg_queue_delay = 0;
}
void gprs_llc::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv)
void gprs_llc_queue::enqueue(struct msgb *llc_msg, const struct timespec *expire_time)
{
MetaInfo *meta_storage;
osmo_static_assert(sizeof(*meta_storage) <= sizeof(llc_msg->cb), info_does_not_fit);
m_queue_size += 1;
m_queue_octets += msgb_length(llc_msg);
meta_storage = (MetaInfo *)&llc_msg->cb[0];
osmo_clock_gettime(CLOCK_MONOTONIC, &meta_storage->recv_time);
meta_storage->expire_time = *expire_time;
msgb_enqueue(&m_queue, llc_msg);
}
void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts)
{
struct msgb *msg;
while ((msg = msgb_dequeue(&q->m_queue))) {
if (bts)
bts_do_rate_ctr_inc(bts, CTR_LLC_FRAME_DROPPED);
msgb_free(msg);
}
q->m_queue_size = 0;
q->m_queue_octets = 0;
}
void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o)
{
struct msgb *msg, *msg1 = NULL, *msg2 = NULL;
struct llist_head new_queue;
size_t queue_size = 0;
size_t queue_octets = 0;
INIT_LLIST_HEAD(&new_queue);
while (1) {
if (msg1 == NULL)
msg1 = msgb_dequeue(&q->m_queue);
if (msg2 == NULL)
msg2 = msgb_dequeue(&o->m_queue);
if (msg1 == NULL && msg2 == NULL)
break;
if (msg1 == NULL) {
msg = msg2;
msg2 = NULL;
} else if (msg2 == NULL) {
msg = msg1;
msg1 = NULL;
} else {
const MetaInfo *mi1 = (MetaInfo *)&msg1->cb[0];
const MetaInfo *mi2 = (MetaInfo *)&msg2->cb[0];
if (timespeccmp(&mi2->recv_time, &mi1->recv_time, >)) {
msg = msg1;
msg1 = NULL;
} else {
msg = msg2;
msg2 = NULL;
}
}
msgb_enqueue(&new_queue, msg);
queue_size += 1;
queue_octets += msgb_length(msg);
}
OSMO_ASSERT(llist_empty(&q->m_queue));
OSMO_ASSERT(llist_empty(&o->m_queue));
o->m_queue_size = 0;
o->m_queue_octets = 0;
llist_splice_init(&new_queue, &q->m_queue);
q->m_queue_size = queue_size;
q->m_queue_octets = queue_octets;
}
#define ALPHA 0.5f
struct msgb *gprs_llc_queue::dequeue(const MetaInfo **info)
{
struct msgb *msg;
struct timespec *tv, tv_now, tv_result;
uint32_t lifetime;
const MetaInfo *meta_storage;
msg = msgb_dequeue(&m_queue);
if (!msg)
return NULL;
meta_storage = (MetaInfo *)&msg->cb[0];
if (info)
*info = meta_storage;
m_queue_size -= 1;
m_queue_octets -= msgb_length(msg);
/* take the second time */
osmo_clock_gettime(CLOCK_MONOTONIC, &tv_now);
tv = (struct timespec *)&msg->data[sizeof(*tv)];
timespecsub(&tv_now, &meta_storage->recv_time, &tv_result);
lifetime = tv_result.tv_sec*1000 + tv_result.tv_nsec/1000000;
m_avg_queue_delay = m_avg_queue_delay * ALPHA + lifetime * (1-ALPHA);
return msg;
}
void gprs_llc_queue::calc_pdu_lifetime(struct gprs_rlcmac_bts *bts, const uint16_t pdu_delay_csec, struct timespec *tv)
{
uint16_t delay_csec;
if (bts->bts_data()->force_llc_lifetime)
delay_csec = bts->bts_data()->force_llc_lifetime;
if (bts->pcu->vty.force_llc_lifetime)
delay_csec = bts->pcu->vty.force_llc_lifetime;
else
delay_csec = pdu_delay_csec;
@@ -96,19 +238,19 @@ void gprs_llc::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct
}
/* calculate timestamp of timeout */
struct timeval now, csec;
gettimeofday(&now, NULL);
csec.tv_usec = (delay_csec % 100) * 10000;
csec.tv_sec = delay_csec / 100;
struct timespec now, csec;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
csecs_to_timespec(delay_csec, &csec);
timeradd(&now, &csec, tv);
timespecadd(&now, &csec, tv);
}
bool gprs_llc::is_frame_expired(struct timeval *tv_now, struct timeval *tv)
bool gprs_llc_queue::is_frame_expired(const struct timespec *tv_now,
const struct timespec *tv)
{
/* Timeout is infinite */
if (tv->tv_sec == 0 && tv->tv_usec == 0)
if (tv->tv_sec == 0 && tv->tv_nsec == 0)
return false;
return timercmp(tv_now, tv, >);
return timespeccmp(tv_now, tv, >);
}

103
src/llc.h
View File

@@ -18,72 +18,117 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <osmocom/core/linuxlist.h>
#ifdef __cplusplus
}
#endif
#include <stdint.h>
#include <string.h>
#include <time.h>
#define LLC_MAX_LEN 1543
struct gprs_rlcmac_bts;
/**
* I represent the LLC data to a MS
*/
struct gprs_llc {
static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv);
static bool is_frame_expired(struct timeval *now, struct timeval *tv);
#ifdef __cplusplus
static bool is_user_data_frame(uint8_t *data, size_t len);
void init();
void reset();
void reset_frame_space();
void enqueue(struct msgb *llc_msg);
struct msgb *dequeue();
void put_frame(const uint8_t *data, size_t len);
void put_dummy_frame(size_t req_len);
void append_frame(const uint8_t *data, size_t len);
void consume(size_t len);
void consume(uint8_t *data, size_t len);
void clear(BTS *bts);
uint16_t chunk_size() const;
uint16_t remaining_space() const;
uint16_t frame_length() const;
bool fits_in_current_frame(uint8_t size) const;
#endif
uint8_t frame[LLC_MAX_LEN]; /* current DL or UL frame */
uint16_t m_index; /* current write/read position of frame */
uint16_t m_length; /* len of current DL LLC_frame, 0 == no frame */
struct llist_head queue; /* queued LLC DL data */
};
inline uint16_t gprs_llc::chunk_size() const
struct MetaInfo {
struct timespec recv_time;
struct timespec expire_time;
};
/**
* I store the LLC frames that come from the SGSN.
*/
struct gprs_llc_queue {
#ifdef __cplusplus
static void calc_pdu_lifetime(struct gprs_rlcmac_bts *bts, const uint16_t pdu_delay_csec,
struct timespec *tv);
static bool is_frame_expired(const struct timespec *now,
const struct timespec *tv);
static bool is_user_data_frame(uint8_t *data, size_t len);
void enqueue(struct msgb *llc_msg, const struct timespec *expire_time);
struct msgb *dequeue(const MetaInfo **info = 0);
#endif
uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */
size_t m_queue_size;
size_t m_queue_octets;
struct llist_head m_queue; /* queued LLC DL data */
};
#ifdef __cplusplus
extern "C" {
#endif
void llc_queue_init(struct gprs_llc_queue *q);
void llc_queue_clear(struct gprs_llc_queue *q, struct gprs_rlcmac_bts *bts);
void llc_queue_move_and_merge(struct gprs_llc_queue *q, struct gprs_llc_queue *o);
static inline uint16_t llc_chunk_size(const struct gprs_llc *llc)
{
return m_length - m_index;
return llc->m_length - llc->m_index;
}
inline uint16_t gprs_llc::remaining_space() const
static inline uint16_t llc_remaining_space(const struct gprs_llc *llc)
{
return LLC_MAX_LEN - m_length;
return LLC_MAX_LEN - llc->m_length;
}
inline uint16_t gprs_llc::frame_length() const
static inline uint16_t llc_frame_length(const struct gprs_llc *llc)
{
return m_length;
return llc->m_length;
}
inline void gprs_llc::consume(size_t len)
static inline void llc_consume(struct gprs_llc *llc, size_t len)
{
m_index += len;
llc->m_index += len;
}
inline void gprs_llc::consume(uint8_t *data, size_t len)
static inline void llc_consume_data(struct gprs_llc *llc, uint8_t *data, size_t len)
{
/* copy and increment index */
memcpy(data, frame + m_index, len);
consume(len);
memcpy(data, llc->frame + llc->m_index, len);
llc_consume(llc, len);
}
inline bool gprs_llc::fits_in_current_frame(uint8_t chunk_size) const
static inline bool llc_fits_in_current_frame(const struct gprs_llc *llc, uint8_t chunk_size)
{
return m_length + chunk_size <= LLC_MAX_LEN;
return llc->m_length + chunk_size <= LLC_MAX_LEN;
}
static inline size_t llc_queue_size(const struct gprs_llc_queue *q)
{
return q->m_queue_size;
}
static inline size_t llc_queue_octets(const struct gprs_llc_queue *q)
{
return q->m_queue_octets;
}
#ifdef __cplusplus
}
#endif

297
src/mslot_class.c Normal file
View File

@@ -0,0 +1,297 @@
/* mslot_class.c
*
* Copyright (C) 2012 Ivan Klyuchnikov
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2013 by Holger Hans Peter Freyther
* Copyright (C) 2017 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <mslot_class.h>
#include <gprs_debug.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <errno.h>
/* 3GPP TS 45.002 Annex B Table B.1 */
struct gprs_ms_multislot_class {
uint8_t rx, tx, sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
uint8_t ta, tb, ra, rb; /* Minimum Number of Slots */
uint8_t type; /* Type of Mobile */
};
static const struct gprs_ms_multislot_class gprs_ms_multislot_class[] = {
/* M-S Class | Max # of slots | Min # of slots | Type */
/* | Rx Tx Sum | Tta Ttb Tra Trb | */
/* N/A */ { MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
/* 1 */ { 1, 1, 2, 3, 2, 4, 2, 1 },
/* 2 */ { 2, 1, 3, 3, 2, 3, 1, 1 },
/* 3 */ { 2, 2, 3, 3, 2, 3, 1, 1 },
/* 4 */ { 3, 1, 4, 3, 1, 3, 1, 1 },
/* 5 */ { 2, 2, 4, 3, 1, 3, 1, 1 },
/* 6 */ { 3, 2, 4, 3, 1, 3, 1, 1 },
/* 7 */ { 3, 3, 4, 3, 1, 3, 1, 1 },
/* 8 */ { 4, 1, 5, 3, 1, 2, 1, 1 },
/* 9 */ { 3, 2, 5, 3, 1, 2, 1, 1 },
/* 10 */ { 4, 2, 5, 3, 1, 2, 1, 1 },
/* 11 */ { 4, 3, 5, 3, 1, 2, 1, 1 },
/* 12 */ { 4, 4, 5, 2, 1, 2, 1, 1 },
/* 13 */ { 3, 3, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
/* 14 */ { 4, 4, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
/* 15 */ { 5, 5, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
/* 16 */ { 6, 6, MS_NA, MS_NA, MS_A, 2, MS_A, 2 },
/* 17 */ { 7, 7, MS_NA, MS_NA, MS_A, 1, 0, 2 },
/* 18 */ { 8, 8, MS_NA, MS_NA, 0, 0, 0, 2 },
/* 19 */ { 6, 2, MS_NA, 3, MS_B, 2, MS_C, 1 },
/* 20 */ { 6, 3, MS_NA, 3, MS_B, 2, MS_C, 1 },
/* 21 */ { 6, 4, MS_NA, 3, MS_B, 2, MS_C, 1 },
/* 22 */ { 6, 4, MS_NA, 2, MS_B, 2, MS_C, 1 },
/* 23 */ { 6, 6, MS_NA, 2, MS_B, 2, MS_C, 1 },
/* 24 */ { 8, 2, MS_NA, 3, MS_B, 2, MS_C, 1 },
/* 25 */ { 8, 3, MS_NA, 3, MS_B, 2, MS_C, 1 },
/* 26 */ { 8, 4, MS_NA, 3, MS_B, 2, MS_C, 1 },
/* 27 */ { 8, 4, MS_NA, 2, MS_B, 2, MS_C, 1 },
/* 28 */ { 8, 6, MS_NA, 2, MS_B, 2, MS_C, 1 },
/* 29 */ { 8, 8, MS_NA, 2, MS_B, 2, MS_C, 1 },
/* 30 */ { 5, 1, 6, 2, 1, 1, 1, 1 },
/* 31 */ { 5, 2, 6, 2, 1, 1, 1, 1 },
/* 32 */ { 5, 3, 6, 2, 1, 1, 1, 1 },
/* 33 */ { 5, 4, 6, 2, 1, 1, 1, 1 },
/* 34 */ { 5, 5, 6, 2, 1, 1, 1, 1 },
/* 35 */ { 5, 1, 6, 2, 1, MS_TO, 1, 1 },
/* 36 */ { 5, 2, 6, 2, 1, MS_TO, 1, 1 },
/* 37 */ { 5, 3, 6, 2, 1, MS_TO, 1, 1 },
/* 38 */ { 5, 4, 6, 2, 1, MS_TO, 1, 1 },
/* 39 */ { 5, 5, 6, 2, 1, MS_TO, 1, 1 },
/* 40 */ { 6, 1, 7, 1, 1, 1, MS_TO, 1 },
/* 41 */ { 6, 2, 7, 1, 1, 1, MS_TO, 1 },
/* 42 */ { 6, 3, 7, 1, 1, 1, MS_TO, 1 },
/* 43 */ { 6, 4, 7, 1, 1, 1, MS_TO, 1 },
/* 44 */ { 6, 5, 7, 1, 1, 1, MS_TO, 1 },
/* 45 */ { 6, 6, 7, 1, 1, 1, MS_TO, 1 },
};
static inline const struct gprs_ms_multislot_class *get_mslot_table(uint8_t ms_cl)
{
uint8_t index = ms_cl ? ms_cl : DEFAULT_MSLOT_CLASS;
if (ms_cl >= ARRAY_SIZE(gprs_ms_multislot_class))
index = 0;
return &gprs_ms_multislot_class[index];
}
uint8_t mslot_class_max()
{
return ARRAY_SIZE(gprs_ms_multislot_class);
}
uint8_t mslot_class_get_ta(uint8_t ms_cl)
{
return get_mslot_table(ms_cl)->ta;
}
/* TODO: Set it to 1 if FH is implemented and enabled
* MS_A and MS_B are 0 iff FH is disabled and there is no Tx/Rx change.
* This is never the case with the current implementation, so 1 will always be used. */
uint8_t mslot_class_get_tb(uint8_t ms_cl)
{
const struct gprs_ms_multislot_class *t = get_mslot_table(ms_cl);
switch (t->tb) {
case MS_A:
return 0;
case MS_B:
return 1;
default:
return t->tb;
}
}
uint8_t mslot_class_get_ra(uint8_t ms_cl, uint8_t ta)
{
const struct gprs_ms_multislot_class *t = get_mslot_table(ms_cl);
switch (t->ra) {
case MS_TO:
return ta + 1;
default:
return t->ra;
}
}
uint8_t mslot_class_get_rb(uint8_t ms_cl, uint8_t ta)
{
const struct gprs_ms_multislot_class *t = get_mslot_table(ms_cl);
switch (t->rb) {
case MS_A:
return 0;
case MS_C:
return 1;
case MS_TO:
return ta;
default:
return t->rb;
}
}
uint8_t mslot_class_get_tx(uint8_t ms_cl)
{
return get_mslot_table(ms_cl)->tx;
}
uint8_t mslot_class_get_rx(uint8_t ms_cl)
{
return get_mslot_table(ms_cl)->rx;
}
uint8_t mslot_class_get_sum(uint8_t ms_cl)
{
return get_mslot_table(ms_cl)->sum;
}
uint8_t mslot_class_get_type(uint8_t ms_cl)
{
return get_mslot_table(ms_cl)->type;
}
/*! Fill in RX mask table for a given MS Class
*
* \param[in] ms_cl MS Class pointer
* \param[in] num_tx Number of TX slots to consider
* \param[out] rx_mask RX mask table
*/
void mslot_fill_rx_mask(uint8_t mslot_class, uint8_t num_tx, uint8_t *rx_mask)
{
static const char *digit[10] = { "0","1","2","3","4","5","6","7","8","9" };
uint8_t Tx = mslot_class_get_tx(mslot_class), /* Max number of Tx slots */
Sum = mslot_class_get_sum(mslot_class), /* Max number of Tx + Rx slots */
Type = mslot_class_get_type(mslot_class), /* Type of Mobile */
Tta = mslot_class_get_ta(mslot_class), /* Minimum number of slots */
Ttb = mslot_class_get_tb(mslot_class),
/* FIXME: use actual TA offset for computation - make sure to adjust "1 + MS_TO" accordingly
see also "Offset required" bit in 3GPP TS 24.008 §10.5.1.7 */
Tra = mslot_class_get_ra(mslot_class, 0),
Trb = mslot_class_get_rb(mslot_class, 0);
if (num_tx == 1) /* it's enough to log this once per TX slot set iteration */
LOGP(DRLCMAC, LOGL_DEBUG,
"Rx=%d Tx=%d Sum Rx+Tx=%s, Tta=%s Ttb=%d, Tra=%d Trb=%d, Type=%d\n",
mslot_class_get_rx(mslot_class), Tx,
(Sum == MS_NA) ? "N/A" : digit[Sum],
(Tta == MS_NA) ? "N/A" : digit[Tta], Ttb, Tra, Trb, Type);
if (Type == 1) {
rx_mask[MASK_TT] = (0x100 >> OSMO_MAX(Ttb, Tta)) - 1;
rx_mask[MASK_TT] &= ~((1 << (Trb + num_tx)) - 1);
rx_mask[MASK_TR] = (0x100 >> Ttb) - 1;
rx_mask[MASK_TR] &= ~((1 << (OSMO_MAX(Trb, Tra) + num_tx)) - 1);
} else {
/* Class type 2 MS have independant RX and TX */
rx_mask[MASK_TT] = 0xff;
rx_mask[MASK_TR] = 0xff;
}
rx_mask[MASK_TT] = (rx_mask[MASK_TT] << 3) | (rx_mask[MASK_TT] >> 5);
rx_mask[MASK_TR] = (rx_mask[MASK_TR] << 3) | (rx_mask[MASK_TR] >> 5);
}
/* look for USF, don't use USF=7 */
int8_t find_free_usf(uint8_t usf_map)
{
uint8_t usf;
if (usf_map == (1 << 7) - 1)
return -1;
for (usf = 0; usf < 7; usf++) {
if (!(usf_map & (1 << usf)))
return usf;
}
return -1;
}
/* look for USF, don't use USF=7 */
int8_t find_free_tfi(uint32_t tfi_map)
{
int8_t tfi;
if (tfi_map == NO_FREE_TFI)
return -1;
for (tfi = 0; tfi < 32; tfi++) {
if (!(tfi_map & (((uint32_t)1) << tfi)))
return tfi;
}
return -1;
}
void masked_override_with(char *buf, uint8_t mask, char set_char)
{
int i;
for (i = 0; mask; i++, mask >>= 1)
if (mask & 1)
buf[i] = set_char;
}
void ts_format(char *buf, uint8_t dl_mask, uint8_t ul_mask)
{
snprintf(buf, 9, OSMO_BIT_SPEC, OSMO_BIT_PRINT_EX(dl_mask, 'D'));
masked_override_with(buf, ul_mask, 'U');
masked_override_with(buf, ul_mask & dl_mask, 'C');
}
uint16_t mslot_wrap_window(uint16_t win)
{
return (win | win >> 8) & 0xFF;
}
bool mslot_test_and_set_bit(uint32_t *bits, size_t elem)
{
bool was_set = bits[elem/32] & (((uint32_t)1) << (elem % 32));
bits[elem/32] |= (((uint32_t)1) << (elem % 32));
return was_set;
}
/*! Filter out bad slots
*
* \param[in] mask TS selection mask
* \param[in] ul_slots set of UL timeslots
* \param[in] dl_slots set of DL timeslots
* \param[in] rx_valid_win Mask for valid RX window value
* \returns negative error code or RX window on success
*/
int16_t mslot_filter_bad(uint8_t mask, uint8_t ul_slots, uint8_t dl_slots, uint16_t rx_valid_win)
{
uint8_t rx_good;
uint16_t rx_bad = (uint16_t)(0xFF & ~mask) << ul_slots;
/* TODO: CHECK this calculation -> separate function for unit testing */
rx_bad = (rx_bad | (rx_bad >> 8)) & 0xFF;
rx_good = dl_slots & ~rx_bad;
if (!rx_good)
return -1;
return rx_good & rx_valid_win;
}

62
src/mslot_class.h Normal file
View File

@@ -0,0 +1,62 @@
/* mslot_class.h
*
* Copyright (C) 2012 Ivan Klyuchnikov
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2013 by Holger Hans Peter Freyther
* Copyright (C) 2017 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
/* 3GPP TS 05.02 Annex B.1 */
#define MS_NA 255 /* N/A */
#define MS_A 254 /* 1 with hopping, 0 without */
#define MS_B 253 /* 1 with hopping, 0 without (change Rx to Tx)*/
#define MS_C 252 /* 1 with hopping, 0 without (change Tx to Rx)*/
#define MS_TO 251 /* 31 symbol periods (this can be provided by a TA offset, i.e. a minimum TA value) */
#define DEFAULT_MSLOT_CLASS 12
#define NO_FREE_TFI 0xffffffff
enum { MASK_TT = 0, MASK_TR = 1 };
/* multislot class selection routines */
uint8_t mslot_class_get_ta(uint8_t ms_cl);
uint8_t mslot_class_get_tb(uint8_t ms_cl);
uint8_t mslot_class_get_ra(uint8_t ms_cl, uint8_t ta);
uint8_t mslot_class_get_rb(uint8_t ms_cl, uint8_t ta);
uint8_t mslot_class_get_tx(uint8_t ms_cl);
uint8_t mslot_class_get_rx(uint8_t ms_cl);
uint8_t mslot_class_get_sum(uint8_t ms_cl);
uint8_t mslot_class_get_type(uint8_t ms_cl);
uint8_t mslot_class_max();
/* multislot allocation helper routines */
void mslot_fill_rx_mask(uint8_t mslot_class, uint8_t num_tx, uint8_t *rx_mask);
int8_t find_free_usf(uint8_t usf_map);
int8_t find_free_tfi(uint32_t tfi_map);
void masked_override_with(char *buf, uint8_t mask, char set_char);
void ts_format(char *buf, uint8_t dl_mask, uint8_t ul_mask);
uint16_t mslot_wrap_window(uint16_t win);
bool mslot_test_and_set_bit(uint32_t *bits, size_t elem);
int16_t mslot_filter_bad(uint8_t mask, uint8_t ul_slots, uint8_t dl_slots, uint16_t rx_valid_win);

904
src/nacc_fsm.c Normal file
View File

@@ -0,0 +1,904 @@
/* nacc_fsm.c
*
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <unistd.h>
#include <talloc.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_bssgp_rim.h>
#include <nacc_fsm.h>
#include <gprs_rlcmac.h>
#include <gprs_debug.h>
#include <gprs_ms.h>
#include <encoding.h>
#include <bts.h>
#include <neigh_cache.h>
#define X(s) (1 << (s))
/* Infer CTRL id (seqnum) for a given tgt arfcn+bsic (bsic range: 0-63) */
#define arfcn_bsic_2_ctrl_id(arfcn, bsic) ((arfcn) * 100 + (bsic))
static const struct osmo_tdef_state_timeout nacc_fsm_timeouts[32] = {
[NACC_ST_INITIAL] = {},
[NACC_ST_WAIT_RESOLVE_RAC_CI] = { .T = PCU_TDEF_NEIGH_RESOLVE_TO },
[NACC_ST_WAIT_REQUEST_SI] = { .T = PCU_TDEF_SI_RESOLVE_TO },
[NACC_ST_TX_NEIGHBOUR_DATA] = {},
[NACC_ST_TX_CELL_CHG_CONTINUE] = {},
[NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK] = {}, /* Timeout through event controlled by tbf::poll_timeout() */
[NACC_ST_DONE] = {},
};
/* Transition to a state, using the T timer defined in nacc_fsm_timeouts.
* The actual timeout value is in turn obtained from conn->T_defs.
* Assumes local variable fi exists. */
#define nacc_fsm_state_chg(fi, NEXT_STATE) \
osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, \
nacc_fsm_timeouts, \
((struct nacc_fsm_ctx*)(fi->priv))->ms->bts->pcu->T_defs, \
-1)
const struct value_string nacc_fsm_event_names[] = {
{ NACC_EV_RX_CELL_CHG_NOTIFICATION, "RX_CELL_CHG_NOTIFICATION" },
{ NACC_EV_RX_RAC_CI, "RX_RAC_CI" },
{ NACC_EV_RX_SI, "RX_SI" },
{ NACC_EV_CREATE_RLCMAC_MSG, "CREATE_RLCMAC_MSG" },
{ NACC_EV_RX_CELL_CHG_CONTINUE_ACK, "RX_CELL_CHG_CONTINUE_ACK"},
{ NACC_EV_TIMEOUT_CELL_CHG_CONTINUE, "TIMEOUT_CELL_CHG_CONTINUE" },
{ 0, NULL }
};
/* TS 44 060 11.2.9e Packet Neighbour Cell Data */
static struct msgb *create_packet_neighbour_cell_data(struct nacc_fsm_ctx *ctx,
const struct gprs_rlcmac_tbf *tbf,
bool *all_si_info_sent)
{
struct msgb *msg;
int rc;
RlcMacDownlink_t *mac_control_block;
struct GprsMs *ms = tbf_ms(tbf);
OSMO_ASSERT(tbf_is_tfi_assigned(tbf));
uint8_t tfi_is_dl = tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF;
uint8_t tfi = tbf_tfi(tbf);
uint8_t container_id = 0;
PNCDContainer_t container;
size_t max_len, len_to_write;
uint8_t *cont_buf;
uint8_t si_type = ctx->si_info.type_psi ? 0x01 : 0x0;
memset(&container, 0, sizeof(container));
if (ctx->container_idx == 0) {
container.UnionType = 1; /* with ID */
container.u.PNCD_Container_With_ID.ARFCN = ctx->neigh_key.tgt_arfcn;
container.u.PNCD_Container_With_ID.BSIC = ctx->neigh_key.tgt_bsic;
cont_buf = &container.u.PNCD_Container_With_ID.CONTAINER[0];
max_len = sizeof(container.u.PNCD_Container_With_ID.CONTAINER) - 1;
} else {
container.UnionType = 0; /* without ID */
cont_buf = &container.u.PNCD_Container_Without_ID.CONTAINER[0];
max_len = sizeof(container.u.PNCD_Container_Without_ID.CONTAINER) - 1;
}
len_to_write = ctx->si_info.si_len - ctx->si_info_bytes_sent;
if (len_to_write == 0) {
/* We sent all info on last message filing it exactly, we now send a zeroed one to finish */
*all_si_info_sent = true;
*cont_buf = (si_type << 5) | 0x00;
} else if (len_to_write >= max_len) {
/* We fill the rlcmac block, we'll need more messages */
*all_si_info_sent = false;
*cont_buf = (si_type << 5) | 0x1F;
memcpy(cont_buf + 1, &ctx->si_info.si_buf[ctx->si_info_bytes_sent], max_len);
ctx->si_info_bytes_sent += max_len;
} else {
/* Last block, we don't fill it exactly */
*all_si_info_sent = true;
*cont_buf = (si_type << 5) | (len_to_write & 0x1F);
memcpy(cont_buf + 1, &ctx->si_info.si_buf[ctx->si_info_bytes_sent], len_to_write);
ctx->si_info_bytes_sent += len_to_write;
}
msg = msgb_alloc(GSM_MACBLOCK_LEN, "neighbour_cell_data");
if (!msg)
return NULL;
/* Initialize a bit vector that uses allocated msgb as the data buffer. */
struct bitvec bv = {
.data = msgb_put(msg, GSM_MACBLOCK_LEN),
.data_len = GSM_MACBLOCK_LEN,
};
bitvec_unhex(&bv, DUMMY_VEC);
mac_control_block = (RlcMacDownlink_t *)talloc_zero(ctx->ms, RlcMacDownlink_t);
write_packet_neighbour_cell_data(mac_control_block,
tfi_is_dl, tfi, container_id,
ctx->container_idx, &container);
LOGP(DNACC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Neighbour Cell Data +++++++++++++++++++++++++\n");
rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block);
if (rc < 0) {
LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Neighbour Cell Data failed (%d)\n", rc);
goto free_ret;
}
LOGP(DNACC, LOGL_DEBUG, "------------------------- TX : Packet Neighbour Cell Data -------------------------\n");
rate_ctr_inc(rate_ctr_group_get_ctr(bts_rate_counters(ms->bts), CTR_PKT_NEIGH_CELL_DATA));
talloc_free(mac_control_block);
ctx->container_idx++;
return msg;
free_ret:
talloc_free(mac_control_block);
msgb_free(msg);
return NULL;
}
/* TS 44 060 11.2.2a Packet Cell Change Continue */
static struct msgb *create_packet_cell_chg_continue(const struct nacc_fsm_ctx *ctx,
const struct nacc_ev_create_rlcmac_msg_ctx *data,
uint32_t *new_poll_fn)
{
struct msgb *msg;
int rc;
RlcMacDownlink_t *mac_control_block;
struct gprs_rlcmac_tbf *tbf = data->tbf;
struct GprsMs *ms = tbf_ms(tbf);
unsigned int rrbp;
rc = tbf_check_polling(tbf, data->fn, data->ts, new_poll_fn, &rrbp);
if (rc < 0) {
LOGP(DTBF, LOGL_ERROR, "Failed registering poll for Pkt Cell Chg Continue (%d)\n", rc);
return NULL;
}
msg = msgb_alloc(GSM_MACBLOCK_LEN, "pkt_cell_chg_continue");
if (!msg)
return NULL;
/* Initialize a bit vector that uses allocated msgb as the data buffer. */
struct bitvec bv = {
.data = msgb_put(msg, GSM_MACBLOCK_LEN),
.data_len = GSM_MACBLOCK_LEN,
};
bitvec_unhex(&bv, DUMMY_VEC);
mac_control_block = (RlcMacDownlink_t *)talloc_zero(ctx->ms, RlcMacDownlink_t);
OSMO_ASSERT(tbf_is_tfi_assigned(tbf));
uint8_t tfi_is_dl = tbf_direction(tbf) == GPRS_RLCMAC_DL_TBF;
uint8_t tfi = tbf_tfi(tbf);
uint8_t container_id = 0;
write_packet_cell_change_continue(mac_control_block, 1, rrbp, tfi_is_dl, tfi, true,
ctx->neigh_key.tgt_arfcn, ctx->neigh_key.tgt_bsic, container_id);
LOGP(DNACC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Cell Change Continue +++++++++++++++++++++++++\n");
rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block);
if (rc < 0) {
LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Cell Change Continue failed (%d)\n", rc);
goto free_ret;
}
LOGP(DNACC, LOGL_DEBUG, "------------------------- TX : Packet Cell Change Continue -------------------------\n");
rate_ctr_inc(rate_ctr_group_get_ctr(bts_rate_counters(ms->bts), CTR_PKT_CELL_CHG_CONTINUE));
talloc_free(mac_control_block);
tbf_set_polling(tbf, *new_poll_fn, data->ts, PDCH_ULC_POLL_CELL_CHG_CONTINUE);
LOGPTBFDL(tbf, LOGL_DEBUG, "Scheduled 'Packet Cell Change Continue' polling on PACCH (FN=%d, TS=%d)\n",
*new_poll_fn, data->ts);
return msg;
free_ret:
talloc_free(mac_control_block);
msgb_free(msg);
return NULL;
}
static int fill_rim_ran_info_req(const struct nacc_fsm_ctx *ctx, struct bssgp_ran_information_pdu *pdu)
{
struct gprs_rlcmac_bts *bts = ctx->ms->bts;
*pdu = (struct bssgp_ran_information_pdu){
.routing_info_dest = {
.discr = BSSGP_RIM_ROUTING_INFO_GERAN,
.geran = {
.raid = {
.mcc = ctx->cgi_ps.rai.lac.plmn.mcc,
.mnc = ctx->cgi_ps.rai.lac.plmn.mnc,
.mnc_3_digits = ctx->cgi_ps.rai.lac.plmn.mnc_3_digits,
.lac = ctx->cgi_ps.rai.lac.lac,
.rac = ctx->cgi_ps.rai.rac,
},
.cid = ctx->cgi_ps.cell_identity,
},
},
.routing_info_src = {
.discr = BSSGP_RIM_ROUTING_INFO_GERAN,
.geran = {
.raid = {
.mcc = bts->cgi_ps.rai.lac.plmn.mcc,
.mnc = bts->cgi_ps.rai.lac.plmn.mnc,
.mnc_3_digits = bts->cgi_ps.rai.lac.plmn.mnc_3_digits,
.lac = bts->cgi_ps.rai.lac.lac,
.rac = bts->cgi_ps.rai.rac,
},
.cid = bts->cgi_ps.cell_identity,
},
},
.rim_cont_iei = BSSGP_IE_RI_REQ_RIM_CONTAINER,
.decoded_present = true,
.decoded = {
.req_rim_cont = {
.app_id = BSSGP_RAN_INF_APP_ID_NACC,
.seq_num = 1,
.pdu_ind = {
.ack_requested = 0,
.pdu_type_ext = RIM_PDU_TYPE_SING_REP,
},
.prot_ver = 1,
.son_trans_app_id = NULL,
.son_trans_app_id_len = 0,
.u = {
.app_cont_nacc = {
.reprt_cell = ctx->cgi_ps,
},
},
},
},
};
return 0;
}
static int fill_neigh_key_from_bts_pkt_cell_chg_not(struct neigh_cache_entry_key *neigh_key,
const struct gprs_rlcmac_bts *bts,
const Packet_Cell_Change_Notification_t *notif)
{
switch (notif->Target_Cell.UnionType) {
case 0: /* GSM */
neigh_key->local_lac = bts->cgi_ps.rai.lac.lac;
neigh_key->local_ci = bts->cgi_ps.cell_identity;
neigh_key->tgt_arfcn = notif->Target_Cell.u.Target_Cell_GSM_Notif.ARFCN;
neigh_key->tgt_bsic = notif->Target_Cell.u.Target_Cell_GSM_Notif.BSIC;
return 0;
default:
return -ENOTSUP;
}
}
#define SI_HDR_LEN 2
static void bts_fill_si_cache_value(const struct gprs_rlcmac_bts *bts, struct si_cache_value *val)
{
val->type_psi = false;
val->si_len = 0;
if (bts->si1_is_set) {
osmo_static_assert(sizeof(bts->si1) - SI_HDR_LEN == BSSGP_RIM_SI_LEN, _si1_header_size);
memcpy(&val->si_buf[val->si_len], bts->si1 + SI_HDR_LEN, BSSGP_RIM_SI_LEN);
val->si_len += BSSGP_RIM_SI_LEN;
}
if (bts->si3_is_set) {
osmo_static_assert(sizeof(bts->si3) - SI_HDR_LEN == BSSGP_RIM_SI_LEN, _si3_header_size);
memcpy(&val->si_buf[val->si_len], bts->si3 + SI_HDR_LEN, BSSGP_RIM_SI_LEN);
val->si_len += BSSGP_RIM_SI_LEN;
}
if (bts->si13_is_set) {
osmo_static_assert(sizeof(bts->si13) - SI_HDR_LEN == BSSGP_RIM_SI_LEN, _si13_header_size);
memcpy(&val->si_buf[val->si_len], bts->si13 + SI_HDR_LEN, BSSGP_RIM_SI_LEN);
val->si_len += BSSGP_RIM_SI_LEN;
}
}
/* Called on event NACC_EV_RX_CELL_CHG_NOTIFICATION on states after
* WAIT_RESOLVE_RAC_CI. Ignore duplicate messages, transition back if target
* cell changed.
*/
static void handle_retrans_pkt_cell_chg_notif(struct nacc_fsm_ctx *ctx, const Packet_Cell_Change_Notification_t *notif)
{
struct gprs_rlcmac_bts *bts = ctx->ms->bts;
struct neigh_cache_entry_key neigh_key;
if (fill_neigh_key_from_bts_pkt_cell_chg_not(&neigh_key, bts, notif) < 0) {
LOGPFSML(ctx->fi, LOGL_NOTICE, "TargetCell type=0x%x not supported\n",
notif->Target_Cell.UnionType);
if (ctx->fi->state != NACC_ST_TX_CELL_CHG_CONTINUE)
nacc_fsm_state_chg(ctx->fi, NACC_ST_TX_CELL_CHG_CONTINUE);
return;
}
/* If tgt cell changed, restart resolving it */
if (!neigh_cache_entry_key_eq(&ctx->neigh_key, &neigh_key)) {
ctx->neigh_key = neigh_key;
nacc_fsm_state_chg(ctx->fi, NACC_ST_WAIT_RESOLVE_RAC_CI);
}
/* else: ignore it, it's a dup, carry on what we were doing */
}
////////////////
// FSM states //
////////////////
static void st_initial(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
struct gprs_rlcmac_bts *bts = ctx->ms->bts;
Packet_Cell_Change_Notification_t *notif;
switch (event) {
case NACC_EV_RX_CELL_CHG_NOTIFICATION:
notif = (Packet_Cell_Change_Notification_t *)data;
if (fill_neigh_key_from_bts_pkt_cell_chg_not(&ctx->neigh_key, bts, notif) < 0) {
LOGPFSML(fi, LOGL_NOTICE, "TargetCell type=0x%x not supported\n",
notif->Target_Cell.UnionType);
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
} else {
nacc_fsm_state_chg(fi, NACC_ST_WAIT_RESOLVE_RAC_CI);
}
break;
default:
OSMO_ASSERT(0);
}
}
static int send_neigh_addr_req_ctrl_iface(struct nacc_fsm_ctx *ctx)
{
struct gprs_rlcmac_bts *bts = ctx->ms->bts;
struct gprs_pcu *pcu = bts->pcu;
struct ctrl_cmd *cmd = NULL;
int rc;
/* We may have changed to this state previously (eg: we are handling
* another Pkt cell Change Notify with different target). Avoid
* re-creating the socket in that case. */
if (ctx->neigh_ctrl_conn->write_queue.bfd.fd == -1) {
rc = osmo_sock_init2_ofd(&ctx->neigh_ctrl_conn->write_queue.bfd,
AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP,
NULL, 0, pcu->vty.neigh_ctrl_addr, pcu->vty.neigh_ctrl_port,
OSMO_SOCK_F_CONNECT);
if (rc < 0) {
LOGPFSML(ctx->fi, LOGL_ERROR,
"Failed to establish CTRL (neighbor resolution) connection to BSC r=%s:%u\n\n",
pcu->vty.neigh_ctrl_addr, pcu->vty.neigh_ctrl_port);
goto err_term;
}
}
cmd = ctrl_cmd_create(ctx, CTRL_TYPE_GET);
if (!cmd) {
LOGPFSML(ctx->fi, LOGL_ERROR, "CTRL msg creation failed\n");
goto err_term;
}
cmd->id = talloc_asprintf(cmd, "%u", arfcn_bsic_2_ctrl_id(ctx->neigh_key.tgt_arfcn,
ctx->neigh_key.tgt_bsic));
cmd->variable = talloc_asprintf(cmd, "neighbor_resolve_cgi_ps_from_lac_ci.%d.%d.%d.%d",
ctx->neigh_key.local_lac, ctx->neigh_key.local_ci,
ctx->neigh_key.tgt_arfcn, ctx->neigh_key.tgt_bsic);
rc = ctrl_cmd_send(&ctx->neigh_ctrl_conn->write_queue, cmd);
if (rc) {
LOGPFSML(ctx->fi, LOGL_ERROR, "CTRL msg sent failed: %d\n", rc);
goto err_term;
}
talloc_free(cmd);
return 0;
err_term:
talloc_free(cmd);
return -1;
}
static int send_neigh_addr_req(struct nacc_fsm_ctx *ctx)
{
struct gprs_rlcmac_bts *bts = ctx->ms->bts;
/* If PCU was configured to use the old CTRL interface, use it: */
if (ctx->neigh_ctrl_conn)
return send_neigh_addr_req_ctrl_iface(ctx);
/* Otherwise, by default the new PCUIF over IPA Abis multiplex proto should be used: */
return pcu_tx_neigh_addr_res_req(bts, &ctx->neigh_key);
}
static void st_wait_resolve_rac_ci_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
struct gprs_rlcmac_bts *bts = ctx->ms->bts;
struct gprs_pcu *pcu = bts->pcu;
const struct osmo_cell_global_id_ps *cgi_ps;
/* First try to find the value in the cache */
cgi_ps = neigh_cache_lookup_value(pcu->neigh_cache, &ctx->neigh_key);
if (cgi_ps) {
ctx->cgi_ps = *cgi_ps;
nacc_fsm_state_chg(fi, NACC_ST_WAIT_REQUEST_SI);
return;
}
/* CGI-PS not in cache, resolve it using BSC Neighbor Resolution CTRL interface */
LOGPFSML(fi, LOGL_DEBUG, "No CGI-PS found in cache, resolving " NEIGH_CACHE_ENTRY_KEY_FMT "...\n",
NEIGH_CACHE_ENTRY_KEY_ARGS(&ctx->neigh_key));
if (send_neigh_addr_req(ctx) < 0)
nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE);
}
static void st_wait_resolve_rac_ci(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
const Packet_Cell_Change_Notification_t *notif;
switch (event) {
case NACC_EV_RX_CELL_CHG_NOTIFICATION:
notif = (const Packet_Cell_Change_Notification_t *)data;
handle_retrans_pkt_cell_chg_notif(ctx, notif);
break;
case NACC_EV_RX_RAC_CI:
/* data is NULL upon failure */
if (data) {
ctx->cgi_ps = *(struct osmo_cell_global_id_ps *)data;
nacc_fsm_state_chg(fi, NACC_ST_WAIT_REQUEST_SI);
} else {
nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE);
}
break;
default:
OSMO_ASSERT(0);
}
}
/* At this point, we expect correct tgt cell info to be already in ctx->cgi_ps */
static void st_wait_request_si_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
struct gprs_rlcmac_bts *bts = ctx->ms->bts;
struct gprs_pcu *pcu = bts->pcu;
struct bssgp_ran_information_pdu pdu;
const struct si_cache_value *si;
struct gprs_rlcmac_bts *bts_i;
int rc;
/* First check if the CGI-PS addresses a cell managed by this PCU. If
* that's the case, we already have the info and there's no need to go
* the RIM way since we'd end up to this same PCU on the other end anyway.
*/
llist_for_each_entry(bts_i, &the_pcu->bts_list, list) {
if (bts_i == bts) /* Makes no sense targeting the same cell */
continue;
if (osmo_cgi_ps_cmp(&ctx->cgi_ps, &bts_i->cgi_ps) != 0)
continue;
LOGPFSML(fi, LOGL_DEBUG, "neighbor CGI-PS %s addresses local BTS %d\n",
osmo_cgi_ps_name(&ctx->cgi_ps), bts_i->nr);
bts_fill_si_cache_value(bts, &ctx->si_info);
/* Tell the PCU scheduler we are ready to go, from here one we
* are polled/driven by the scheduler */
nacc_fsm_state_chg(fi, NACC_ST_TX_NEIGHBOUR_DATA);
return;
}
/* First check if we have SI info for the target cell in cache */
si = si_cache_lookup_value(pcu->si_cache, &ctx->cgi_ps);
if (si) {
/* Copy info since cache can be deleted at any point */
memcpy(&ctx->si_info, si, sizeof(ctx->si_info));
/* Tell the PCU scheduler we are ready to go, from here one we
* are polled/driven by the scheduler */
nacc_fsm_state_chg(fi, NACC_ST_TX_NEIGHBOUR_DATA);
return;
}
/* SI info not in cache, resolve it using RIM procedure against SGSN */
if (fill_rim_ran_info_req(ctx, &pdu) < 0) {
nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE);
return;
}
LOGPFSML(fi, LOGL_INFO, "Tx RIM RAN-INFO to request SI of %s\n",
osmo_cgi_ps_name(&ctx->cgi_ps));
rc = bssgp_tx_rim(&pdu, gprs_ns2_nse_nsei(ctx->ms->bts->nse));
if (rc < 0) {
LOGPFSML(fi, LOGL_ERROR, "Failed transmitting RIM RAN-INFO %s PDU: %d\n",
osmo_cgi_ps_name(&ctx->cgi_ps), rc);
nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE);
return;
}
}
static void st_wait_request_si(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
const Packet_Cell_Change_Notification_t *notif;
struct si_cache_entry *entry;
switch (event) {
case NACC_EV_RX_CELL_CHG_NOTIFICATION:
notif = (const Packet_Cell_Change_Notification_t *)data;
handle_retrans_pkt_cell_chg_notif(ctx, notif);
break;
case NACC_EV_RX_SI:
entry = (struct si_cache_entry *)data;
/* Copy info since cache can be deleted at any point */
memcpy(&ctx->si_info, &entry->value, sizeof(ctx->si_info));
/* Tell the PCU scheduler we are ready to go, from here one we
* are polled/driven by the scheduler */
nacc_fsm_state_chg(fi, NACC_ST_TX_NEIGHBOUR_DATA);
break;
default:
OSMO_ASSERT(0);
}
}
/* At this point, we already received all required SI information to send stored
* in struct nacc_fsm_ctx. We now wait for scheduler to ask us to construct
* RLCMAC DL CTRL messages to move FSM states forward
*/
static void st_tx_neighbour_data_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
ctx->si_info_bytes_sent = 0;
ctx->container_idx = 0;
}
static void st_tx_neighbour_data(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
const Packet_Cell_Change_Notification_t *notif;
struct nacc_ev_create_rlcmac_msg_ctx *data_ctx;
bool all_si_info_sent;
switch (event) {
case NACC_EV_RX_CELL_CHG_NOTIFICATION:
notif = (const Packet_Cell_Change_Notification_t *)data;
handle_retrans_pkt_cell_chg_notif(ctx, notif);
break;
case NACC_EV_CREATE_RLCMAC_MSG:
data_ctx = (struct nacc_ev_create_rlcmac_msg_ctx *)data;
data_ctx->msg = create_packet_neighbour_cell_data(ctx, data_ctx->tbf, &all_si_info_sent);
if (!data_ctx->msg) {
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
return;
}
if (all_si_info_sent) /* DONE */
nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE);
break;
default:
OSMO_ASSERT(0);
}
}
/* st_cell_chg_continue_on_enter:
* At this point, we already sent all Pkt Cell Neighbour Change rlcmac
* blocks, and we only need to wait to be scheduled again to send PKT
* CELL CHANGE NOTIFICATION and then we are done
*/
static void st_cell_chg_continue(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
const Packet_Cell_Change_Notification_t *notif;
struct nacc_ev_create_rlcmac_msg_ctx *data_ctx;
switch (event) {
case NACC_EV_RX_CELL_CHG_NOTIFICATION:
notif = (const Packet_Cell_Change_Notification_t *)data;
handle_retrans_pkt_cell_chg_notif(ctx, notif);
break;
case NACC_EV_CREATE_RLCMAC_MSG:
data_ctx = (struct nacc_ev_create_rlcmac_msg_ctx *)data;
data_ctx->msg = create_packet_cell_chg_continue(ctx, data_ctx, &ctx->continue_poll_fn);
if (data_ctx->msg) {
ctx->continue_poll_ts = data_ctx->ts;
nacc_fsm_state_chg(fi, NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK);
}
break;
default:
OSMO_ASSERT(0);
}
}
static void st_wait_cell_chg_continue_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
const Packet_Cell_Change_Notification_t *notif;
switch (event) {
case NACC_EV_RX_CELL_CHG_NOTIFICATION:
notif = (const Packet_Cell_Change_Notification_t *)data;
handle_retrans_pkt_cell_chg_notif(ctx, notif);
break;
case NACC_EV_TIMEOUT_CELL_CHG_CONTINUE:
nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE);
break;
case NACC_EV_RX_CELL_CHG_CONTINUE_ACK:
nacc_fsm_state_chg(fi, NACC_ST_DONE);
break;
default:
OSMO_ASSERT(0);
}
}
static void st_done_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
}
static void nacc_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)fi->priv;
/* after cleanup() finishes, FSM termination calls osmo_fsm_inst_free,
so we need to avoid double-freeing it during ctx talloc free
destructor */
talloc_reparent(ctx, ctx->ms, ctx->fi);
ctx->fi = NULL;
/* remove references from owning MS and free entire ctx */
ctx->ms->nacc = NULL;
talloc_free(ctx);
}
static int nacc_fsm_timer_cb(struct osmo_fsm_inst *fi)
{
switch (fi->T) {
case PCU_TDEF_NEIGH_RESOLVE_TO:
case PCU_TDEF_SI_RESOLVE_TO:
nacc_fsm_state_chg(fi, NACC_ST_TX_CELL_CHG_CONTINUE);
break;
}
return 0;
}
static struct osmo_fsm_state nacc_fsm_states[] = {
[NACC_ST_INITIAL] = {
.in_event_mask =
X(NACC_EV_RX_CELL_CHG_NOTIFICATION),
.out_state_mask =
X(NACC_ST_WAIT_RESOLVE_RAC_CI),
.name = "INITIAL",
.action = st_initial,
},
[NACC_ST_WAIT_RESOLVE_RAC_CI] = {
.in_event_mask =
X(NACC_EV_RX_CELL_CHG_NOTIFICATION) |
X(NACC_EV_RX_RAC_CI),
.out_state_mask =
X(NACC_ST_WAIT_RESOLVE_RAC_CI) |
X(NACC_ST_WAIT_REQUEST_SI) |
X(NACC_ST_TX_CELL_CHG_CONTINUE),
.name = "WAIT_RESOLVE_RAC_CI",
.onenter = st_wait_resolve_rac_ci_on_enter,
.action = st_wait_resolve_rac_ci,
},
[NACC_ST_WAIT_REQUEST_SI] = {
.in_event_mask =
X(NACC_EV_RX_CELL_CHG_NOTIFICATION) |
X(NACC_EV_RX_SI),
.out_state_mask =
X(NACC_ST_WAIT_RESOLVE_RAC_CI) |
X(NACC_ST_TX_NEIGHBOUR_DATA) |
X(NACC_ST_TX_CELL_CHG_CONTINUE),
.name = "WAIT_REQUEST_SI",
.onenter = st_wait_request_si_on_enter,
.action = st_wait_request_si,
},
[NACC_ST_TX_NEIGHBOUR_DATA] = {
.in_event_mask =
X(NACC_EV_RX_CELL_CHG_NOTIFICATION) |
X(NACC_EV_CREATE_RLCMAC_MSG),
.out_state_mask =
X(NACC_ST_WAIT_RESOLVE_RAC_CI) |
X(NACC_ST_TX_CELL_CHG_CONTINUE),
.name = "TX_NEIGHBOUR_DATA",
.onenter = st_tx_neighbour_data_on_enter,
.action = st_tx_neighbour_data,
},
[NACC_ST_TX_CELL_CHG_CONTINUE] = {
.in_event_mask =
X(NACC_EV_RX_CELL_CHG_NOTIFICATION) |
X(NACC_EV_CREATE_RLCMAC_MSG),
.out_state_mask =
X(NACC_ST_WAIT_RESOLVE_RAC_CI) |
X(NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK),
.name = "TX_CELL_CHG_CONTINUE",
.action = st_cell_chg_continue,
},
[NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK] = {
.in_event_mask =
X(NACC_EV_RX_CELL_CHG_NOTIFICATION) |
X(NACC_EV_RX_CELL_CHG_CONTINUE_ACK) |
X(NACC_EV_TIMEOUT_CELL_CHG_CONTINUE),
.out_state_mask =
X(NACC_ST_WAIT_RESOLVE_RAC_CI) |
X(NACC_ST_TX_CELL_CHG_CONTINUE) |
X(NACC_ST_DONE),
.name = "WAIT_CELL_CHG_CONTINUE_ACK",
.action = st_wait_cell_chg_continue_ack,
},
[NACC_ST_DONE] = {
.in_event_mask = 0,
.out_state_mask = 0,
.name = "DONE",
.onenter = st_done_on_enter,
},
};
static struct osmo_fsm nacc_fsm = {
.name = "NACC",
.states = nacc_fsm_states,
.num_states = ARRAY_SIZE(nacc_fsm_states),
.timer_cb = nacc_fsm_timer_cb,
.cleanup = nacc_fsm_cleanup,
.log_subsys = DNACC,
.event_names = nacc_fsm_event_names,
};
static __attribute__((constructor)) void nacc_fsm_init(void)
{
OSMO_ASSERT(osmo_fsm_register(&nacc_fsm) == 0);
}
void nacc_fsm_ctrl_reply_cb(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd, void *data)
{
struct nacc_fsm_ctx *ctx = (struct nacc_fsm_ctx *)data;
char *tmp = NULL, *tok, *saveptr;
unsigned int exp_id;
struct osmo_cell_global_id_ps cgi_ps;
LOGPFSML(ctx->fi, LOGL_NOTICE, "Received CTRL message: type=%d %s %s: %s\n",
cmd->type, cmd->variable, cmd->id, osmo_escape_str(cmd->reply, -1));
if (cmd->type != CTRL_TYPE_GET_REPLY || !cmd->reply) {
osmo_fsm_inst_dispatch(ctx->fi, NACC_EV_RX_RAC_CI, NULL);
return;
}
/* Validate it's the seqnum from our last GET cmd, and not from older
* one we may have requested in case MS decided to resend Pkt Cell
* Change Notify with a different tgt cell:
*/
exp_id = arfcn_bsic_2_ctrl_id(ctx->neigh_key.tgt_arfcn, ctx->neigh_key.tgt_bsic);
if ((unsigned int)atoi(cmd->id) != exp_id) {
LOGPFSML(ctx->fi, LOGL_INFO,
"Received CTRL message with id=%s doesn't match our expected last id=%d, ignoring\n",
cmd->id, exp_id);
return;
}
/* TODO: Potentially validate cmd->variable contains same params as we
sent, and that cmd->id matches the original set. We may want to keep
the original cmd around by setting cmd->defer=1 when sending it. */
tmp = talloc_strdup(cmd, cmd->reply);
if (!tmp)
goto free_ret;
if (!(tok = strtok_r(tmp, "-", &saveptr)))
goto free_ret;
cgi_ps.rai.lac.plmn.mcc = atoi(tok);
if (!(tok = strtok_r(NULL, "-", &saveptr)))
goto free_ret;
cgi_ps.rai.lac.plmn.mnc = atoi(tok);
if (!(tok = strtok_r(NULL, "-", &saveptr)))
goto free_ret;
cgi_ps.rai.lac.lac = atoi(tok);
if (!(tok = strtok_r(NULL, "-", &saveptr)))
goto free_ret;
cgi_ps.rai.rac = atoi(tok);
if (!(tok = strtok_r(NULL, "\0", &saveptr)))
goto free_ret;
cgi_ps.cell_identity = atoi(tok);
/* Cache the cgi_ps so we can avoid requesting again same resolution for a while */
neigh_cache_add(ctx->ms->bts->pcu->neigh_cache, &ctx->neigh_key, &cgi_ps);
osmo_fsm_inst_dispatch(ctx->fi, NACC_EV_RX_RAC_CI, &cgi_ps);
return;
free_ret:
talloc_free(tmp);
osmo_fsm_inst_dispatch(ctx->fi, NACC_EV_RX_RAC_CI, NULL);
return;
}
static int nacc_fsm_ctx_talloc_destructor(struct nacc_fsm_ctx *ctx)
{
if (ctx->fi) {
osmo_fsm_inst_free(ctx->fi);
ctx->fi = NULL;
}
if (ctx->neigh_ctrl_conn) {
if (ctx->neigh_ctrl_conn->write_queue.bfd.fd != -1) {
osmo_wqueue_clear(&ctx->neigh_ctrl_conn->write_queue);
osmo_fd_unregister(&ctx->neigh_ctrl_conn->write_queue.bfd);
close(ctx->neigh_ctrl_conn->write_queue.bfd.fd);
ctx->neigh_ctrl_conn->write_queue.bfd.fd = -1;
}
}
return 0;
}
struct nacc_fsm_ctx *nacc_fsm_alloc(struct GprsMs* ms)
{
struct nacc_fsm_ctx *ctx = talloc_zero(ms, struct nacc_fsm_ctx);
char buf[64];
talloc_set_destructor(ctx, nacc_fsm_ctx_talloc_destructor);
ctx->ms = ms;
snprintf(buf, sizeof(buf), "TLLI-0x%08x", ms_tlli(ms));
ctx->fi = osmo_fsm_inst_alloc(&nacc_fsm, ctx, ctx, LOGL_INFO, buf);
if (!ctx->fi)
goto free_ret;
/* If CTRL ip present, use the old CTRL interface for neighbor resolution */
if (ms->bts->pcu->vty.neigh_ctrl_addr) {
ctx->neigh_ctrl = ctrl_handle_alloc(ctx, ctx, NULL);
ctx->neigh_ctrl->reply_cb = nacc_fsm_ctrl_reply_cb;
ctx->neigh_ctrl_conn = osmo_ctrl_conn_alloc(ctx, ctx->neigh_ctrl);
if (!ctx->neigh_ctrl_conn)
goto free_ret;
/* Older versions of osmo_ctrl_conn_alloc didn't properly initialize fd to -1,
* so make sure to do it here otherwise fd may be valid fd 0 and cause trouble */
ctx->neigh_ctrl_conn->write_queue.bfd.fd = -1;
llist_add(&ctx->neigh_ctrl_conn->list_entry, &ctx->neigh_ctrl->ccon_list);
}
return ctx;
free_ret:
talloc_free(ctx);
return NULL;
}
bool nacc_fsm_is_waiting_addr_resolution(const struct nacc_fsm_ctx *ctx,
const struct neigh_cache_entry_key *neigh_key)
{
if (ctx->fi->state != NACC_ST_WAIT_RESOLVE_RAC_CI)
return false;
return neigh_cache_entry_key_eq(&ctx->neigh_key, neigh_key);
}
bool nacc_fsm_is_waiting_si_resolution(const struct nacc_fsm_ctx *ctx,
const struct osmo_cell_global_id_ps *cgi_ps)
{
if (ctx->fi->state != NACC_ST_WAIT_REQUEST_SI)
return false;
return !osmo_cgi_ps_cmp(&ctx->cgi_ps, cgi_ps);
}
bool nacc_fsm_exp_ctrl_ack(const struct nacc_fsm_ctx *ctx, uint32_t fn, uint8_t ts)
{
return ctx->fi->state == NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK &&
ctx->continue_poll_fn == fn &&
ctx->continue_poll_ts == ts;
}

79
src/nacc_fsm.h Normal file
View File

@@ -0,0 +1,79 @@
/* nacc_fsm.h
*
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include <osmocom/core/fsm.h>
#include <osmocom/gsm/gsm23003.h>
#include <neigh_cache.h>
struct GprsMs;
struct gprs_rlcmac_tbf;
enum nacc_fsm_event {
NACC_EV_RX_CELL_CHG_NOTIFICATION, /* data: Packet_Cell_Change_Notification_t* */
NACC_EV_RX_RAC_CI, /* RAC_CI became available in neigh_cache. NULL on failure, pointer to ctx->cgi_ps on success */
NACC_EV_RX_SI, /* data: struct si_cache_entry* */
NACC_EV_CREATE_RLCMAC_MSG, /* data: struct nacc_ev_create_rlcmac_msg_ctx* */
NACC_EV_RX_CELL_CHG_CONTINUE_ACK,
NACC_EV_TIMEOUT_CELL_CHG_CONTINUE, /* Poll Timeout */
};
enum nacc_fsm_states {
NACC_ST_INITIAL,
NACC_ST_WAIT_RESOLVE_RAC_CI,
NACC_ST_WAIT_REQUEST_SI,
NACC_ST_TX_NEIGHBOUR_DATA,
NACC_ST_TX_CELL_CHG_CONTINUE,
NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK,
NACC_ST_DONE,
};
struct nacc_fsm_ctx {
struct osmo_fsm_inst *fi;
struct GprsMs* ms; /* back pointer */
struct ctrl_handle *neigh_ctrl;
struct ctrl_connection *neigh_ctrl_conn;
struct neigh_cache_entry_key neigh_key; /* target cell info from MS */
struct osmo_cell_global_id_ps cgi_ps; /* target cell info resolved from req_{arfcn+bsic} */
struct si_cache_value si_info; /* SI info resolved from SGSN, to be sent to MS */
size_t si_info_bytes_sent; /* How many bytes out of si_info->si_len were already sent to MS */
size_t container_idx; /* Next container_idx to assign when sending Packet Neighbor Data message */
uint32_t continue_poll_fn; /* Scheduled poll FN to CTRL ACK the Pkt Cell Chg Continue */
uint8_t continue_poll_ts; /* Scheduled poll TS to CTRL ACK the Pkt Cell Chg Continue */
};
/* passed as data in NACC_EV_CREATE_RLCMAC_MSG */
struct nacc_ev_create_rlcmac_msg_ctx {
struct gprs_rlcmac_tbf *tbf; /* target tbf to create messages for */
uint32_t fn; /* FN where the created DL ctrl block is to be sent */
uint8_t ts; /* TS where the created DL ctrl block is to be sent */
struct msgb *msg; /* to be filled by FSM during event processing */
};
struct nacc_fsm_ctx *nacc_fsm_alloc(struct GprsMs* ms);
bool nacc_fsm_is_waiting_addr_resolution(const struct nacc_fsm_ctx *ctx,
const struct neigh_cache_entry_key *neigh_key);
bool nacc_fsm_is_waiting_si_resolution(const struct nacc_fsm_ctx *ctx,
const struct osmo_cell_global_id_ps *cgi_ps);
bool nacc_fsm_exp_ctrl_ack(const struct nacc_fsm_ctx *ctx, uint32_t fn, uint8_t ts);

289
src/neigh_cache.c Normal file
View File

@@ -0,0 +1,289 @@
/* si_cache.c
*
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <talloc.h>
#include <inttypes.h>
#include <osmocom/core/utils.h>
#include <neigh_cache.h>
#include <gprs_debug.h>
static void neigh_cache_schedule_cleanup(struct neigh_cache *cache);
static void neigh_cache_cleanup_cb(void *data)
{
struct timespec now, threshold;
struct neigh_cache *cache = (struct neigh_cache *)data;
struct neigh_cache_entry *it, *tmp;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
/* Instead of adding keep_time_intval to each, substract it from now once */
timespecsub(&now, &cache->keep_time_intval, &threshold);
llist_for_each_entry_safe(it, tmp, &cache->list, list) {
if (timespeccmp(&threshold, &it->update_ts, <))
break;
LOGP(DNACC, LOGL_DEBUG,
"neigh_cache: Removing entry " NEIGH_CACHE_ENTRY_KEY_FMT " => %s\n",
NEIGH_CACHE_ENTRY_KEY_ARGS(&it->key), osmo_cgi_ps_name(&it->value));
llist_del(&it->list);
talloc_free(it);
}
neigh_cache_schedule_cleanup(cache);
}
static void neigh_cache_schedule_cleanup(struct neigh_cache *cache)
{
struct neigh_cache_entry *it;
struct timespec now, threshold, result;
/* First item is the one with oldest update_ts */
it = llist_first_entry_or_null(&cache->list, struct neigh_cache_entry, list);
if (!it)
return;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
timespecadd(&it->update_ts, &cache->keep_time_intval, &threshold);
if (timespeccmp(&now, &threshold, >=)) {
/* Too late, let's flush asynchonously so newly added isn't
* immediatelly freed before return. */
result = (struct timespec){ .tv_sec = 0, .tv_nsec = 0 };
} else {
timespecsub(&threshold, &now, &result);
}
osmo_timer_schedule(&cache->cleanup_timer, result.tv_sec, result.tv_nsec*1000);
}
struct neigh_cache *neigh_cache_alloc(void *ctx, unsigned int keep_time_sec)
{
struct neigh_cache *cache = talloc_zero(ctx, struct neigh_cache);
OSMO_ASSERT(cache);
INIT_LLIST_HEAD(&cache->list);
osmo_timer_setup(&cache->cleanup_timer, neigh_cache_cleanup_cb, cache);
cache->keep_time_intval = (struct timespec){ .tv_sec = keep_time_sec, .tv_nsec = 0};
return cache;
}
void neigh_cache_set_keep_time_interval(struct neigh_cache *cache, unsigned int keep_time_sec)
{
cache->keep_time_intval = (struct timespec){ .tv_sec = keep_time_sec, .tv_nsec = 0};
neigh_cache_schedule_cleanup(cache);
}
struct neigh_cache_entry *neigh_cache_add(struct neigh_cache *cache,
const struct neigh_cache_entry_key *key,
const struct osmo_cell_global_id_ps *value)
{
struct neigh_cache_entry *it;
/* First check if it already exists. If so, simply update timer+value */
it = neigh_cache_lookup_entry(cache, key);
if (!it) {
LOGP(DNACC, LOGL_DEBUG,
"neigh_cache: Inserting new entry " NEIGH_CACHE_ENTRY_KEY_FMT " => %s\n",
NEIGH_CACHE_ENTRY_KEY_ARGS(key), osmo_cgi_ps_name(value));
it = talloc_zero(cache, struct neigh_cache_entry);
OSMO_ASSERT(it);
memcpy(&it->key, key, sizeof(it->key));
} else {
LOGP(DNACC, LOGL_DEBUG,
"neigh_cache: Updating entry " NEIGH_CACHE_ENTRY_KEY_FMT " => (%s -> %s)\n",
NEIGH_CACHE_ENTRY_KEY_ARGS(key), osmo_cgi_ps_name(&it->value), osmo_cgi_ps_name2(value));
/* remove item, we'll add it to the end to have them sorted by last update */
llist_del(&it->list);
}
memcpy(&it->value, value, sizeof(it->value));
OSMO_ASSERT(osmo_clock_gettime(CLOCK_MONOTONIC, &it->update_ts) == 0);
llist_add_tail(&it->list, &cache->list);
neigh_cache_schedule_cleanup(cache);
return it;
}
struct neigh_cache_entry *neigh_cache_lookup_entry(struct neigh_cache *cache,
const struct neigh_cache_entry_key *key)
{
struct neigh_cache_entry *tmp;
llist_for_each_entry(tmp, &cache->list, list) {
if (neigh_cache_entry_key_eq(&tmp->key, key))
return tmp;
}
return NULL;
}
const struct osmo_cell_global_id_ps *neigh_cache_lookup_value(struct neigh_cache *cache,
const struct neigh_cache_entry_key *key)
{
struct neigh_cache_entry *it = neigh_cache_lookup_entry(cache, key);
if (it)
return &it->value;
return NULL;
}
void neigh_cache_free(struct neigh_cache *cache)
{
struct neigh_cache_entry *it, *tmp;
if (!cache)
return;
llist_for_each_entry_safe(it, tmp, &cache->list, list) {
llist_del(&it->list);
talloc_free(it);
}
osmo_timer_del(&cache->cleanup_timer);
talloc_free(cache);
}
////////////////////
// SI CACHE
///////////////////
static void si_cache_schedule_cleanup(struct si_cache *cache);
static void si_cache_cleanup_cb(void *data)
{
struct timespec now, threshold;
struct si_cache *cache = (struct si_cache *)data;
struct si_cache_entry *it, *tmp;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
/* Instead of adding keep_time_intval to each, substract it from now once */
timespecsub(&now, &cache->keep_time_intval, &threshold);
llist_for_each_entry_safe(it, tmp, &cache->list, list) {
if (timespeccmp(&threshold, &it->update_ts, <))
break;
LOGP(DNACC, LOGL_DEBUG, "si_cache: Removing entry %s\n",
osmo_cgi_ps_name(&it->key));
llist_del(&it->list);
talloc_free(it);
}
si_cache_schedule_cleanup(cache);
}
static void si_cache_schedule_cleanup(struct si_cache *cache)
{
struct si_cache_entry *it;
struct timespec now, threshold, result;
/* First item is the one with oldest update_ts */
it = llist_first_entry_or_null(&cache->list, struct si_cache_entry, list);
if (!it)
return;
osmo_clock_gettime(CLOCK_MONOTONIC, &now);
timespecadd(&it->update_ts, &cache->keep_time_intval, &threshold);
if (timespeccmp(&now, &threshold, >=)) {
/* Too late, let's flush asynchonously so newly added isn't
* immediatelly freed before return. */
result = (struct timespec){ .tv_sec = 0, .tv_nsec = 0 };
} else {
timespecsub(&threshold, &now, &result);
}
osmo_timer_schedule(&cache->cleanup_timer, result.tv_sec, result.tv_nsec*1000);
}
struct si_cache *si_cache_alloc(void *ctx, unsigned int keep_time_sec)
{
struct si_cache *cache = talloc_zero(ctx, struct si_cache);
OSMO_ASSERT(cache);
INIT_LLIST_HEAD(&cache->list);
osmo_timer_setup(&cache->cleanup_timer, si_cache_cleanup_cb, cache);
cache->keep_time_intval = (struct timespec){ .tv_sec = keep_time_sec, .tv_nsec = 0};
return cache;
}
void si_cache_set_keep_time_interval(struct si_cache *cache, unsigned int keep_time_sec)
{
cache->keep_time_intval = (struct timespec){ .tv_sec = keep_time_sec, .tv_nsec = 0};
si_cache_schedule_cleanup(cache);
}
struct si_cache_entry *si_cache_add(struct si_cache *cache,
const struct osmo_cell_global_id_ps *key,
const struct si_cache_value *value)
{
struct si_cache_entry *it;
/* First check if it already exists. If so, simply update timer+value */
it = si_cache_lookup_entry(cache, key);
if (!it) {
LOGP(DNACC, LOGL_DEBUG, "si_cache: Inserting new entry %s\n",
osmo_cgi_ps_name(key));
it = talloc_zero(cache, struct si_cache_entry);
OSMO_ASSERT(it);
memcpy(&it->key, key, sizeof(it->key));
} else {
LOGP(DNACC, LOGL_DEBUG, "si_cache: Updating entry %s\n",
osmo_cgi_ps_name(&it->key));
/* remove item, we'll add it to the end to have them sorted by last update */
llist_del(&it->list);
}
memcpy(&it->value, value, sizeof(it->value));
OSMO_ASSERT(osmo_clock_gettime(CLOCK_MONOTONIC, &it->update_ts) == 0);
llist_add_tail(&it->list, &cache->list);
si_cache_schedule_cleanup(cache);
return it;
}
struct si_cache_entry *si_cache_lookup_entry(struct si_cache *cache,
const struct osmo_cell_global_id_ps *key)
{
struct si_cache_entry *tmp;
llist_for_each_entry(tmp, &cache->list, list) {
if (osmo_cgi_ps_cmp(&tmp->key, key) == 0)
return tmp;
}
return NULL;
}
const struct si_cache_value *si_cache_lookup_value(struct si_cache *cache,
const struct osmo_cell_global_id_ps *key)
{
struct si_cache_entry *it = si_cache_lookup_entry(cache, key);
if (it)
return &it->value;
return NULL;
}
void si_cache_free(struct si_cache *cache)
{
struct si_cache_entry *it, *tmp;
if (!cache)
return;
llist_for_each_entry_safe(it, tmp, &cache->list, list) {
llist_del(&it->list);
talloc_free(it);
}
osmo_timer_del(&cache->cleanup_timer);
talloc_free(cache);
}

112
src/neigh_cache.h Normal file
View File

@@ -0,0 +1,112 @@
/* neigh_cache.h
*
* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#pragma once
#include <stdint.h>
#include <inttypes.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/gprs/gprs_bssgp_rim.h>
////////////////////
// NEIGH CACHE
///////////////////
/* ARFC+BSIC -> CGI PS cache */
struct neigh_cache {
struct llist_head list; /* list of neigh_cache_entry items */
struct osmo_timer_list cleanup_timer; /* Timer removing too-old entries */
struct timespec keep_time_intval;
};
struct neigh_cache_entry_key {
uint16_t local_lac;
uint16_t local_ci;
uint16_t tgt_arfcn;
uint8_t tgt_bsic;
};
#define NEIGH_CACHE_ENTRY_KEY_FMT "%" PRIu16 "-%" PRIu16 "-%" PRIu16 "-%" PRIu8
#define NEIGH_CACHE_ENTRY_KEY_ARGS(key) (key)->local_lac, (key)->local_ci, (key)->tgt_arfcn, (key)->tgt_bsic
static inline bool neigh_cache_entry_key_eq(const struct neigh_cache_entry_key *a,
const struct neigh_cache_entry_key *b)
{
return a->local_lac == b->local_lac &&
a->local_ci == b->local_ci &&
a->tgt_arfcn == b->tgt_arfcn &&
a->tgt_bsic == b->tgt_bsic;
}
struct neigh_cache_entry {
struct llist_head list; /* to be included in neigh_cache->list */
struct timespec update_ts;
struct neigh_cache_entry_key key;
struct osmo_cell_global_id_ps value;
};
struct neigh_cache *neigh_cache_alloc(void *ctx, unsigned int keep_time_sec);
void neigh_cache_set_keep_time_interval(struct neigh_cache *cache, unsigned int keep_time_sec);
struct neigh_cache_entry *neigh_cache_add(struct neigh_cache *cache,
const struct neigh_cache_entry_key *key,
const struct osmo_cell_global_id_ps *value);
struct neigh_cache_entry *neigh_cache_lookup_entry(struct neigh_cache *cache,
const struct neigh_cache_entry_key *key);
const struct osmo_cell_global_id_ps *neigh_cache_lookup_value(struct neigh_cache *cache,
const struct neigh_cache_entry_key *key);
void neigh_cache_free(struct neigh_cache *cache);
////////////////////
// SI CACHE
///////////////////
/* CGI-PS-> SI cache */
struct si_cache {
struct llist_head list; /* list of si_cache_entry items */
struct osmo_timer_list cleanup_timer; /* Timer removing too-old entries */
struct timespec keep_time_intval;
};
struct si_cache_value {
uint8_t si_buf[BSSGP_RIM_PSI_LEN * 127]; /* 3GPP TS 48.018 11.3.63.2.1 */
size_t si_len;
bool type_psi;
};
struct si_cache_entry {
struct llist_head list; /* to be included in si_cache->list */
struct timespec update_ts;
struct osmo_cell_global_id_ps key;
struct si_cache_value value;
};
struct si_cache *si_cache_alloc(void *ctx, unsigned int keep_time_sec);
void si_cache_set_keep_time_interval(struct si_cache *cache, unsigned int keep_time_sec);
struct si_cache_entry *si_cache_add(struct si_cache *cache,
const struct osmo_cell_global_id_ps *key,
const struct si_cache_value *value);
struct si_cache_entry *si_cache_lookup_entry(struct si_cache *cache,
const struct osmo_cell_global_id_ps *key);
const struct si_cache_value *si_cache_lookup_value(struct si_cache *cache,
const struct osmo_cell_global_id_ps *key);
void si_cache_free(struct si_cache *cache);

View File

@@ -1,186 +0,0 @@
/* openbts_sock.cpp
*
* Copyright (C) 2012 Ivan Klyuchnikov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <errno.h>
#include <string.h>
#include <gprs_rlcmac.h>
#include <gprs_bssgp_pcu.h>
#include <pcu_l1_if.h>
#include <gprs_debug.h>
#include <bitvector.h>
#include <sys/socket.h>
#include <arpa/inet.h>
extern "C" {
#include <osmocom/core/talloc.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/gsm_utils.h>
#include <pcuif_proto.h>
}
extern void *tall_pcu_ctx;
struct femtol1_hdl {
struct gsm_time gsm_time;
uint32_t hLayer1; /* handle to the L1 instance in the DSP */
uint32_t dsp_trace_f;
uint16_t clk_cal;
struct llist_head wlc_list;
void *priv; /* user reference */
struct osmo_timer_list alive_timer;
unsigned int alive_prim_cnt;
struct osmo_fd read_ofd; /* osmo file descriptors */
struct osmo_wqueue write_q;
struct {
uint16_t arfcn;
uint8_t tn;
uint8_t tsc;
uint16_t ta;
} channel_info;
};
struct l1fwd_hdl {
struct sockaddr_storage remote_sa;
socklen_t remote_sa_len;
struct osmo_wqueue udp_wq;
struct femtol1_hdl *fl1h;
};
struct l1fwd_hdl *l1fh = talloc_zero(NULL, struct l1fwd_hdl);
// TODO: We should move this parameters to config file.
#define PCU_L1_IF_PORT 5944
/* OpenBTS socket functions */
int pcu_sock_send(struct msgb *msg)
{
osmo_wqueue_enqueue(&l1fh->udp_wq, msg);
return 0;
}
/* data has arrived on the udp socket */
static int udp_read_cb(struct osmo_fd *ofd)
{
struct msgb *msg = msgb_alloc_headroom(2048, 128, "udp_rx");
struct l1fwd_hdl *l1fh = (l1fwd_hdl *)ofd->data;
struct femtol1_hdl *fl1h = l1fh->fl1h;
int rc;
if (!msg)
return -ENOMEM;
msg->l1h = msg->data;
l1fh->remote_sa_len = sizeof(l1fh->remote_sa);
rc = recvfrom(ofd->fd, msg->l1h, msgb_tailroom(msg), 0,
(struct sockaddr *) &l1fh->remote_sa, &l1fh->remote_sa_len);
if (rc < 0) {
perror("read from udp");
msgb_free(msg);
return rc;
} else if (rc == 0) {
perror("len=0 read from udp");
msgb_free(msg);
return rc;
}
msgb_put(msg, rc);
struct gsm_pcu_if *pcu_prim = (gsm_pcu_if *)(msg->l1h);
rc = pcu_rx(pcu_prim->msg_type, pcu_prim);
msgb_free(msg);
return rc;
}
/* callback when we can write to the UDP socket */
static int udp_write_cb(struct osmo_fd *ofd, struct msgb *msg)
{
int rc;
struct l1fwd_hdl *l1fh = (l1fwd_hdl *)ofd->data;
//LOGP(DPCU, LOGL_ERROR, "UDP: Writing %u bytes for MQ_L1_WRITE queue\n", msgb_length(msg));
rc = sendto(ofd->fd, msgb_data(msg), msgb_length(msg), 0,
(const struct sockaddr *)&l1fh->remote_sa, l1fh->remote_sa_len);
if (rc < 0) {
LOGP(DPCU, LOGL_ERROR, "error writing to L1 msg_queue: %s\n",
strerror(errno));
return rc;
} else if (rc < (int)msgb_length(msg)) {
LOGP(DPCU, LOGL_ERROR, "short write to L1 msg_queue: "
"%u < %u\n", rc, msgb_length(msg));
return -EIO;
}
return 0;
}
int pcu_l1if_open()
{
struct femtol1_hdl *fl1h;
int rc;
/* allocate new femtol1_handle */
fl1h = talloc_zero(tall_pcu_ctx, struct femtol1_hdl);
INIT_LLIST_HEAD(&fl1h->wlc_list);
l1fh->fl1h = fl1h;
fl1h->priv = l1fh;
struct osmo_wqueue * queue = &((l1fh->fl1h)->write_q);
osmo_wqueue_init(queue, 10);
queue->bfd.when |= BSC_FD_READ;
queue->bfd.data = l1fh;
queue->bfd.priv_nr = 0;
/* Open UDP */
struct osmo_wqueue *wq = &l1fh->udp_wq;
osmo_wqueue_init(wq, 10);
wq->write_cb = udp_write_cb;
wq->read_cb = udp_read_cb;
wq->bfd.when |= BSC_FD_READ;
wq->bfd.data = l1fh;
wq->bfd.priv_nr = 0;
rc = osmo_sock_init_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM,
IPPROTO_UDP, NULL, PCU_L1_IF_PORT,
OSMO_SOCK_F_BIND);
if (rc < 0) {
perror("sock_init");
exit(1);
}
return 0;
}
void pcu_l1if_close(void)
{
gprs_bssgp_destroy_or_exit();
/* FIXME: cleanup l1if */
talloc_free(l1fh->fl1h);
}

Some files were not shown because too many files have changed in this diff Show More