Compare commits

..

74 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
503f445d2c bsc: Do not re-start the grace timer when we are in the grace period 2011-08-25 23:22:02 +02:00
Holger Hans Peter Freyther
7c13f4b975 bsc: Simplify the trap sending by using the location state method 2011-08-25 23:22:01 +02:00
Holger Hans Peter Freyther
158a382212 bsc: Send a TRAP with the locations on a MSC connection
Send the current position when the MSC connection is established.
2011-08-25 23:21:55 +02:00
Holger Hans Peter Freyther
82e5339504 bsc: Introduce an authenticated signal for the MSC connection
Send the signal whenever a MSC appears to be authenticated.
2011-08-25 23:19:56 +02:00
Holger Hans Peter Freyther
63c2c828c0 bsc: Auto RF Off in case of missing MSC connection
For short IP failures we want the RF to stay up and wait for
the re-connect but in case the A-link is gone too long it is
good to switch off the RF and wait for commands to enable it
again.
2011-08-25 23:19:45 +02:00
Holger Hans Peter Freyther
1979e7227f bsc: Use the BSC RF CTRL to change the RF state of the TRXs
Use the delayed scheduling feature of the osmo_bsc_rf class to
avoid crashing the site controller of the nanoBTS.
2011-08-25 23:19:39 +02:00
Holger Hans Peter Freyther
ff4ded5903 bsc: Crash fix for the osmo-nitb/MNCC code
It is possible that MNCC sends a MNCC_LCHAN_MODIFY and
wants a channel mode that is not possible on the current
lchan, in that case a new channel is assigned. We now crash
as the osmo-nitb is not having an assignment complete handler,
add a NULL check.
2011-08-25 23:19:35 +02:00
Holger Hans Peter Freyther
684908e167 bsc: Fix crash that can occur on RF Failure
When we got a clear request we did not clear the internal
association between the gsm_subscriber_connection and the SCCP
part. When we got a DTAP message before the CLEAR COMMAND we
will end up in a crash as the ->bts pointer of the connection
has been cleared.

 #0  bsc_scan_msc_msg (conn=0xde178, msg=<value optimized out>) at osmo_bsc_filter.c:258
 #1  0x000112c8 in bsc_handle_dt1 (conn=0xdebd8, msg=0xd1f58, len=<value optimized out>) at osmo_bsc_bssap.c:507
 #2  0x00010208 in msc_outgoing_sccp_data (conn=<value optimized out>, msg=0xdfacc, len=858696) at osmo_bsc_sccp.c:73
 #3  0x0003c110 in sccp_system_incoming (msgb=0xd1f58) at sccp.c:1064
2011-08-25 23:19:33 +02:00
Holger Hans Peter Freyther
bb976dada9 audio: Make AMR multirate configurable for the osmo-bsc
Provide VTY options to allow/forbid the usage of a
specific multirate option.
2011-08-25 23:19:32 +02:00
Holger Hans Peter Freyther
614da5e88a audio: Make the BSC handle the new mr_config request of the BSC API
Handle the mr_config request and set the AMR multirate config for
the given MSC. Initialize the mr_config with the AMR5.9 default we
have been using until now.
2011-08-25 23:19:17 +02:00
Holger Hans Peter Freyther
fee372e673 audio: Move the setting of MultiRateConfig to one place
Move it to one place so it is more easy to make changes to
that.
2011-08-25 23:19:13 +02:00
Holger Hans Peter Freyther
34ae47f8d3 audio: From RTP point of view we can use one payload for HR/FR AMR
Remove the separation of half-rate and full-rate AMR. The used rate
can be found inside the AMR payload. The signalling of what kind of
traffic channel is used can be done with the GSM 08.08 Chosen
Channel IE in the Assignment Complete message.

This way I can use a fixed payload type in the MGCP GateWay but
have a mixed TCH/F and TCH/H config. E.g. use TCH/F FR3 for some
subscribers when connected to MSC A but use AMR5.9 on a TCH/F for
MSC B when all TCH/Hs are gone.
2011-08-25 23:19:04 +02:00
Holger Hans Peter Freyther
649f5a41e3 audio: Remove the hardcoding of the RTP Payload
The MGCP config must be correct and use 99 for RTP AMR.
2011-08-25 23:18:13 +02:00
Holger Hans Peter Freyther
be20696c67 mgcp: Make CRCX deal better with UDP retransmissions
When the CRCX 200 is lost on the way to the CallAgent we will
get another CRCX (retransmission) which was answered with a 400.

Change the code to extract the CallID, Mode and the optional
LocalOptions first. Then check if the endp is allocated with the
same call identifier, in that case return the current session
information.
2011-08-25 23:18:11 +02:00
Holger Hans Peter Freyther
44da0a3949 mgcp: FreeSWITCH requiresn us to provide the o= and t= param
The SDP file for FreeSWITCH should contain o= (Origin) and the
t= (Timing) for the session. The data of the Origin should be
globally unique but this is not the case yet. We will need to
store the (NTP) time of the creation of the endpoint.
2011-08-25 23:18:08 +02:00
Holger Hans Peter Freyther
4d888fc3ca bsc: Put the full stop before the \n in the log message 2011-08-25 23:18:07 +02:00
Holger Hans Peter Freyther
f87cc7156a bsc: Fix crash when the new route is not available
When we are asked to route calls on a local link and
the link is not available we would crash when trying
to send a packet over a deadline. When we have decided
to move a connection it is guranteed that the current
SCCP connection will vanish, we either migrate to another
MSC or the RSL/subscriber connection will be closed.
2011-08-25 23:18:05 +02:00
Holger Hans Peter Freyther
7b08c794e5 bsc: Add new SCCP connections to the tail 2011-08-25 23:18:03 +02:00
Holger Hans Peter Freyther
aa54e28857 msc: Only kill connections belonging to the given MSC
When a MSC connection drops, only kill the connections that
belong to the given MSC and not all other connections.
2011-08-25 23:18:02 +02:00
Holger Hans Peter Freyther
a8a5ffa1dc bsc: Add VTY code for the local area prefix 2011-08-25 23:18:00 +02:00
Holger Hans Peter Freyther
eca2b31f62 bsc: Add vty code for allowing emergency 2011-08-25 23:17:58 +02:00
Holger Hans Peter Freyther
45a833b4cd bsc: Add vty function for the MSC type 2011-08-25 23:17:56 +02:00
Holger Hans Peter Freyther
7c3524922b bsc: Inspect a CC Setup message and attempt to reroute the traffic
Inspect the CC Setup messages and if the dialed number is matching
the regexp of the local MSC the connection will be rerouted. The
original MSC will get a GSM0808 CLEAR REQUEST, a new connection with
a CC Setup message will be opened.
2011-08-25 23:17:46 +02:00
Holger Hans Peter Freyther
735c714a74 bsc: Look for CM Service Requests with emergency cause
Look for emergency calls and send them to a MSC that can
handle them properly.
2011-08-25 23:17:36 +02:00
Holger Hans Peter Freyther
935eac12aa bsc: Introduce a local MSC type and forbid it from being selected 2011-08-25 23:17:26 +02:00
Holger Hans Peter Freyther
5135fbefd0 bsc: Attempt to respond to paging to the MSC that paged
Inspect the message and see if it is a paging response,
then try to find the MSC that has paged this subscriber
and select this as the target MSC, also move the MSC to
the back of the list for 'load balancing'.
2011-08-25 23:17:24 +02:00
Holger Hans Peter Freyther
934355a268 bsc: Hand the msc_connection to the UDT handling, pass it to paging
Pass the osmo_msc_data to the paging sub system, change the code
to pass the osmo_msc_data instead of network + bsc_msc_conn.
2011-08-25 23:17:20 +02:00
Holger Hans Peter Freyther
6bceb8a5b0 bsc: Move the finding of a MSC into the filter code
For responding to paging on the right link we will need to
figure out if the msg is a paging response.
2011-08-25 23:17:17 +02:00
Holger Hans Peter Freyther
4084e87af9 bsc: Select a MSC in a round-robin fashion
Select a MSC, add it to the back of the list after we have
selected it.
2011-08-25 23:17:13 +02:00
Holger Hans Peter Freyther
6545f7c6b7 bsc: Allow to configure more than one MSC in the VTY 2011-08-25 23:16:57 +02:00
Holger Hans Peter Freyther
deafac1ad0 bsc: Prepare to have multiple MSC connections
We now have a list of MSCs but in the code we will
try to access the MSC with the nr 0.
2011-08-25 23:16:47 +02:00
Holger Hans Peter Freyther
ddb93a6e5e bsc: Use the right connection for outgoing packets
This is needed for simple UDT messages where we do not have
a SCCP connection.
2011-08-25 23:16:45 +02:00
Holger Hans Peter Freyther
6d447a765e bsc: Move more things to use osmo_msc_data* directly 2011-08-25 23:16:34 +02:00
Holger Hans Peter Freyther
1b69ddc65f bsc: Move the bsc_filter to use the osmo_bsc_sccp_con 2011-08-25 23:16:33 +02:00
Holger Hans Peter Freyther
6e7e0fe514 bsc: Move away from ->bsc.msc to use the selected MSC
For multiple MSCs we should only have one place where the MSC
is selected and the rest will extract it from somewhere.
2011-08-25 23:16:29 +02:00
Holger Hans Peter Freyther
6cadfa7328 bsc: Stop using net->bsc->msc and get the right msc from somewhere else 2011-08-25 23:16:27 +02:00
Holger Hans Peter Freyther
6c21ff3d2e bsc: Create a osmo_bsc_data and embed osmo_msc_data
We want to have multiple MSCs but we also have some data
that is only present on a per BSC basis. Right now the
MSC data is not allocated with talloc, so we have some
change in the talloc contexts.
2011-08-25 23:16:21 +02:00
Holger Hans Peter Freyther
d7ff30eb62 misc: Move the bsc_parse_reg to libcommom and name it gsm_parse_reg
Move the regexp parsing code from the NAT to libcommon as it will
be used by the NAT and BSC code. This also adds the #include <regex.h>
include to gsm_data. This header should be split up.
2011-08-25 23:02:53 +02:00
Daniel Willmann
c4cc3aab64 nat: Change the ctrl command path
The commands net.<netid>.bsc.<bscid>.* are now forwarded to the
appropriate osmo-bsc. <netid> for now is just 0. <bscid> is not the LAC
anymore (since that could be ambiguous), but instead the number as
configured in bsc-nat.cfg
2011-08-25 17:08:07 +02:00
Daniel Willmann
b59f450314 libctrl, osmo-bsc: Get rid of net prefix
net is now implicit in the root node
2011-08-25 17:07:10 +02:00
Holger Hans Peter Freyther
68399ea77e bsc: Add a null check and return early 2011-08-25 15:02:05 +02:00
Holger Hans Peter Freyther
eabdf75936 ctrl: Fix leak, check null pointer 2011-08-25 15:01:23 +02:00
Daniel Willmann
d9e70a3e07 libctrl: Fix a compiler warning 2011-08-25 14:36:40 +02:00
Daniel Willmann
fc6fc13826 osmo-bsc: Whitespace change - fix indentation of struct value_string 2011-08-25 14:36:39 +02:00
Daniel Willmann
7c6405b5ce osmo-bsc: Include rf stati in the location-state TRAP as well
The first fields are still the location up to the height.
The next field is "operational" if any of the trx are operational,
otherwise "inoperational"
The second to last field contains "locked" if all of the trx are in the
admin state, otherwise "unlocked".
The last field represents the rf policy currently in effect. It is one
of (on|off|grace|unknown).

<tstamp>,<valid>,<lat>,<lon>,<height>,<oper>,<admin>,<policy>
2011-08-25 14:36:01 +02:00
Daniel Willmann
efda919e2d osmo-bsc: Prepare to send more than just the location in the TRAP 2011-08-22 19:27:49 +02:00
Daniel Willmann
1bb18c8e61 osmo-bsc: Use NM_OPSTATE_* to check for operational attributes 2011-08-22 19:27:49 +02:00
Daniel Willmann
67e2f74d01 ctrl: Use strtol instead of atoi to detect conversion errors 2011-08-22 19:27:49 +02:00
Daniel Willmann
ccdc490c33 ctrl: Improve error messages in ctrl_cmd_handle 2011-08-22 19:27:49 +02:00
Daniel Willmann
65e4168e8e ctrl: Change the paths to bts.%i. instead of bts%i 2011-08-22 19:27:49 +02:00
Holger Hans Peter Freyther
b63c4be047 ctrl: Add a function to create the cmd 2011-08-22 19:27:49 +02:00
Holger Hans Peter Freyther
5fff97fa1c ctrl: Do not allow to set the RF Lock for a single trx
The ip.access nanoBTS has issues if the admin changes are called
too often in too little time. This will lead to a situation where
the site manager will fail to start properly. Remove the TRX code
as the RF Control class does not support setting this per TRX.
2011-08-22 19:27:49 +02:00
Daniel Willmann
e3e4f9c4b4 osmo-bsc: Move location command to bts node and use the bts location 2011-08-22 19:27:49 +02:00
Daniel Willmann
d70ea4dd0a osmo-bsc: Change variable name to better reflect current/last location 2011-08-22 19:27:49 +02:00
Daniel Willmann
4caacdf15f osmo-nitb: Fix a warning about undefined reference 2011-08-22 19:27:49 +02:00
Daniel Willmann
b09d1a8fa6 gsm_data: Include a structure for the geographical location in gsm_bts 2011-08-22 19:27:49 +02:00
Daniel Willmann
40f917f3a6 libctrl: Improve error handling if controlif setup fails 2011-08-22 19:27:49 +02:00
Daniel Willmann
5c5bfc4e3c osmo-bsc: Put the control commands in osmo_bsc_ctrl.c 2011-08-22 19:27:47 +02:00
Daniel Willmann
91914cbec2 libctrl: Mark the cmd set/get/verify functions static 2011-08-22 19:24:34 +02:00
Daniel Willmann
4af112527a nat: Fix error in get_next_free_bsc_id
The new function now mimcis the behaviour of
assign_src_local_reference from bsc_sccp.c
2011-08-22 19:24:34 +02:00
Daniel Willmann
1b7e0c0385 osmo-bsc: Change the net.location format
The format is now: <tstamp>,<valid>,<lat>,<lon>,<height>
<tstamp> is the UNIX time (seconds since 1970-01-01 00:00:00 UTC
<valid> is any of the strings "invalid", "fix2d" or "fix3d"
The remaining fields are simple floating point numbers.

If the values given violate the format a meaningful error message is
returned.
2011-08-22 19:24:34 +02:00
Daniel Willmann
c61beefa50 libctrl: Don't overwrite error reply if the verify function sets one 2011-08-22 19:24:34 +02:00
Daniel Willmann
691a68926d libctrl: Bind control interface to localhost 2011-08-22 19:24:34 +02:00
Daniel Willmann
9748a9c1c0 osmo-bsc: Only send a TRAP if the location changes 2011-08-22 19:24:34 +02:00
Daniel Willmann
d13f32ccd8 osmo-bsc: Allow location tstamp to be zero if fix is invalid 2011-08-22 19:24:34 +02:00
Daniel Willmann
505ccabd64 contrib/bsc_control.py: Patch by Holger to handle connection resets 2011-08-22 19:24:34 +02:00
Daniel Willmann
58534aa408 osmo-nitb: Update control interface API in osmo-nitb 2011-08-22 19:24:34 +02:00
Daniel Willmann
73f3f2866f nat: Add support for traps to the nat 2011-08-22 19:24:34 +02:00
Daniel Willmann
d280f2dfbd osmo-bsc: Add support for traps to the location command 2011-08-22 19:24:29 +02:00
Daniel Willmann
72feed7c70 libctrl: Add trap helper function 2011-07-28 19:40:26 +02:00
Daniel Willmann
e7a75b6be2 libctrl: Add function ctrl_cmd_send_to_all
Sends a command to all ctrl connections except the one it originated
from.
2011-07-28 19:40:26 +02:00
Daniel Willmann
81671d54b0 libctrl: Change controlif_setup so it returns the ctrl handle
nat: Catch up with controlif_setup API change
We now save a control handle reference in the nat
osmo-bsc: Catch up with controlif_setup API change
We now save a control handle reference in the gsm network
2011-07-28 19:40:26 +02:00
Daniel Willmann
145c58df93 libctrl: Keep track of connections in struct ctrl_handle 2011-07-28 19:40:26 +02:00
Daniel Willmann
f997e56945 libctrl: Use DCTRL as logging destination in libctrl 2011-07-28 19:40:26 +02:00
178 changed files with 8374 additions and 7279 deletions

10
openbsc/.gitignore vendored
View File

@@ -7,7 +7,7 @@ bscconfig.h
bscconfig.h.in
openbsc.pc
src/osmo-nitb/osmo-nitb
src/osmo-bsc_mgcp/osmo-bsc_mgcp
bsc_mgcp
src/osmo-bsc/osmo-bsc
*.*~
*.sw?
@@ -51,13 +51,5 @@ tests/mgcp/mgcp_test
tests/sccp/sccp_test
tests/sms/sms_test
tests/timer/timer_test
tests/gprs/gprs_test
tests/atconfig
tests/atlocal
tests/package.m4
tests/testsuite
tests/testsuite.log
src/openbsc.cfg*

View File

@@ -4,7 +4,6 @@ AC_INIT([openbsc],
[openbsc-devel@lists.openbsc.org])
AM_INIT_AUTOMAKE([dist-bzip2])
AC_CONFIG_TESTDIR(tests)
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -18,6 +17,10 @@ AC_PROG_RANLIB
dnl checks for libraries
AC_SEARCH_LIBS(crypt, crypt,
[LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
AC_SEARCH_LIBS(gtp_new, gtp,
[LIBCRYPT="-lgtp"; AC_SUBST([GPRS_LIBGTP], [1])])
AM_CONDITIONAL(HAVE_LIBGTP, test "x$GPRS_LIBGTP" != "x")
AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])],
@@ -29,7 +32,6 @@ AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Require
osmo_ac_build_nat="no"
])
AM_CONDITIONAL(BUILD_NAT, test "x$osmo_ac_build_nat" = "xyes")
AC_SUBST(osmo_ac_build_nat)
AC_ARG_ENABLE([osmo-bsc], [AS_HELP_STRING([--enable-osmo-bsc], [Build the Osmo BSC])],
[
@@ -44,11 +46,6 @@ AM_CONDITIONAL(BUILD_BSC, test "x$osmo_ac_build_bsc" = "xyes")
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.2)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.1.0)
found_libgtp=yes
PKG_CHECK_MODULES(LIBGTP, libgtp, , found_libgtp=no)
AM_CONDITIONAL(HAVE_LIBGTP, test "$found_libgtp" = yes)
dnl checks for header files
AC_HEADER_STDC
@@ -83,30 +80,6 @@ if test "$enable_coverage" = "yes"; then
AC_SUBST([COVERAGE_LDFLAGS])
fi
AC_DEFUN([CHECK_TM_INCLUDES_TM_GMTOFF], [
AC_CACHE_CHECK(
[whether struct tm has tm_gmtoff member],
osmo_cv_tm_includes_tm_gmtoff,
[AC_LINK_IFELSE([
AC_LANG_PROGRAM([
#include <time.h>
], [
time_t t = time(NULL);
struct tm* lt = localtime(&t);
int off = lt->tm_gmtoff;
])
],
osmo_cv_tm_includes_tm_gmtoff=yes,
osmo_cv_tm_includes_tm_gmtoff=no
)]
)
if test "x$osmo_cv_tm_includes_tm_gmtoff" = xyes; then
AC_DEFINE(HAVE_TM_GMTOFF_IN_TM, 1,
[Define if struct tm has tm_gmtoff member.])
fi
])
CHECK_TM_INCLUDES_TM_GMTOFF
dnl Generate the output
AM_CONFIG_HEADER(bscconfig.h)
@@ -117,6 +90,7 @@ AC_OUTPUT(
include/Makefile
src/Makefile
src/libtrau/Makefile
src/libabis/Makefile
src/libbsc/Makefile
src/libctrl/Makefile
src/libmsc/Makefile
@@ -131,14 +105,12 @@ AC_OUTPUT(
src/libgb/Makefile
src/gprs/Makefile
tests/Makefile
tests/atlocal
tests/debug/Makefile
tests/gsm0408/Makefile
tests/db/Makefile
tests/channel/Makefile
tests/bsc-nat/Makefile
tests/mgcp/Makefile
tests/gprs/Makefile
doc/Makefile
doc/examples/Makefile
Makefile)

View File

@@ -1,56 +0,0 @@
"
Simple UDP replay from the state files
"
PackageLoader fileInPackage: #Sockets.
Eval [
| last_time last_image udp_send socket dest |
last_time := nil.
last_image := nil.
file := FileStream open: 'rtp_ssrc13529910.240.240.1_to_10.240.240.50.state'.
"Send the payload"
dest := Sockets.SocketAddress byName: '127.0.0.1'.
socket := Sockets.DatagramSocket new.
udp_send := [:payload | | datagram |
datagram := Sockets.Datagram data: payload contents address: dest port: 4000.
socket nextPut: datagram
].
[file atEnd] whileFalse: [
| lineStream time data now_image |
lineStream := file nextLine readStream.
"Read the time, skip the blank, parse the data"
time := Number readFrom: lineStream.
lineStream skip: 1.
data := WriteStream on: (ByteArray new: 30).
[lineStream atEnd] whileFalse: [
| hex |
hex := lineStream next: 2.
data nextPut: (Number readFrom: hex readStream radix: 16).
].
last_time isNil
ifTrue: [
"First time, send it right now"
last_time := time.
last_image := Time millisecondClockValue.
udp_send value: data.
]
ifFalse: [
| wait_image new_image_time |
"How long to wait?"
wait_image := last_image + ((time - last_time) * 1000).
[ wait_image > Time millisecondClockValue ] whileTrue: [].
udp_send value: data.
last_time := time.
last_image := wait_image.
]
].
]

View File

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

View File

@@ -1,2 +1,2 @@
/usr/bin/osmo-bsc_mgcp
/usr/bin/bsc_mgcp
/usr/bin/osmo-bsc

View File

@@ -1 +0,0 @@
doc/examples/osmo-sgsn

View File

@@ -55,7 +55,7 @@ bsc_api.c:gsm0808_clear
* Release a channel used for handover
* Release the primary lchan with normal release, SACH deactivate
chan_alloc.c:lchan_release(chan, sacch_deactivate, reason)
chan_alloc.c:lchan_release(chan, sach_deactivate, reason)
* Start release procedure. It is working in steps with callbacks
coming from the abis_rsl.c code.
* Release all SAPI's > 0, wait for them to be released

View File

@@ -39,8 +39,6 @@ log stderr
line vty
no login
!
e1_input
e1_line 0 driver ipa
network
network country code 1
mobile network code 1
@@ -88,7 +86,7 @@ network
rach tx integer 9
rach max transmission 7
ip.access unit_id 0 0
oml ip.access stream_id 255 line 0
oml ip.access stream_id 255
neighbor-list mode manual-si5
neighbor-list add arfcn 100
neighbor-list add arfcn 200

View File

@@ -6,8 +6,6 @@ password foo
line vty
no login
!
e1_input
e1_line 0 driver hsl
network
network country code 262
mobile network code 42
@@ -56,7 +54,6 @@ network
rach max transmission 1
hsl serial-number 8303701
neighbor-list mode automatic
oml hsl line 0
gprs mode none
trx 0
rf_locked 0

View File

@@ -6,8 +6,6 @@ password foo
line vty
no login
!
e1_input
e1_line 0 driver ipa
network
network country code 1
mobile network code 1
@@ -51,7 +49,7 @@ network
rach tx integer 9
rach max transmission 7
ip.access unit_id 1800 0
oml ip.access stream_id 255 line 0
oml ip.access stream_id 255
gprs mode none
trx 0
rf_locked 0

View File

@@ -6,8 +6,6 @@ password foo
line vty
no login
!
e1_input
e1_line 0 driver ipa
network
network country code 1
mobile network code 1
@@ -51,7 +49,7 @@ network
rach tx integer 9
rach max transmission 7
ip.access unit_id 1801 0
oml ip.access stream_id 255 line 0
oml ip.access stream_id 255
gprs mode none
trx 0
rf_locked 0

View File

@@ -1,118 +0,0 @@
!
! OpenBSC configuration saved from vty
! !
password foo
!
line vty
no login
!
e1_input
e1_line 0 driver misdn
network
network country code 1
mobile network code 1
short name OpenBSC
long name OpenBSC
auth policy accept-all
timer t3101 10
timer t3113 60
bts 0
type nokia_site
band GSM1800
cell_identity 1
location_area_code 1
base_station_id_code 63
training_sequence_code 7
oml e1 line 0 timeslot 1 sub-slot full
oml e1 tei 1
trx 0
arfcn 866
max_power_red 24
rsl e1 line 0 timeslot 2 sub-slot full
rsl e1 tei 1
timeslot 0
phys_chan_config CCCH+SDCCH4
e1 line 0 timeslot 6 sub-slot full
timeslot 1
phys_chan_config SDCCH8
e1 line 0 timeslot 6 sub-slot 1
timeslot 2
phys_chan_config TCH/F
e1 line 0 timeslot 6 sub-slot 2
timeslot 3
phys_chan_config TCH/F
e1 line 0 timeslot 6 sub-slot 3
timeslot 4
phys_chan_config TCH/F
e1 line 0 timeslot 7 sub-slot 0
timeslot 5
phys_chan_config TCH/F
e1 line 0 timeslot 7 sub-slot 1
timeslot 6
phys_chan_config TCH/F
e1 line 0 timeslot 7 sub-slot 2
timeslot 7
phys_chan_config TCH/F
e1 line 0 timeslot 7 sub-slot 3
trx 1
arfcn 870
max_power_red 24
rsl e1 line 0 timeslot 3 sub-slot full
rsl e1 tei 2
timeslot 0
phys_chan_config TCH/F
e1 line 0 timeslot 8 sub-slot 0
timeslot 1
phys_chan_config TCH/F
e1 line 0 timeslot 8 sub-slot 1
timeslot 2
phys_chan_config TCH/F
e1 line 0 timeslot 8 sub-slot 2
timeslot 3
phys_chan_config TCH/F
e1 line 0 timeslot 8 sub-slot 3
timeslot 4
phys_chan_config TCH/F
e1 line 0 timeslot 9 sub-slot 0
timeslot 5
phys_chan_config TCH/F
e1 line 0 timeslot 9 sub-slot 1
timeslot 6
phys_chan_config TCH/F
e1 line 0 timeslot 9 sub-slot 2
timeslot 7
phys_chan_config TCH/F
e1 line 0 timeslot 9 sub-slot 3
trx 2
arfcn 874
max_power_red 24
rsl e1 line 0 timeslot 4 sub-slot full
rsl e1 tei 3
timeslot 0
phys_chan_config TCH/F
e1 line 0 timeslot 10 sub-slot 0
timeslot 1
phys_chan_config TCH/F
e1 line 0 timeslot 10 sub-slot 1
timeslot 2
phys_chan_config TCH/F
e1 line 0 timeslot 10 sub-slot 2
timeslot 3
phys_chan_config TCH/F
e1 line 0 timeslot 10 sub-slot 3
timeslot 4
phys_chan_config TCH/F
e1 line 0 timeslot 11 sub-slot 0
timeslot 5
phys_chan_config TCH/F
e1 line 0 timeslot 11 sub-slot 1
timeslot 6
phys_chan_config TCH/F
e1 line 0 timeslot 11 sub-slot 2
timeslot 7
phys_chan_config TCH/F
e1 line 0 timeslot 11 sub-slot 3

View File

@@ -1,26 +0,0 @@
!
! Osmocom SGSN configuration
!
!
line vty
no login
!
sgsn
gtp local-ip 10.23.23.23
ggsn 0 remote-ip 192.168.0.101
ggsn 0 gtp-version 1
!
ns
timer tns-block 3
timer tns-block-retries 3
timer tns-reset 3
timer tns-reset-retries 3
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-ip 192.168.0.101
encapsulation udp local-port 23000
encapsulation framerelay-gre enabled 0
!
bssgp
!

View File

@@ -1,18 +1,18 @@
noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
gsm_subscriber.h gsm_04_11.h debug.h signal.h \
misdn.h chan_alloc.h paging.h \
trau_mux.h rs232.h openbscdefines.h rtp_proxy.h \
subchan_demux.h trau_frame.h e1_input.h trau_mux.h \
ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \
silent_call.h mgcp.h meas_rep.h rest_octets.h \
system_information.h handover.h mgcp_internal.h \
vty.h socket.h e1_config.h trau_upqueue.h token_auth.h \
handover_decision.h rrlp.h control_if.h \
vty.h socket.h \
crc24.h gprs_bssgp.h gprs_llc.h gprs_ns.h gprs_gmm.h \
gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.h \
gprs_ns_frgre.h auth.h osmo_msc.h bsc_msc.h bsc_nat.h \
osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \
osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \
bss.h gsm_data_shared.h control_cmd.h ipaccess.h mncc_int.h
bss.h gsm_data_shared.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc

View File

@@ -160,8 +160,5 @@ int abis_nm_vty_init(void);
void abis_nm_clear_queue(struct gsm_bts *bts);
int _abis_nm_sendmsg(struct msgb *msg);
void abis_nm_queue_send_next(struct gsm_bts *bts); /* for bs11_config. */
#endif /* _NM_H */

View File

@@ -72,6 +72,7 @@ int rsl_release_request(struct gsm_lchan *lchan, uint8_t link_id, uint8_t reason
int rsl_lchan_set_state(struct gsm_lchan *lchan, int);
/* to be provided by external code */
int abis_rsl_sendmsg(struct msgb *msg);
int rsl_deact_sacch(struct gsm_lchan *lchan);
int rsl_lchan_rll_release(struct gsm_lchan *lchan, uint8_t link_id);
@@ -89,12 +90,5 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm);
int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
uint8_t cb_command, const uint8_t *data, int len);
/* some Nokia specific stuff */
int rsl_nokia_si_begin(struct gsm_bts_trx *trx);
int rsl_nokia_si_end(struct gsm_bts_trx *trx);
/* required for Nokia BTS power control */
int rsl_bs_power_control(struct gsm_bts_trx *trx, uint8_t channel, uint8_t reduction);
#endif /* RSL_MT_H */

View File

@@ -9,35 +9,31 @@
#define BSC_API_CONN_POL_REJECT 1
struct bsc_api {
/*! \brief BTS->MSC: tell MSC a SAPI was not established */
void (*sapi_n_reject)(struct gsm_subscriber_connection *conn, int dlci);
/*! \brief MS->MSC: Tell MSC that ciphering has been enabled */
void (*cipher_mode_compl)(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint8_t chosen_encr);
/*! \brief MS->MSC: New MM context with L3 payload */
int (*compl_l3)(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint16_t chosen_channel);
/*! \brief MS->BSC/MSC: Um L3 message */
void (*dtap)(struct gsm_subscriber_connection *conn, uint8_t link_id,
struct msgb *msg);
/*! \brief BSC->MSC: Assignment of lchan successful */
void (*assign_compl)(struct gsm_subscriber_connection *conn,
uint8_t rr_cause, uint8_t chosen_channel,
uint8_t encr_alg_id, uint8_t speech_mode);
/*! \brief BSC->MSC: Assignment of lchan failed */
void (*assign_fail)(struct gsm_subscriber_connection *conn,
uint8_t cause, uint8_t *rr_cause);
/*! \brief BSC->MSC: RR conn has been cleared */
int (*clear_request)(struct gsm_subscriber_connection *conn,
uint32_t cause);
/*! \brief BSC->MSC: Classmark Update */
void (*classmark_chg)(struct gsm_subscriber_connection *conn,
const uint8_t *cm2, uint8_t cm2_len,
const uint8_t *cm3, uint8_t cm3_len);
/**
* Configure the multirate setting on this channel. If it is
* not implemented AMR5.9 will be used.
*/
void (*mr_config)(struct gsm_subscriber_connection *conn,
struct gsm48_multi_rate_conf *conf);
};
int bsc_api_init(struct gsm_network *network, struct bsc_api *api);
int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg, int link_id, int allow_sacch);
int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg, int link_id, int allow_sach);
int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate);
int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
const uint8_t *key, int len, int include_imeisv);

View File

@@ -295,10 +295,6 @@ struct bsc_nat {
struct llist_head smsc_rewr;
char *tpdest_match_name;
struct llist_head tpdest_match;
char *sms_clear_tp_srr_name;
struct llist_head sms_clear_tp_srr;
char *sms_num_rewr_name;
struct llist_head sms_num_rewr;
/* USSD messages we want to match */
char *ussd_lst_name;
@@ -314,6 +310,9 @@ struct bsc_nat {
/* statistics */
struct bsc_nat_statistics stats;
/* control interface */
struct ctrl_handle *ctrl;
};
struct bsc_nat_ussd_con {

View File

@@ -14,5 +14,4 @@ extern int bts_model_bs11_init(void);
extern int bts_model_rbs2k_init(void);
extern int bts_model_nanobts_init(void);
extern int bts_model_hslfemto_init(void);
extern int bts_model_nokia_site_init(void);
#endif

View File

@@ -46,7 +46,7 @@ void lchan_free(struct gsm_lchan *lchan);
void lchan_reset(struct gsm_lchan *lchan);
/* Release the given lchan */
int lchan_release(struct gsm_lchan *lchan, int sacch_deact, int release_mode);
int lchan_release(struct gsm_lchan *lchan, int sach_deact, int reason);
struct load_counter {
unsigned int total;

View File

@@ -12,7 +12,6 @@
enum ctrl_node_type {
CTRL_NODE_ROOT, /* Root elements */
CTRL_NODE_NET, /* Network specific (net.) */
CTRL_NODE_BTS, /* BTS specific (net.btsN.) */
CTRL_NODE_TRX, /* TRX specific (net.btsN.trxM.) */
CTRL_NODE_TS, /* TS specific (net.btsN.trxM.tsI.) */
@@ -29,6 +28,14 @@ enum ctrl_type {
CTRL_TYPE_ERROR
};
struct ctrl_handle {
struct osmo_fd listen_fd;
struct gsm_network *gsmnet;
/* List of control connections */
struct llist_head ccon_list;
};
struct ctrl_connection {
struct llist_head list_entry;
@@ -75,9 +82,11 @@ int ctrl_cmd_exec(vector vline, struct ctrl_cmd *command, vector node, void *dat
int ctrl_cmd_install(enum ctrl_node_type node, struct ctrl_cmd_element *cmd);
int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data);
int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd);
int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_parse(void *ctx, struct msgb *msg);
struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_cpy(void *ctx, struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_trap(struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_create(void *ctx, enum ctrl_type);
#define CTRL_CMD_DEFINE_RANGE(cmdname, cmdstr, dtype, element, min, max) \
@@ -150,6 +159,6 @@ struct ctrl_cmd_element cmd_##cmdname = { \
}
struct gsm_network;
int controlif_setup(struct gsm_network *gsmnet, uint16_t port);
struct ctrl_handle *controlif_setup(struct gsm_network *gsmnet, uint16_t port);
#endif /* _CONTROL_CMD_H */

View File

@@ -1,13 +0,0 @@
#ifndef _CONTROL_IF_H
#define _CONTROL_IF_H
#include <osmocom/core/write_queue.h>
#include <openbsc/control_cmd.h>
#include <openbsc/gsm_data.h>
int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd);
int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data);
int controlif_setup(struct gsm_network *gsmnet, uint16_t port);
#endif /* _CONTROL_IF_H */

View File

@@ -19,6 +19,10 @@ enum {
DSMS,
DPAG,
DMEAS,
DMI,
DMIB,
DMUX,
DINP,
DSCCP,
DMSC,
DMGCP,

View File

@@ -1,11 +0,0 @@
#ifndef _E1_CONFIG_H
#define _E1_CONFIG_H
#include <openbsc/gsm_data_shared.h>
int e1_reconfig_ts(struct gsm_bts_trx_ts *ts);
int e1_reconfig_trx(struct gsm_bts_trx *trx);
int e1_reconfig_bts(struct gsm_bts *bts);
#endif /* _E1_CONFIG_H */

View File

@@ -0,0 +1,188 @@
#ifndef _E1_INPUT_H
#define _E1_INPUT_H
#include <stdlib.h>
#include <netinet/in.h>
#include <osmocom/core/linuxlist.h>
#include <openbsc/gsm_data.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <openbsc/subchan_demux.h>
#define NUM_E1_TS 32
enum e1inp_sign_type {
E1INP_SIGN_NONE,
E1INP_SIGN_OML,
E1INP_SIGN_RSL,
};
const char *e1inp_signtype_name(enum e1inp_sign_type tp);
struct e1inp_ts;
struct e1inp_sign_link {
/* list of signalling links */
struct llist_head list;
/* to which timeslot do we belong? */
struct e1inp_ts *ts;
enum e1inp_sign_type type;
/* trx for msg->trx of received msgs */
struct gsm_bts_trx *trx;
/* msgb queue of to-be-transmitted msgs */
struct llist_head tx_list;
/* SAPI and TEI on the E1 TS */
uint8_t sapi;
uint8_t tei;
union {
struct {
uint8_t channel;
} misdn;
} driver;
};
enum e1inp_ts_type {
E1INP_TS_TYPE_NONE,
E1INP_TS_TYPE_SIGN,
E1INP_TS_TYPE_TRAU,
};
const char *e1inp_tstype_name(enum e1inp_ts_type tp);
/* A timeslot in the E1 interface */
struct e1inp_ts {
enum e1inp_ts_type type;
int num;
/* to which line do we belong ? */
struct e1inp_line *line;
union {
struct {
/* list of all signalling links on this TS */
struct llist_head sign_links;
/* delay for the queue */
int delay;
/* timer when to dequeue next frame */
struct osmo_timer_list tx_timer;
} sign;
struct {
/* subchannel demuxer for frames from E1 */
struct subch_demux demux;
/* subchannel muxer for frames to E1 */
struct subch_mux mux;
} trau;
};
union {
struct {
/* mISDN driver has one fd for each ts */
struct osmo_fd fd;
} misdn;
struct {
/* ip.access driver has one fd for each ts */
struct osmo_fd fd;
} ipaccess;
struct {
/* DAHDI driver has one fd for each ts */
struct osmo_fd fd;
struct lapd_instance *lapd;
} dahdi;
} driver;
};
struct e1inp_driver {
struct llist_head list;
const char *name;
int (*want_write)(struct e1inp_ts *ts);
int (*line_update)(struct e1inp_line *line);
int default_delay;
};
struct e1inp_line {
struct llist_head list;
unsigned int num;
const char *name;
/* array of timestlots */
struct e1inp_ts ts[NUM_E1_TS];
struct e1inp_driver *driver;
void *driver_data;
};
/* register a driver with the E1 core */
int e1inp_driver_register(struct e1inp_driver *drv);
/* fine a previously registered driver */
struct e1inp_driver *e1inp_driver_find(const char *name);
/* register a line with the E1 core */
int e1inp_line_register(struct e1inp_line *line);
/* get a line by its ID */
struct e1inp_line *e1inp_line_get(uint8_t e1_nr);
/* create a line in the E1 input core */
struct e1inp_line *e1inp_line_create(uint8_t e1_nr, const char *driver_name);
/* find a sign_link for given TEI and SAPI in a TS */
struct e1inp_sign_link *
e1inp_lookup_sign_link(struct e1inp_ts *ts, uint8_t tei,
uint8_t sapi);
/* create a new signalling link in a E1 timeslot */
struct e1inp_sign_link *
e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type,
struct gsm_bts_trx *trx, uint8_t tei,
uint8_t sapi);
/* configure and initialize one e1inp_ts */
int e1inp_ts_config(struct e1inp_ts *ts, struct e1inp_line *line,
enum e1inp_ts_type type);
/* Call from the Stack: configuration of this TS has changed */
int e1inp_update_ts(struct e1inp_ts *ts);
/* Receive a packet from the E1 driver */
int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
uint8_t tei, uint8_t sapi);
/* called by driver if it wants to transmit on a given TS */
struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts,
struct e1inp_sign_link **sign_link);
/* called by driver in case some kind of link state event */
int e1inp_event(struct e1inp_ts *ts, int evt, uint8_t tei, uint8_t sapi);
/* Write LAPD frames to the fd. */
void e1_set_pcap_fd(int fd);
/* called by TRAU muxer to obtain the destination mux entity */
struct subch_mux *e1inp_get_mux(uint8_t e1_nr, uint8_t ts_nr);
void e1inp_sign_link_destroy(struct e1inp_sign_link *link);
int e1inp_line_update(struct e1inp_line *line);
/* e1_config.c */
int e1_reconfig_ts(struct gsm_bts_trx_ts *ts);
int e1_reconfig_trx(struct gsm_bts_trx *trx);
int e1_reconfig_bts(struct gsm_bts *bts);
int ia_config_connect(struct gsm_bts *bts, struct sockaddr_in *sin);
int ipaccess_setup(struct gsm_network *gsmnet);
int hsl_setup(struct gsm_network *gsmnet);
extern struct llist_head e1inp_driver_list;
extern struct llist_head e1inp_line_list;
int e1inp_vty_init(void);
void e1inp_init(void);
int _abis_nm_sendmsg(struct msgb *msg, int to_trx_oml);
#endif /* _E1_INPUT_H */

View File

@@ -3,11 +3,11 @@
#include <stdint.h>
/*! \brief Fixed BVCI definitions (Section 5.4.1) */
/* Section 5.4.1 */
#define BVCI_SIGNALLING 0x0000
#define BVCI_PTM 0x0001
/*! \brief BSSGP PDU types (Section 11.3.26 / Table 11.27) */
/* Section 11.3.26 / Table 11.27 */
enum bssgp_pdu_type {
/* PDUs between RL and BSSGP SAPs */
BSSGP_PDUT_DL_UNITDATA = 0x00,
@@ -53,21 +53,19 @@ enum bssgp_pdu_type {
BSSGP_PDUT_DELETE_BSS_PFC_ACK = 0x57,
};
/*! \brief BSSGP User-Data header (Section 10.2.1 and 10.2.2) */
/* Section 10.2.1 and 10.2.2 */
struct bssgp_ud_hdr {
uint8_t pdu_type; /*!< BSSGP PDU type */
uint32_t tlli; /*!< Temporary Link-Local Identifier */
uint8_t qos_profile[3]; /*!< QoS profile */
uint8_t data[0]; /* optional/conditional IEs as TLVs */
uint8_t pdu_type;
uint32_t tlli;
uint8_t qos_profile[3];
uint8_t data[0]; /* TLV's */
} __attribute__((packed));
/*! \brief BSSGP normal header */
struct bssgp_normal_hdr {
uint8_t pdu_type; /*!< BSSGP PDU type */
uint8_t data[0]; /*!< optional/conditional IEs as TLVs */
uint8_t pdu_type;
uint8_t data[0]; /* TLV's */
};
/*! \brief BSSGP Information Element Identifiers */
enum bssgp_iei_type {
BSSGP_IE_ALIGNMENT = 0x00,
BSSGP_IE_BMAX_DEFAULT_MS = 0x01,
@@ -117,7 +115,7 @@ enum bssgp_iei_type {
BSSGP_IE_SERVICE_UTRAN_CCO = 0x3d,
};
/*! \brief Cause coding (Section 11.3.8 / Table 11.10) */
/* Section 11.3.8 / Table 11.10: Cause coding */
enum gprs_bssgp_cause {
BSSGP_CAUSE_PROC_OVERLOAD = 0x00,
BSSGP_CAUSE_EQUIP_FAIL = 0x01,
@@ -161,8 +159,9 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg);
struct bssgp_bvc_ctx {
struct llist_head list;
struct gprs_ra_id ra_id; /*!< parsed RA ID of the remote BTS */
uint16_t cell_id; /*!< Cell ID of the remote BTS */
/* parsed RA ID and Cell ID of the remote BTS */
struct gprs_ra_id ra_id;
uint16_t cell_id;
/* NSEI and BVCI of underlying Gb link. Together they
* uniquely identify a link to a BTS (5.4.4) */
@@ -183,18 +182,6 @@ struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t
/* Find a BTS context based on BVCI+NSEI tuple */
struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei);
#define BVC_F_BLOCKED 0x0001
enum bssgp_ctr {
BSSGP_CTR_PKTS_IN,
BSSGP_CTR_PKTS_OUT,
BSSGP_CTR_BYTES_IN,
BSSGP_CTR_BYTES_OUT,
BSSGP_CTR_BLOCKED,
BSSGP_CTR_DISCARDED,
};
#include <osmocom/gsm/tlv.h>
/* BSSGP-UL-UNITDATA.ind */
@@ -205,8 +192,6 @@ struct sgsn_mm_ctx;
int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx);
uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf);
int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid,
uint16_t cid);
/* Wrapper around TLV parser to parse BSSGP IEs */
static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len)
@@ -214,30 +199,27 @@ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len)
return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0);
}
/*! \brief BSSGP Paging mode */
enum bssgp_paging_mode {
BSSGP_PAGING_PS,
BSSGP_PAGING_CS,
};
/*! \brief BSSGP Paging scope */
enum bssgp_paging_scope {
BSSGP_PAGING_BSS_AREA, /*!< all cells in BSS */
BSSGP_PAGING_LOCATION_AREA, /*!< all cells in LA */
BSSGP_PAGING_ROUTEING_AREA, /*!< all cells in RA */
BSSGP_PAGING_BVCI, /*!< one cell */
BSSGP_PAGING_BSS_AREA, /* all cells in BSS */
BSSGP_PAGING_LOCATION_AREA, /* all cells in LA */
BSSGP_PAGING_ROUTEING_AREA, /* all cells in RA */
BSSGP_PAGING_BVCI, /* one cell */
};
/*! \brief BSSGP paging information */
struct bssgp_paging_info {
enum bssgp_paging_mode mode; /*!< CS or PS paging */
enum bssgp_paging_scope scope; /*!< bssgp_paging_scope */
struct gprs_ra_id raid; /*!< RA Identifier */
uint16_t bvci; /*!< BVCI */
char *imsi; /*!< IMSI, if any */
uint32_t *ptmsi; /*!< P-TMSI, if any */
uint16_t drx_params; /*!< DRX parameters */
uint8_t qos[3]; /*!< QoS parameters */
enum bssgp_paging_mode mode;
enum bssgp_paging_scope scope;
struct gprs_ra_id raid;
uint16_t bvci;
const char *imsi;
uint32_t *ptmsi;
uint16_t drx_params;
uint8_t qos[3];
};
/* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */

View File

@@ -27,23 +27,6 @@ enum gprs_llc_u_cmd {
GPRS_LLC_U_NULL_CMD = 0x00,
};
/* Section 6.4.1.6 / Table 6 */
enum gprs_llc_xid_type {
GPRS_LLC_XID_T_VERSION = 0,
GPRS_LLC_XID_T_IOV_UI = 1,
GPRS_LLC_XID_T_IOV_I = 2,
GPRS_LLC_XID_T_T200 = 3,
GPRS_LLC_XID_T_N200 = 4,
GPRS_LLC_XID_T_N201_U = 5,
GPRS_LLC_XID_T_N201_I = 6,
GPRS_LLC_XID_T_mD = 7,
GPRS_LLC_XID_T_mU = 8,
GPRS_LLC_XID_T_kD = 9,
GPRS_LLC_XID_T_kU = 10,
GPRS_LLC_XID_T_L3_PAR = 11,
GPRS_LLC_XID_T_RESET = 12,
};
/* TS 04.64 Section 7.1.2 Table 7: LLC layer primitives (GMM/SNDCP/SMS/TOM) */
/* TS 04.65 Section 5.1.2 Table 2: Service primitives used by SNDCP */
enum gprs_llc_primitive {
@@ -168,9 +151,6 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv);
int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
void *mmctx);
/* Chapter 7.2.1.2 LLGMM-RESET.req */
int gprs_llgmm_reset(struct gprs_llc_llme *llme);
/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
int gprs_llgmm_assign(struct gprs_llc_llme *llme,
uint32_t old_tlli, uint32_t new_tlli,
@@ -179,20 +159,4 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
int gprs_llc_init(const char *cipher_plugin_path);
int gprs_llc_vty_init(void);
/**
* \short Check if N(U) should be considered a retransmit
*
* Implements the range check as of GSM 04.64 8.4.2
* Receipt of unacknowledged information.
*
* @returns Returns 1 if (V(UR)-32) <= N(U) < V(UR)
* @param nu N(U) unconfirmed sequence number of the UI frame
* @param vur V(UR) unconfirmend received state variable
*/
static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur)
{
int delta = (vur - nu) & 0x1ff;
return 0 < delta && delta < 32;
}
#endif

View File

@@ -7,19 +7,12 @@
* 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)
* 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */
/*! \addtogroup libgb
* @{
*/
/*! \file gprs_ns.h */
/*! \brief Common header of GPRS NS */
struct gprs_ns_hdr {
uint8_t pdu_type; /*!< NS PDU type */
uint8_t data[0]; /*!< variable-length payload */
uint8_t pdu_type;
uint8_t data[0];
} __attribute__((packed));
/*! \brief NS PDU Type (TS 08.16, Section 10.3.7, Table 14) */
/* TS 08.16, Section 10.3.7, Table 14 */
enum ns_pdu_type {
NS_PDUT_UNITDATA = 0x00,
NS_PDUT_RESET = 0x02,
@@ -42,7 +35,7 @@ enum ns_pdu_type {
SNS_PDUT_SIZE_ACK = 0x13,
};
/*! \brief NS Control IE (TS 08.16, Section 10.3, Table 12) */
/* TS 08.16, Section 10.3, Table 12 */
enum ns_ctrl_ie {
NS_IE_CAUSE = 0x00,
NS_IE_VCI = 0x01,
@@ -59,7 +52,7 @@ enum ns_ctrl_ie {
NS_IE_IP_ADDR = 0x0b,
};
/*! \brief NS Cause (TS 08.16, Section 10.3.2, Table 13) */
/* TS 08.16, Section 10.3.2, Table 13 */
enum ns_cause {
NS_CAUSE_TRANSIT_FAIL = 0x00,
NS_CAUSE_OM_INTERVENTION = 0x01,
@@ -97,8 +90,6 @@ enum ns_cause {
"Reset Timer (Tns-reset) timeout\n" \
"Reset Timer (Tns-reset) number of retries\n" \
"Test Timer (Tns-test) timeout\n" \
"Alive Timer (Tns-alive) timeout\n" \
"Alive Timer (Tns-alive) number of retries\n"
enum ns_timeout {
NS_TOUT_TNS_BLOCK,
@@ -113,48 +104,44 @@ enum ns_timeout {
#define NSE_S_BLOCKED 0x0001
#define NSE_S_ALIVE 0x0002
/*! \brief Osmocom NS link layer types */
enum gprs_ns_ll {
GPRS_NS_LL_UDP, /*!< NS/UDP/IP */
GPRS_NS_LL_E1, /*!< NS/E1 */
GPRS_NS_LL_FR_GRE, /*!< NS/FR/GRE/IP */
GPRS_NS_LL_UDP,
GPRS_NS_LL_E1,
GPRS_NS_LL_FR_GRE,
};
/*! \brief Osmoco NS events */
enum gprs_ns_evt {
GPRS_NS_EVT_UNIT_DATA,
};
struct gprs_nsvc;
/*! \brief Osmocom GPRS callback function type */
typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
struct msgb *msg, uint16_t bvci);
/*! \brief An instance of the NS protocol stack */
/* An instance of the NS protocol stack */
struct gprs_ns_inst {
/*! \brief callback to the user for incoming UNIT DATA IND */
/* callback to the user for incoming UNIT DATA IND */
gprs_ns_cb_t *cb;
/*! \brief linked lists of all NSVC in this instance */
/* linked lists of all NSVC in this instance */
struct llist_head gprs_nsvcs;
/*! \brief a NSVC object that's needed to deal with packets for
* unknown NSVC */
/* a NSVC object that's needed to deal with packets for unknown NSVC */
struct gprs_nsvc *unknown_nsvc;
uint16_t timeout[NS_TIMERS_COUNT];
/*! \brief NS-over-IP specific bits */
/* NS-over-IP specific bits */
struct {
struct osmo_fd fd;
uint32_t local_ip;
uint16_t local_port;
} nsip;
/*! \brief NS-over-FR-over-GRE-over-IP specific bits */
/* NS-over-FR-over-GRE-over-IP specific bits */
struct {
struct osmo_fd fd;
uint32_t local_ip;
unsigned int enabled:1;
int enabled:1;
} frgre;
};
@@ -166,15 +153,12 @@ enum nsvc_timer_mode {
_NSVC_TIMER_NR,
};
/*! \brief Structure representing a single NS-VC */
struct gprs_nsvc {
/*! \brief list of NS-VCs within NS Instance */
struct llist_head list;
/*! \brief pointer to NS Instance */
struct gprs_ns_inst *nsi;
uint16_t nsei; /*! \brief end-to-end significance */
uint16_t nsvci; /*! \brief uniquely identifies NS-VC at SGSN */
uint16_t nsei; /* end-to-end significance */
uint16_t nsvci; /* uniquely identifies NS-VC at SGSN */
uint32_t state;
uint32_t remote_state;
@@ -188,7 +172,7 @@ struct gprs_nsvc {
struct rate_ctr_group *ctrg;
/*! \brief which link-layer are we based on? */
/* which link-layer are we based on? */
enum gprs_ns_ll ll;
union {
@@ -245,6 +229,4 @@ static inline struct msgb *gprs_ns_msgb_alloc(void)
return msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "GPRS/NS");
}
/*! }@ */
#endif

View File

@@ -4,8 +4,6 @@
#include <stdint.h>
#include <netinet/in.h>
#include <osmocom/core/timer.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/crypt/gprs_cipher.h>

View File

@@ -69,7 +69,4 @@ struct msgb *gsm48_create_loc_upd_rej(uint8_t cause);
void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
const struct gsm_lchan *lchan);
void release_security_operation(struct gsm_subscriber_connection *conn);
void allocate_security_operation(struct gsm_subscriber_connection *conn);
#endif

View File

@@ -378,4 +378,6 @@ struct gsm48_qos {
};
int gprs_tlli_type(uint32_t tlli);
#endif /* _GSM48_GPRS_H */

View File

@@ -10,8 +10,6 @@
#define OBSC_NM_W_ACK_CB(__msgb) (__msgb)->cb[3]
struct mncc_sock_state;
/* the data structure stored in msgb->cb for openbsc apps */
struct openbsc_msgb_cb {
unsigned char *bssgph;
@@ -248,7 +246,6 @@ struct gsm_network {
struct gsmnet_stats stats;
/* layer 4 */
struct mncc_sock_state *mncc_state;
int (*mncc_recv) (struct gsm_network *net, struct msgb *msg);
struct llist_head upqueue;
struct llist_head trans_list;
@@ -290,6 +287,9 @@ struct gsm_network {
/* subscriber related features */
int keep_subscr;
struct gsm_sms_queue *sms_queue;
/* control interface */
struct ctrl_handle *ctrl;
};
#define SMS_HDR_SIZE 128
@@ -384,7 +384,4 @@ void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat);
struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr);
/* generic E1 line operations for all ISDN-based BTS. */
extern struct e1inp_line_ops bts_isdn_e1inp_line_ops;
#endif /* _GSM_DATA_H */

View File

@@ -17,10 +17,7 @@
#include <osmocom/gsm/protocol/gsm_08_58.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
#include <osmocom/abis/e1_input.h>
struct osmo_bsc_data;
struct osmo_bsc_sccp_con;
struct gsm_sms_queue;
@@ -78,7 +75,6 @@ enum bts_gprs_mode {
struct gsm_lchan;
struct gsm_subscriber;
struct gsm_mncc;
struct osmo_rtp_socket;
struct rtp_socket;
struct bsc_api;
@@ -112,7 +108,7 @@ struct gsm_abis_mo {
/* state of a logical channel */
enum gsm_lchan_state {
LCHAN_S_NONE, /* channel is not active */
LCHAN_S_ACT_REQ, /* channel activation requested */
LCHAN_S_ACT_REQ, /* channel activatin requested */
LCHAN_S_ACTIVE, /* channel is active and operational */
LCHAN_S_REL_REQ, /* channel release has been requested */
LCHAN_S_REL_ERR, /* channel is in an error state */
@@ -136,17 +132,6 @@ struct bts_ul_meas {
/* RSSI in dBm * -1 */
uint8_t inv_rssi;
};
struct amr_mode {
uint8_t mode;
uint8_t threshold;
uint8_t hysteresis;
};
struct amr_multirate_conf {
uint8_t gsm48_ie[2];
struct amr_mode mode[4];
uint8_t num_modes;
};
/* /BTS ONLY */
struct gsm_lchan {
@@ -177,10 +162,8 @@ struct gsm_lchan {
/* Established data link layer services */
uint8_t sapis[8];
int sacch_deact;
/** GSM 08.58 9.3.20 */
int release_mode;
int sach_deact;
int release_reason;
struct {
uint32_t bound_ip;
@@ -191,11 +174,7 @@ struct gsm_lchan {
uint8_t rtp_payload;
uint8_t rtp_payload2;
uint8_t speech_mode;
#ifdef ROLE_BSC
struct rtp_socket *rtp_socket;
#else
struct osmo_rtp_socket *rtp_socket;
#endif
} abis_ip;
uint8_t rqd_ta;
@@ -204,7 +183,6 @@ struct gsm_lchan {
struct osmo_timer_list T3101;
struct osmo_timer_list T3111;
struct osmo_timer_list error_timer;
struct osmo_timer_list act_timer;
/* table of neighbor cell measurements */
struct neigh_meas_proc neigh_meas[MAX_NEIGH_MEAS];
@@ -219,7 +197,6 @@ struct gsm_lchan {
struct gsm_subscriber_connection *conn;
#else
struct lapdm_channel lapdm_ch;
struct llist_head dl_tch_queue;
struct {
/* bitmask of all SI that are present/valid in si_buf */
uint32_t valid;
@@ -245,19 +222,19 @@ struct gsm_lchan {
uint8_t rxqual_sub;
} res;
} meas;
struct {
struct amr_multirate_conf amr_mr;
struct {
uint8_t buf[16];
uint8_t len;
} last_sid;
} tch;
/* BTS-side ciphering state (rx only, bi-directional, ...) */
uint8_t ciph_state;
uint8_t loopback;
#endif
};
struct gsm_e1_subslot {
/* Number of E1 link */
uint8_t e1_nr;
/* Number of E1 TS inside E1 link */
uint8_t e1_ts;
/* Sub-slot within the E1 TS, 0xff if full TS */
uint8_t e1_ts_ss;
};
#define TS_F_PDCH_MODE 0x1000
/* One Timeslot in a TRX */
struct gsm_bts_trx_ts {
@@ -305,11 +282,7 @@ struct gsm_bts_trx {
/* how do we talk RSL with this TRX? */
struct gsm_e1_subslot rsl_e1_link;
uint8_t rsl_tei;
#ifdef ROLE_BSC
struct e1inp_sign_link *rsl_link;
#else
struct ipabis_link *rsl_link;
#endif
/* Some BTS (specifically Ericsson RBS) have a per-TRX OML Link */
struct e1inp_sign_link *oml_link;
@@ -353,7 +326,6 @@ enum gsm_bts_type {
GSM_BTS_TYPE_NANOBTS,
GSM_BTS_TYPE_RBS2000,
GSM_BTS_TYPE_HSL_FEMTO,
GSM_BTS_TYPE_NOKIA_SITE,
};
struct vty;
@@ -368,8 +340,6 @@ struct gsm_bts_model {
int (*start)(struct gsm_network *net);
int (*oml_rcvmsg)(struct msgb *msg);
void (*e1line_bind_ops)(struct e1inp_line *line);
void (*config_write_bts)(struct vty *vty, struct gsm_bts *bts);
void (*config_write_trx)(struct vty *vty, struct gsm_bts_trx *trx);
void (*config_write_ts)(struct vty *vty, struct gsm_bts_trx_ts *ts);
@@ -431,11 +401,29 @@ enum neigh_list_manual_mode {
NL_MODE_MANUAL_SI5SEP = 2, /* SI2 and SI5 have separate neighbor lists */
};
enum bts_loc_fix {
BTS_LOC_FIX_INVALID = 0,
BTS_LOC_FIX_2D = 1,
BTS_LOC_FIX_3D = 2,
};
struct bts_location {
struct llist_head list;
time_t tstamp;
enum bts_loc_fix valid;
double lat;
double lon;
double height;
};
/* One BTS */
struct gsm_bts {
/* list header in net->bts_list */
struct llist_head list;
/* Geographical location of the BTS */
struct llist_head loc_list;
/* number of ths BTS in network */
uint8_t nr;
/* human readable name / description */
@@ -483,11 +471,6 @@ struct gsm_bts {
/* buffers where we put the pre-computed SI */
sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE];
/* TimeZone hours, mins, and bts specific */
int tzhr;
int tzmn;
int tz_bts_specific;
/* ip.accesss Unit ID's have Site/BTS/TRX layout */
union {
struct {
@@ -523,14 +506,6 @@ struct gsm_bts {
struct {
unsigned long serno;
} hsl;
struct {
uint8_t bts_type;
unsigned int configured:1,
skip_reset:1,
did_reset:1,
wait_reset:1;
struct osmo_timer_list reset_timer;
} nokia;
};
/* Not entirely sure how ip.access specific this is */
@@ -600,15 +575,15 @@ struct gsm_bts {
struct gsm_bts *gsm_bts_alloc(void *talloc_ctx);
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num);
const char *gsm_pchan_name(enum gsm_phys_chan_config c);
enum gsm_phys_chan_config gsm_pchan_parse(const char *name);
const char *gsm_lchant_name(enum gsm_chan_t c);
const char *gsm_chreq_name(enum gsm_chreq_reason_t c);
char *gsm_trx_name(const struct gsm_bts_trx *trx);
char *gsm_ts_name(const struct gsm_bts_trx_ts *ts);
char *gsm_lchan_name(const struct gsm_lchan *lchan);
char *gsm_trx_name(struct gsm_bts_trx *trx);
char *gsm_ts_name(struct gsm_bts_trx_ts *ts);
char *gsm_lchan_name(struct gsm_lchan *lchan);
const char *gsm_lchans_name(enum gsm_lchan_state s);
@@ -616,14 +591,14 @@ void gsm_abis_mo_reset(struct gsm_abis_mo *mo);
struct gsm_abis_mo *
gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
const struct abis_om_obj_inst *obj_inst);
struct abis_om_obj_inst *obj_inst);
struct gsm_nm_state *
gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
const struct abis_om_obj_inst *obj_inst);
struct abis_om_obj_inst *obj_inst);
void *
gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
const struct abis_om_obj_inst *obj_inst);
struct abis_om_obj_inst *obj_inst);
/* reset the state of all MO in the BTS */
void gsm_bts_mo_reset(struct gsm_bts *bts);

View File

@@ -1,7 +0,0 @@
#ifndef _HANDOVER_DECISION_H
#define _HANDOVER_DECISION_H
void on_dso_load_ho_dec(void);
#endif /* _HANDOVER_DECISION_H */

View File

@@ -1,7 +1,7 @@
#ifndef _IPACCESS_H
#define _IPACCESS_H
#include <osmocom/abis/e1_input.h>
#include "e1_input.h"
#include "gsm_subscriber.h"
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/protocol/ipaccess.h>
@@ -26,10 +26,13 @@ struct ipac_ext_lac_cmd {
uint8_t data[0];
} __attribute__((packed));
int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa);
/*
* methods for parsing and sending a message
*/
int ipaccess_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd);
struct msgb *ipaccess_read_msg(struct osmo_fd *bfd, int *error);
void ipaccess_prepend_header(struct msgb *msg, int proto);
void ipaccess_prepend_header_ext(struct msgb *msg, int proto);
int ipaccess_send_pong(int fd);

View File

@@ -114,8 +114,6 @@ struct mgcp_trunk_config {
int audio_payload;
int audio_loop;
int omit_rtcp;
/* spec handling */
int force_realloc;
@@ -192,8 +190,5 @@ static inline void mgcp_endpoint_to_timeslot(int endpoint, int *multiplex, int *
*timeslot = endpoint % 32;
}
int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint);
int mgcp_send_reset_all(struct mgcp_config *cfg);
#endif

View File

@@ -131,6 +131,9 @@ struct mgcp_msg_ptr {
unsigned int length;
};
int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
struct mgcp_msg_ptr *ptr, int size,
const char **transaction_id, struct mgcp_endpoint **endp);
int mgcp_send_dummy(struct mgcp_endpoint *endp);
int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port);

View File

@@ -19,7 +19,7 @@
#ifndef MISDN_H
#define MISDN_H
#include <osmocom/abis/e1_input.h>
#include "e1_input.h"
int mi_setup(int cardnr, struct e1inp_line *line, int release_l2);
int mi_e1_line_update(struct e1inp_line *line);

View File

@@ -96,8 +96,6 @@ struct gsm_call {
#define GSM_TCHF_FRAME 0x0300
#define GSM_TCHF_FRAME_EFR 0x0301
#define MNCC_SOCKET_HELLO 0x0400
#define GSM_MAX_FACILITY 128
#define GSM_MAX_SSVERSION 128
#define GSM_MAX_USERUSER 128
@@ -150,7 +148,6 @@ struct gsm_mncc {
int emergency;
char imsi[16];
unsigned char lchan_type;
unsigned char lchan_mode;
};
@@ -160,22 +157,6 @@ struct gsm_data_frame {
unsigned char data[0];
};
#define MNCC_SOCK_VERSION 2
struct gsm_mncc_hello {
uint32_t msg_type;
uint32_t version;
/* send the sizes of the structs */
uint32_t mncc_size;
uint32_t data_frame_size;
/* send some offsets */
uint32_t called_offset;
uint32_t signal_offset;
uint32_t emergency_offset;
uint32_t lchan_type_offset;
};
char *get_mncc_name(int value);
void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg);

View File

@@ -1,12 +0,0 @@
#ifndef _MNCC_INT_H
#define _MNCC_INT_H
#include <stdint.h>
struct mncc_int {
uint8_t def_codec[2];
};
extern struct mncc_int mncc_int;
#endif

View File

@@ -32,14 +32,17 @@ struct bsc_api *osmo_bsc_api();
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg);
int bsc_open_connection(struct osmo_bsc_sccp_con *sccp, struct msgb *msg);
int bsc_create_new_connection(struct gsm_subscriber_connection *conn);
int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct osmo_msc_data *msc);
int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp);
struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *);
int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_handle_udt(struct gsm_network *net, struct bsc_msc_connection *conn, struct msgb *msg, unsigned int length);
int bsc_handle_udt(struct osmo_msc_data *msc, struct msgb *msg, unsigned int length);
int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int len);
int bsc_ctrl_cmds_install();
#endif

View File

@@ -1,9 +1,28 @@
#ifndef OSMO_BSC_RF
#define OSMO_BSC_RF
#include <openbsc/gsm_data.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
enum osmo_bsc_rf_opstate {
OSMO_BSC_RF_OPSTATE_INOPERATIONAL,
OSMO_BSC_RF_OPSTATE_OPERATIONAL,
};
enum osmo_bsc_rf_adminstate {
OSMO_BSC_RF_ADMINSTATE_UNLOCKED,
OSMO_BSC_RF_ADMINSTATE_LOCKED,
};
enum osmo_bsc_rf_policy {
OSMO_BSC_RF_POLICY_OFF,
OSMO_BSC_RF_POLICY_ON,
OSMO_BSC_RF_POLICY_GRACE,
OSMO_BSC_RF_POLICY_UNKNOWN,
};
struct gsm_network;
struct osmo_bsc_rf {
@@ -23,6 +42,9 @@ struct osmo_bsc_rf {
/* some handling for the automatic grace switch */
struct osmo_timer_list grace_timeout;
/* auto RF switch-off due lack of MSC connection */
struct osmo_timer_list auto_off_timer;
};
struct osmo_bsc_rf_conn {
@@ -30,6 +52,10 @@ struct osmo_bsc_rf_conn {
struct osmo_bsc_rf *rf;
};
enum osmo_bsc_rf_opstate osmo_bsc_rf_get_opstate_by_bts(struct gsm_bts *bts);
enum osmo_bsc_rf_adminstate osmo_bsc_rf_get_adminstate_by_bts(struct gsm_bts *bts);
enum osmo_bsc_rf_policy osmo_bsc_rf_get_policy_by_bts(struct gsm_bts *bts);
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net);
void osmo_bsc_rf_schedule_lock(struct osmo_bsc_rf *rf, char cmd);
#endif

View File

@@ -26,6 +26,9 @@
#include "bsc_msc.h"
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <regex.h>
struct osmo_bsc_rf;
struct gsm_network;
@@ -35,12 +38,25 @@ struct gsm_audio_support {
ver : 7;
};
enum {
MSC_CON_TYPE_NORMAL,
MSC_CON_TYPE_LOCAL,
};
struct osmo_msc_data {
struct llist_head entry;
/* Back pointer */
struct gsm_network *network;
int allow_emerg;
int type;
/* local call routing */
char *local_pref;
regex_t local_pref_reg;
/* Connection data */
char *bsc_token;
int ping_timeout;
@@ -53,6 +69,7 @@ struct osmo_msc_data {
int rtp_base;
/* audio codecs */
struct gsm48_multi_rate_conf amr_conf;
struct gsm_audio_support **audio_support;
int audio_length;
@@ -82,6 +99,7 @@ struct osmo_bsc_data {
int mid_call_timeout;
char *rf_ctrl_name;
struct osmo_bsc_rf *rf_ctrl;
int auto_off_timeout;
};

View File

@@ -1,7 +0,0 @@
#ifndef _RRLP_H
#define _RRLP_H
void on_dso_load_rrlp(void);
#endif /* _RRLP_H */

View File

@@ -60,7 +60,5 @@ int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
struct msgb *msg, uint32_t npdu_len, uint8_t *npdu);
int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
void *mmcontext);
int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
uint8_t *hdr, uint16_t len);
#endif

View File

@@ -40,13 +40,14 @@ enum signal_subsystems {
SS_LCHAN,
SS_SUBSCR,
SS_SCALL,
SS_GLOBAL,
SS_CHALLOC,
SS_NS,
SS_IPAC_NWL,
SS_RF,
SS_MSC,
SS_HO,
SS_CCCH,
SS_INPUT,
};
/* SS_PAGING signals */
@@ -128,6 +129,7 @@ enum signal_ipaccess {
};
enum signal_global {
S_GLOBAL_SHUTDOWN,
S_GLOBAL_BTS_CLOSE_OM,
};
@@ -138,6 +140,16 @@ enum signal_rf {
S_RF_GRACE,
};
/* SS_INPUT signals */
enum signal_input {
S_INP_NONE,
S_INP_TEI_UP,
S_INP_TEI_DN,
S_INP_LINE_INIT,
S_INP_LINE_ALARM,
S_INP_LINE_NOALARM,
};
struct gsm_subscriber;
struct paging_signal_data {
@@ -231,6 +243,7 @@ struct ns_signal_data {
enum signal_msc {
S_MSC_LOST,
S_MSC_CONNECTED,
S_MSC_AUTHENTICATED,
};
struct osmo_msc_data;
@@ -248,18 +261,12 @@ struct ho_signal_data {
struct gsm_lchan *new_lchan;
};
/* SS_CCCH signals */
enum signal_ccch {
S_CCCH_PAGING_LOAD,
S_CCCH_RACH_LOAD,
};
struct ccch_signal_data {
struct gsm_bts *bts;
uint16_t pg_buf_space;
uint16_t rach_slot_count;
uint16_t rach_busy_count;
uint16_t rach_access_count;
struct input_signal_data {
int link_type;
uint8_t tei;
uint8_t sapi;
struct gsm_bts_trx *trx;
struct e1inp_line *line;
};
#endif

View File

@@ -0,0 +1,101 @@
#ifndef _SUBCH_DEMUX_H
#define _SUBCH_DEMUX_H
/* A E1 sub-channel (de)multiplexer with TRAU frame sync */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#define NR_SUBCH 4
#define TRAU_FRAME_SIZE 40
#define TRAU_FRAME_BITS (TRAU_FRAME_SIZE*8)
/***********************************************************************/
/* DEMULTIPLEXER */
/***********************************************************************/
struct demux_subch {
uint8_t out_bitbuf[TRAU_FRAME_BITS];
uint16_t out_idx; /* next bit to be written in out_bitbuf */
/* number of consecutive zeros that we have received (for sync) */
unsigned int consecutive_zeros;
/* are we in TRAU frame sync or not? */
unsigned int in_sync;
};
struct subch_demux {
/* bitmask of currently active subchannels */
uint8_t chan_activ;
/* one demux_subch struct for every subchannel */
struct demux_subch subch[NR_SUBCH];
/* callback to be called once we have received a complete
* frame on a given subchannel */
int (*out_cb)(struct subch_demux *dmx, int ch, uint8_t *data, int len,
void *);
/* user-provided data, transparently passed to out_cb() */
void *data;
};
/* initialize one demultiplexer instance */
int subch_demux_init(struct subch_demux *dmx);
/* feed 'len' number of muxed bytes into the demultiplexer */
int subch_demux_in(struct subch_demux *dmx, uint8_t *data, int len);
/* activate decoding/processing for one subchannel */
int subch_demux_activate(struct subch_demux *dmx, int subch);
/* deactivate decoding/processing for one subchannel */
int subch_demux_deactivate(struct subch_demux *dmx, int subch);
/***********************************************************************/
/* MULTIPLEXER */
/***********************************************************************/
/* one element in the tx_queue of a muxer sub-channel */
struct subch_txq_entry {
struct llist_head list;
unsigned int bit_len; /* total number of bits in 'bits' */
unsigned int next_bit; /* next bit to be transmitted */
uint8_t bits[0]; /* one bit per byte */
};
struct mux_subch {
struct llist_head tx_queue;
};
/* structure representing one instance of the subchannel muxer */
struct subch_mux {
struct mux_subch subch[NR_SUBCH];
};
/* initialize a subchannel muxer instance */
int subchan_mux_init(struct subch_mux *mx);
/* request the output of 'len' multiplexed bytes */
int subchan_mux_out(struct subch_mux *mx, uint8_t *data, int len);
/* enqueue some data into one sub-channel of the muxer */
int subchan_mux_enqueue(struct subch_mux *mx, int s_nr, const uint8_t *data,
int len);
#endif /* _SUBCH_DEMUX_H */

View File

@@ -1,7 +0,0 @@
#ifndef _TOKEN_AUTH_H
#define _TOKEN_AUTH_H
void on_dso_load_token(void);
#endif /* _TOKEN_AUTH_H */

View File

@@ -0,0 +1,64 @@
#ifndef _TRAU_FRAME_H
#define _TRAU_FRAME_H
/* TRAU frame handling according to GSM TS 08.60 */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
/* 21 for FR/EFR, 25 for AMR, 15 for OM, 15 for data, 13 for E-data, 21 idle */
#define MAX_C_BITS 25
/* 260 for FR/EFR, 256 for AMR, 264 for OM, 288 for E-data */
#define MAX_D_BITS 288
/* for all speech frames */
#define MAX_T_BITS 4
/* for OM */
#define MAX_S_BITS 6
/* for E-data */
#define MAX_M_BITS 2
struct decoded_trau_frame {
uint8_t c_bits[MAX_C_BITS];
uint8_t d_bits[MAX_D_BITS];
uint8_t t_bits[MAX_T_BITS];
uint8_t s_bits[MAX_S_BITS];
uint8_t m_bits[MAX_M_BITS];
};
#define TRAU_FT_FR_UP 0x02 /* 0 0 0 1 0 - 3.5.1.1.1 */
#define TRAU_FT_FR_DOWN 0x1c /* 1 1 1 0 0 - 3.5.1.1.1 */
#define TRAU_FT_EFR 0x1a /* 1 1 0 1 0 - 3.5.1.1.1 */
#define TRAU_FT_AMR 0x06 /* 0 0 1 1 0 - 3.5.1.2 */
#define TRAU_FT_OM_UP 0x07 /* 0 0 1 0 1 - 3.5.2 */
#define TRAU_FT_OM_DOWN 0x1b /* 1 1 0 1 1 - 3.5.2 */
#define TRAU_FT_DATA_UP 0x08 /* 0 1 0 0 0 - 3.5.3 */
#define TRAU_FT_DATA_DOWN 0x16 /* 1 0 1 1 0 - 3.5.3 */
#define TRAU_FT_D145_SYNC 0x14 /* 1 0 1 0 0 - 3.5.3 */
#define TRAU_FT_EDATA 0x1f /* 1 1 1 1 1 - 3.5.4 */
#define TRAU_FT_IDLE_UP 0x10 /* 1 0 0 0 0 - 3.5.5 */
#define TRAU_FT_IDLE_DOWN 0x0e /* 0 1 1 1 0 - 3.5.5 */
int decode_trau_frame(struct decoded_trau_frame *fr, const uint8_t *trau_bits);
int encode_trau_frame(uint8_t *trau_bits, const struct decoded_trau_frame *fr);
int trau_frame_up2down(struct decoded_trau_frame *fr);
uint8_t *trau_idle_frame(void);
#endif /* _TRAU_FRAME_H */

View File

@@ -50,6 +50,3 @@ int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref);
/* send trau from application */
int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame);
/* callback invoked if we receive TRAU frames */
int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len, void *_priv);

View File

@@ -1,7 +0,0 @@
#ifndef _TRAU_UPQUEUE_H
#define _TRAU_UPQUEUE_H
void trau_tx_to_mncc(struct gsm_network *net, struct msgb *msg);
#endif /* _TRAU_UPQUEUE_H */

View File

@@ -29,13 +29,14 @@ enum bsc_vty_node {
NS_NODE,
BSSGP_NODE,
OML_NODE,
E1INP_NODE,
NAT_NODE,
NAT_BSC_NODE,
MSC_NODE,
OM2K_NODE,
TRUNK_NODE,
PGROUP_NODE,
MNCC_INT_NODE,
BSC_NODE,
};
extern int bsc_vty_is_config_node(struct vty *vty, int node);

View File

@@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libctrl osmo-nitb osmo-bsc_mgcp utils ipaccess libgb gprs
SUBDIRS = libcommon libabis libmgcp libbsc libmsc libtrau libctrl osmo-nitb osmo-bsc_mgcp utils ipaccess libgb gprs
# Conditional modules
if BUILD_NAT

View File

@@ -1,8 +1,6 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS)
AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAGE_LDFLAGS)
noinst_HEADERS = gprs_sndcp.h
@@ -14,12 +12,11 @@ endif
osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c
osmo_gbproxy_LDADD = $(top_builddir)/src/libgb/libgb.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS)
$(top_builddir)/src/libcommon/libcommon.a
osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
sgsn_main.c sgsn_vty.c sgsn_libgtp.c \
gprs_llc.c gprs_llc_vty.c crc24.c
osmo_sgsn_LDADD = $(top_builddir)/src/libgb/libgb.a \
$(top_builddir)/src/libcommon/libcommon.a \
-lgtp $(OSMO_LIBS)
-lgtp

View File

@@ -84,7 +84,7 @@ static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
default:
LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
if (msg)
msgb_free(msg);
talloc_free(msg);
rc = -EIO;
break;
}
@@ -97,7 +97,7 @@ static void signal_handler(int signal)
switch (signal) {
case SIGINT:
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
sleep(1);
exit(0);
break;

View File

@@ -65,9 +65,7 @@ DEFUN(cfg_gbproxy,
DEFUN(cfg_nsip_sgsn_nsei,
cfg_nsip_sgsn_nsei_cmd,
"sgsn nsei <0-65534>",
"SGSN information\n"
"NSEI to be used in the connection with the SGSN\n"
"The NSEI\n")
"Set the NSEI to be used in the connection with the SGSN")
{
unsigned int port = atoi(argv[0]);

View File

@@ -231,7 +231,7 @@ static void mmctx_timer_stop(struct sgsn_mm_ctx *mm, unsigned int T)
/* Send a message through the underlying layer */
static int gsm48_gmm_sendmsg(struct msgb *msg, int command,
struct sgsn_mm_ctx *mm)
const struct sgsn_mm_ctx *mm)
{
if (mm)
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
@@ -598,7 +598,7 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
struct sgsn_mm_ctx *ictx;
ictx = sgsn_mm_ctx_by_imsi(mi_string);
if (ictx) {
DEBUGP(DMM, "Deleting old MM Context for same IMSI "
DEBUGP(DMM, "Deleting old MM Context for same IMSI ",
"p_tmsi_old=0x%08x, p_tmsi_new=0x%08x\n",
ictx->p_tmsi, ctx->p_tmsi);
gprs_llgmm_assign(ictx->llme, ictx->tlli,
@@ -867,7 +867,7 @@ static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
}
static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
const uint8_t *pdp_status)
uint16_t pdp_status)
{
struct sgsn_pdp_ctx *pdp, *pdp2;
/* 24.008 4.7.5.1.3: If the PDP context status information element is
@@ -878,20 +878,11 @@ static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
* being in state PDP-INACTIVE. */
llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
if (pdp->nsapi < 8) {
if (!(pdp_status[0] & (1 << pdp->nsapi))) {
LOGP(DMM, LOGL_NOTICE, "Dropping PDP context for NSAPI=%u "
"due to PDP CTX STATUS IE= 0x%02x%02x\n",
pdp->nsapi, pdp_status[1], pdp_status[0]);
sgsn_delete_pdp_ctx(pdp);
}
} else {
if (!(pdp_status[1] & (1 << (pdp->nsapi - 8)))) {
LOGP(DMM, LOGL_NOTICE, "Dropping PDP context for NSAPI=%u "
"due to PDP CTX STATUS IE= 0x%02x%02x\n",
pdp->nsapi, pdp_status[1], pdp_status[0]);
sgsn_delete_pdp_ctx(pdp);
}
if (!(pdp_status & (1 << pdp->nsapi))) {
LOGP(DMM, LOGL_NOTICE, "Dropping PDP context for NSAPI=%u "
"due to PDP CTX STATUS IE= 0x%04x\n",
pdp->nsapi, pdp_status);
sgsn_delete_pdp_ctx(pdp);
}
}
}
@@ -945,10 +936,6 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Look-up the MM context based on old RA-ID and TLLI */
mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &old_ra_id);
if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) {
/* send a XID reset to re-set all LLC sequence numbers
* in the MS */
DEBUGPC(DMM, " LLC XID RESET ");
gprs_llgmm_reset(llme);
/* The MS has to perform GPRS attach */
DEBUGPC(DMM, " REJECT\n");
/* Device is still IMSI atached for CS but initiate GPRS ATTACH */
@@ -988,13 +975,11 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Look at PDP Context Status IE and see if MS's view of
* activated/deactivated NSAPIs agrees with our view */
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
uint16_t pdp_status = ntohs(*(uint16_t *)
TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS));
process_ms_ctx_status(mmctx, pdp_status);
}
/* Make sure we are NORMAL (i.e. not SUSPENDED anymore) */
mmctx->mm_state = GMM_REGISTERED_NORMAL;
/* Send RA UPDATE ACCEPT */
return gsm48_tx_gmm_ra_upd_ack(mmctx);
}
@@ -1022,7 +1007,6 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) {
LOGP(DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
gprs_llgmm_reset(llme);
return gsm48_tx_gmm_status_oldmsg(msg, GMM_CAUSE_MS_ID_NOT_DERIVED);
}
@@ -1051,7 +1035,6 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->tlli = mmctx->tlli_new;
gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new,
GPRS_ALGO_GEA0, NULL);
rc = 0;
break;
case GSM48_MT_GMM_RA_UPD_COMPL:
/* only in case SGSN offered new P-TMSI */
@@ -1062,7 +1045,6 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->tlli = mmctx->tlli_new;
gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new,
GPRS_ALGO_GEA0, NULL);
rc = 0;
break;
case GSM48_MT_GMM_PTMSI_REALL_COMPL:
DEBUGP(DMM, "-> PTMSI REALLLICATION COMPLETE\n");
@@ -1071,7 +1053,6 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Unassign the old TLLI */
mmctx->tlli = mmctx->tlli_new;
//gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, GPRS_ALGO_GEA0, NULL);
rc = 0;
break;
case GSM48_MT_GMM_AUTH_CIPH_RESP:
rc = gsm48_rx_gmm_auth_ciph_resp(mmctx, msg);

View File

@@ -34,7 +34,6 @@
#include <openbsc/gprs_bssgp.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/crc24.h>
#include <openbsc/sgsn.h>
/* Section 8.9.9 LLC layer parameter default values */
static const struct gprs_llc_params llc_default_params[] = {
@@ -312,15 +311,14 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
}
/* Send XID response to LLE */
static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
int command)
static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg)
{
/* copy identifiers from LLE to ensure lower layers can route */
msgb_tlli(msg) = lle->llme->tlli;
msgb_bvci(msg) = lle->llme->bvci;
msgb_nsei(msg) = lle->llme->nsei;
return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1);
return gprs_llc_tx_u(msg, lle->sapi, 0, GPRS_LLC_U_XID, 1);
}
/* Transmit a UI frame over the given SAPI */
@@ -423,54 +421,6 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
return gprs_bssgp_tx_dl_ud(msg, mmctx);
}
/* According to 6.4.1.6 / Figure 11 */
static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data)
{
uint8_t header_len = 1;
uint8_t *cur;
/* type is a 5-bit field... */
if (type > 0x1f)
return -EINVAL;
if (length > 3)
header_len = 2;
cur = msgb_put(msg, length + header_len);
/* build the header without or with XL bit */
if (length <= 3) {
*cur++ = (type << 2) | (length & 3);
} else {
*cur++ = 0x80 | (type << 2) | (length >> 6);
*cur++ = (length << 2);
}
/* copy over the payload of the parameter*/
memcpy(cur, data, length);
return length + header_len;
}
static void rx_llc_xid(struct gprs_llc_lle *lle,
struct gprs_llc_hdr_parsed *gph)
{
/* FIXME: 8.5.3.3: check if XID is invalid */
if (gph->is_cmd) {
/* FIXME: implement XID negotiation using SNDCP */
struct msgb *resp;
uint8_t *xid;
resp = msgb_alloc_headroom(4096, 1024, "LLC_XID");
xid = msgb_put(resp, gph->data_len);
memcpy(xid, gph->data, gph->data_len);
gprs_llc_tx_xid(lle, resp, 0);
} else {
/* FIXME: if we had sent a XID reset, send
* LLGMM-RESET.conf to GMM */
/* FIXME: implement XID negotiation using SNDCP */
}
}
static void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph)
{
DEBUGP(DLLC, "LLC SAPI=%u %c %c FCS=0x%06x",
@@ -515,12 +465,19 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
case GPRS_LLC_FRMR: /* Section 6.4.1.5 */
break;
case GPRS_LLC_XID: /* Section 6.4.1.6 */
rx_llc_xid(lle, gph);
/* FIXME: implement XID negotiation using SNDCP */
{
struct msgb *resp;
uint8_t *xid;
resp = msgb_alloc_headroom(4096, 1024, "LLC_XID");
xid = msgb_put(resp, gph->data_len);
memcpy(xid, gph->data, gph->data_len);
gprs_llc_tx_xid(lle, resp);
}
break;
case GPRS_LLC_UI:
if (gprs_llc_is_retransmit(gph->seq_tx, lle->vu_recv)) {
LOGP(DLLC, LOGL_NOTICE,
"TLLI=%08x dropping UI, N(U=%d) not in window V(URV(UR:%d).\n",
if (gph->seq_tx < lle->vu_recv) {
LOGP(DLLC, LOGL_NOTICE, "TLLI=%08x dropping UI, vurecv %u <= %u\n",
lle->llme ? lle->llme->tlli : -1,
gph->seq_tx, lle->vu_recv);
return -EIO;
@@ -541,6 +498,7 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
uint8_t *llc_hdr, int len)
{
uint8_t *ctrl = llc_hdr+1;
int is_sack = 0;
if (len <= CRC24_LENGTH)
return -EIO;
@@ -700,7 +658,7 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
{
struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
struct gprs_llc_hdr *lh = (struct gprs_llc_hdr *) msgb_llch(msg);
struct gprs_llc_hdr *lh = msgb_llch(msg);
struct gprs_llc_hdr_parsed llhp;
struct gprs_llc_lle *lle;
int rc = 0;
@@ -888,21 +846,6 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
return 0;
}
/* Chapter 7.2.1.2 LLGMM-RESET.req */
int gprs_llgmm_reset(struct gprs_llc_llme *llme)
{
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
int random = rand();
/* First XID component must be RESET */
msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL);
/* randomly select new IOV-UI */
msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &random);
/* FIXME: Start T200, wait for XID response */
return gprs_llc_tx_xid(&llme->lle[1], msg, 1);
}
int gprs_llc_init(const char *cipher_plugin_path)
{
return gprs_cipher_load(cipher_plugin_path);

View File

@@ -162,7 +162,7 @@ static int defrag_segments(struct gprs_sndcp_entity *sne)
dqe = defrag_get_seg(sne, seg_nr);
if (!dqe) {
LOGP(DSNDCP, LOGL_ERROR, "Segment %u missing\n", seg_nr);
msgb_free(msg);
talloc_free(msg);
return -EIO;
}
/* actually append the segment to the N-PDU */
@@ -566,15 +566,11 @@ static int sndcp_ll_reset_ind(struct gprs_sndcp_entity *se)
{
/* treat all outstanding SNDCP-LLC request type primitives as not sent */
/* reset all SNDCP XID parameters to default values */
LOGP(DSNDCP, LOGL_NOTICE, "not implemented.\n");
return 0;
}
static int sndcp_ll_status_ind()
{
/* inform the SM sub-layer by means of SNSM-STATUS.req */
LOGP(DSNDCP, LOGL_NOTICE, "not implemented.\n");
return 0;
}
#if 0

View File

@@ -37,6 +37,7 @@
#include <osmocom/core/select.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/process.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
@@ -91,7 +92,7 @@ static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
default:
LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
if (msg)
msgb_free(msg);
talloc_free(msg);
rc = -EIO;
break;
}
@@ -104,7 +105,7 @@ static void signal_handler(int signal)
switch (signal) {
case SIGINT:
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
sleep(1);
exit(0);
break;
@@ -200,6 +201,7 @@ static void handle_options(int argc, char **argv)
int main(int argc, char **argv)
{
struct gsm_network dummy_network;
struct sockaddr_in sin;
int rc;
tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn");

View File

@@ -129,8 +129,7 @@ static int config_write_sgsn(struct vty *vty)
return CMD_SUCCESS;
}
#define SGSN_STR "Configure the SGSN\n"
#define GGSN_STR "Configure the GGSN information\n"
#define SGSN_STR "Configure the SGSN"
DEFUN(cfg_sgsn, cfg_sgsn_cmd,
"sgsn",
@@ -143,8 +142,7 @@ DEFUN(cfg_sgsn, cfg_sgsn_cmd,
DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
"gtp local-ip A.B.C.D",
"GTP Parameters\n"
"Set the IP address for the local GTP bind\n"
"IPv4 Address\n")
"Set the IP address for the local GTP bind\n")
{
inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr);
@@ -153,7 +151,7 @@ DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
"ggsn <0-255> remote-ip A.B.C.D",
GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n")
"")
{
uint32_t id = atoi(argv[0]);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
@@ -177,8 +175,7 @@ DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd,
DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
"ggsn <0-255> gtp-version (0|1)",
GGSN_STR "GGSN Number\n" "GTP Version\n"
"Version 0\n" "Version 1\n")
"")
{
uint32_t id = atoi(argv[0]);
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
@@ -314,7 +311,7 @@ DEFUN(show_ggsn, show_ggsn_cmd,
DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
"show pdp-context all",
SHOW_STR "Display information on PDP Context\n" "Show everything\n")
SHOW_STR "Display information on PDP Context\n")
{
struct sgsn_pdp_ctx *pdp;

View File

@@ -1,16 +1,15 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
bin_PROGRAMS = ipaccess-find ipaccess-config ipaccess-proxy
ipaccess_find_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libabis/libabis.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS)
$(top_builddir)/src/libcommon/libcommon.a
ipaccess_find_SOURCES = ipaccess-find.c
ipaccess_config_SOURCES = ipaccess-config.c ipaccess-firmware.c network_listen.c
@@ -18,15 +17,16 @@ ipaccess_config_SOURCES = ipaccess-config.c ipaccess-firmware.c network_listen.c
# FIXME: resolve the bogus dependencies patched around here:
ipaccess_config_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libabis/libabis.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
-ldl -ldbi $(LIBCRYPT) $(OSMO_LIBS)
-ldl -ldbi $(LIBCRYPT)
ipaccess_proxy_SOURCES = ipaccess-proxy.c
ipaccess_proxy_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libabis/libabis.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS)
$(top_builddir)/src/libcommon/libcommon.a

View File

@@ -39,19 +39,12 @@
#include <osmocom/core/timer.h>
#include <openbsc/ipaccess.h>
#include <openbsc/gsm_data.h>
#include <osmocom/abis/e1_input.h>
#include <openbsc/abis_nm.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
#include <openbsc/network_listen.h>
#include <osmocom/abis/ipaccess.h>
#include <openbsc/gsm_data.h>
#include <openbsc/e1_input.h>
#include <openbsc/abis_nm.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
#include <openbsc/network_listen.h>
#include <osmocom/core/talloc.h>
#include <osmocom/abis/abis.h>
static struct gsm_network *gsmnet;
@@ -87,86 +80,6 @@ static uint8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00,
static uint8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
*/
extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what);
extern struct e1inp_line_ops ipaccess_e1inp_line_ops;
/* Actively connect to a BTS. Currently used by ipaccess-config.c */
static int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa)
{
struct e1inp_ts *e1i_ts = &line->ts[0];
struct osmo_fd *bfd = &e1i_ts->driver.ipaccess.fd;
int ret, on = 1;
bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ | BSC_FD_WRITE;
bfd->data = line;
bfd->priv_nr = E1INP_SIGN_OML;
if (bfd->fd < 0) {
LOGP(DLINP, LOGL_ERROR, "could not create TCP socket.\n");
return -EIO;
}
setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
if (ret < 0) {
LOGP(DLINP, LOGL_ERROR, "could not connect socket\n");
close(bfd->fd);
return ret;
}
ret = osmo_fd_register(bfd);
if (ret < 0) {
close(bfd->fd);
return ret;
}
return ret;
//return e1inp_line_register(line);
}
/* configure pseudo E1 line in ip.access style and connect to BTS */
static int ia_config_connect(struct gsm_bts *bts, struct sockaddr_in *sin)
{
struct e1inp_line *line;
struct e1inp_ts *sign_ts, *rsl_ts;
struct e1inp_sign_link *oml_link, *rsl_link;
line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
if (!line)
return -ENOMEM;
line->driver = e1inp_driver_find("ipa");
if (!line->driver) {
fprintf(stderr, "cannot `ipa' driver, giving up.\n");
return -EINVAL;
}
line->ops = &ipaccess_e1inp_line_ops;
/* create E1 timeslots for signalling and TRAU frames */
e1inp_ts_config_sign(&line->ts[1-1], line);
e1inp_ts_config_sign(&line->ts[2-1], line);
/* create signalling links for TS1 */
sign_ts = &line->ts[1-1];
rsl_ts = &line->ts[2-1];
oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
bts->c0, 0xff, 0);
rsl_link = e1inp_sign_link_create(rsl_ts, E1INP_SIGN_RSL,
bts->c0, 0, 0);
/* create back-links from bts/trx */
bts->oml_link = oml_link;
bts->c0->rsl_link = rsl_link;
/* default port at BTS for incoming connections is 3006 */
if (sin->sin_port == 0)
sin->sin_port = htons(3006);
return ipaccess_connect(line, sin);
}
/*
* Callback function for NACK on the OML NM
*
@@ -978,7 +891,6 @@ int main(int argc, char **argv)
fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n");
exit(2);
}
libosmo_abis_init(tall_ctx_config);
gsmnet = gsm_network_init(1, 1, NULL);
if (!gsmnet)

View File

@@ -210,12 +210,12 @@ static int handle_udp_read(struct osmo_fd *bfd)
ret = recv(bfd->fd, msg->data, msg->data_len, 0);
if (ret < 0) {
if (errno != EAGAIN)
LOGP(DLINP, LOGL_ERROR, "recv error %s\n", strerror(errno));
LOGP(DINP, LOGL_ERROR, "recv error %s\n", strerror(errno));
msgb_free(msg);
return ret;
}
if (ret == 0) {
DEBUGP(DLINP, "UDP peer disappeared, dead socket\n");
DEBUGP(DINP, "UDP peer disappeared, dead socket\n");
osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
@@ -223,16 +223,16 @@ static int handle_udp_read(struct osmo_fd *bfd)
return -EIO;
}
if (ret < sizeof(*hh)) {
DEBUGP(DLINP, "could not even read header!?!\n");
DEBUGP(DINP, "could not even read header!?!\n");
msgb_free(msg);
return -EIO;
}
msgb_put(msg, ret);
msg->l2h = msg->data + sizeof(*hh);
DEBUGP(DLMI, "UDP RX: %s\n", osmo_hexdump(msg->data, msg->len));
DEBUGP(DMI, "UDP RX: %s\n", osmo_hexdump(msg->data, msg->len));
if (hh->len != msg->len - sizeof(*hh)) {
DEBUGP(DLINP, "length (%u/%u) disagrees with header(%u)\n",
DEBUGP(DINP, "length (%u/%u) disagrees with header(%u)\n",
msg->len, msg->len - 3, hh->len);
msgb_free(msg);
return -EIO;
@@ -247,7 +247,7 @@ static int handle_udp_read(struct osmo_fd *bfd)
other_conn = ipbc->rsl_conn[0];
break;
default:
DEBUGP(DLINP, "Unknown protocol 0x%02x, sending to "
DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
"OML FD\n", hh->proto);
/* fall through */
case IPAC_PROTO_IPACCESS:
@@ -264,7 +264,7 @@ static int handle_udp_read(struct osmo_fd *bfd)
other_conn = ipbc->bsc_rsl_conn[0];
break;
default:
DEBUGP(DLINP, "Unknown protocol 0x%02x, sending to "
DEBUGP(DINP, "Unknown protocol 0x%02x, sending to "
"OML FD\n", hh->proto);
case IPAC_PROTO_IPACCESS:
case IPAC_PROTO_OML:
@@ -273,7 +273,7 @@ static int handle_udp_read(struct osmo_fd *bfd)
}
break;
default:
DEBUGP(DLINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr);
DEBUGP(DINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr);
break;
}
@@ -323,12 +323,12 @@ static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct osmo_fd *bfd,
sin.sin_family = AF_INET;
inet_aton(bsc_ipaddr, &sin.sin_addr);
DEBUGP(DLINP, "(%u/%u/%u) New BTS connection: ",
DEBUGP(DINP, "(%u/%u/%u) New BTS connection: ",
site_id, bts_id, trx_id);
/* OML needs to be established before RSL */
if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) {
DEBUGPC(DLINP, "Not a OML connection ?!?\n");
DEBUGPC(DINP, "Not a OML connection ?!?\n");
return -EIO;
}
@@ -339,7 +339,7 @@ static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct osmo_fd *bfd,
goto err_out;
}
DEBUGPC(DLINP, "Created BTS Conn data structure\n");
DEBUGPC(DINP, "Created BTS Conn data structure\n");
ipbc->ipp = ipp;
ipbc->unit_id.site_id = site_id;
ipbc->unit_id.bts_id = bts_id;
@@ -360,7 +360,7 @@ static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct osmo_fd *bfd,
goto err_bsc_conn;
}
DEBUGP(DLINP, "(%u/%u/%u) OML Connected to BSC\n",
DEBUGP(DINP, "(%u/%u/%u) OML Connected to BSC\n",
site_id, bts_id, trx_id);
/* Create UDP socket for BTS packet injection */
@@ -369,7 +369,7 @@ static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct osmo_fd *bfd,
UDP_TO_BTS, udp_fd_cb, ipbc);
if (ret < 0)
goto err_udp_bts;
DEBUGP(DLINP, "(%u/%u/%u) Created UDP socket for injection "
DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
"towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port);
/* Create UDP socket for BSC packet injection */
@@ -378,7 +378,7 @@ static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct osmo_fd *bfd,
UDP_TO_BSC, udp_fd_cb, ipbc);
if (ret < 0)
goto err_udp_bsc;
DEBUGP(DLINP, "(%u/%u/%u) Created UDP socket for injection "
DEBUGP(DINP, "(%u/%u/%u) Created UDP socket for injection "
"towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port);
@@ -394,13 +394,13 @@ static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct osmo_fd *bfd,
ret = make_sock(&ipbc->gprs_ns_fd, IPPROTO_UDP, ip, 0, 0,
gprs_ns_cb, ipbc);
if (ret < 0) {
LOGP(DLINP, LOGL_ERROR, "Creating the GPRS socket failed.\n");
LOGP(DINP, LOGL_ERROR, "Creating the GPRS socket failed.\n");
goto err_udp_bsc;
}
ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len);
ipbc->gprs_local_port = ntohs(sock.sin_port);
LOGP(DLINP, LOGL_NOTICE,
LOGP(DINP, LOGL_NOTICE,
"Created GPRS NS Socket. Listening on: %s:%d\n",
inet_ntoa(sock.sin_addr), ipbc->gprs_local_port);
@@ -445,17 +445,17 @@ static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
ret = ipaccess_send_pong(bfd->fd);
break;
case IPAC_MSGT_PONG:
DEBUGP(DLMI, "PONG!\n");
DEBUGP(DMI, "PONG!\n");
break;
case IPAC_MSGT_ID_RESP:
DEBUGP(DLMI, "ID_RESP ");
DEBUGP(DMI, "ID_RESP ");
/* parse tags, search for Unit ID */
ipaccess_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2,
msgb_l2len(msg)-2);
DEBUGP(DLMI, "\n");
DEBUGP(DMI, "\n");
if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
LOGP(DLINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n");
LOGP(DINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n");
return -EIO;
}
@@ -479,17 +479,17 @@ static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
sin.sin_family = AF_INET;
inet_aton(bsc_ipaddr, &sin.sin_addr);
DEBUGP(DLINP, "Identified BTS %u/%u/%u\n",
DEBUGP(DINP, "Identified BTS %u/%u/%u\n",
site_id, bts_id, trx_id);
if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) {
LOGP(DLINP, LOGL_ERROR, "Second OML connection from "
LOGP(DINP, LOGL_ERROR, "Second OML connection from "
"same BTS ?!?\n");
return 0;
}
if (trx_id >= MAX_TRX) {
LOGP(DLINP, LOGL_ERROR, "We don't support more "
LOGP(DINP, LOGL_ERROR, "We don't support more "
"than %u TRX\n", MAX_TRX);
return -EINVAL;
}
@@ -505,30 +505,30 @@ static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
connect_bsc(&sin, RSL_TO_BSC | (trx_id << 8), ipbc);
if (!ipbc->bsc_oml_conn)
return -EIO;
DEBUGP(DLINP, "(%u/%u/%u) Connected RSL to BSC\n",
DEBUGP(DINP, "(%u/%u/%u) Connected RSL to BSC\n",
site_id, bts_id, trx_id);
}
break;
case IPAC_MSGT_ID_GET:
DEBUGP(DLMI, "ID_GET\n");
DEBUGP(DMI, "ID_GET\n");
if ((bfd->priv_nr & 0xff) != OML_TO_BSC &&
(bfd->priv_nr & 0xff) != RSL_TO_BSC) {
DEBUGP(DLINP, "IDentity REQuest from BTS ?!?\n");
DEBUGP(DINP, "IDentity REQuest from BTS ?!?\n");
return -EIO;
}
ipbc = ipc->bts_conn;
if (!ipbc) {
DEBUGP(DLINP, "ID_GET from BSC before we have ID_RESP from BTS\n");
DEBUGP(DINP, "ID_GET from BSC before we have ID_RESP from BTS\n");
return -EIO;
}
ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len);
break;
case IPAC_MSGT_ID_ACK:
DEBUGP(DLMI, "ID_ACK? -> ACK!\n");
DEBUGP(DMI, "ID_ACK? -> ACK!\n");
ret = ipaccess_send_id_ack(bfd->fd);
break;
default:
LOGP(DLMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type);
LOGP(DMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type);
return 1;
break;
}
@@ -551,7 +551,7 @@ struct msgb *ipaccess_proxy_read_msg(struct osmo_fd *bfd, int *error)
ret = recv(bfd->fd, msg->data, 3, 0);
if (ret < 0) {
if (errno != EAGAIN)
LOGP(DLINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
LOGP(DINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
msgb_free(msg);
*error = ret;
return NULL;
@@ -568,7 +568,7 @@ struct msgb *ipaccess_proxy_read_msg(struct osmo_fd *bfd, int *error)
len = ntohs(hh->len);
ret = recv(bfd->fd, msg->l2h, len, 0);
if (ret < len) {
LOGP(DLINP, LOGL_ERROR, "short read!\n");
LOGP(DINP, LOGL_ERROR, "short read!\n");
msgb_free(msg);
*error = -EIO;
return NULL;
@@ -611,7 +611,7 @@ static void reconn_tmr_cb(void *data)
struct sockaddr_in sin;
int i;
DEBUGP(DLINP, "Running reconnect timer\n");
DEBUGP(DINP, "Running reconnect timer\n");
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
@@ -621,13 +621,13 @@ static void reconn_tmr_cb(void *data)
/* if OML to BSC is dead, try to restore it */
if (ipbc->oml_conn && !ipbc->bsc_oml_conn) {
sin.sin_port = htons(IPA_TCP_PORT_OML);
logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, 0);
LOGPC(DLINP, LOGL_NOTICE, "OML Trying to reconnect\n");
logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
LOGPC(DINP, LOGL_NOTICE, "OML Trying to reconnect\n");
ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
if (!ipbc->bsc_oml_conn)
goto reschedule;
logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, 0);
LOGPC(DLINP, LOGL_NOTICE, "OML Reconnected\n");
logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, 0);
LOGPC(DINP, LOGL_NOTICE, "OML Reconnected\n");
}
/* if we (still) don't have a OML connection, skip RSL */
if (!ipbc->oml_conn || !ipbc->bsc_oml_conn)
@@ -644,13 +644,13 @@ static void reconn_tmr_cb(void *data)
priv_nr &= ~0xff;
priv_nr |= RSL_TO_BSC;
sin.sin_port = htons(IPA_TCP_PORT_RSL);
logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
LOGPC(DLINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
LOGPC(DINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc);
if (!ipbc->bsc_rsl_conn)
goto reschedule;
logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
LOGPC(DLINP, LOGL_NOTICE, "RSL Reconnected\n");
logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
LOGPC(DINP, LOGL_NOTICE, "RSL Reconnected\n");
}
}
return;
@@ -778,8 +778,8 @@ static int handle_tcp_read(struct osmo_fd *bfd)
msg = ipaccess_proxy_read_msg(bfd, &ret);
if (!msg) {
if (ret == 0) {
logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
LOGPC(DLINP, LOGL_NOTICE, "%s disappeared, "
logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
LOGPC(DINP, LOGL_NOTICE, "%s disappeared, "
"dead socket\n", btsbsc);
handle_dead_socket(bfd);
}
@@ -787,8 +787,8 @@ static int handle_tcp_read(struct osmo_fd *bfd)
}
msgb_put(msg, ret);
logp_ipbc_uid(DLMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
DEBUGPC(DLMI, "RX<-%s: %s\n", btsbsc, osmo_hexdump(msg->data, msg->len));
logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
DEBUGPC(DMI, "RX<-%s: %s\n", btsbsc, osmo_hexdump(msg->data, msg->len));
hh = (struct ipaccess_head *) msg->data;
if (hh->proto == IPAC_PROTO_IPACCESS) {
@@ -809,7 +809,7 @@ static int handle_tcp_read(struct osmo_fd *bfd)
}
if (!ipbc) {
LOGP(DLINP, LOGL_ERROR,
LOGP(DINP, LOGL_ERROR,
"received %s packet but no ipc->bts_conn?!?\n", btsbsc);
msgb_free(msg);
return -EIO;
@@ -824,8 +824,8 @@ static int handle_tcp_read(struct osmo_fd *bfd)
/* mark respective filedescriptor as 'we want to write' */
bsc_conn->fd.when |= BSC_FD_WRITE;
} else {
logp_ipbc_uid(DLINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
LOGPC(DLINP, LOGL_INFO, "Dropping packet from %s, "
logp_ipbc_uid(DINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
LOGPC(DINP, LOGL_INFO, "Dropping packet from %s, "
"since remote connection is dead\n", btsbsc);
msgb_free(msg);
}
@@ -858,16 +858,16 @@ static int handle_tcp_write(struct osmo_fd *bfd)
llist_del(lh);
msg = llist_entry(lh, struct msgb, list);
logp_ipbc_uid(DLMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
DEBUGPC(DLMI, "TX %04x: %s\n", bfd->priv_nr,
logp_ipbc_uid(DMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
DEBUGPC(DMI, "TX %04x: %s\n", bfd->priv_nr,
osmo_hexdump(msg->data, msg->len));
ret = send(bfd->fd, msg->data, msg->len, 0);
msgb_free(msg);
if (ret == 0) {
logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
LOGP(DLINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
logp_ipbc_uid(DINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
LOGP(DINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
handle_dead_socket(bfd);
}
@@ -907,7 +907,7 @@ static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
perror("accept");
return ret;
}
DEBUGP(DLINP, "accept()ed new %s link from %s\n",
DEBUGP(DINP, "accept()ed new %s link from %s\n",
(listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
inet_ntoa(sa.sin_addr));
@@ -925,7 +925,7 @@ static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
bfd->when = BSC_FD_READ;
ret = osmo_fd_register(bfd);
if (ret < 0) {
LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
LOGP(DINP, LOGL_ERROR, "could not register FD\n");
close(bfd->fd);
talloc_free(ipc);
return ret;
@@ -950,7 +950,7 @@ static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int po
ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len);
if (ret < 0) {
LOGP(DLINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
LOGP(DINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
}
}
@@ -965,7 +965,7 @@ static int gprs_ns_cb(struct osmo_fd *bfd, unsigned int what)
/* 1. get the data... */
ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len);
if (ret < 0) {
LOGP(DLINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
LOGP(DINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
return -1;
}
@@ -973,13 +973,13 @@ static int gprs_ns_cb(struct osmo_fd *bfd, unsigned int what)
/* 2. figure out where to send it to */
if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) {
LOGP(DLINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000);
} else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) {
LOGP(DLINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
LOGP(DINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000);
} else {
LOGP(DLINP, LOGL_ERROR, "Unknown GPRS source: %s\n", inet_ntoa(sock.sin_addr));
LOGP(DINP, LOGL_ERROR, "Unknown GPRS source: %s\n", inet_ntoa(sock.sin_addr));
}
return 0;
@@ -1009,7 +1009,7 @@ static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, v
ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
if (ret < 0) {
LOGP(DLINP, LOGL_ERROR, "Could not connect socket: %s\n",
LOGP(DINP, LOGL_ERROR, "Could not connect socket: %s\n",
inet_ntoa(sa->sin_addr));
close(bfd->fd);
talloc_free(ipc);
@@ -1184,7 +1184,7 @@ int main(int argc, char **argv)
tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
osmo_init_logging(&log_info);
log_parse_category_mask(osmo_stderr_target, "DLINP:DLMI");
log_parse_category_mask(osmo_stderr_target, "DINP:DMI");
handle_options(argc, argv);

View File

@@ -37,7 +37,6 @@
#include <openbsc/abis_nm.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
#include <osmocom/abis/e1_input.h>
#define WHITELIST_MAX_SIZE ((NUM_ARFCNS*2)+2+1)
@@ -130,7 +129,6 @@ static int test_rep(void *_msg)
uint16_t test_rep_len, ferr_list_len;
struct ipacc_ferr_elem *ife;
struct ipac_bcch_info binfo;
struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
int i, rc;
DEBUGP(DNM, "TEST REPORT: ");
@@ -170,7 +168,7 @@ static int test_rep(void *_msg)
uint16_t arfcn = cu & 0x3ff;
uint8_t rxlev = cu >> 10;
DEBUGP(DNM, "==> ARFCN %4u, RxLev %2u\n", arfcn, rxlev);
rxlev_stat_input(&sign_link->trx->ipaccess.rxlev_stat,
rxlev_stat_input(&msg->trx->ipaccess.rxlev_stat,
arfcn, rxlev);
}
break;
@@ -221,14 +219,13 @@ static int test_rep(void *_msg)
case NM_IPACC_TESTRES_STOPPED:
case NM_IPACC_TESTRES_TIMEOUT:
case NM_IPACC_TESTRES_NO_CHANS:
sign_link->trx->ipaccess.test_state = IPAC_TEST_S_IDLE;
msg->trx->ipaccess.test_state = IPAC_TEST_S_IDLE;
/* Send signal to notify higher layers of test completion */
DEBUGP(DNM, "dispatching S_IPAC_NWL_COMPLETE signal\n");
osmo_signal_dispatch(SS_IPAC_NWL, S_IPAC_NWL_COMPLETE,
sign_link->trx);
osmo_signal_dispatch(SS_IPAC_NWL, S_IPAC_NWL_COMPLETE, msg->trx);
break;
case NM_IPACC_TESTRES_PARTIAL:
sign_link->trx->ipaccess.test_state = IPAC_TEST_S_PARTIAL;
msg->trx->ipaccess.test_state = IPAC_TEST_S_PARTIAL;
break;
}

View File

@@ -0,0 +1,14 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
noinst_LIBRARIES = libabis.a
libabis_a_SOURCES = e1_input.c e1_input_vty.c \
input/misdn.c \
input/ipaccess.c \
input/hsl.c \
input/dahdi.c \
input/lapd.c
EXTRA_DIST = input/lapd.h

View File

@@ -0,0 +1,652 @@
/* OpenBSC Abis interface to E1 */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <mISDNif.h>
//#define AF_COMPATIBILITY_FUNC
//#include <compat_af_isdn.h>
#ifndef AF_ISDN
#define AF_ISDN 34
#define PF_ISDN AF_ISDN
#endif
#include <osmocom/core/select.h>
#include <osmocom/core/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/e1_input.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <osmocom/core/linuxlist.h>
#include <openbsc/subchan_demux.h>
#include <openbsc/trau_frame.h>
#include <openbsc/trau_mux.h>
#include <osmocom/core/talloc.h>
#include <openbsc/signal.h>
#include <openbsc/misdn.h>
#include "../../bscconfig.h"
#define NUM_E1_TS 32
/* list of all E1 drivers */
LLIST_HEAD(e1inp_driver_list);
/* list of all E1 lines */
LLIST_HEAD(e1inp_line_list);
static void *tall_sigl_ctx;
/*
* pcap writing of the misdn load
* pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat
*/
#define DLT_LINUX_LAPD 177
#define PCAP_INPUT 0
#define PCAP_OUTPUT 1
struct pcap_hdr {
uint32_t magic_number;
uint16_t version_major;
uint16_t version_minor;
int32_t thiszone;
uint32_t sigfigs;
uint32_t snaplen;
uint32_t network;
} __attribute__((packed));
struct pcaprec_hdr {
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t incl_len;
uint32_t orig_len;
} __attribute__((packed));
struct fake_linux_lapd_header {
uint16_t pkttype;
uint16_t hatype;
uint16_t halen;
uint64_t addr;
int16_t protocol;
} __attribute__((packed));
struct lapd_header {
uint8_t ea1 : 1;
uint8_t cr : 1;
uint8_t sapi : 6;
uint8_t ea2 : 1;
uint8_t tei : 7;
uint8_t control_foo; /* fake UM's ... */
} __attribute__((packed));
osmo_static_assert(offsetof(struct fake_linux_lapd_header, hatype) == 2, hatype_offset);
osmo_static_assert(offsetof(struct fake_linux_lapd_header, halen) == 4, halen_offset);
osmo_static_assert(offsetof(struct fake_linux_lapd_header, addr) == 6, addr_offset);
osmo_static_assert(offsetof(struct fake_linux_lapd_header, protocol) == 14, proto_offset);
osmo_static_assert(sizeof(struct fake_linux_lapd_header) == 16, lapd_header_size);
static int pcap_fd = -1;
void e1_set_pcap_fd(int fd)
{
int ret;
struct pcap_hdr header = {
.magic_number = 0xa1b2c3d4,
.version_major = 2,
.version_minor = 4,
.thiszone = 0,
.sigfigs = 0,
.snaplen = 65535,
.network = DLT_LINUX_LAPD,
};
pcap_fd = fd;
ret = write(pcap_fd, &header, sizeof(header));
}
/* This currently only works for the D-Channel */
static void write_pcap_packet(int direction, int sapi, int tei,
struct msgb *msg) {
if (pcap_fd < 0)
return;
int ret;
time_t cur_time;
struct tm *tm;
struct fake_linux_lapd_header header = {
.pkttype = 4,
.hatype = 0,
.halen = 0,
.addr = direction == PCAP_OUTPUT ? 0x0 : 0x1,
.protocol = ntohs(48),
};
struct lapd_header lapd_header = {
.ea1 = 0,
.cr = direction == PCAP_OUTPUT ? 1 : 0,
.sapi = sapi & 0x3F,
.ea2 = 1,
.tei = tei & 0x7F,
.control_foo = 0x03 /* UI */,
};
struct pcaprec_hdr payload_header = {
.ts_sec = 0,
.ts_usec = 0,
.incl_len = msgb_l2len(msg) + sizeof(struct fake_linux_lapd_header)
+ sizeof(struct lapd_header),
.orig_len = msgb_l2len(msg) + sizeof(struct fake_linux_lapd_header)
+ sizeof(struct lapd_header),
};
cur_time = time(NULL);
tm = localtime(&cur_time);
payload_header.ts_sec = mktime(tm);
ret = write(pcap_fd, &payload_header, sizeof(payload_header));
ret = write(pcap_fd, &header, sizeof(header));
ret = write(pcap_fd, &lapd_header, sizeof(lapd_header));
ret = write(pcap_fd, msg->l2h, msgb_l2len(msg));
}
static const char *sign_types[] = {
[E1INP_SIGN_NONE] = "None",
[E1INP_SIGN_OML] = "OML",
[E1INP_SIGN_RSL] = "RSL",
};
const char *e1inp_signtype_name(enum e1inp_sign_type tp)
{
if (tp >= ARRAY_SIZE(sign_types))
return "undefined";
return sign_types[tp];
}
static const char *ts_types[] = {
[E1INP_TS_TYPE_NONE] = "None",
[E1INP_TS_TYPE_SIGN] = "Signalling",
[E1INP_TS_TYPE_TRAU] = "TRAU",
};
const char *e1inp_tstype_name(enum e1inp_ts_type tp)
{
if (tp >= ARRAY_SIZE(ts_types))
return "undefined";
return ts_types[tp];
}
/* callback when a TRAU frame was received */
static int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len,
void *_priv)
{
struct e1inp_ts *e1i_ts = _priv;
struct gsm_e1_subslot src_ss;
src_ss.e1_nr = e1i_ts->line->num;
src_ss.e1_ts = e1i_ts->num;
src_ss.e1_ts_ss = ch;
return trau_mux_input(&src_ss, data, len);
}
int abis_rsl_sendmsg(struct msgb *msg)
{
struct e1inp_sign_link *sign_link;
struct e1inp_driver *e1inp_driver;
struct e1inp_ts *e1i_ts;
msg->l2h = msg->data;
if (!msg->trx) {
LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx == NULL: %s\n",
osmo_hexdump(msg->data, msg->len));
talloc_free(msg);
return -EINVAL;
} else if (!msg->trx->rsl_link) {
LOGP(DRSL, LOGL_ERROR, "rsl_sendmsg: msg->trx->rsl_link == NULL: %s\n",
osmo_hexdump(msg->data, msg->len));
talloc_free(msg);
return -EIO;
}
sign_link = msg->trx->rsl_link;
e1i_ts = sign_link->ts;
if (!osmo_timer_pending(&e1i_ts->sign.tx_timer)) {
/* notify the driver we have something to write */
e1inp_driver = sign_link->ts->line->driver;
e1inp_driver->want_write(e1i_ts);
}
msgb_enqueue(&sign_link->tx_list, msg);
/* dump it */
write_pcap_packet(PCAP_OUTPUT, sign_link->sapi, sign_link->tei, msg);
return 0;
}
int _abis_nm_sendmsg(struct msgb *msg, int to_trx_oml)
{
struct e1inp_sign_link *sign_link;
struct e1inp_driver *e1inp_driver;
struct e1inp_ts *e1i_ts;
msg->l2h = msg->data;
if (!msg->trx || !msg->trx->bts || !msg->trx->bts->oml_link) {
LOGP(DNM, LOGL_ERROR, "nm_sendmsg: msg->trx == NULL\n");
return -EINVAL;
}
/* Check for TRX-specific OML link first */
if (to_trx_oml) {
if (!msg->trx->oml_link)
return -ENODEV;
sign_link = msg->trx->oml_link;
} else
sign_link = msg->trx->bts->oml_link;
e1i_ts = sign_link->ts;
if (!osmo_timer_pending(&e1i_ts->sign.tx_timer)) {
/* notify the driver we have something to write */
e1inp_driver = sign_link->ts->line->driver;
e1inp_driver->want_write(e1i_ts);
}
msgb_enqueue(&sign_link->tx_list, msg);
/* dump it */
write_pcap_packet(PCAP_OUTPUT, sign_link->sapi, sign_link->tei, msg);
return 0;
}
/* Timeslot */
/* configure and initialize one e1inp_ts */
int e1inp_ts_config(struct e1inp_ts *ts, struct e1inp_line *line,
enum e1inp_ts_type type)
{
if (ts->type == type && ts->line && line)
return 0;
ts->type = type;
ts->line = line;
switch (type) {
case E1INP_TS_TYPE_SIGN:
if (line && line->driver)
ts->sign.delay = line->driver->default_delay;
else
ts->sign.delay = 100000;
INIT_LLIST_HEAD(&ts->sign.sign_links);
break;
case E1INP_TS_TYPE_TRAU:
subchan_mux_init(&ts->trau.mux);
ts->trau.demux.out_cb = subch_cb;
ts->trau.demux.data = ts;
subch_demux_init(&ts->trau.demux);
break;
default:
LOGP(DMI, LOGL_ERROR, "unsupported E1 timeslot type %u\n",
ts->type);
return -EINVAL;
}
return 0;
}
struct e1inp_line *e1inp_line_get(uint8_t e1_nr)
{
struct e1inp_line *e1i_line;
/* iterate over global list of e1 lines */
llist_for_each_entry(e1i_line, &e1inp_line_list, list) {
if (e1i_line->num == e1_nr)
return e1i_line;
}
return NULL;
}
struct e1inp_line *e1inp_line_create(uint8_t e1_nr, const char *driver_name)
{
struct e1inp_driver *driver;
struct e1inp_line *line;
int i;
line = e1inp_line_get(e1_nr);
if (line) {
LOGP(DINP, LOGL_ERROR, "E1 Line %u already exists\n",
e1_nr);
return NULL;
}
driver = e1inp_driver_find(driver_name);
if (!driver) {
LOGP(DINP, LOGL_ERROR, "No such E1 driver '%s'\n",
driver_name);
return NULL;
}
line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
if (!line)
return NULL;
line->driver = driver;
line->num = e1_nr;
for (i = 0; i < NUM_E1_TS; i++) {
line->ts[i].num = i+1;
line->ts[i].line = line;
}
llist_add_tail(&line->list, &e1inp_line_list);
return line;
}
#if 0
struct e1inp_line *e1inp_line_get_create(uint8_t e1_nr)
{
struct e1inp_line *line;
int i;
line = e1inp_line_get(e1_nr);
if (line)
return line;
line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
if (!line)
return NULL;
line->num = e1_nr;
for (i = 0; i < NUM_E1_TS; i++) {
line->ts[i].num = i+1;
line->ts[i].line = line;
}
llist_add_tail(&line->list, &e1inp_line_list);
return line;
}
#endif
static struct e1inp_ts *e1inp_ts_get(uint8_t e1_nr, uint8_t ts_nr)
{
struct e1inp_line *e1i_line;
e1i_line = e1inp_line_get(e1_nr);
if (!e1i_line)
return NULL;
return &e1i_line->ts[ts_nr-1];
}
struct subch_mux *e1inp_get_mux(uint8_t e1_nr, uint8_t ts_nr)
{
struct e1inp_ts *e1i_ts = e1inp_ts_get(e1_nr, ts_nr);
if (!e1i_ts)
return NULL;
return &e1i_ts->trau.mux;
}
/* Signalling Link */
struct e1inp_sign_link *e1inp_lookup_sign_link(struct e1inp_ts *e1i,
uint8_t tei, uint8_t sapi)
{
struct e1inp_sign_link *link;
llist_for_each_entry(link, &e1i->sign.sign_links, list) {
if (link->sapi == sapi && link->tei == tei)
return link;
}
return NULL;
}
/* create a new signalling link in a E1 timeslot */
struct e1inp_sign_link *
e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type,
struct gsm_bts_trx *trx, uint8_t tei,
uint8_t sapi)
{
struct e1inp_sign_link *link;
if (ts->type != E1INP_TS_TYPE_SIGN)
return NULL;
link = talloc_zero(tall_sigl_ctx, struct e1inp_sign_link);
if (!link)
return NULL;
link->ts = ts;
link->type = type;
INIT_LLIST_HEAD(&link->tx_list);
link->trx = trx;
link->tei = tei;
link->sapi = sapi;
llist_add_tail(&link->list, &ts->sign.sign_links);
return link;
}
void e1inp_sign_link_destroy(struct e1inp_sign_link *link)
{
struct msgb *msg;
llist_del(&link->list);
while (!llist_empty(&link->tx_list)) {
msg = msgb_dequeue(&link->tx_list);
msgb_free(msg);
}
if (link->ts->type == E1INP_TS_TYPE_SIGN)
osmo_timer_del(&link->ts->sign.tx_timer);
talloc_free(link);
}
/* the E1 driver tells us he has received something on a TS */
int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
uint8_t tei, uint8_t sapi)
{
struct e1inp_sign_link *link;
struct gsm_bts *bts;
int ret;
switch (ts->type) {
case E1INP_TS_TYPE_SIGN:
/* consult the list of signalling links */
write_pcap_packet(PCAP_INPUT, sapi, tei, msg);
link = e1inp_lookup_sign_link(ts, tei, sapi);
if (!link) {
LOGP(DMI, LOGL_ERROR, "didn't find signalling link for "
"tei %d, sapi %d\n", tei, sapi);
return -EINVAL;
}
log_set_context(BSC_CTX_BTS, link->trx->bts);
switch (link->type) {
case E1INP_SIGN_OML:
msg->trx = link->trx;
bts = msg->trx->bts;
ret = bts->model->oml_rcvmsg(msg);
break;
case E1INP_SIGN_RSL:
msg->trx = link->trx;
ret = abis_rsl_rcvmsg(msg);
break;
default:
ret = -EINVAL;
LOGP(DMI, LOGL_ERROR, "unknown link type %u\n", link->type);
break;
}
break;
case E1INP_TS_TYPE_TRAU:
ret = subch_demux_in(&ts->trau.demux, msg->l2h, msgb_l2len(msg));
break;
default:
ret = -EINVAL;
LOGP(DMI, LOGL_ERROR, "unknown TS type %u\n", ts->type);
break;
}
return ret;
}
#define TSX_ALLOC_SIZE 4096
/* called by driver if it wants to transmit on a given TS */
struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts,
struct e1inp_sign_link **sign_link)
{
struct e1inp_sign_link *link;
struct msgb *msg = NULL;
int len;
switch (e1i_ts->type) {
case E1INP_TS_TYPE_SIGN:
/* FIXME: implement this round robin */
llist_for_each_entry(link, &e1i_ts->sign.sign_links, list) {
msg = msgb_dequeue(&link->tx_list);
if (msg) {
if (sign_link)
*sign_link = link;
break;
}
}
break;
case E1INP_TS_TYPE_TRAU:
msg = msgb_alloc(TSX_ALLOC_SIZE, "TRAU_TX");
if (!msg)
return NULL;
len = subchan_mux_out(&e1i_ts->trau.mux, msg->data, 40);
msgb_put(msg, 40);
break;
default:
LOGP(DMI, LOGL_ERROR, "unsupported E1 TS type %u\n", e1i_ts->type);
return NULL;
}
return msg;
}
/* called by driver in case some kind of link state event */
int e1inp_event(struct e1inp_ts *ts, int evt, uint8_t tei, uint8_t sapi)
{
struct e1inp_sign_link *link;
struct input_signal_data isd;
link = e1inp_lookup_sign_link(ts, tei, sapi);
if (!link)
return -EINVAL;
isd.link_type = link->type;
isd.trx = link->trx;
isd.tei = tei;
isd.sapi = sapi;
/* report further upwards */
osmo_signal_dispatch(SS_INPUT, evt, &isd);
return 0;
}
/* register a driver with the E1 core */
int e1inp_driver_register(struct e1inp_driver *drv)
{
llist_add_tail(&drv->list, &e1inp_driver_list);
return 0;
}
struct e1inp_driver *e1inp_driver_find(const char *name)
{
struct e1inp_driver *drv;
llist_for_each_entry(drv, &e1inp_driver_list, list) {
if (!strcasecmp(name, drv->name))
return drv;
}
return NULL;
}
int e1inp_line_update(struct e1inp_line *line)
{
struct input_signal_data isd;
int rc;
if (line->driver && line->driver->line_update)
rc = line->driver->line_update(line);
else
rc = 0;
/* Send a signal to anyone who is interested in new lines being
* configured */
memset(&isd, 0, sizeof(isd));
isd.line = line;
osmo_signal_dispatch(SS_INPUT, S_INP_LINE_INIT, &isd);
return rc;
}
static int e1i_sig_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
if (subsys != SS_GLOBAL ||
signal != S_GLOBAL_SHUTDOWN)
return 0;
if (pcap_fd) {
close(pcap_fd);
pcap_fd = -1;
}
return 0;
}
void e1inp_misdn_init(void);
void e1inp_dahdi_init(void);
void e1inp_ipaccess_init(void);
void e1inp_hsl_init(void);
void e1inp_init(void)
{
tall_sigl_ctx = talloc_named_const(tall_bsc_ctx, 1,
"e1inp_sign_link");
osmo_signal_register_handler(SS_GLOBAL, e1i_sig_cb, NULL);
e1inp_misdn_init();
#ifdef HAVE_DAHDI_USER_H
e1inp_dahdi_init();
#endif
e1inp_ipaccess_init();
e1inp_hsl_init();
}

View File

@@ -0,0 +1,104 @@
/* OpenBSC E1 vty interface */
/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/buffer.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/core/linuxlist.h>
#include <openbsc/gsm_data.h>
#include <openbsc/e1_input.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/talloc.h>
#include <openbsc/vty.h>
#include <openbsc/debug.h>
#include "../../bscconfig.h"
#define E1_DRIVER_NAMES "(misdn|dahdi)"
#define E1_DRIVER_HELP "mISDN supported E1 Card\n" \
"DAHDI supported E1/T1/J1 Card\n"
DEFUN(cfg_e1line_driver, cfg_e1_line_driver_cmd,
"e1_line <0-255> driver " E1_DRIVER_NAMES,
"Configure E1/T1/J1 Line\n" "Line Number\n" "Set driver for this line\n"
E1_DRIVER_HELP)
{
struct e1inp_line *line;
int e1_nr = atoi(argv[0]);
line = e1inp_line_get(e1_nr);
if (line) {
vty_out(vty, "%% Line %d already exists%s", e1_nr, VTY_NEWLINE);
return CMD_WARNING;
}
line = e1inp_line_create(e1_nr, argv[1]);
if (!line) {
vty_out(vty, "%% Error creating line %d%s", e1_nr, VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_e1inp, cfg_e1inp_cmd,
"e1_input",
"Configure E1/T1/J1 TDM input\n")
{
vty->node = E1INP_NODE;
return CMD_SUCCESS;
}
static int e1inp_config_write(struct vty *vty)
{
struct e1inp_line *line;
if (llist_empty(&e1inp_line_list))
return CMD_SUCCESS;
vty_out(vty, "e1_input%s", VTY_NEWLINE);
llist_for_each_entry(line, &e1inp_line_list, list) {
vty_out(vty, " e1_line %u driver %s%s", line->num,
line->driver->name, VTY_NEWLINE);
}
return CMD_SUCCESS;
}
struct cmd_node e1inp_node = {
E1INP_NODE,
"%s(e1_input)#",
1,
};
int e1inp_vty_init(void)
{
install_element(CONFIG_NODE, &cfg_e1inp_cmd);
install_node(&e1inp_node, e1inp_config_write);
install_element(E1INP_NODE, &cfg_e1_line_driver_cmd);
return 0;
}

View File

@@ -0,0 +1,493 @@
/* OpenBSC Abis input driver for DAHDI */
/* (C) 2008-2011 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by Digium and Matthew Fredrickson <creslin@digium.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "../../../bscconfig.h"
#ifdef HAVE_DAHDI_USER_H
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <dahdi/user.h>
#include <osmocom/core/select.h>
#include <osmocom/core/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/subchan_demux.h>
#include <openbsc/e1_input.h>
#include <openbsc/signal.h>
#include <osmocom/core/talloc.h>
#include "lapd.h"
#define TS1_ALLOC_SIZE 300
/* Corresponds to dahdi/user.h, only PRI related events */
static const struct value_string dahdi_evt_names[] = {
{ DAHDI_EVENT_NONE, "NONE" },
{ DAHDI_EVENT_ALARM, "ALARM" },
{ DAHDI_EVENT_NOALARM, "NOALARM" },
{ DAHDI_EVENT_ABORT, "HDLC ABORT" },
{ DAHDI_EVENT_OVERRUN, "HDLC OVERRUN" },
{ DAHDI_EVENT_BADFCS, "HDLC BAD FCS" },
{ DAHDI_EVENT_REMOVED, "REMOVED" },
{ 0, NULL }
};
static void handle_dahdi_exception(struct e1inp_ts *ts)
{
int rc, evt;
struct input_signal_data isd;
rc = ioctl(ts->driver.dahdi.fd.fd, DAHDI_GETEVENT, &evt);
if (rc < 0)
return;
LOGP(DMI, LOGL_NOTICE, "Line %u(%s) / TS %u DAHDI EVENT %s\n",
ts->line->num, ts->line->name, ts->num,
get_value_string(dahdi_evt_names, evt));
isd.line = ts->line;
switch (evt) {
case DAHDI_EVENT_ALARM:
/* we should notify the code that the line is gone */
osmo_signal_dispatch(SS_INPUT, S_INP_LINE_ALARM, &isd);
break;
case DAHDI_EVENT_NOALARM:
/* alarm has gone, we should re-start the SABM requests */
osmo_signal_dispatch(SS_INPUT, S_INP_LINE_NOALARM, &isd);
break;
}
}
static int handle_ts1_read(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "DAHDI TS1");
lapd_mph_type prim;
unsigned int sapi, tei;
int ilen, ret;
uint8_t *idata;
if (!msg)
return -ENOMEM;
ret = read(bfd->fd, msg->data, TS1_ALLOC_SIZE - 16);
if (ret == -1)
handle_dahdi_exception(e1i_ts);
else if (ret < 0) {
perror("read ");
}
msgb_put(msg, ret - 2);
if (ret <= 3) {
perror("read ");
}
sapi = msg->data[0] >> 2;
tei = msg->data[1] >> 1;
DEBUGP(DMI, "<= len = %d, sapi(%d) tei(%d)", ret, sapi, tei);
idata = lapd_receive(e1i_ts->driver.dahdi.lapd, msg->data, msg->len, &ilen, &prim);
if (!idata && prim == 0)
return -EIO;
msgb_pull(msg, 2);
DEBUGP(DMI, "prim %08x\n", prim);
switch (prim) {
case 0:
break;
case LAPD_MPH_ACTIVATE_IND:
DEBUGP(DMI, "MPH_ACTIVATE_IND: sapi(%d) tei(%d)\n", sapi, tei);
ret = e1inp_event(e1i_ts, S_INP_TEI_UP, tei, sapi);
break;
case LAPD_MPH_DEACTIVATE_IND:
DEBUGP(DMI, "MPH_DEACTIVATE_IND: sapi(%d) tei(%d)\n", sapi, tei);
ret = e1inp_event(e1i_ts, S_INP_TEI_DN, tei, sapi);
break;
case LAPD_DL_DATA_IND:
case LAPD_DL_UNITDATA_IND:
if (prim == LAPD_DL_DATA_IND)
msg->l2h = msg->data + 2;
else
msg->l2h = msg->data + 1;
DEBUGP(DMI, "RX: %s\n", osmo_hexdump(msgb_l2(msg), ret));
ret = e1inp_rx_ts(e1i_ts, msg, tei, sapi);
break;
default:
printf("ERROR: unknown prim\n");
break;
}
DEBUGP(DMI, "Returned ok\n");
return ret;
}
static int ts_want_write(struct e1inp_ts *e1i_ts)
{
/* We never include the DAHDI B-Channel FD into the
* writeset, since it doesn't support poll() based
* write flow control */
if (e1i_ts->type == E1INP_TS_TYPE_TRAU) {
fprintf(stderr, "Trying to write TRAU ts\n");
return 0;
}
e1i_ts->driver.dahdi.fd.when |= BSC_FD_WRITE;
return 0;
}
static void timeout_ts1_write(void *data)
{
struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
/* trigger write of ts1, due to tx delay timer */
ts_want_write(e1i_ts);
}
static void dahdi_write_msg(uint8_t *data, int len, void *cbdata)
{
struct osmo_fd *bfd = cbdata;
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
int ret;
ret = write(bfd->fd, data, len + 2);
if (ret == -1)
handle_dahdi_exception(e1i_ts);
else if (ret < 0)
LOGP(DMI, LOGL_NOTICE, "%s write failed %d\n", __func__, ret);
}
static int handle_ts1_write(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct e1inp_sign_link *sign_link;
struct msgb *msg;
bfd->when &= ~BSC_FD_WRITE;
/* get the next msg for this timeslot */
msg = e1inp_tx_ts(e1i_ts, &sign_link);
if (!msg) {
/* no message after tx delay timer */
return 0;
}
DEBUGP(DMI, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
lapd_transmit(e1i_ts->driver.dahdi.lapd, sign_link->tei,
sign_link->sapi, msg->data, msg->len);
msgb_free(msg);
/* set tx delay timer for next event */
e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
e1i_ts->sign.tx_timer.data = e1i_ts;
osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, 50000);
return 0;
}
static int invertbits = 1;
static uint8_t flip_table[256];
static void init_flip_bits(void)
{
int i,k;
for (i = 0 ; i < 256 ; i++) {
uint8_t sample = 0 ;
for (k = 0; k<8; k++) {
if ( i & 1 << k ) sample |= 0x80 >> k;
}
flip_table[i] = sample;
}
}
static uint8_t * flip_buf_bits ( uint8_t * buf , int len)
{
int i;
uint8_t * start = buf;
for (i = 0 ; i < len; i++) {
buf[i] = flip_table[(uint8_t)buf[i]];
}
return start;
}
#define D_BCHAN_TX_GRAN 160
/* write to a B channel TS */
static int handle_tsX_write(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
uint8_t tx_buf[D_BCHAN_TX_GRAN];
struct subch_mux *mx = &e1i_ts->trau.mux;
int ret;
ret = subchan_mux_out(mx, tx_buf, D_BCHAN_TX_GRAN);
if (ret != D_BCHAN_TX_GRAN) {
fprintf(stderr, "Huh, got ret of %d\n", ret);
if (ret < 0)
return ret;
}
DEBUGP(DMIB, "BCHAN TX: %s\n",
osmo_hexdump(tx_buf, D_BCHAN_TX_GRAN));
if (invertbits) {
flip_buf_bits(tx_buf, ret);
}
ret = write(bfd->fd, tx_buf, ret);
if (ret < D_BCHAN_TX_GRAN)
fprintf(stderr, "send returns %d instead of %d\n", ret,
D_BCHAN_TX_GRAN);
return ret;
}
#define D_TSX_ALLOC_SIZE (D_BCHAN_TX_GRAN)
/* FIXME: read from a B channel TS */
static int handle_tsX_read(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct msgb *msg = msgb_alloc(D_TSX_ALLOC_SIZE, "DAHDI TSx");
int ret;
if (!msg)
return -ENOMEM;
ret = read(bfd->fd, msg->data, D_TSX_ALLOC_SIZE);
if (ret < 0 || ret != D_TSX_ALLOC_SIZE) {
fprintf(stderr, "read error %d %s\n", ret, strerror(errno));
return ret;
}
if (invertbits) {
flip_buf_bits(msg->data, ret);
}
msgb_put(msg, ret);
msg->l2h = msg->data;
DEBUGP(DMIB, "BCHAN RX: %s\n",
osmo_hexdump(msgb_l2(msg), ret));
ret = e1inp_rx_ts(e1i_ts, msg, 0, 0);
/* physical layer indicates that data has been sent,
* we thus can send some more data */
ret = handle_tsX_write(bfd);
msgb_free(msg);
return ret;
}
/* callback from select.c in case one of the fd's can be read/written */
static int dahdi_fd_cb(struct osmo_fd *bfd, unsigned int what)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
unsigned int idx = ts_nr-1;
struct e1inp_ts *e1i_ts = &line->ts[idx];
int rc = 0;
switch (e1i_ts->type) {
case E1INP_TS_TYPE_SIGN:
if (what & BSC_FD_EXCEPT)
handle_dahdi_exception(e1i_ts);
if (what & BSC_FD_READ)
rc = handle_ts1_read(bfd);
if (what & BSC_FD_WRITE)
rc = handle_ts1_write(bfd);
break;
case E1INP_TS_TYPE_TRAU:
if (what & BSC_FD_EXCEPT)
handle_dahdi_exception(e1i_ts);
if (what & BSC_FD_READ)
rc = handle_tsX_read(bfd);
if (what & BSC_FD_WRITE)
rc = handle_tsX_write(bfd);
/* We never include the DAHDI B-Channel FD into the
* writeset, since it doesn't support poll() based
* write flow control */
break;
default:
fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
break;
}
return rc;
}
static int dahdi_e1_line_update(struct e1inp_line *line);
struct e1inp_driver dahdi_driver = {
.name = "dahdi",
.want_write = ts_want_write,
.line_update = &dahdi_e1_line_update,
};
void dahdi_set_bufinfo(int fd, int as_sigchan)
{
struct dahdi_bufferinfo bi;
int x = 0;
if (ioctl(fd, DAHDI_GET_BUFINFO, &bi)) {
fprintf(stderr, "Error getting bufinfo\n");
exit(-1);
}
if (as_sigchan) {
bi.numbufs = 4;
bi.bufsize = 512;
} else {
bi.numbufs = 8;
bi.bufsize = D_BCHAN_TX_GRAN;
bi.txbufpolicy = DAHDI_POLICY_WHEN_FULL;
}
if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
fprintf(stderr, "Error setting bufinfo\n");
exit(-1);
}
if (!as_sigchan) {
if (ioctl(fd, DAHDI_AUDIOMODE, &x)) {
fprintf(stderr, "Error setting bufinfo\n");
exit(-1);
}
} else {
int one = 1;
ioctl(fd, DAHDI_HDLCFCSMODE, &one);
/* we cannot reliably check for the ioctl return value here
* as this command will fail if the slot _already_ was a
* signalling slot before :( */
}
}
static int dahdi_e1_setup(struct e1inp_line *line)
{
int ts, ret;
/* TS0 is CRC4, don't need any fd for it */
for (ts = 1; ts < NUM_E1_TS; ts++) {
unsigned int idx = ts-1;
char openstr[128];
struct e1inp_ts *e1i_ts = &line->ts[idx];
struct osmo_fd *bfd = &e1i_ts->driver.dahdi.fd;
bfd->data = line;
bfd->priv_nr = ts;
bfd->cb = dahdi_fd_cb;
snprintf(openstr, sizeof(openstr), "/dev/dahdi/%d", ts);
switch (e1i_ts->type) {
case E1INP_TS_TYPE_NONE:
continue;
break;
case E1INP_TS_TYPE_SIGN:
bfd->fd = open(openstr, O_RDWR | O_NONBLOCK);
if (bfd->fd == -1) {
fprintf(stderr, "%s could not open %s %s\n",
__func__, openstr, strerror(errno));
exit(-1);
}
bfd->when = BSC_FD_READ | BSC_FD_EXCEPT;
dahdi_set_bufinfo(bfd->fd, 1);
e1i_ts->driver.dahdi.lapd = lapd_instance_alloc(1, dahdi_write_msg, bfd);
break;
case E1INP_TS_TYPE_TRAU:
bfd->fd = open(openstr, O_RDWR | O_NONBLOCK);
if (bfd->fd == -1) {
fprintf(stderr, "%s could not open %s %s\n",
__func__, openstr, strerror(errno));
exit(-1);
}
dahdi_set_bufinfo(bfd->fd, 0);
/* We never include the DAHDI B-Channel FD into the
* writeset, since it doesn't support poll() based
* write flow control */
bfd->when = BSC_FD_READ | BSC_FD_EXCEPT;// | BSC_FD_WRITE;
break;
}
if (bfd->fd < 0) {
fprintf(stderr, "%s could not open %s %s\n",
__func__, openstr, strerror(errno));
return bfd->fd;
}
ret = osmo_fd_register(bfd);
if (ret < 0) {
fprintf(stderr, "could not register FD: %s\n",
strerror(ret));
return ret;
}
}
return 0;
}
static int dahdi_e1_line_update(struct e1inp_line *line)
{
if (line->driver != &dahdi_driver)
return -EINVAL;
return dahdi_e1_setup(line);
}
int e1inp_dahdi_init(void)
{
init_flip_bits();
/* register the driver with the core */
return e1inp_driver_register(&dahdi_driver);
}
#endif /* HAVE_DAHDI_USER_H */

View File

@@ -0,0 +1,458 @@
/* OpenBSC Abis input driver for HSL Femto */
/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
* (C) 2011 by On-Waves
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* HSL uses a much more primitive/simplified version of the IPA multiplex.
*
* They have taken out the nice parts like the ID_GET / ID_RESP for resolving
* the UNIT ID, as well as the keepalive ping/pong messages. Furthermore, the
* Stream Identifiers are fixed on the BTS side (RSL always 0, OML always 0xff)
* and both OML+RSL share a single TCP connection.
*
* Other oddities include the encapsulation of BSSGP messages in the L3_INFO IE
* of RSL
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <osmocom/core/select.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/msgb.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/subchan_demux.h>
#include <openbsc/e1_input.h>
#include <openbsc/ipaccess.h>
#include <openbsc/socket.h>
#include <openbsc/signal.h>
#include <osmocom/core/talloc.h>
#define HSL_TCP_PORT 2500
#define HSL_PROTO_DEBUG 0xdd
#define PRIV_OML 1
#define PRIV_RSL 2
/* data structure for one E1 interface with A-bis */
struct hsl_e1_handle {
struct osmo_fd listen_fd;
struct gsm_network *gsmnet;
};
static struct hsl_e1_handle *e1h;
#define TS1_ALLOC_SIZE 900
#define OML_UP 0x0001
#define RSL_UP 0x0002
int hsl_drop_oml(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
struct e1inp_ts *ts;
struct e1inp_line *line;
struct osmo_fd *bfd;
if (!bts || !bts->oml_link)
return -1;
/* send OML down */
ts = bts->oml_link->ts;
line = ts->line;
e1inp_event(ts, S_INP_TEI_DN, bts->oml_link->tei, bts->oml_link->sapi);
bfd = &ts->driver.ipaccess.fd;
osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
/* clean up OML and RSL */
e1inp_sign_link_destroy(bts->oml_link);
bts->oml_link = NULL;
e1inp_sign_link_destroy(bts->c0->rsl_link);
bts->c0->rsl_link = NULL;
bts->ip_access.flags = 0;
/* kill the E1 line now... as we have no one left to use it */
talloc_free(line);
return -1;
}
static int hsl_drop_ts_fd(struct e1inp_ts *ts, struct osmo_fd *bfd)
{
struct e1inp_sign_link *link, *link2;
int bts_nr = -1;
llist_for_each_entry_safe(link, link2, &ts->sign.sign_links, list) {
bts_nr = link->trx->bts->bts_nr;
e1inp_sign_link_destroy(link);
}
osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
talloc_free(ts->line);
return bts_nr;
}
struct gsm_bts *find_bts_by_serno(struct gsm_network *net, unsigned long serno)
{
struct gsm_bts *bts;
llist_for_each_entry(bts, &net->bts_list, list) {
if (bts->type != GSM_BTS_TYPE_HSL_FEMTO)
continue;
if (serno == bts->hsl.serno)
return bts;
}
return NULL;
}
static int process_hsl_rsl(struct msgb *msg, struct e1inp_line *line)
{
char serno_buf[16];
uint8_t serno_len;
unsigned long serno;
struct gsm_bts *bts;
switch (msg->l2h[1]) {
case 0x80:
/*, contains Serial Number + SW version */
if (msg->l2h[2] != 0xc0)
break;
serno_len = msg->l2h[3];
if (serno_len > sizeof(serno_buf)-1)
serno_len = sizeof(serno_buf)-1;
memcpy(serno_buf, msg->l2h+4, serno_len);
serno_buf[serno_len] = '\0';
serno = strtoul(serno_buf, NULL, 10);
bts = find_bts_by_serno(e1h->gsmnet, serno);
if (!bts) {
LOGP(DINP, LOGL_ERROR, "Unable to find BTS config for "
"serial number %lu(%s)\n", serno, serno_buf);
return -EIO;
}
DEBUGP(DINP, "Identified HSL BTS Serial Number %lu\n", serno);
/* we shouldn't hardcode it, but HSL femto also hardcodes it... */
bts->oml_tei = 255;
bts->c0->rsl_tei = 0;
bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1],
E1INP_SIGN_OML, bts->c0,
bts->oml_tei, 0);
bts->c0->rsl_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1],
E1INP_SIGN_RSL, bts->c0,
bts->c0->rsl_tei, 0);
e1inp_event(&line->ts[PRIV_OML-1], S_INP_TEI_UP, 255, 0);
e1inp_event(&line->ts[PRIV_OML-1], S_INP_TEI_UP, 0, 0);
bts->ip_access.flags |= OML_UP;
bts->ip_access.flags |= (RSL_UP << 0);
msgb_free(msg);
return 1; /* == we have taken over the msg */
case 0x82:
/* FIXME: do something with BSSGP, i.e. forward it over
* NSIP to OsmoSGSN */
msgb_free(msg);
return 1;
}
return 0;
}
static int handle_ts1_read(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct e1inp_sign_link *link;
struct msgb *msg;
struct ipaccess_head *hh;
int ret = 0, error;
msg = ipaccess_read_msg(bfd, &error);
if (!msg) {
if (error == 0) {
int ret = hsl_drop_ts_fd(e1i_ts, bfd);
if (ret >= 0)
LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n",
ret);
else
LOGP(DINP, LOGL_NOTICE, "unknown BTS disappeared, dead socket\n");
}
return error;
}
DEBUGP(DMI, "RX %u: %s\n", ts_nr, osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
hh = (struct ipaccess_head *) msg->data;
if (hh->proto == HSL_PROTO_DEBUG) {
LOGP(DINP, LOGL_NOTICE, "HSL debug: %s\n", msg->data + sizeof(*hh));
msgb_free(msg);
return ret;
}
/* HSL proprietary RSL extension */
if (hh->proto == 0 && (msg->l2h[0] == 0x81 || msg->l2h[0] == 0x80)) {
ret = process_hsl_rsl(msg, line);
if (ret < 0) {
/* FIXME: close connection */
hsl_drop_ts_fd(e1i_ts, bfd);
return ret;
} else if (ret == 1)
return 0;
/* else: continue... */
}
#ifdef HSL_SR_1_0
/* HSL for whatever reason chose to use 0x81 instead of 0x80 for FOM */
if (hh->proto == 255 && msg->l2h[0] == (ABIS_OM_MDISC_FOM | 0x01))
msg->l2h[0] = ABIS_OM_MDISC_FOM;
#endif
link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0);
if (!link) {
LOGP(DINP, LOGL_ERROR, "no matching signalling link for "
"hh->proto=0x%02x\n", hh->proto);
msgb_free(msg);
return -EIO;
}
msg->trx = link->trx;
switch (link->type) {
case E1INP_SIGN_RSL:
if (!(msg->trx->bts->ip_access.flags & (RSL_UP << msg->trx->nr))) {
e1inp_event(e1i_ts, S_INP_TEI_UP, link->tei, link->sapi);
msg->trx->bts->ip_access.flags |= (RSL_UP << msg->trx->nr);
}
ret = abis_rsl_rcvmsg(msg);
break;
case E1INP_SIGN_OML:
if (!(msg->trx->bts->ip_access.flags & OML_UP)) {
e1inp_event(e1i_ts, S_INP_TEI_UP, link->tei, link->sapi);
msg->trx->bts->ip_access.flags |= OML_UP;
}
ret = abis_nm_rcvmsg(msg);
break;
default:
LOGP(DINP, LOGL_NOTICE, "Unknown HSL protocol class 0x%02x\n", hh->proto);
msgb_free(msg);
break;
}
return ret;
}
static int ts_want_write(struct e1inp_ts *e1i_ts)
{
e1i_ts->driver.ipaccess.fd.when |= BSC_FD_WRITE;
return 0;
}
static void timeout_ts1_write(void *data)
{
struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
/* trigger write of ts1, due to tx delay timer */
ts_want_write(e1i_ts);
}
static int handle_ts1_write(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct e1inp_sign_link *sign_link;
struct msgb *msg;
uint8_t proto;
int ret;
bfd->when &= ~BSC_FD_WRITE;
/* get the next msg for this timeslot */
msg = e1inp_tx_ts(e1i_ts, &sign_link);
if (!msg) {
/* no message after tx delay timer */
return 0;
}
switch (sign_link->type) {
case E1INP_SIGN_OML:
proto = IPAC_PROTO_OML;
#ifdef HSL_SR_1_0
/* HSL uses 0x81 for FOM for some reason */
if (msg->data[0] == ABIS_OM_MDISC_FOM)
msg->data[0] = ABIS_OM_MDISC_FOM | 0x01;
#endif
break;
case E1INP_SIGN_RSL:
proto = IPAC_PROTO_RSL;
break;
default:
msgb_free(msg);
bfd->when |= BSC_FD_WRITE; /* come back for more msg */
return -EINVAL;
}
msg->l2h = msg->data;
ipaccess_prepend_header(msg, sign_link->tei);
DEBUGP(DMI, "TX %u: %s\n", ts_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg)));
ret = send(bfd->fd, msg->data, msg->len, 0);
msgb_free(msg);
/* set tx delay timer for next event */
e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
e1i_ts->sign.tx_timer.data = e1i_ts;
/* Reducing this might break the nanoBTS 900 init. */
osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
return ret;
}
/* callback from select.c in case one of the fd's can be read/written */
static int hsl_fd_cb(struct osmo_fd *bfd, unsigned int what)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
unsigned int idx = ts_nr-1;
struct e1inp_ts *e1i_ts;
int rc = 0;
/* In case of early RSL we might not yet have a line */
if (line)
e1i_ts = &line->ts[idx];
if (!line || e1i_ts->type == E1INP_TS_TYPE_SIGN) {
if (what & BSC_FD_READ)
rc = handle_ts1_read(bfd);
if (what & BSC_FD_WRITE)
rc = handle_ts1_write(bfd);
} else
LOGP(DINP, LOGL_ERROR, "unknown E1 TS type %u\n", e1i_ts->type);
return rc;
}
struct e1inp_driver hsl_driver = {
.name = "HSL",
.want_write = ts_want_write,
.default_delay = 0,
};
/* callback of the OML listening filedescriptor */
static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
{
int ret;
int idx = 0;
int i;
struct e1inp_line *line;
struct e1inp_ts *e1i_ts;
struct osmo_fd *bfd;
struct sockaddr_in sa;
socklen_t sa_len = sizeof(sa);
if (!(what & BSC_FD_READ))
return 0;
ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (ret < 0) {
perror("accept");
return ret;
}
LOGP(DINP, LOGL_NOTICE, "accept()ed new HSL link from %s\n",
inet_ntoa(sa.sin_addr));
line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
if (!line) {
close(ret);
return -ENOMEM;
}
line->driver = &hsl_driver;
//line->driver_data = e1h;
/* create virrtual E1 timeslots for signalling */
e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
/* initialize the fds */
for (i = 0; i < ARRAY_SIZE(line->ts); ++i)
line->ts[i].driver.ipaccess.fd.fd = -1;
e1i_ts = &line->ts[idx];
bfd = &e1i_ts->driver.ipaccess.fd;
bfd->fd = ret;
bfd->data = line;
bfd->priv_nr = PRIV_OML;
bfd->cb = hsl_fd_cb;
bfd->when = BSC_FD_READ;
ret = osmo_fd_register(bfd);
if (ret < 0) {
LOGP(DINP, LOGL_ERROR, "could not register FD\n");
close(bfd->fd);
talloc_free(line);
return ret;
}
return ret;
//return e1inp_line_register(line);
}
int hsl_setup(struct gsm_network *gsmnet)
{
int ret;
e1h = talloc_zero(tall_bsc_ctx, struct hsl_e1_handle);
if (!e1h)
return -ENOMEM;
e1h->gsmnet = gsmnet;
/* Listen for connections */
ret = make_sock(&e1h->listen_fd, IPPROTO_TCP, INADDR_ANY, HSL_TCP_PORT,
0, listen_fd_cb, NULL);
if (ret < 0)
return ret;
return 0;
}
void e1inp_hsl_init(void)
{
e1inp_driver_register(&hsl_driver);
}

View File

@@ -0,0 +1,842 @@
/* OpenBSC Abis input driver for ip.access */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by Holger Hans Peter Freyther
* (C) 2010 by On-Waves
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <osmocom/core/select.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/subchan_demux.h>
#include <openbsc/e1_input.h>
#include <openbsc/ipaccess.h>
#include <openbsc/socket.h>
#include <openbsc/signal.h>
#define PRIV_OML 1
#define PRIV_RSL 2
/* data structure for one E1 interface with A-bis */
struct ia_e1_handle {
struct osmo_fd listen_fd;
struct osmo_fd rsl_listen_fd;
struct gsm_network *gsmnet;
};
static struct ia_e1_handle *e1h;
#define TS1_ALLOC_SIZE 900
/*
* Common propietary IPA messages:
* - PONG: in reply to PING.
* - ID_REQUEST: first messages once OML has been established.
* - ID_ACK: in reply to ID_ACK.
*/
const uint8_t ipa_pong_msg[] = {
0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG
};
const uint8_t ipa_id_ack_msg[] = {
0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
};
const uint8_t ipa_id_req_msg[] = {
0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
0x01, IPAC_IDTAG_UNIT,
0x01, IPAC_IDTAG_MACADDR,
0x01, IPAC_IDTAG_LOCATION1,
0x01, IPAC_IDTAG_LOCATION2,
0x01, IPAC_IDTAG_EQUIPVERS,
0x01, IPAC_IDTAG_SWVERSION,
0x01, IPAC_IDTAG_UNITNAME,
0x01, IPAC_IDTAG_SERNR,
};
static const char *idtag_names[] = {
[IPAC_IDTAG_SERNR] = "Serial_Number",
[IPAC_IDTAG_UNITNAME] = "Unit_Name",
[IPAC_IDTAG_LOCATION1] = "Location_1",
[IPAC_IDTAG_LOCATION2] = "Location_2",
[IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
[IPAC_IDTAG_SWVERSION] = "Software_Version",
[IPAC_IDTAG_IPADDR] = "IP_Address",
[IPAC_IDTAG_MACADDR] = "MAC_Address",
[IPAC_IDTAG_UNIT] = "Unit_ID",
};
const char *ipaccess_idtag_name(uint8_t tag)
{
if (tag >= ARRAY_SIZE(idtag_names))
return "unknown";
return idtag_names[tag];
}
int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
{
uint8_t t_len;
uint8_t t_tag;
uint8_t *cur = buf;
memset(dec, 0, sizeof(*dec));
while (len >= 2) {
len -= 2;
t_len = *cur++;
t_tag = *cur++;
if (t_len > len + 1) {
LOGP(DMI, LOGL_ERROR, "The tag does not fit: %d\n", t_len);
return -EINVAL;
}
DEBUGPC(DMI, "%s='%s' ", ipaccess_idtag_name(t_tag), cur);
dec->lv[t_tag].len = t_len;
dec->lv[t_tag].val = cur;
cur += t_len;
len -= t_len;
}
return 0;
}
struct gsm_bts *find_bts_by_unitid(struct gsm_network *net,
uint16_t site_id, uint16_t bts_id)
{
struct gsm_bts *bts;
llist_for_each_entry(bts, &net->bts_list, list) {
if (!is_ipaccess_bts(bts))
continue;
if (bts->ip_access.site_id == site_id &&
bts->ip_access.bts_id == bts_id)
return bts;
}
return NULL;
}
int ipaccess_parse_unitid(const char *str, uint16_t *site_id,
uint16_t *bts_id, uint16_t *trx_id)
{
unsigned long ul;
char *endptr;
const char *nptr;
nptr = str;
ul = strtoul(nptr, &endptr, 10);
if (endptr <= nptr)
return -EINVAL;
if (site_id)
*site_id = ul & 0xffff;
if (*endptr++ != '/')
return -EINVAL;
nptr = endptr;
ul = strtoul(nptr, &endptr, 10);
if (endptr <= nptr)
return -EINVAL;
if (bts_id)
*bts_id = ul & 0xffff;
if (*endptr++ != '/')
return -EINVAL;
nptr = endptr;
ul = strtoul(nptr, &endptr, 10);
if (endptr <= nptr)
return -EINVAL;
if (trx_id)
*trx_id = ul & 0xffff;
return 0;
}
static int ipaccess_send(int fd, const void *msg, size_t msglen)
{
int ret;
ret = write(fd, msg, msglen);
if (ret < 0)
return ret;
if (ret < msglen) {
LOGP(DINP, LOGL_ERROR, "ipaccess_send: short write\n");
return -EIO;
}
return ret;
}
int ipaccess_send_pong(int fd)
{
return ipaccess_send(fd, ipa_pong_msg, sizeof(ipa_pong_msg));
}
int ipaccess_send_id_ack(int fd)
{
return ipaccess_send(fd, ipa_id_ack_msg, sizeof(ipa_id_ack_msg));
}
int ipaccess_send_id_req(int fd)
{
return ipaccess_send(fd, ipa_id_req_msg, sizeof(ipa_id_req_msg));
}
/* base handling of the ip.access protocol */
int ipaccess_rcvmsg_base(struct msgb *msg,
struct osmo_fd *bfd)
{
uint8_t msg_type = *(msg->l2h);
int ret = 0;
switch (msg_type) {
case IPAC_MSGT_PING:
ret = ipaccess_send_pong(bfd->fd);
break;
case IPAC_MSGT_PONG:
DEBUGP(DMI, "PONG!\n");
break;
case IPAC_MSGT_ID_ACK:
DEBUGP(DMI, "ID_ACK? -> ACK!\n");
ret = ipaccess_send_id_ack(bfd->fd);
break;
}
return 0;
}
static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
struct osmo_fd *bfd)
{
struct tlv_parsed tlvp;
uint8_t msg_type = *(msg->l2h);
uint16_t site_id = 0, bts_id = 0, trx_id = 0;
struct gsm_bts *bts;
char *unitid;
int len, ret;
/* handle base messages */
ipaccess_rcvmsg_base(msg, bfd);
switch (msg_type) {
case IPAC_MSGT_ID_RESP:
DEBUGP(DMI, "ID_RESP ");
/* parse tags, search for Unit ID */
ret = ipaccess_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2,
msgb_l2len(msg)-2);
DEBUGP(DMI, "\n");
if (ret < 0) {
LOGP(DINP, LOGL_ERROR, "ignoring IPA response message "
"with malformed TLVs\n");
return ret;
}
if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT))
break;
len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT);
if (len < 1)
break;
/* lookup BTS, create sign_link, ... */
unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT);
unitid[len - 1] = '\0';
ipaccess_parse_unitid(unitid, &site_id, &bts_id, &trx_id);
bts = find_bts_by_unitid(e1h->gsmnet, site_id, bts_id);
if (!bts) {
LOGP(DINP, LOGL_ERROR, "Unable to find BTS configuration for "
" %u/%u/%u, disconnecting\n", site_id, bts_id,
trx_id);
return -EIO;
}
DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id);
if (bfd->priv_nr == PRIV_OML) {
/* drop any old oml connection */
ipaccess_drop_oml(bts);
bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1],
E1INP_SIGN_OML, bts->c0,
bts->oml_tei, 0);
} else if (bfd->priv_nr == PRIV_RSL) {
struct e1inp_ts *e1i_ts;
struct osmo_fd *newbfd;
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id);
/* drop any old rsl connection */
ipaccess_drop_rsl(trx);
if (!bts->oml_link) {
osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
talloc_free(bfd);
return 0;
}
bfd->data = line = bts->oml_link->ts->line;
e1i_ts = &line->ts[PRIV_RSL + trx_id - 1];
newbfd = &e1i_ts->driver.ipaccess.fd;
e1inp_ts_config(e1i_ts, line, E1INP_TS_TYPE_SIGN);
trx->rsl_link = e1inp_sign_link_create(e1i_ts,
E1INP_SIGN_RSL, trx,
trx->rsl_tei, 0);
trx->rsl_link->ts->sign.delay = 0;
/* get rid of our old temporary bfd */
memcpy(newbfd, bfd, sizeof(*newbfd));
newbfd->priv_nr = PRIV_RSL + trx_id;
osmo_fd_unregister(bfd);
bfd->fd = -1;
talloc_free(bfd);
osmo_fd_register(newbfd);
}
break;
}
return 0;
}
#define OML_UP 0x0001
#define RSL_UP 0x0002
/*
* read one ipa message from the socket
* return NULL in case of error
*/
struct msgb *ipaccess_read_msg(struct osmo_fd *bfd, int *error)
{
struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "Abis/IP");
struct ipaccess_head *hh;
int len, ret = 0;
if (!msg) {
*error = -ENOMEM;
return NULL;
}
/* first read our 3-byte header */
hh = (struct ipaccess_head *) msg->data;
ret = recv(bfd->fd, msg->data, sizeof(*hh), 0);
if (ret == 0) {
msgb_free(msg);
*error = ret;
return NULL;
} else if (ret != sizeof(*hh)) {
if (errno != EAGAIN)
LOGP(DINP, LOGL_ERROR, "recv error %d %s\n", ret, strerror(errno));
msgb_free(msg);
*error = ret;
return NULL;
}
msgb_put(msg, ret);
/* then read te length as specified in header */
msg->l2h = msg->data + sizeof(*hh);
len = ntohs(hh->len);
if (len < 0 || TS1_ALLOC_SIZE < len + sizeof(*hh)) {
LOGP(DINP, LOGL_ERROR, "Can not read this packet. %d avail\n", len);
msgb_free(msg);
*error = -EIO;
return NULL;
}
ret = recv(bfd->fd, msg->l2h, len, 0);
if (ret < len) {
LOGP(DINP, LOGL_ERROR, "short read! Got %d from %d\n", ret, len);
msgb_free(msg);
*error = -EIO;
return NULL;
}
msgb_put(msg, ret);
return msg;
}
int ipaccess_drop_oml(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
struct e1inp_ts *ts;
struct e1inp_line *line;
struct osmo_fd *bfd;
if (!bts || !bts->oml_link)
return -1;
/* send OML down */
ts = bts->oml_link->ts;
line = ts->line;
e1inp_event(ts, S_INP_TEI_DN, bts->oml_link->tei, bts->oml_link->sapi);
bfd = &ts->driver.ipaccess.fd;
osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
/* clean up OML and RSL */
e1inp_sign_link_destroy(bts->oml_link);
bts->oml_link = NULL;
bts->ip_access.flags = 0;
/* drop all RSL connections too */
llist_for_each_entry(trx, &bts->trx_list, list)
ipaccess_drop_rsl(trx);
/* kill the E1 line now... as we have no one left to use it */
talloc_free(line);
return -1;
}
static int ipaccess_drop(struct e1inp_ts *ts, struct osmo_fd *bfd)
{
struct e1inp_sign_link *link;
int bts_nr;
if (!ts || !bfd->data) {
/*
* If we don't have a TS this means that this is a RSL
* connection but we are not past the authentication
* handling yet. So we can safely delete this bfd and
* wait for a reconnect.
* If we don't have bfd->data this means that a RSL
* connection was accept()ed, but nothing was recv()ed
* and the connection gets close()ed.
*/
osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
talloc_free(bfd);
return -1;
}
/* attempt to find a signalling link */
if (ts->type == E1INP_TS_TYPE_SIGN) {
llist_for_each_entry(link, &ts->sign.sign_links, list) {
bts_nr = link->trx->bts->bts_nr;
/* we have issues just reconnecting RLS so we drop OML */
ipaccess_drop_oml(link->trx->bts);
return bts_nr;
}
}
/* error case */
LOGP(DINP, LOGL_ERROR, "Failed to find a signalling link for ts: %p\n", ts);
osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
return -1;
}
int ipaccess_drop_rsl(struct gsm_bts_trx *trx)
{
struct osmo_fd *bfd;
struct e1inp_ts *ts;
if (!trx || !trx->rsl_link)
return -1;
/* send RSL down */
ts = trx->rsl_link->ts;
e1inp_event(ts, S_INP_TEI_DN, trx->rsl_link->tei, trx->rsl_link->sapi);
/* close the socket */
bfd = &ts->driver.ipaccess.fd;
osmo_fd_unregister(bfd);
close(bfd->fd);
bfd->fd = -1;
/* destroy */
e1inp_sign_link_destroy(trx->rsl_link);
trx->rsl_link = NULL;
return -1;
}
static int handle_ts1_read(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct e1inp_sign_link *link;
struct msgb *msg;
struct ipaccess_head *hh;
int ret = 0, error;
msg = ipaccess_read_msg(bfd, &error);
if (!msg) {
if (error == 0) {
int ret = ipaccess_drop(e1i_ts, bfd);
if (ret >= 0)
LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n",
ret);
else
LOGP(DINP, LOGL_NOTICE, "unknown BTS disappeared, dead socket\n");
}
return error;
}
DEBUGP(DMI, "RX %u: %s\n", ts_nr, osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
hh = (struct ipaccess_head *) msg->data;
if (hh->proto == IPAC_PROTO_IPACCESS) {
ret = ipaccess_rcvmsg(line, msg, bfd);
if (ret < 0)
ipaccess_drop(e1i_ts, bfd);
msgb_free(msg);
return ret;
}
/* BIG FAT WARNING: bfd might no longer exist here, since ipaccess_rcvmsg()
* might have free'd it !!! */
link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0);
if (!link) {
LOGP(DINP, LOGL_ERROR, "no matching signalling link for "
"hh->proto=0x%02x\n", hh->proto);
msgb_free(msg);
return -EIO;
}
msg->trx = link->trx;
switch (link->type) {
case E1INP_SIGN_RSL:
if (!(msg->trx->bts->ip_access.flags & (RSL_UP << msg->trx->nr))) {
e1inp_event(e1i_ts, S_INP_TEI_UP, link->tei, link->sapi);
msg->trx->bts->ip_access.flags |= (RSL_UP << msg->trx->nr);
}
ret = abis_rsl_rcvmsg(msg);
break;
case E1INP_SIGN_OML:
if (!(msg->trx->bts->ip_access.flags & OML_UP)) {
e1inp_event(e1i_ts, S_INP_TEI_UP, link->tei, link->sapi);
msg->trx->bts->ip_access.flags |= OML_UP;
}
ret = abis_nm_rcvmsg(msg);
break;
default:
LOGP(DINP, LOGL_NOTICE, "Unknown IP.access protocol proto=0x%02x\n", hh->proto);
msgb_free(msg);
break;
}
return ret;
}
void ipaccess_prepend_header_ext(struct msgb *msg, int proto)
{
struct ipaccess_head_ext *hh_ext;
/* prepend the osmo ip.access header extension */
hh_ext = (struct ipaccess_head_ext *) msgb_push(msg, sizeof(*hh_ext));
hh_ext->proto = proto;
}
void ipaccess_prepend_header(struct msgb *msg, int proto)
{
struct ipaccess_head *hh;
/* prepend the ip.access header */
hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
hh->len = htons(msg->len - sizeof(*hh));
hh->proto = proto;
}
static int ts_want_write(struct e1inp_ts *e1i_ts)
{
e1i_ts->driver.ipaccess.fd.when |= BSC_FD_WRITE;
return 0;
}
static void timeout_ts1_write(void *data)
{
struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
/* trigger write of ts1, due to tx delay timer */
ts_want_write(e1i_ts);
}
static int handle_ts1_write(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct e1inp_sign_link *sign_link;
struct msgb *msg;
uint8_t proto;
int ret;
bfd->when &= ~BSC_FD_WRITE;
/* get the next msg for this timeslot */
msg = e1inp_tx_ts(e1i_ts, &sign_link);
if (!msg) {
/* no message after tx delay timer */
return 0;
}
switch (sign_link->type) {
case E1INP_SIGN_OML:
proto = IPAC_PROTO_OML;
break;
case E1INP_SIGN_RSL:
proto = IPAC_PROTO_RSL;
break;
default:
msgb_free(msg);
bfd->when |= BSC_FD_WRITE; /* come back for more msg */
return -EINVAL;
}
msg->l2h = msg->data;
ipaccess_prepend_header(msg, sign_link->tei);
DEBUGP(DMI, "TX %u: %s\n", ts_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg)));
ret = send(bfd->fd, msg->data, msg->len, 0);
msgb_free(msg);
/* set tx delay timer for next event */
e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
e1i_ts->sign.tx_timer.data = e1i_ts;
/* Reducing this might break the nanoBTS 900 init. */
osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
return ret;
}
/* callback from select.c in case one of the fd's can be read/written */
static int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
unsigned int idx = ts_nr-1;
struct e1inp_ts *e1i_ts;
int rc = 0;
/* In case of early RSL we might not yet have a line */
if (line)
e1i_ts = &line->ts[idx];
if (!line || e1i_ts->type == E1INP_TS_TYPE_SIGN) {
if (what & BSC_FD_READ)
rc = handle_ts1_read(bfd);
if (what & BSC_FD_WRITE)
rc = handle_ts1_write(bfd);
} else
LOGP(DINP, LOGL_ERROR, "unknown E1 TS type %u\n", e1i_ts->type);
return rc;
}
struct e1inp_driver ipaccess_driver = {
.name = "ip.access",
.want_write = ts_want_write,
.default_delay = 0,
};
/* callback of the OML listening filedescriptor */
static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
{
int ret;
int idx = 0;
int i;
struct e1inp_line *line;
struct e1inp_ts *e1i_ts;
struct osmo_fd *bfd;
struct sockaddr_in sa;
socklen_t sa_len = sizeof(sa);
if (!(what & BSC_FD_READ))
return 0;
ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (ret < 0) {
perror("accept");
return ret;
}
LOGP(DINP, LOGL_NOTICE, "accept()ed new OML link from %s\n",
inet_ntoa(sa.sin_addr));
line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
if (!line) {
close(ret);
return -ENOMEM;
}
line->driver = &ipaccess_driver;
//line->driver_data = e1h;
/* create virrtual E1 timeslots for signalling */
e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
/* initialize the fds */
for (i = 0; i < ARRAY_SIZE(line->ts); ++i)
line->ts[i].driver.ipaccess.fd.fd = -1;
e1i_ts = &line->ts[idx];
bfd = &e1i_ts->driver.ipaccess.fd;
bfd->fd = ret;
bfd->data = line;
bfd->priv_nr = PRIV_OML;
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ;
ret = osmo_fd_register(bfd);
if (ret < 0) {
LOGP(DINP, LOGL_ERROR, "could not register FD\n");
close(bfd->fd);
talloc_free(line);
return ret;
}
/* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
ret = ipaccess_send_id_req(bfd->fd);
return ret;
//return e1inp_line_register(line);
}
static int rsl_listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
{
struct sockaddr_in sa;
socklen_t sa_len = sizeof(sa);
struct osmo_fd *bfd;
int ret;
if (!(what & BSC_FD_READ))
return 0;
bfd = talloc_zero(tall_bsc_ctx, struct osmo_fd);
if (!bfd)
return -ENOMEM;
/* Some BTS has connected to us, but we don't know yet which line
* (as created by the OML link) to associate it with. Thus, we
* allocate a temporary bfd until we have received ID from BTS */
bfd->fd = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (bfd->fd < 0) {
perror("accept");
return bfd->fd;
}
LOGP(DINP, LOGL_NOTICE, "accept()ed new RSL link from %s\n", inet_ntoa(sa.sin_addr));
bfd->priv_nr = PRIV_RSL;
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ;
ret = osmo_fd_register(bfd);
if (ret < 0) {
LOGP(DINP, LOGL_ERROR, "could not register FD\n");
close(bfd->fd);
talloc_free(bfd);
return ret;
}
/* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
ret = ipaccess_send_id_req(bfd->fd);
return 0;
}
/* Actively connect to a BTS. Currently used by ipaccess-config.c */
int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa)
{
struct e1inp_ts *e1i_ts = &line->ts[0];
struct osmo_fd *bfd = &e1i_ts->driver.ipaccess.fd;
int ret, on = 1;
bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ | BSC_FD_WRITE;
bfd->data = line;
bfd->priv_nr = PRIV_OML;
if (bfd->fd < 0) {
LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n");
return -EIO;
}
setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
if (ret < 0) {
LOGP(DINP, LOGL_ERROR, "could not connect socket\n");
close(bfd->fd);
return ret;
}
ret = osmo_fd_register(bfd);
if (ret < 0) {
close(bfd->fd);
return ret;
}
line->driver = &ipaccess_driver;
return ret;
//return e1inp_line_register(line);
}
int ipaccess_setup(struct gsm_network *gsmnet)
{
int ret;
e1h = talloc_zero(tall_bsc_ctx, struct ia_e1_handle);
if (!e1h)
return -ENOMEM;
e1h->gsmnet = gsmnet;
/* Listen for OML connections */
ret = make_sock(&e1h->listen_fd, IPPROTO_TCP, INADDR_ANY,
IPA_TCP_PORT_OML, 0, listen_fd_cb, NULL);
if (ret < 0)
return ret;
/* Listen for RSL connections */
ret = make_sock(&e1h->rsl_listen_fd, IPPROTO_TCP, INADDR_ANY,
IPA_TCP_PORT_RSL, 0, rsl_listen_fd_cb, NULL);
if (ret < 0)
return ret;
return ret;
}
void e1inp_ipaccess_init(void)
{
e1inp_driver_register(&ipaccess_driver);
}

View File

@@ -0,0 +1,710 @@
/* OpenBSC minimal LAPD implementation */
/* (C) 2009 by oystein@homelien.no
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by Digium and Matthew Fredrickson <creslin@digium.com>
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
/* TODO:
* detect RR timeout and set SAP state back to SABM_RETRANSMIT
* use of value_string
* further code cleanup (spaghetti)
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "lapd.h"
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/timer.h>
#include <openbsc/debug.h>
#define SABM_INTERVAL 0, 300000
typedef enum {
LAPD_TEI_NONE = 0,
LAPD_TEI_ASSIGNED,
LAPD_TEI_ACTIVE,
} lapd_tei_state;
const char *lapd_tei_states[] = {
"NONE",
"ASSIGNED",
"ACTIVE",
};
typedef enum {
LAPD_TYPE_NONE = 0,
LAPD_TYPE_I,
LAPD_TYPE_S,
LAPD_TYPE_U,
} lapd_msg_type;
typedef enum {
/* commands/responses */
LAPD_CMD_NONE = 0,
LAPD_CMD_I,
LAPD_CMD_RR,
LAPD_CMD_RNR,
LAPD_CMD_REJ,
LAPD_CMD_SABME,
LAPD_CMD_DM,
LAPD_CMD_UI,
LAPD_CMD_DISC,
LAPD_CMD_UA,
LAPD_CMD_FRMR,
LAPD_CMD_XID,
} lapd_cmd_type;
const char *lapd_cmd_types[] = {
"NONE",
"I",
"RR",
"RNR",
"REJ",
"SABME",
"DM",
"UI",
"DISC",
"UA",
"FRMR",
"XID",
};
enum lapd_sap_state {
SAP_STATE_INACTIVE,
SAP_STATE_SABM_RETRANS,
SAP_STATE_ACTIVE,
};
const char *lapd_sap_states[] = {
"INACTIVE",
"SABM_RETRANS",
"ACTIVE",
};
const char *lapd_msg_types = "?ISU";
/* structure representing an allocated TEI within a LAPD instance */
struct lapd_tei {
struct llist_head list;
struct lapd_instance *li;
uint8_t tei;
lapd_tei_state state;
struct llist_head sap_list;
};
/* Structure representing a SAP within a TEI. We use this for TE-mode to
* re-transmit SABM */
struct lapd_sap {
struct llist_head list;
struct lapd_tei *tei;
uint8_t sapi;
enum lapd_sap_state state;
/* A valid N(R) value is one that is in the range V(A) ≤ N(R) ≤ V(S). */
int vs; /* next to be transmitted */
int va; /* last acked by peer */
int vr; /* next expected to be received */
struct osmo_timer_list sabme_timer; /* timer to re-transmit SABM message */
};
/* 3.5.2.2 Send state variable V(S)
* Each point-to-point data link connection endpoint shall have an associated V(S) when using I frame
* commands. V(S) denotes the sequence number of the next I frame to be transmitted. The V(S) can
* take on the value 0 through n minus 1. The value of V(S) shall be incremented by 1 with each
* successive I frame transmission, and shall not exceed V(A) by more than the maximum number of
* outstanding I frames k. The value of k may be in the range of 1 ≤ k ≤ 127.
*
* 3.5.2.3 Acknowledge state variable V(A)
* Each point-to-point data link connection endpoint shall have an associated V(A) when using I frame
* commands and supervisory frame commands/responses. V(A) identifies the last I frame that has been
* acknowledged by its peer [V(A) 1 equals the N(S) of the last acknowledged I frame]. V(A) can
* take on the value 0 through n minus 1. The value of V(A) shall be updated by the valid N(R) values
* received from its peer (see 3.5.2.6). A valid N(R) value is one that is in the range V(A) ≤ N(R) ≤
* V(S).
*
* 3.5.2.5 Receive state variable V(R)
* Each point-to-point data link connection endpoint shall have an associated V(R) when using I frame
* commands and supervisory frame commands/responses. V(R) denotes the sequence number of the
* next in-sequence I frame expected to be received. V(R) can take on the value 0 through n minus 1.
* The value of V(R) shall be incremented by one with the receipt of an error-free, in-sequence I frame
* whose N(S) equals V(R).
*/
#define LAPD_NS(sap) (sap->vs)
#define LAPD_NR(sap) (sap->vr)
/* 3.5.2.4 Send sequence number N(S)
* Only I frames contain N(S), the send sequence number of transmitted I frames. At the time that an in-
* sequence I frame is designated for transmission, the value of N(S) is set equal to V(S).
*
* 3.5.2.6 Receive sequence number N(R)
* All I frames and supervisory frames contain N(R), the expected send sequence number of the next
* received I frame. At the time that a frame of the above types is designated for transmission, the value
* of N(R) is set equal to V(R). N(R) indicates that the data link layer entity transmitting the N(R) has
* correctly received all I frames numbered up to and including N(R) 1.
*/
/* Resolve TEI structure from given numeric TEI */
static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei)
{
struct lapd_tei *lt;
llist_for_each_entry(lt, &li->tei_list, list) {
if (lt->tei == tei)
return lt;
}
return NULL;
};
static void lapd_tei_set_state(struct lapd_tei *teip, int newstate)
{
DEBUGP(DMI, "state change on TEI %d: %s -> %s\n", teip->tei,
lapd_tei_states[teip->state], lapd_tei_states[newstate]);
teip->state = newstate;
};
/* Allocate a new TEI */
struct lapd_tei *lapd_tei_alloc(struct lapd_instance *li, uint8_t tei)
{
struct lapd_tei *teip;
teip = talloc_zero(li, struct lapd_tei);
if (!teip)
return NULL;
teip->li = li;
teip->tei = tei;
llist_add(&teip->list, &li->tei_list);
INIT_LLIST_HEAD(&teip->sap_list);
lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
return teip;
}
/* Find a SAP within a given TEI */
static struct lapd_sap *lapd_sap_find(struct lapd_tei *teip, uint8_t sapi)
{
struct lapd_sap *sap;
llist_for_each_entry(sap, &teip->sap_list, list) {
if (sap->sapi == sapi)
return sap;
}
return NULL;
}
static void sabme_timer_cb(void *_sap);
/* Allocate a new SAP within a given TEI */
static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi)
{
struct lapd_sap *sap = talloc_zero(teip, struct lapd_sap);
LOGP(DMI, LOGL_INFO, "Allocating SAP for SAPI=%u / TEI=%u\n",
sapi, teip->tei);
sap->sapi = sapi;
sap->tei = teip;
sap->sabme_timer.cb = &sabme_timer_cb;
sap->sabme_timer.data = sap;
llist_add(&sap->list, &teip->sap_list);
return sap;
}
static void lapd_sap_set_state(struct lapd_tei *teip, uint8_t sapi,
enum lapd_sap_state newstate)
{
struct lapd_sap *sap = lapd_sap_find(teip, sapi);
if (!sap)
return;
DEBUGP(DMI, "state change on TEI %u / SAPI %u: %s -> %s\n", teip->tei,
sapi, lapd_sap_states[sap->state], lapd_sap_states[newstate]);
switch (sap->state) {
case SAP_STATE_SABM_RETRANS:
if (newstate != SAP_STATE_SABM_RETRANS)
osmo_timer_del(&sap->sabme_timer);
break;
default:
if (newstate == SAP_STATE_SABM_RETRANS)
osmo_timer_schedule(&sap->sabme_timer, SABM_INTERVAL);
break;
}
sap->state = newstate;
};
/* Input function into TEI manager */
static void lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
{
uint8_t entity = data[0];
uint8_t ref = data[1];
uint8_t mt = data[3];
uint8_t action = data[4] >> 1;
uint8_t e = data[4] & 1;
uint8_t resp[8];
struct lapd_tei *teip;
DEBUGP(DMI, "TEIMGR: entity %x, ref %x, mt %x, action %x, e %x\n", entity, ref, mt, action, e);
switch (mt) {
case 0x01: /* IDENTITY REQUEST */
DEBUGP(DMI, "TEIMGR: identity request for TEI %u\n", action);
teip = teip_from_tei(li, action);
if (!teip) {
LOGP(DMI, LOGL_INFO, "TEI MGR: New TEI %u\n", action);
teip = lapd_tei_alloc(li, action);
}
/* Send ACCEPT */
memmove(resp, "\xfe\xff\x03\x0f\x00\x00\x02\x00", 8);
resp[7] = (action << 1) | 1;
li->transmit_cb(resp, 8, li->cbdata);
if (teip->state == LAPD_TEI_NONE)
lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
break;
default:
LOGP(DMI, LOGL_NOTICE, "TEIMGR: unknown mt %x action %x\n",
mt, action);
break;
};
};
/* General input function for any data received for this LAPD instance */
uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len,
int *ilen, lapd_mph_type *prim)
{
uint8_t sapi, cr, tei, command;
int pf, ns, nr;
uint8_t *contents;
struct lapd_tei *teip;
struct lapd_sap *sap;
uint8_t resp[8];
int l = 0;
*ilen = 0;
*prim = 0;
if (len < 2) {
DEBUGP(DMI, "len %d < 2\n", len);
return NULL;
};
if ((data[0] & 1) != 0 || (data[1] & 1) != 1) {
DEBUGP(DMI, "address field %x/%x not well formed\n", data[0],
data[1]);
return NULL;
};
sapi = data[0] >> 2;
cr = (data[0] >> 1) & 1;
tei = data[1] >> 1;
command = li->network_side ^ cr;
//DEBUGP(DMI, " address sapi %x tei %d cmd %d cr %d\n", sapi, tei, command, cr);
if (len < 3) {
DEBUGP(DMI, "len %d < 3\n", len);
return NULL;
};
lapd_msg_type typ = 0;
lapd_cmd_type cmd = 0;
pf = -1;
ns = -1;
nr = -1;
if ((data[2] & 1) == 0) {
typ = LAPD_TYPE_I;
assert(len >= 4);
ns = data[2] >> 1;
nr = data[3] >> 1;
pf = data[3] & 1;
cmd = LAPD_CMD_I;
} else if ((data[2] & 3) == 1) {
typ = LAPD_TYPE_S;
assert(len >= 4);
nr = data[3] >> 1;
pf = data[3] & 1;
switch (data[2]) {
case 0x1:
cmd = LAPD_CMD_RR;
break;
case 0x5:
cmd = LAPD_CMD_RNR;
break;
case 0x9:
cmd = LAPD_CMD_REJ;
break;
default:
LOGP(DMI, LOGL_ERROR, "unknown LAPD S cmd %x\n", data[2]);
return NULL;
};
} else if ((data[2] & 3) == 3) {
typ = LAPD_TYPE_U;
pf = (data[2] >> 4) & 1;
int val = data[2] & ~(1 << 4);
switch (val) {
case 0x6f:
cmd = LAPD_CMD_SABME;
break;
case 0x0f:
cmd = LAPD_CMD_DM;
break;
case 0x03:
cmd = LAPD_CMD_UI;
break;
case 0x43:
cmd = LAPD_CMD_DISC;
break;
case 0x63:
cmd = LAPD_CMD_UA;
break;
case 0x87:
cmd = LAPD_CMD_FRMR;
break;
case 0xaf:
cmd = LAPD_CMD_XID;
break;
default:
LOGP(DMI, LOGL_ERROR, "unknown U cmd %x "
"(pf %x data %x)\n", val, pf, data[2]);
return NULL;
};
};
contents = &data[4];
if (typ == LAPD_TYPE_U)
contents--;
*ilen = len - (contents - data);
if (tei == 127)
lapd_tei_receive(li, contents, *ilen);
teip = teip_from_tei(li, tei);
if (!teip) {
LOGP(DMI, LOGL_NOTICE, "Unknown TEI %u\n", tei);
return NULL;
}
sap = lapd_sap_find(teip, sapi);
if (!sap) {
LOGP(DMI, LOGL_INFO, "No SAP for TEI=%u / SAPI=%u, "
"allocating\n", tei, sapi);
sap = lapd_sap_alloc(teip, sapi);
}
DEBUGP(DMI, "<- %c %s sapi %x tei %3d cmd %x pf %x ns %3d nr %3d "
"ilen %d teip %p vs %d va %d vr %d len %d\n",
lapd_msg_types[typ], lapd_cmd_types[cmd], sapi, tei, command, pf,
ns, nr, *ilen, teip, sap->vs, sap->va, sap->vr, len);
switch (cmd) {
case LAPD_CMD_I:
if (ns != sap->vr) {
DEBUGP(DMI, "ns %d != vr %d\n", ns, sap->vr);
if (ns == ((sap->vr - 1) & 0x7f)) {
DEBUGP(DMI, "DOUBLE FRAME, ignoring\n");
cmd = 0; // ignore
} else {
assert(0);
};
} else {
//printf("IN SEQUENCE\n");
sap->vr = (ns + 1) & 0x7f; // FIXME: hack!
};
break;
case LAPD_CMD_UI:
break;
case LAPD_CMD_SABME:
sap->vs = 0;
sap->vr = 0;
sap->va = 0;
// ua
resp[l++] = data[0];
resp[l++] = (tei << 1) | 1;
resp[l++] = 0x73;
li->transmit_cb(resp, l, li->cbdata);
if (teip->state != LAPD_TEI_ACTIVE) {
if (teip->state == LAPD_TEI_ASSIGNED) {
lapd_tei_set_state(teip,
LAPD_TEI_ACTIVE);
//printf("ASSIGNED and ACTIVE\n");
} else {
#if 0
DEBUGP(DMI, "rr in strange state, send rej\n");
// rej
resp[l++] = (sap-> sapi << 2) | (li->network_side ? 0 : 2);
resp[l++] = (tei << 1) | 1;
resp[l++] = 0x09; //rej
resp[l++] = ((sap->vr + 1) << 1) | 0;
li->transmit_cb(resp, l, li->cbdata);
pf = 0; // dont reply
#endif
};
};
*prim = LAPD_MPH_ACTIVATE_IND;
break;
case LAPD_CMD_UA:
sap->vs = 0;
sap->vr = 0;
sap->va = 0;
lapd_tei_set_state(teip, LAPD_TEI_ACTIVE);
lapd_sap_set_state(teip, sapi, SAP_STATE_ACTIVE);
*prim = LAPD_MPH_ACTIVATE_IND;
break;
case LAPD_CMD_RR:
sap->va = (nr & 0x7f);
#if 0
if (teip->state != LAPD_TEI_ACTIVE) {
if (teip->state == LAPD_TEI_ASSIGNED) {
lapd_tei_set_state(teip, LAPD_TEI_ACTIVE);
*prim = LAPD_MPH_ACTIVATE_IND;
//printf("ASSIGNED and ACTIVE\n");
} else {
#if 0
DEBUGP(DMI, "rr in strange " "state, send rej\n");
// rej
resp[l++] = (sap-> sapi << 2) | (li->network_side ? 0 : 2);
resp[l++] = (tei << 1) | 1;
resp[l++] = 0x09; //rej
resp[l++] =
((sap->vr + 1) << 1) | 0;
li->transmit_cb(resp, l, li->cbdata);
pf = 0; // dont reply
#endif
};
};
#endif
if (pf) {
// interrogating us, send rr
resp[l++] = data[0];
resp[l++] = (tei << 1) | 1;
resp[l++] = 0x01; // rr
resp[l++] = (LAPD_NR(sap) << 1) | (data[3] & 1); // pf bit from req
li->transmit_cb(resp, l, li->cbdata);
};
break;
case LAPD_CMD_FRMR:
// frame reject
#if 0
if (teip->state == LAPD_TEI_ACTIVE)
*prim = LAPD_MPH_DEACTIVATE_IND;
lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
#endif
LOGP(DMI, LOGL_NOTICE, "frame reject, ignoring\n");
break;
case LAPD_CMD_DISC:
// disconnect
resp[l++] = data[0];
resp[l++] = (tei << 1) | 1;
resp[l++] = 0x73;
li->transmit_cb(resp, l, li->cbdata);
lapd_tei_set_state(teip, LAPD_TEI_NONE);
break;
default:
LOGP(DMI, LOGL_NOTICE, "unknown cmd for tei %d (cmd %x)\n",
tei, cmd);
break;
}
if (typ == LAPD_TYPE_I) {
/* send rr
* Thu Jan 22 19:17:13 2009 <4000> sangoma.c:340 read (62/25) 4: fa 33 01 0a
* lapd <- S RR sapi 3e tei 25 cmd 0 pf 0 ns -1 nr 5 ilen 0 teip 0x613800 vs 7 va 5 vr 2 len 4
*/
/* interrogating us, send rr */
DEBUGP(DMI, "Sending RR response\n");
resp[l++] = data[0];
resp[l++] = (tei << 1) | 1;
resp[l++] = 0x01; // rr
resp[l++] = (LAPD_NR(sap) << 1) | (data[3] & 1); // pf bit from req
li->transmit_cb(resp, l, li->cbdata);
if (cmd != 0) {
*prim = LAPD_DL_DATA_IND;
return contents;
}
} else if (tei != 127 && typ == LAPD_TYPE_U && cmd == LAPD_CMD_UI) {
*prim = LAPD_DL_UNITDATA_IND;
return contents;
}
return NULL;
};
/* low-level function to send a single SABM message */
static int lapd_send_sabm(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
{
struct msgb *msg = msgb_alloc_headroom(1024, 128, "LAPD SABM");
if (!msg)
return -ENOMEM;
DEBUGP(DMI, "Sending SABM for TEI=%u, SAPI=%u\n", tei, sapi);
msgb_put_u8(msg, (sapi << 2) | (li->network_side ? 2 : 0));
msgb_put_u8(msg, (tei << 1) | 1);
msgb_put_u8(msg, 0x7F);
li->transmit_cb(msg->data, msg->len, li->cbdata);
msgb_free(msg);
return 0;
}
/* timer call-back function for SABM re-transmission */
static void sabme_timer_cb(void *_sap)
{
struct lapd_sap *sap = _sap;
lapd_send_sabm(sap->tei->li, sap->tei->tei, sap->sapi);
if (sap->state == SAP_STATE_SABM_RETRANS)
osmo_timer_schedule(&sap->sabme_timer, SABM_INTERVAL);
}
/* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
int lapd_sap_start(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
{
struct lapd_sap *sap;
struct lapd_tei *teip;
teip = teip_from_tei(li, tei);
if (!teip)
teip = lapd_tei_alloc(li, tei);
sap = lapd_sap_find(teip, sapi);
if (sap)
return -EEXIST;
sap = lapd_sap_alloc(teip, sapi);
lapd_sap_set_state(teip, sapi, SAP_STATE_SABM_RETRANS);
return 0;
}
/* Stop a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
{
struct lapd_tei *teip;
struct lapd_sap *sap;
teip = teip_from_tei(li, tei);
if (!teip)
return -ENODEV;
sap = lapd_sap_find(teip, sapi);
if (!sap)
return -ENODEV;
lapd_sap_set_state(teip, sapi, SAP_STATE_INACTIVE);
llist_del(&sap->list);
talloc_free(sap);
return 0;
}
/* Transmit Data (I-Frame) on the given LAPD Instance / TEI / SAPI */
void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
uint8_t *data, unsigned int len)
{
struct lapd_tei *teip = teip_from_tei(li, tei);
struct lapd_sap *sap;
if (!teip) {
LOGP(DMI, LOGL_ERROR, "Cannot transmit on non-existing "
"TEI %u\n", tei);
return;
}
sap = lapd_sap_find(teip, sapi);
if (!sap) {
LOGP(DMI, LOGL_INFO, "Tx on unknown SAPI=%u in TEI=%u, "
"allocating\n", sapi, tei);
sap = lapd_sap_alloc(teip, sapi);
}
/* prepend stuff */
uint8_t buf[10000];
memset(buf, 0, sizeof(buf));
memmove(buf + 4, data, len);
len += 4;
buf[0] = (sapi << 2) | (li->network_side ? 2 : 0);
buf[1] = (tei << 1) | 1;
buf[2] = (LAPD_NS(sap) << 1);
buf[3] = (LAPD_NR(sap) << 1) | 0;
sap->vs = (sap->vs + 1) & 0x7f;
li->transmit_cb(buf, len, li->cbdata);
};
/* Allocate a new LAPD instance */
struct lapd_instance *lapd_instance_alloc(int network_side,
void (*tx_cb)(uint8_t *data, int len,
void *cbdata), void *cbdata)
{
struct lapd_instance *li;
li = talloc_zero(NULL, struct lapd_instance);
if (!li)
return NULL;
li->transmit_cb = tx_cb;
li->cbdata = cbdata;
li->network_side = network_side;
INIT_LLIST_HEAD(&li->tei_list);
return li;
}

View File

@@ -0,0 +1,46 @@
#ifndef OPENBSC_LAPD_H
#define OPENBSC_LAPD_H
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
typedef enum {
LAPD_MPH_NONE = 0,
LAPD_MPH_ACTIVATE_IND,
LAPD_MPH_DEACTIVATE_IND,
LAPD_DL_DATA_IND,
LAPD_DL_UNITDATA_IND,
} lapd_mph_type;
struct lapd_instance {
struct llist_head list; /* list of LAPD instances */
int network_side;
void (*transmit_cb)(uint8_t *data, int len, void *cbdata);
void *cbdata;
struct llist_head tei_list; /* list of TEI in this LAPD instance */
};
extern uint8_t *lapd_receive(struct lapd_instance *li, uint8_t *data, unsigned int len,
int *ilen, lapd_mph_type *prim);
extern void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
uint8_t *data, unsigned int len);
struct lapd_instance *lapd_instance_alloc(int network_side,
void (*tx_cb)(uint8_t *data, int len,
void *cbdata), void *cbdata);
/* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
int lapd_sap_start(struct lapd_instance *li, uint8_t tei, uint8_t sapi);
/* Stop a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi);
#endif /* OPENBSC_LAPD_H */

View File

@@ -0,0 +1,541 @@
/* OpenBSC Abis input driver for mISDNuser */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <mISDNif.h>
//#define AF_COMPATIBILITY_FUNC
//#include <compat_af_isdn.h>
#ifndef AF_ISDN
#define AF_ISDN 34
#define PF_ISDN AF_ISDN
#endif
#include <osmocom/core/select.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/subchan_demux.h>
#include <openbsc/e1_input.h>
#include <openbsc/signal.h>
#define TS1_ALLOC_SIZE 300
struct prim_name {
unsigned int prim;
const char *name;
};
const struct prim_name prim_names[] = {
{ PH_CONTROL_IND, "PH_CONTROL_IND" },
{ PH_DATA_IND, "PH_DATA_IND" },
{ PH_DATA_CNF, "PH_DATA_CNF" },
{ PH_ACTIVATE_IND, "PH_ACTIVATE_IND" },
{ DL_ESTABLISH_IND, "DL_ESTABLISH_IND" },
{ DL_ESTABLISH_CNF, "DL_ESTABLISH_CNF" },
{ DL_RELEASE_IND, "DL_RELEASE_IND" },
{ DL_RELEASE_CNF, "DL_RELEASE_CNF" },
{ DL_DATA_IND, "DL_DATA_IND" },
{ DL_UNITDATA_IND, "DL_UNITDATA_IND" },
{ DL_INFORMATION_IND, "DL_INFORMATION_IND" },
{ MPH_ACTIVATE_IND, "MPH_ACTIVATE_IND" },
{ MPH_DEACTIVATE_IND, "MPH_DEACTIVATE_IND" },
};
const char *get_prim_name(unsigned int prim)
{
int i;
for (i = 0; i < ARRAY_SIZE(prim_names); i++) {
if (prim_names[i].prim == prim)
return prim_names[i].name;
}
return "UNKNOWN";
}
static int handle_ts1_read(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct e1inp_sign_link *link;
struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "mISDN TS1");
struct sockaddr_mISDN l2addr;
struct mISDNhead *hh;
socklen_t alen;
int ret;
if (!msg)
return -ENOMEM;
hh = (struct mISDNhead *) msg->data;
alen = sizeof(l2addr);
ret = recvfrom(bfd->fd, msg->data, 300, 0,
(struct sockaddr *) &l2addr, &alen);
if (ret < 0) {
fprintf(stderr, "recvfrom error %s\n", strerror(errno));
return ret;
}
if (alen != sizeof(l2addr)) {
fprintf(stderr, "%s error len\n", __func__);
return -EINVAL;
}
msgb_put(msg, ret);
DEBUGP(DMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n",
alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei);
DEBUGP(DMI, "<= len = %d, prim(0x%x) id(0x%x): %s\n",
ret, hh->prim, hh->id, get_prim_name(hh->prim));
switch (hh->prim) {
case DL_INFORMATION_IND:
/* mISDN tells us which channel number is allocated for this
* tuple of (SAPI, TEI). */
DEBUGP(DMI, "DL_INFORMATION_IND: use channel(%d) sapi(%d) tei(%d) for now\n",
l2addr.channel, l2addr.sapi, l2addr.tei);
link = e1inp_lookup_sign_link(e1i_ts, l2addr.tei, l2addr.sapi);
if (!link) {
DEBUGPC(DMI, "mISDN message for unknown sign_link\n");
msgb_free(msg);
return -EINVAL;
}
/* save the channel number in the driver private struct */
link->driver.misdn.channel = l2addr.channel;
break;
case DL_ESTABLISH_IND:
DEBUGP(DMI, "DL_ESTABLISH_IND: channel(%d) sapi(%d) tei(%d)\n",
l2addr.channel, l2addr.sapi, l2addr.tei);
/* For some strange reason, sometimes the DL_INFORMATION_IND tells
* us the wrong channel, and we only get the real channel number
* during the DL_ESTABLISH_IND */
link = e1inp_lookup_sign_link(e1i_ts, l2addr.tei, l2addr.sapi);
if (!link) {
DEBUGPC(DMI, "mISDN message for unknown sign_link\n");
msgb_free(msg);
return -EINVAL;
}
/* save the channel number in the driver private struct */
link->driver.misdn.channel = l2addr.channel;
ret = e1inp_event(e1i_ts, S_INP_TEI_UP, l2addr.tei, l2addr.sapi);
break;
case DL_RELEASE_IND:
DEBUGP(DMI, "DL_RELEASE_IND: channel(%d) sapi(%d) tei(%d)\n",
l2addr.channel, l2addr.sapi, l2addr.tei);
ret = e1inp_event(e1i_ts, S_INP_TEI_DN, l2addr.tei, l2addr.sapi);
break;
case DL_DATA_IND:
case DL_UNITDATA_IND:
msg->l2h = msg->data + MISDN_HEADER_LEN;
DEBUGP(DMI, "RX: %s\n", osmo_hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN));
ret = e1inp_rx_ts(e1i_ts, msg, l2addr.tei, l2addr.sapi);
break;
case PH_ACTIVATE_IND:
DEBUGP(DMI, "PH_ACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n",
l2addr.channel, l2addr.sapi, l2addr.tei);
break;
case PH_DEACTIVATE_IND:
DEBUGP(DMI, "PH_DEACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n",
l2addr.channel, l2addr.sapi, l2addr.tei);
break;
default:
break;
}
return ret;
}
static int ts_want_write(struct e1inp_ts *e1i_ts)
{
/* We never include the mISDN B-Channel FD into the
* writeset, since it doesn't support poll() based
* write flow control */
if (e1i_ts->type == E1INP_TS_TYPE_TRAU)
return 0;
e1i_ts->driver.misdn.fd.when |= BSC_FD_WRITE;
return 0;
}
static void timeout_ts1_write(void *data)
{
struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
/* trigger write of ts1, due to tx delay timer */
ts_want_write(e1i_ts);
}
static int handle_ts1_write(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct e1inp_sign_link *sign_link;
struct sockaddr_mISDN sa;
struct msgb *msg;
struct mISDNhead *hh;
uint8_t *l2_data;
int ret;
bfd->when &= ~BSC_FD_WRITE;
/* get the next msg for this timeslot */
msg = e1inp_tx_ts(e1i_ts, &sign_link);
if (!msg) {
/* no message after tx delay timer */
return 0;
}
l2_data = msg->data;
/* prepend the mISDNhead */
hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
hh->prim = DL_DATA_REQ;
DEBUGP(DMI, "TX channel(%d) TEI(%d) SAPI(%d): %s\n",
sign_link->driver.misdn.channel, sign_link->tei,
sign_link->sapi, osmo_hexdump(l2_data, msg->len - MISDN_HEADER_LEN));
/* construct the sockaddr */
sa.family = AF_ISDN;
sa.sapi = sign_link->sapi;
sa.dev = sign_link->tei;
sa.channel = sign_link->driver.misdn.channel;
ret = sendto(bfd->fd, msg->data, msg->len, 0,
(struct sockaddr *)&sa, sizeof(sa));
if (ret < 0)
fprintf(stderr, "%s sendto failed %d\n", __func__, ret);
msgb_free(msg);
/* set tx delay timer for next event */
e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
e1i_ts->sign.tx_timer.data = e1i_ts;
osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
return ret;
}
#define BCHAN_TX_GRAN 160
/* write to a B channel TS */
static int handle_tsX_write(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct mISDNhead *hh;
uint8_t tx_buf[BCHAN_TX_GRAN + sizeof(*hh)];
struct subch_mux *mx = &e1i_ts->trau.mux;
int ret;
hh = (struct mISDNhead *) tx_buf;
hh->prim = PH_DATA_REQ;
subchan_mux_out(mx, tx_buf+sizeof(*hh), BCHAN_TX_GRAN);
DEBUGP(DMIB, "BCHAN TX: %s\n",
osmo_hexdump(tx_buf+sizeof(*hh), BCHAN_TX_GRAN));
ret = send(bfd->fd, tx_buf, sizeof(*hh) + BCHAN_TX_GRAN, 0);
if (ret < sizeof(*hh) + BCHAN_TX_GRAN)
DEBUGP(DMIB, "send returns %d instead of %zu\n", ret,
sizeof(*hh) + BCHAN_TX_GRAN);
return ret;
}
#define TSX_ALLOC_SIZE 4096
/* FIXME: read from a B channel TS */
static int handle_tsX_read(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct msgb *msg = msgb_alloc(TSX_ALLOC_SIZE, "mISDN TSx");
struct mISDNhead *hh;
int ret;
if (!msg)
return -ENOMEM;
hh = (struct mISDNhead *) msg->data;
ret = recv(bfd->fd, msg->data, TSX_ALLOC_SIZE, 0);
if (ret < 0) {
fprintf(stderr, "recvfrom error %s\n", strerror(errno));
return ret;
}
msgb_put(msg, ret);
if (hh->prim != PH_CONTROL_IND)
DEBUGP(DMIB, "<= BCHAN len = %d, prim(0x%x) id(0x%x): %s\n",
ret, hh->prim, hh->id, get_prim_name(hh->prim));
switch (hh->prim) {
case PH_DATA_IND:
msg->l2h = msg->data + MISDN_HEADER_LEN;
DEBUGP(DMIB, "BCHAN RX: %s\n",
osmo_hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN));
ret = e1inp_rx_ts(e1i_ts, msg, 0, 0);
break;
case PH_ACTIVATE_IND:
case PH_DATA_CNF:
/* physical layer indicates that data has been sent,
* we thus can send some more data */
ret = handle_tsX_write(bfd);
default:
break;
}
/* FIXME: why do we free signalling msgs in the caller, and trau not? */
msgb_free(msg);
return ret;
}
/* callback from select.c in case one of the fd's can be read/written */
static int misdn_fd_cb(struct osmo_fd *bfd, unsigned int what)
{
struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
unsigned int idx = ts_nr-1;
struct e1inp_ts *e1i_ts = &line->ts[idx];
int rc = 0;
switch (e1i_ts->type) {
case E1INP_TS_TYPE_SIGN:
if (what & BSC_FD_READ)
rc = handle_ts1_read(bfd);
if (what & BSC_FD_WRITE)
rc = handle_ts1_write(bfd);
break;
case E1INP_TS_TYPE_TRAU:
if (what & BSC_FD_READ)
rc = handle_tsX_read(bfd);
/* We never include the mISDN B-Channel FD into the
* writeset, since it doesn't support poll() based
* write flow control */
break;
default:
fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
break;
}
return rc;
}
static int activate_bchan(struct e1inp_line *line, int ts, int act)
{
struct mISDNhead hh;
int ret;
unsigned int idx = ts-1;
struct e1inp_ts *e1i_ts = &line->ts[idx];
struct osmo_fd *bfd = &e1i_ts->driver.misdn.fd;
fprintf(stdout, "activate bchan\n");
if (act)
hh.prim = PH_ACTIVATE_REQ;
else
hh.prim = PH_DEACTIVATE_REQ;
hh.id = MISDN_ID_ANY;
ret = sendto(bfd->fd, &hh, sizeof(hh), 0, NULL, 0);
if (ret < 0) {
fprintf(stdout, "could not send ACTIVATE_RQ %s\n",
strerror(errno));
}
return ret;
}
static int mi_e1_line_update(struct e1inp_line *line);
struct e1inp_driver misdn_driver = {
.name = "misdn",
.want_write = ts_want_write,
.default_delay = 50000,
.line_update = &mi_e1_line_update,
};
static int mi_e1_setup(struct e1inp_line *line, int release_l2)
{
int ts, ret;
/* TS0 is CRC4, don't need any fd for it */
for (ts = 1; ts < NUM_E1_TS; ts++) {
unsigned int idx = ts-1;
struct e1inp_ts *e1i_ts = &line->ts[idx];
struct osmo_fd *bfd = &e1i_ts->driver.misdn.fd;
struct sockaddr_mISDN addr;
bfd->data = line;
bfd->priv_nr = ts;
bfd->cb = misdn_fd_cb;
switch (e1i_ts->type) {
case E1INP_TS_TYPE_NONE:
continue;
break;
case E1INP_TS_TYPE_SIGN:
bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_NT);
bfd->when = BSC_FD_READ;
break;
case E1INP_TS_TYPE_TRAU:
bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
/* We never include the mISDN B-Channel FD into the
* writeset, since it doesn't support poll() based
* write flow control */
bfd->when = BSC_FD_READ;
break;
}
if (bfd->fd < 0) {
fprintf(stderr, "%s could not open socket %s\n",
__func__, strerror(errno));
return bfd->fd;
}
memset(&addr, 0, sizeof(addr));
addr.family = AF_ISDN;
addr.dev = line->num;
switch (e1i_ts->type) {
case E1INP_TS_TYPE_SIGN:
addr.channel = 0;
/* SAPI not supported yet in kernel */
//addr.sapi = e1inp_ts->sign.sapi;
addr.sapi = 0;
addr.tei = GROUP_TEI;
break;
case E1INP_TS_TYPE_TRAU:
addr.channel = ts;
break;
default:
DEBUGP(DMI, "unsupported E1 TS type: %u\n",
e1i_ts->type);
break;
}
ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
fprintf(stderr, "could not bind l2 socket %s\n",
strerror(errno));
return -EIO;
}
if (e1i_ts->type == E1INP_TS_TYPE_SIGN) {
ret = ioctl(bfd->fd, IMCLEAR_L2, &release_l2);
if (ret < 0) {
fprintf(stderr, "could not send IOCTL IMCLEAN_L2 %s\n", strerror(errno));
return -EIO;
}
}
/* FIXME: only activate B-Channels once we start to
* use them to conserve CPU power */
if (e1i_ts->type == E1INP_TS_TYPE_TRAU)
activate_bchan(line, ts, 1);
ret = osmo_fd_register(bfd);
if (ret < 0) {
fprintf(stderr, "could not register FD: %s\n",
strerror(ret));
return ret;
}
}
return 0;
}
static int mi_e1_line_update(struct e1inp_line *line)
{
struct mISDN_devinfo devinfo;
int sk, ret, cnt;
if (line->driver != &misdn_driver)
return -EINVAL;
/* open the ISDN card device */
sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
if (sk < 0) {
fprintf(stderr, "%s could not open socket %s\n",
__func__, strerror(errno));
return sk;
}
ret = ioctl(sk, IMGETCOUNT, &cnt);
if (ret) {
fprintf(stderr, "%s error getting interf count: %s\n",
__func__, strerror(errno));
close(sk);
return -ENODEV;
}
//DEBUGP(DMI,"%d device%s found\n", cnt, (cnt==1)?"":"s");
printf("%d device%s found\n", cnt, (cnt==1)?"":"s");
#if 1
devinfo.id = line->num;
ret = ioctl(sk, IMGETDEVINFO, &devinfo);
if (ret < 0) {
fprintf(stdout, "error getting info for device %d: %s\n",
line->num, strerror(errno));
return -ENODEV;
}
fprintf(stdout, " id: %d\n", devinfo.id);
fprintf(stdout, " Dprotocols: %08x\n", devinfo.Dprotocols);
fprintf(stdout, " Bprotocols: %08x\n", devinfo.Bprotocols);
fprintf(stdout, " protocol: %d\n", devinfo.protocol);
fprintf(stdout, " nrbchan: %d\n", devinfo.nrbchan);
fprintf(stdout, " name: %s\n", devinfo.name);
#endif
if (!(devinfo.Dprotocols & (1 << ISDN_P_NT_E1))) {
fprintf(stderr, "error: card is not of type E1 (NT-mode)\n");
return -EINVAL;
}
ret = mi_e1_setup(line, 1);
if (ret)
return ret;
return 0;
}
void e1inp_misdn_init(void)
{
/* register the driver with the core */
e1inp_driver_register(&misdn_driver);
}

View File

@@ -1,6 +1,6 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
noinst_LIBRARIES = libbsc.a
@@ -11,7 +11,6 @@ libbsc_a_SOURCES = abis_nm.c abis_nm_vty.c \
bts_ericsson_rbs2000.c \
bts_ipaccess_nanobts.c \
bts_siemens_bs11.c \
bts_nokia_site.c \
bts_hsl_femtocell.c \
bts_unknown.c \
chan_alloc.c \
@@ -21,5 +20,5 @@ libbsc_a_SOURCES = abis_nm.c abis_nm_vty.c \
e1_config.c \
bsc_api.c bsc_msc.c bsc_vty.c \
gsm_04_08_utils.c \
bsc_init.c bts_init.c bsc_rf_ctrl.c
bsc_init.c bts_init.c

View File

@@ -43,7 +43,6 @@
#include <openbsc/abis_nm.h>
#include <openbsc/misdn.h>
#include <openbsc/signal.h>
#include <osmocom/abis/e1_input.h>
#define OM_ALLOC_SIZE 1024
#define OM_HEADROOM_SIZE 128
@@ -114,27 +113,15 @@ static struct msgb *nm_msgb_alloc(void)
"OML");
}
int _abis_nm_sendmsg(struct msgb *msg)
{
msg->l2h = msg->data;
if (!msg->dst) {
LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
return -EINVAL;
}
return abis_sendmsg(msg);
}
/* Send a OML NM Message from BSC to BTS */
static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
{
msg->dst = bts->oml_link;
msg->trx = bts->c0;
/* queue OML messages */
if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
return _abis_nm_sendmsg(msg);
return _abis_nm_sendmsg(msg, 0);
} else {
msgb_enqueue(&bts->abis_queue, msg);
return 0;
@@ -199,8 +186,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct e1inp_sign_link *sign_link = mb->dst;
struct gsm_bts *bts = sign_link->trx->bts;
struct gsm_bts *bts = mb->trx->bts;
struct tlv_parsed tp;
struct gsm_nm_state *nm_state, new_state;
@@ -274,14 +260,13 @@ static int rx_fail_evt_rep(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct e1inp_sign_link *sign_link = mb->dst;
struct tlv_parsed tp;
const uint8_t *p_val;
char *p_text;
LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
LOGPC(DNM, LOGL_ERROR, "Type=%s ",
@@ -406,7 +391,6 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct e1inp_sign_link *sign_link = mb->dst;
struct tlv_parsed tp;
const uint8_t *sw_config;
int ret, sw_config_len, sw_descr_len;
@@ -417,23 +401,17 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb)
DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
foh->obj_inst.bts_nr,
foh->obj_inst.trx_nr,
foh->obj_inst.ts_nr, 0,
foh->data, oh->length-sizeof(*foh));
if (ret != 0) {
LOGP(DNM, LOGL_ERROR,
"Sending SW ActReq ACK failed: %d\n", ret);
return ret;
}
abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
LOGP(DNM, LOGL_ERROR,
"SW config not found! Can't continue.\n");
DEBUGP(DNM, "SW config not found! Can't continue.\n");
return -EINVAL;
} else {
DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
@@ -444,7 +422,7 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb)
if (sw_descr_len < 0)
return -EINVAL;
return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
foh->obj_inst.bts_nr,
foh->obj_inst.trx_nr,
foh->obj_inst.ts_nr,
@@ -456,28 +434,26 @@ static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct e1inp_sign_link *sign_link = mb->dst;
struct tlv_parsed tp;
uint8_t adm_state;
abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
return -EINVAL;
adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
}
static int abis_nm_rx_lmt_event(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct e1inp_sign_link *sign_link = mb->dst;
struct tlv_parsed tp;
DEBUGP(DNM, "LMT Event ");
abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
@@ -498,7 +474,7 @@ static int abis_nm_rx_lmt_event(struct msgb *mb)
return 0;
}
void abis_nm_queue_send_next(struct gsm_bts *bts)
static void abis_nm_queue_send_next(struct gsm_bts *bts)
{
int wait = 0;
struct msgb *msg;
@@ -506,7 +482,7 @@ void abis_nm_queue_send_next(struct gsm_bts *bts)
while (!llist_empty(&bts->abis_queue)) {
msg = msgb_dequeue(&bts->abis_queue);
wait = OBSC_NM_W_ACK_CB(msg);
_abis_nm_sendmsg(msg);
_abis_nm_sendmsg(msg, 0);
if (wait)
break;
@@ -520,7 +496,6 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct e1inp_sign_link *sign_link = mb->dst;
uint8_t mt = foh->msg_type;
int ret = 0;
@@ -539,7 +514,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
DEBUGPC(DNM, "CAUSE=%s\n",
abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
@@ -549,7 +524,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
nack_data.msg = mb;
nack_data.mt = mt;
osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
return 0;
}
#if 0
@@ -590,13 +565,13 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb)
break;
case NM_MT_SET_BTS_ATTR_ACK:
/* The HSL wants an OPSTART _after_ the SI has been set */
if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
}
break;
}
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
return ret;
}
@@ -605,13 +580,12 @@ static int abis_nm_rx_ipacc(struct msgb *mb);
static int abis_nm_rcvmsg_manuf(struct msgb *mb)
{
int rc;
struct e1inp_sign_link *sign_link = mb->dst;
int bts_type = sign_link->trx->bts->type;
int bts_type = mb->trx->bts->type;
switch (bts_type) {
case GSM_BTS_TYPE_NANOBTS:
rc = abis_nm_rx_ipacc(mb);
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
break;
default:
LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
@@ -1032,7 +1006,6 @@ static int sw_fill_window(struct abis_nm_sw *sw)
static int abis_nm_rcvmsg_sw(struct msgb *mb)
{
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct e1inp_sign_link *sign_link = mb->dst;
int rc = -1;
struct abis_nm_sw *sw = &g_sw;
enum sw_state old_state = sw->state;
@@ -1050,7 +1023,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cb_data, NULL);
rc = sw_fill_window(sw);
sw->state = SW_STATE_WAIT_SEGACK;
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
break;
case NM_MT_LOAD_INIT_NACK:
if (sw->forced) {
@@ -1071,7 +1044,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cb_data, NULL);
sw->state = SW_STATE_ERROR;
}
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
break;
}
break;
@@ -1092,7 +1065,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->state = SW_STATE_WAIT_ENDACK;
rc = sw_load_end(sw);
}
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
break;
case NM_MT_LOAD_ABORT:
if (sw->cbfn)
@@ -1114,7 +1087,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
NM_MT_LOAD_END_ACK, mb,
sw->cb_data, NULL);
rc = 0;
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
break;
case NM_MT_LOAD_END_NACK:
if (sw->forced) {
@@ -1134,7 +1107,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
NM_MT_LOAD_END_NACK, mb,
sw->cb_data, NULL);
}
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
break;
}
case SW_STATE_WAIT_ACTACK:
@@ -1148,7 +1121,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cbfn(GSM_HOOK_NM_SWLOAD,
NM_MT_ACTIVATE_SW_ACK, mb,
sw->cb_data, NULL);
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
break;
case NM_MT_ACTIVATE_SW_NACK:
DEBUGP(DNM, "Activate Software NACK\n");
@@ -1158,7 +1131,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
sw->cbfn(GSM_HOOK_NM_SWLOAD,
NM_MT_ACTIVATE_SW_NACK, mb,
sw->cb_data, NULL);
abis_nm_queue_send_next(sign_link->trx->bts);
abis_nm_queue_send_next(mb->trx->bts);
break;
}
case SW_STATE_NONE:
@@ -2308,7 +2281,6 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
uint8_t idstrlen = oh->data[0];
struct tlv_parsed tp;
struct ipacc_ack_signal_data signal;
struct e1inp_sign_link *sign_link = msg->dst;
if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
@@ -2316,7 +2288,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
}
foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
abis_nm_debugp_foh(DNM, foh);
@@ -2393,12 +2365,12 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
case NM_MT_IPACC_RSL_CONNECT_NACK:
case NM_MT_IPACC_SET_NVATTR_NACK:
case NM_MT_IPACC_GET_NVATTR_NACK:
signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
signal.msg_type = foh->msg_type;
osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
break;
case NM_MT_IPACC_SET_NVATTR_ACK:
signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
signal.msg_type = foh->msg_type;
osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
break;

View File

@@ -133,6 +133,28 @@ DEFUN(oml_classnum_inst, oml_classnum_inst_cmd,
return CMD_SUCCESS;
}
DEFUN(oml_attrib_get, oml_attrib_get_cmd,
"attribute get <0-255>",
"OML Attribute Actions\n" "Get a single OML Attribute\n"
"OML Attribute Number\n")
{
struct oml_node_state *oms = vty->index;
/* FIXME */
return CMD_SUCCESS;
}
DEFUN(oml_attrib_set, oml_attrib_set_cmd,
"attribute set <0-255> .HEX",
"OML Attribute Actions\n" "Set a single OML Attribute\n"
"OML Attribute Number\n")
{
struct oml_node_state *oms = vty->index;
/* FIXME */
return CMD_SUCCESS;
}
DEFUN(oml_chg_adm_state, oml_chg_adm_state_cmd,
"change-adm-state (locked|unlocked|shutdown|null)",
"Change the Administrative State\n"
@@ -168,6 +190,8 @@ int abis_nm_vty_init(void)
install_default(OML_NODE);
install_element(OML_NODE, &ournode_exit_cmd);
install_element(OML_NODE, &oml_attrib_get_cmd);
install_element(OML_NODE, &oml_attrib_set_cmd);
install_element(OML_NODE, &oml_chg_adm_state_cmd);
install_element(OML_NODE, &oml_opstart_cmd);

View File

@@ -40,7 +40,7 @@
#include <openbsc/abis_nm.h>
#include <openbsc/abis_om2000.h>
#include <openbsc/signal.h>
#include <osmocom/abis/e1_input.h>
#include <openbsc/e1_input.h>
#define OM_ALLOC_SIZE 1024
#define OM_HEADROOM_SIZE 128
@@ -800,7 +800,7 @@ static void signal_op_state(struct gsm_bts *bts, struct abis_om2k_mo *mo)
static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
{
struct abis_om2k_hdr *o2h;
struct gsm_bts_trx *trx;
int to_trx_oml;
msg->l2h = msg->data;
o2h = (struct abis_om2k_hdr *) msg->l2h;
@@ -813,8 +813,9 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
case OM2K_MO_CLS_TX:
case OM2K_MO_CLS_RX:
/* Route through per-TRX OML Link to the appropriate TRX */
trx = gsm_bts_trx_by_nr(bts, o2h->mo.inst);
if (!trx) {
to_trx_oml = 1;
msg->trx = gsm_bts_trx_by_nr(bts, o2h->mo.inst);
if (!msg->trx) {
LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
"non-existing TRX\n", om2k_mo_name(&o2h->mo));
return -ENODEV;
@@ -822,8 +823,9 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
break;
case OM2K_MO_CLS_TS:
/* Route through per-TRX OML Link to the appropriate TRX */
trx = gsm_bts_trx_by_nr(bts, o2h->mo.assoc_so);
if (!trx) {
to_trx_oml = 1;
msg->trx = gsm_bts_trx_by_nr(bts, o2h->mo.assoc_so);
if (!msg->trx) {
LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
"non-existing TRX\n", om2k_mo_name(&o2h->mo));
return -ENODEV;
@@ -831,12 +833,12 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
break;
default:
/* Route through the IXU/DXU OML Link */
trx = bts->c0;
msg->trx = bts->c0;
to_trx_oml = 0;
break;
}
msg->dst = trx->oml_link;
return _abis_nm_sendmsg(msg);
return _abis_nm_sendmsg(msg, to_trx_oml);
}
static void fill_om2k_hdr(struct abis_om2k_hdr *o2h, const struct abis_om2k_mo *mo,
@@ -1261,7 +1263,6 @@ struct iwd_type {
static int om2k_rx_negot_req(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
struct abis_om2k_hdr *o2h = msgb_l2(msg);
struct iwd_type iwd_types[16];
uint8_t num_iwd_types = o2h->data[2];
@@ -1315,31 +1316,29 @@ static int om2k_rx_negot_req(struct msgb *msg)
out_buf[0] = out_num_types;
return abis_om2k_tx_negot_req_ack(sign_link->trx->bts, &o2h->mo, out_buf, out_cur - out_buf);
return abis_om2k_tx_negot_req_ack(msg->trx->bts, &o2h->mo, out_buf, out_cur - out_buf);
}
static int om2k_rx_start_res(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
struct abis_om2k_hdr *o2h = msgb_l2(msg);
int rc;
rc = abis_om2k_tx_simple(sign_link->trx->bts, &o2h->mo, OM2K_MSGT_START_RES_ACK);
rc = abis_om2k_tx_op_info(sign_link->trx->bts, &o2h->mo, 1);
rc = abis_om2k_tx_simple(msg->trx->bts, &o2h->mo, OM2K_MSGT_START_RES_ACK);
rc = abis_om2k_tx_op_info(msg->trx->bts, &o2h->mo, 1);
return rc;
}
static int om2k_rx_op_info_ack(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
struct abis_om2k_hdr *o2h = msgb_l2(msg);
/* This Acknowledgement does not contain the actual operational state,
* so we signal whatever state we saved when we sent the Op Info
* request */
signal_op_state(sign_link->trx->bts, &o2h->mo);
signal_op_state(msg->trx->bts, &o2h->mo);
return 0;
}
@@ -1464,8 +1463,7 @@ static int process_mo_state(struct gsm_bts *bts, struct msgb *msg)
int abis_om2k_rcvmsg(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
struct gsm_bts *bts = sign_link->trx->bts;
struct gsm_bts *bts = msg->trx->bts;
struct abis_om2k_hdr *o2h = msgb_l2(msg);
struct abis_om_hdr *oh = &o2h->om;
uint16_t msg_type = ntohs(o2h->msg_type);

View File

@@ -38,8 +38,8 @@
#include <openbsc/signal.h>
#include <openbsc/meas_rep.h>
#include <openbsc/rtp_proxy.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/gsm/rsl.h>
#include <osmocom/core/talloc.h>
#define RSL_ALLOC_SIZE 1024
@@ -178,30 +178,6 @@ static void print_rsl_cause(int lvl, const uint8_t *cause_v, uint8_t cause_len)
LOGPC(DRSL, lvl, "%02x ", cause_v[i]);
}
static void lchan_act_tmr_cb(void *data)
{
struct gsm_lchan *lchan = data;
LOGP(DRSL, LOGL_NOTICE, "%s Timeout during activation!\n",
gsm_lchan_name(lchan));
rsl_lchan_set_state(lchan, LCHAN_S_NONE);
lchan_free(lchan);
}
static void lchan_deact_tmr_cb(void *data)
{
struct gsm_lchan *lchan = data;
LOGP(DRSL, LOGL_NOTICE, "%s Timeout during deactivation!\n",
gsm_lchan_name(lchan));
if (lchan->state != LCHAN_S_REL_ERR)
rsl_lchan_set_state(lchan, LCHAN_S_NONE);
lchan_free(lchan);
}
/* Send a BCCH_INFO message as per Chapter 8.5.1 */
int rsl_bcch_info(struct gsm_bts_trx *trx, uint8_t type,
const uint8_t *data, int len)
@@ -216,7 +192,7 @@ int rsl_bcch_info(struct gsm_bts_trx *trx, uint8_t type,
msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data);
msg->dst = trx->rsl_link;
msg->trx = trx;
return abis_rsl_sendmsg(msg);
}
@@ -234,7 +210,7 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type,
msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data);
msg->dst = trx->rsl_link;
msg->trx = trx;
return abis_rsl_sendmsg(msg);
}
@@ -253,7 +229,7 @@ int rsl_sacch_info_modify(struct gsm_lchan *lchan, uint8_t type,
msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data);
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -280,7 +256,7 @@ int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db)
msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power);
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -309,7 +285,7 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm)
msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -408,7 +384,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, uint8_t chan_nr,
msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power);
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
msg->dst = trx->rsl_link;
msg->trx = trx;
return abis_rsl_sendmsg(msg);
}
@@ -487,7 +463,7 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type,
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
(uint8_t *) &lchan->mr_conf);
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -526,7 +502,7 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
(uint8_t *) &lchan->mr_conf);
}
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -558,7 +534,7 @@ int rsl_encryption_cmd(struct msgb *msg)
init_dchan_hdr(dh, RSL_MT_ENCR_CMD);
dh->chan_nr = chan_nr;
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -574,7 +550,7 @@ int rsl_deact_sacch(struct gsm_lchan *lchan)
dh->chan_nr = gsm_lchan2chan_nr(lchan);
msg->lchan = lchan;
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_lchan_name(lchan));
@@ -616,7 +592,7 @@ static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
dh->chan_nr = gsm_lchan2chan_nr(lchan);
msg->lchan = lchan;
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
DEBUGP(DRSL, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error);
@@ -626,20 +602,13 @@ static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
* be a problem when we have reassigned the channel to someone else and then can
* not figure out who used this channel.
*/
struct e1inp_sign_link *sign_link = msg->dst;
rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
lchan->error_timer.data = lchan;
lchan->error_timer.cb = error_timeout_cb;
osmo_timer_schedule(&lchan->error_timer,
sign_link->trx->bts->network->T3111 + 2, 0);
msg->trx->bts->network->T3111 + 2, 0);
}
/* Start another timer or assume the BTS sends a ACK/NACK? */
lchan->act_timer.cb = lchan_deact_tmr_cb;
lchan->act_timer.data = lchan;
osmo_timer_schedule(&lchan->act_timer, 4, 0);
rc = abis_rsl_sendmsg(msg);
/* BTS will respond by RF CHAN REL ACK */
@@ -657,8 +626,6 @@ static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan)
DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", gsm_lchan_name(lchan));
osmo_timer_del(&lchan->act_timer);
if (lchan->state != LCHAN_S_REL_REQ && lchan->state != LCHAN_S_REL_ERR)
LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
gsm_lchan_name(lchan),
@@ -686,7 +653,7 @@ int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group, uint8_t len,
msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len-2, ms_ident+2);
msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed);
msg->dst = bts->c0->rsl_link;
msg->trx = bts->c0;
return abis_rsl_sendmsg(msg);
}
@@ -730,7 +697,7 @@ int rsl_imm_assign_cmd(struct gsm_bts *bts, uint8_t len, uint8_t *val)
break;
}
msg->dst = bts->c0->rsl_link;
msg->trx = bts->c0;
return abis_rsl_sendmsg(msg);
}
@@ -750,7 +717,7 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci)
DEBUGP(DRSL, "%s TX Siemens MRPCI 0x%02x\n",
gsm_lchan_name(lchan), *(uint8_t *)mrpci);
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -768,7 +735,7 @@ int rsl_data_request(struct msgb *msg, uint8_t link_id)
rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, gsm_lchan2chan_nr(msg->lchan),
link_id, 1);
msg->dst = msg->lchan->ts->trx->rsl_link;
msg->trx = msg->lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -781,10 +748,7 @@ int rsl_establish_request(struct gsm_lchan *lchan, uint8_t link_id)
msg = rsl_rll_simple(RSL_MT_EST_REQ, gsm_lchan2chan_nr(lchan),
link_id, 0);
msg->dst = lchan->ts->trx->rsl_link;
DEBUGP(DRLL, "%s RSL RLL ESTABLISH REQ (link_id=0x%02x)\n",
gsm_lchan_name(lchan), link_id);
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -806,10 +770,7 @@ int rsl_release_request(struct gsm_lchan *lchan, uint8_t link_id, uint8_t reason
/* FIXME: start some timer in case we don't receive a REL ACK ? */
msg->dst = lchan->ts->trx->rsl_link;
DEBUGP(DRLL, "%s RSL RLL RELEASE REQ (link_id=0x%02x, reason=%u)\n",
gsm_lchan_name(lchan), link_id, reason);
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -830,8 +791,6 @@ static int rsl_rx_chan_act_ack(struct msgb *msg)
if (rslh->ie_chan != RSL_IE_CHAN_NR)
return -EINVAL;
osmo_timer_del(&msg->lchan->act_timer);
if (msg->lchan->state != LCHAN_S_ACT_REQ)
LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
gsm_lchan_name(msg->lchan),
@@ -856,9 +815,7 @@ static int rsl_rx_chan_act_nack(struct msgb *msg)
struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
struct tlv_parsed tp;
osmo_timer_del(&msg->lchan->act_timer);
LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK ",
LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK",
gsm_lchan_name(msg->lchan));
/* BTS has rejected channel activation ?!? */
@@ -872,9 +829,6 @@ static int rsl_rx_chan_act_nack(struct msgb *msg)
TLVP_LEN(&tp, RSL_IE_CAUSE));
if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
else
rsl_rf_chan_release(msg->lchan, 1);
} else
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
@@ -1007,18 +961,12 @@ static int rsl_rx_meas_res(struct msgb *msg)
*TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET);
if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) {
struct e1inp_sign_link *sign_link = msg->dst;
val = TLVP_VAL(&tp, RSL_IE_L1_INFO);
mr->flags |= MEAS_REP_F_MS_L1;
mr->ms_l1.pwr = ms_pwr_dbm(sign_link->trx->bts->band, val[0] >> 3);
mr->ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3);
if (val[0] & 0x04)
mr->flags |= MEAS_REP_F_FPC;
mr->ms_l1.ta = val[1];
/* BS11 and Nokia reports TA shifted by 2 bits */
if (msg->lchan->ts->trx->bts->type == GSM_BTS_TYPE_BS11
|| msg->lchan->ts->trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE)
mr->ms_l1.ta >>= 2;
}
if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
msg->l3h = (uint8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO);
@@ -1060,9 +1008,8 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
int rc = 0;
char *ts_name;
struct e1inp_sign_link *sign_link = msg->dst;
msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr);
msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
ts_name = gsm_lchan_name(msg->lchan);
switch (rslh->c.msg_type) {
@@ -1129,9 +1076,8 @@ static int rsl_rx_error_rep(struct msgb *msg)
{
struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
struct tlv_parsed tp;
struct e1inp_sign_link *sign_link = msg->dst;
LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(sign_link->trx));
LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(msg->trx));
rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh));
@@ -1147,7 +1093,6 @@ static int rsl_rx_error_rep(struct msgb *msg)
static int abis_rsl_rx_trx(struct msgb *msg)
{
struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
struct e1inp_sign_link *sign_link = msg->dst;
int rc = 0;
switch (rslh->msg_type) {
@@ -1156,22 +1101,16 @@ static int abis_rsl_rx_trx(struct msgb *msg)
break;
case RSL_MT_RF_RES_IND:
/* interference on idle channels of TRX */
//DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(sign_link->trx));
//DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(msg->trx));
break;
case RSL_MT_OVERLOAD:
/* indicate CCCH / ACCH / processor overload */
LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n",
gsm_trx_name(sign_link->trx));
break;
case 0x42: /* Nokia specific: SI End ACK */
LOGP(DRSL, LOGL_INFO, "Nokia SI End ACK\n");
break;
case 0x43: /* Nokia specific: SI End NACK */
LOGP(DRSL, LOGL_INFO, "Nokia SI End NACK\n");
gsm_trx_name(msg->trx));
break;
default:
LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message "
"type 0x%02x\n", gsm_trx_name(sign_link->trx), rslh->msg_type);
"type 0x%02x\n", gsm_trx_name(msg->trx), rslh->msg_type);
return -EINVAL;
}
return rc;
@@ -1237,8 +1176,7 @@ static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
/* MS has requested a channel on the RACH */
static int rsl_rx_chan_rqd(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = msg->dst;
struct gsm_bts *bts = sign_link->trx->bts;
struct gsm_bts *bts = msg->trx->bts;
struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg);
struct gsm48_req_ref *rqd_ref;
enum gsm_chan_t lctype;
@@ -1248,7 +1186,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
int is_lu;
uint16_t arfcn;
uint8_t subch;
uint8_t ts_number, subch;
/* parse request reference to be used in immediate assign */
if (rqd_hdr->data[0] != RSL_IE_REQ_REFERENCE)
@@ -1290,6 +1228,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel "
"in state %s\n", gsm_lchan_name(lchan),
gsm_lchans_name(lchan->state));
rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
/* save the RACH data as we need it after the CHAN ACT ACK */
lchan->rqd_ref = talloc_zero(bts, struct gsm48_req_ref);
@@ -1299,10 +1238,10 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
return -ENOMEM;
}
rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
memcpy(lchan->rqd_ref, rqd_ref, sizeof(*rqd_ref));
lchan->rqd_ta = rqd_ta;
ts_number = lchan->ts->nr;
arfcn = lchan->ts->trx->arfcn;
subch = lchan->nr;
@@ -1312,21 +1251,13 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
lchan->tch_mode = GSM48_CMODE_SIGN;
/* Start another timer or assume the BTS sends a ACK/NACK? */
lchan->act_timer.cb = lchan_act_tmr_cb;
lchan->act_timer.data = lchan;
osmo_timer_schedule(&lchan->act_timer, 4, 0);
DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s "
"r=%s ra=0x%02x ta=%d\n", gsm_lchan_name(lchan), arfcn, subch,
gsm_lchant_name(lchan->type), gsm_chreq_name(chreq_reason),
rqd_ref->ra, rqd_ta);
/* BS11 requires TA shifted by 2 bits */
if (bts->type == GSM_BTS_TYPE_BS11)
rqd_ta <<= 2;
/* FIXME: Start another timer or assume the BTS sends a ACK/NACK? */
rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, 0);
DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s "
"r=%s ra=0x%02x\n", gsm_lchan_name(lchan), arfcn, subch,
gsm_lchant_name(lchan->type), gsm_chreq_name(chreq_reason),
rqd_ref->ra);
return 0;
}
@@ -1365,34 +1296,29 @@ static int rsl_send_imm_assignment(struct gsm_lchan *lchan)
return rsl_imm_assign_cmd(bts, sizeof(*ia)+ia->mob_alloc_len, (uint8_t *) ia);
}
/* current load on the CCCH */
/* MS has requested a channel on the RACH */
static int rsl_rx_ccch_load(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = msg->dst;
struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
struct ccch_signal_data sd;
sd.bts = sign_link->trx->bts;
sd.rach_slot_count = -1;
sd.rach_busy_count = -1;
sd.rach_access_count = -1;
uint16_t pg_buf_space;
uint16_t rach_slot_count = -1;
uint16_t rach_busy_count = -1;
uint16_t rach_access_count = -1;
switch (rslh->data[0]) {
case RSL_IE_PAGING_LOAD:
sd.pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
if (is_ipaccess_bts(sign_link->trx->bts) && sd.pg_buf_space == 0xffff) {
pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
if (is_ipaccess_bts(msg->trx->bts) && pg_buf_space == 0xffff) {
/* paging load below configured threshold, use 50 as default */
sd.pg_buf_space = 50;
pg_buf_space = 50;
}
paging_update_buffer_space(sign_link->trx->bts, sd.pg_buf_space);
osmo_signal_dispatch(SS_CCCH, S_CCCH_PAGING_LOAD, &sd);
paging_update_buffer_space(msg->trx->bts, pg_buf_space);
break;
case RSL_IE_RACH_LOAD:
if (msg->data_len >= 7) {
sd.rach_slot_count = rslh->data[2] << 8 | rslh->data[3];
sd.rach_busy_count = rslh->data[4] << 8 | rslh->data[5];
sd.rach_access_count = rslh->data[6] << 8 | rslh->data[7];
osmo_signal_dispatch(SS_CCCH, S_CCCH_RACH_LOAD, &sd);
rach_slot_count = rslh->data[2] << 8 | rslh->data[3];
rach_busy_count = rslh->data[4] << 8 | rslh->data[5];
rach_access_count = rslh->data[6] << 8 | rslh->data[7];
}
break;
default:
@@ -1404,11 +1330,10 @@ static int rsl_rx_ccch_load(struct msgb *msg)
static int abis_rsl_rx_cchan(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = msg->dst;
struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
int rc = 0;
msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr);
msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
switch (rslh->c.msg_type) {
case RSL_MT_CHAN_RQD:
@@ -1488,13 +1413,12 @@ static void rsl_handle_release(struct gsm_lchan *lchan)
static int abis_rsl_rx_rll(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = msg->dst;
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
int rc = 0;
char *ts_name;
uint8_t sapi = rllh->link_id & 7;
msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr);
msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
ts_name = gsm_lchan_name(msg->lchan);
DEBUGP(DRLL, "%s SAPI=%u ", ts_name, sapi);
@@ -1596,6 +1520,8 @@ static uint8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan)
static uint8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
{
struct gsm_network *net = lchan->ts->trx->bts->network;
switch (lchan->tch_mode) {
case GSM48_CMODE_SPEECH_V1:
switch (lchan->type) {
@@ -1705,7 +1631,7 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan)
gsm_lchan_name(lchan), lchan->abis_ip.speech_mode,
lchan->abis_ip.rtp_payload);
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -1747,8 +1673,8 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, uint32_t ip, uint16_t port,
msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
if (rtp_payload2)
msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2);
msg->dst = lchan->ts->trx->rsl_link;
msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -1786,7 +1712,7 @@ int rsl_ipacc_pdch_activate(struct gsm_bts_trx_ts *ts, int act)
DEBUGP(DRSL, "%s IPAC_PDCH_%sACT\n", gsm_ts_name(ts),
act ? "" : "DE");
msg->dst = ts->trx->rsl_link;
msg->trx = ts->trx;
return abis_rsl_sendmsg(msg);
}
@@ -1851,12 +1777,11 @@ static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg)
static int abis_rsl_rx_ipacc(struct msgb *msg)
{
struct e1inp_sign_link *sign_link = msg->dst;
struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
char *ts_name;
int rc = 0;
msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr);
msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
ts_name = gsm_lchan_name(msg->lchan);
switch (rllh->c.msg_type) {
@@ -1962,50 +1887,3 @@ int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
return abis_rsl_sendmsg(cb_cmd);
}
int rsl_nokia_si_begin(struct gsm_bts_trx *trx)
{
struct abis_rsl_common_hdr *ch;
struct msgb *msg = rsl_msgb_alloc();
ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
ch->msg_discr = ABIS_RSL_MDISC_TRX;
ch->msg_type = 0x40; /* Nokia SI Begin */
msg->dst = trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
int rsl_nokia_si_end(struct gsm_bts_trx *trx)
{
struct abis_rsl_common_hdr *ch;
struct msgb *msg = rsl_msgb_alloc();
ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
ch->msg_discr = ABIS_RSL_MDISC_TRX;
ch->msg_type = 0x41; /* Nokia SI End */
msgb_tv_put(msg, 0xFD, 0x00); /* Nokia Pagemode Info, No paging reorganisation required */
msg->dst = trx->rsl_link;
return abis_rsl_sendmsg(msg);
}
int rsl_bs_power_control(struct gsm_bts_trx *trx, uint8_t channel, uint8_t reduction)
{
struct abis_rsl_common_hdr *ch;
struct msgb *msg = rsl_msgb_alloc();
ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
ch->msg_discr = ABIS_RSL_MDISC_DED_CHAN;
ch->msg_type = RSL_MT_BS_POWER_CONTROL;
msgb_tv_put(msg, RSL_IE_CHAN_NR, channel);
msgb_tv_put(msg, RSL_IE_BS_POWER, reduction); /* reduction in 2dB steps */
msg->dst = trx->rsl_link;
return abis_rsl_sendmsg(msg);
}

View File

@@ -136,12 +136,8 @@ static void assignment_t10_timeout(void *_conn)
LOGP(DMSC, LOGL_ERROR, "Assigment T10 timeout on %p\n", conn);
/*
* normal release on the secondary channel but only if the
* secondary_channel has not been released by the handle_chan_nack.
*/
if (conn->secondary_lchan)
lchan_release(conn->secondary_lchan, 0, 1);
/* normal release on the secondary channel */
lchan_release(conn->secondary_lchan, 0, 1);
conn->secondary_lchan = NULL;
/* inform them about the failure */
@@ -155,6 +151,12 @@ static void assignment_t10_timeout(void *_conn)
static void handle_mr_config(struct gsm_subscriber_connection *conn,
struct gsm_lchan *lchan)
{
struct bsc_api *api;
api = conn->bts->network->bsc_api;
if (api->mr_config)
return api->mr_config(conn, &lchan->mr_conf);
lchan->mr_conf.ver = 1;
lchan->mr_conf.icmi = 1;
lchan->mr_conf.m5_90 = 1;
@@ -270,9 +272,8 @@ int bsc_api_init(struct gsm_network *network, struct bsc_api *api)
return 0;
}
/*! \brief process incoming 08.08 DTAP from MSC (send via BTS to MS) */
int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
struct msgb *msg, int link_id, int allow_sacch)
struct msgb *msg, int link_id, int allow_sach)
{
uint8_t sapi;
@@ -286,18 +287,16 @@ int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
sapi = link_id & 0x7;
msg->lchan = conn->lchan;
msg->dst = msg->lchan->ts->trx->rsl_link;
msg->trx = msg->lchan->ts->trx;
/* If we are on a TCH and need to submit a SMS (on SAPI=3) we need to use the SACH */
if (allow_sacch && sapi != 0) {
if (allow_sach && sapi != 0) {
if (conn->lchan->type == GSM_LCHAN_TCH_F || conn->lchan->type == GSM_LCHAN_TCH_H)
link_id |= 0x40;
}
msg->l3h = msg->data;
/* is requested SAPI already up? */
if (conn->lchan->sapis[sapi] == LCHAN_SAPI_UNUSED) {
/* Establish L2 for additional SAPI */
OBSC_LINKID_CB(msg) = link_id;
if (rll_establish(msg->lchan, sapi, rll_ind_cb, msg) != 0) {
msgb_free(msg);
@@ -306,42 +305,23 @@ int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
}
return 0;
} else {
/* Directly forward via RLL/RSL to BTS */
return rsl_data_request(msg, link_id);
}
}
/*
* \brief Check if the given channel is compatible with the mode/fullrate
*
* NOTE: This code is only written with TCH/F and TCH/H in mind. This means
* that it will not work for CSD, handover, etc. This also assumes that the
* type of the lchan is either a TCH or a SDCCH.
*/
static int chan_compat_with_mode(struct gsm_lchan *lchan, int chan_mode, int full_rate)
{
if (lchan->type == GSM_LCHAN_SDCCH)
return 1;
if (full_rate && lchan->type != GSM_LCHAN_TCH_F)
return 1;
return 0;
}
/**
* Send a GSM08.08 Assignment Request. Right now this does not contain the
* audio codec type or the allowed rates for the config. It is assumed that
* this is for audio handling only. In case the current channel does not allow
* the selected mode a new one will be allocated.
*
* TODO: Add multirate configuration, make it work for more than audio.
* this is for audio handling and that when we have a TCH it is capable of
* handling the audio codec. In case AMR is used we will leave the multi
* rate configuration to someone else.
*/
int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate)
{
struct bsc_api *api;
api = conn->bts->network->bsc_api;
if (chan_compat_with_mode(conn->lchan, chan_mode, full_rate) != 0) {
if (conn->lchan->type == GSM_LCHAN_SDCCH) {
if (handle_new_assignment(conn, chan_mode, full_rate) != 0)
goto error;
} else {
@@ -398,7 +378,8 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
rsl_ipacc_crcx(conn->lchan);
api->assign_compl(conn, gh->data[0],
if (api->assign_compl)
api->assign_compl(conn, gh->data[0],
lchan_to_chosen_channel(conn->lchan),
conn->lchan->encr.alg_id,
chan_mode_to_speech(conn->lchan));
@@ -436,75 +417,6 @@ static void handle_ass_fail(struct gsm_subscriber_connection *conn,
rr_failure);
}
static void handle_classmark_chg(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
struct gsm48_hdr *gh = msgb_l3(msg);
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
uint8_t cm2_len, cm3_len = 0;
uint8_t *cm2, *cm3 = NULL;
DEBUGP(DRR, "CLASSMARK CHANGE ");
/* classmark 2 */
cm2_len = gh->data[0];
cm2 = &gh->data[1];
DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
if (payload_len > cm2_len + 1) {
/* we must have a classmark3 */
if (gh->data[cm2_len+1] != 0x20) {
DEBUGPC(DRR, "ERR CM3 TAG\n");
return;
}
if (cm2_len > 3) {
DEBUGPC(DRR, "CM2 too long!\n");
return;
}
cm3_len = gh->data[cm2_len+2];
cm3 = &gh->data[cm2_len+3];
if (cm3_len > 14) {
DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
return;
}
DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
}
api->classmark_chg(conn, cm2, cm2_len, cm3, cm3_len);
}
/* Chapter 9.1.16 Handover complete */
static void handle_rr_ho_compl(struct msgb *msg)
{
struct lchan_signal_data sig;
struct gsm48_hdr *gh = msgb_l3(msg);
DEBUGP(DRR, "HANDOVER COMPLETE cause = %s\n",
rr_cause_name(gh->data[0]));
sig.lchan = msg->lchan;
sig.mr = NULL;
osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, &sig);
/* FIXME: release old channel */
}
/* Chapter 9.1.17 Handover Failure */
static void handle_rr_ho_fail(struct msgb *msg)
{
struct lchan_signal_data sig;
struct gsm48_hdr *gh = msgb_l3(msg);
DEBUGP(DRR, "HANDOVER FAILED cause = %s\n",
rr_cause_name(gh->data[0]));
sig.lchan = msg->lchan;
sig.mr = NULL;
osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, &sig);
/* FIXME: release allocated new channel */
}
static void dispatch_dtap(struct gsm_subscriber_connection *conn,
uint8_t link_id, struct msgb *msg)
{
@@ -520,38 +432,12 @@ static void dispatch_dtap(struct gsm_subscriber_connection *conn,
gh = msgb_l3(msg);
pdisc = gh->proto_discr & 0x0f;
/* the idea is to handle all RR messages here, and only hand
* MM/CC/SMS-CP/LCS up to the MSC. Some messages like PAGING
* RESPONSE or CM SERVICE REQUEST will not be covered here, as
* they are only possible in the first L3 message of each L2
* channel, i.e. 'conn' will not exist and gsm0408_rcvmsg()
* will call api->compl_l3() for it */
switch (pdisc) {
case GSM48_PDISC_RR:
switch (gh->msg_type) {
case GSM48_MT_RR_GPRS_SUSP_REQ:
DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
break;
case GSM48_MT_RR_STATUS:
LOGP(DRR, LOGL_NOTICE, "RR STATUS (cause: %s)\n",
rr_cause_name(gh->data[0]));
break;
case GSM48_MT_RR_MEAS_REP:
/* This shouldn't actually end up here, as RSL treats
* L3 Info of 08.58 MEASUREMENT REPORT different by calling
* directly into gsm48_parse_meas_rep */
LOGP(DMEAS, LOGL_ERROR, "DIRECT GSM48 MEASUREMENT REPORT ?!? ");
break;
case GSM48_MT_RR_HANDO_COMPL:
handle_rr_ho_compl(msg);
break;
case GSM48_MT_RR_HANDO_FAIL:
handle_rr_ho_fail(msg);
break;
case GSM48_MT_RR_CIPH_M_COMPL:
if (api->cipher_mode_compl)
api->cipher_mode_compl(conn, msg,
return api->cipher_mode_compl(conn, msg,
conn->lchan->encr.alg_id);
break;
case GSM48_MT_RR_ASS_COMPL:
@@ -563,38 +449,28 @@ static void dispatch_dtap(struct gsm_subscriber_connection *conn,
case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
osmo_timer_del(&conn->T10);
rc = gsm48_rx_rr_modif_ack(msg);
if (rc < 0) {
if (rc < 0 && api->assign_fail) {
api->assign_fail(conn,
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
NULL);
} else if (rc >= 0) {
} else if (rc >= 0 && api->assign_compl)
api->assign_compl(conn, 0,
lchan_to_chosen_channel(conn->lchan),
conn->lchan->encr.alg_id,
chan_mode_to_speech(conn->lchan));
}
return;
break;
case GSM48_MT_RR_CLSM_CHG:
handle_classmark_chg(conn, msg);
break;
default:
/* Normally, a MSC should never receive RR
* messages, but we'd rather forward what we
* don't know than drop it... */
LOGP(DRR, LOGL_NOTICE, "BSC: Passing unknown 04.08 "
"RR message type 0x%02x to MSC\n", gh->msg_type);
if (api->dtap)
api->dtap(conn, link_id, msg);
}
break;
default:
if (api->dtap)
api->dtap(conn, link_id, msg);
case GSM48_PDISC_MM:
break;
}
/* default case */
if (api->dtap)
api->dtap(conn, link_id, msg);
}
/*! \brief RSL has received a DATA INDICATION with L3 from MS */
int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
{
int rc;
@@ -610,32 +486,27 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
if (lchan->conn) {
/* if we already have a connection, forward via DTAP to
* MSC */
dispatch_dtap(lchan->conn, link_id, msg);
} else {
/* allocate a new connection */
rc = BSC_API_CONN_POL_REJECT;
lchan->conn = subscr_con_allocate(msg->lchan);
if (!lchan->conn) {
lchan_release(lchan, 1, 0);
lchan_release(lchan, 0, 0);
return -1;
}
/* fwd via bsc_api to send COMPLETE L3 INFO to MSC */
rc = api->compl_l3(lchan->conn, msg, 0);
if (rc != BSC_API_CONN_POL_ACCEPT) {
lchan->conn->lchan = NULL;
subscr_con_free(lchan->conn);
lchan_release(lchan, 1, 0);
lchan_release(lchan, 0, 0);
}
}
return 0;
}
/*! \brief We received a GSM 08.08 CIPHER MODE from the MSC */
int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
const uint8_t *key, int len, int include_imeisv)
{
@@ -796,7 +667,7 @@ static void handle_chan_ack(struct gsm_subscriber_connection *conn,
return;
LOGP(DMSC, LOGL_NOTICE, "Sending assignment on chan: %p\n", lchan);
gsm48_send_rr_ass_cmd(conn->lchan, lchan, lchan->ms_power);
gsm48_send_rr_ass_cmd(conn->lchan, lchan, 0x3);
}
static void handle_chan_nack(struct gsm_subscriber_connection *conn,

View File

@@ -33,8 +33,6 @@
#include <openbsc/chan_alloc.h>
#include <osmocom/core/talloc.h>
#include <openbsc/ipaccess.h>
#include <osmocom/gsm/sysinfo.h>
#include <openbsc/e1_config.h>
/* global pointer to the gsm network data structure */
extern struct gsm_network *bsc_gsmnet;
@@ -47,21 +45,16 @@ static int oml_msg_nack(struct nm_nack_signal_data *nack)
if (nack->mt == NM_MT_SET_BTS_ATTR_NACK) {
LOGP(DNM, LOGL_ERROR, "Failed to set BTS attributes. That is fatal. "
LOGP(DNM, LOGL_FATAL, "Failed to set BTS attributes. That is fatal. "
"Was the bts type and frequency properly specified?\n");
goto drop_bts;
exit(-1);
} else {
LOGP(DNM, LOGL_ERROR, "Got a NACK going to drop the OML links.\n");
goto drop_bts;
}
return 0;
drop_bts:
for (i = 0; i < bsc_gsmnet->num_bts; ++i) {
struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, i);
if (is_ipaccess_bts(bts))
ipaccess_drop_oml(bts);
for (i = 0; i < bsc_gsmnet->num_bts; ++i) {
struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, i);
if (is_ipaccess_bts(bts))
ipaccess_drop_oml(bts);
}
}
return 0;
@@ -89,16 +82,24 @@ int bsc_shutdown_net(struct gsm_network *net)
llist_for_each_entry(bts, &net->bts_list, list) {
LOGP(DNM, LOGL_NOTICE, "shutting down OML for BTS %u\n", bts->nr);
osmo_signal_dispatch(SS_L_GLOBAL, S_GLOBAL_BTS_CLOSE_OM, bts);
osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_BTS_CLOSE_OM, bts);
}
return 0;
}
static int rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i, int si_len)
static int generate_and_rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i)
{
struct gsm_bts *bts = trx->bts;
int rc, j;
int si_len, rc, j;
/* Only generate SI if this SI is not in "static" (user-defined) mode */
if (!(bts->si_mode_static & (1 << i))) {
rc = gsm_generate_si(bts, i);
if (rc < 0)
return rc;
si_len = rc;
}
DEBUGP(DRR, "SI%s: %s\n", get_value_string(osmo_sitype_strs, i),
osmo_hexdump(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN));
@@ -126,11 +127,11 @@ static int rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i, int si_len)
}
} else
rc = rsl_sacch_filling(trx, osmo_sitype2rsl(i),
GSM_BTS_SI(bts, i), si_len);
GSM_BTS_SI(bts, i), rc);
break;
default:
rc = rsl_bcch_info(trx, osmo_sitype2rsl(i),
GSM_BTS_SI(bts, i), si_len);
GSM_BTS_SI(bts, i), rc);
break;
}
@@ -142,8 +143,6 @@ static int set_system_infos(struct gsm_bts_trx *trx)
{
int i, rc;
struct gsm_bts *bts = trx->bts;
uint8_t gen_si[_MAX_SYSINFO_TYPE], n_si = 0, n;
int si_len[_MAX_SYSINFO_TYPE];
bts->si_common.cell_sel_par.ms_txpwr_max_ccch =
ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
@@ -153,55 +152,26 @@ static int set_system_infos(struct gsm_bts_trx *trx)
if (trx == bts->c0) {
/* 1...4 are always present on a C0 TRX */
gen_si[n_si++] = SYSINFO_TYPE_1;
gen_si[n_si++] = SYSINFO_TYPE_2;
gen_si[n_si++] = SYSINFO_TYPE_2bis;
gen_si[n_si++] = SYSINFO_TYPE_2ter;
gen_si[n_si++] = SYSINFO_TYPE_3;
gen_si[n_si++] = SYSINFO_TYPE_4;
for (i = SYSINFO_TYPE_1; i <= SYSINFO_TYPE_4; i++)
bts->si_valid |= (1 << i);
/* 13 is always present on a C0 TRX of a GPRS BTS */
if (bts->gprs.mode != BTS_GPRS_NONE)
gen_si[n_si++] = SYSINFO_TYPE_13;
bts->si_valid |= (1 << SYSINFO_TYPE_13);
}
/* 5 and 6 are always present on every TRX */
gen_si[n_si++] = SYSINFO_TYPE_5;
gen_si[n_si++] = SYSINFO_TYPE_5bis;
gen_si[n_si++] = SYSINFO_TYPE_5ter;
gen_si[n_si++] = SYSINFO_TYPE_6;
/* Second, we generate the selected SI via RSL */
for (n = 0; n < n_si; n++) {
i = gen_si[n];
bts->si_valid |= (1 << i);
/* Only generate SI if this SI is not in "static" (user-defined) mode */
if (!(bts->si_mode_static & (1 << i))) {
rc = gsm_generate_si(bts, i);
if (rc < 0)
goto err_out;
si_len[i] = rc;
} else {
if (i == SYSINFO_TYPE_5 || i == SYSINFO_TYPE_5bis
|| i == SYSINFO_TYPE_5ter)
si_len[i] = 18;
else if (i == SYSINFO_TYPE_6)
si_len[i] = 11;
else
si_len[i] = 23;
}
}
/* Third, we send the selected SI via RSL */
bts->si_valid |= (1 << SYSINFO_TYPE_5);
bts->si_valid |= (1 << SYSINFO_TYPE_6);
/* Second, we generate and send the selected SI via RSL */
for (i = SYSINFO_TYPE_1; i < _MAX_SYSINFO_TYPE; i++) {
if (!(bts->si_valid & (1 << i)))
continue;
rc = rsl_si(trx, i, si_len[i]);
rc = generate_and_rsl_si(trx, i);
if (rc < 0)
return rc;
goto err_out;
}
return 0;
@@ -233,7 +203,7 @@ static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
/* count the number of ARFCNs in the cell channel allocation */
num_cell_arfcns = 0;
for (i = 0; i < 1024; i++) {
for (i = 1; i < 1024; i++) {
if (bitvec_get_bit_pos(cell_chan, i))
num_cell_arfcns++;
}
@@ -244,7 +214,7 @@ static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
ts->hopping.ma_len++;
n_chan = 0;
for (i = 0; i < 1024; i++) {
for (i = 1; i < 1024; i++) {
if (!bitvec_get_bit_pos(cell_chan, i))
continue;
/* set the corresponding bit in the MA */
@@ -279,19 +249,8 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx)
trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code,
bsc_gsmnet->network_code, trx->bts->location_area_code,
trx->bts->cell_identity, trx->bts->bsic, trx->bts->tsc);
if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
rsl_nokia_si_begin(trx);
}
set_system_infos(trx);
if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
/* channel unspecific, power reduction in 2 dB steps */
rsl_bs_power_control(trx, 0xFF, trx->max_power_red / 2);
rsl_nokia_si_end(trx);
}
for (i = 0; i < ARRAY_SIZE(trx->ts); i++)
generate_ma_for_ts(&trx->ts[i]);
}
@@ -304,34 +263,16 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
struct gsm_bts_trx *trx = isd->trx;
int ts_no, lchan_no;
if (subsys != SS_L_INPUT)
if (subsys != SS_INPUT)
return -EINVAL;
switch (signal) {
case S_L_INP_TEI_UP:
if (isd->link_type == E1INP_SIGN_OML) {
/* TODO: this is required for the Nokia BTS, hopping is configured
during OML, other MA is not set. */
struct gsm_bts_trx *cur_trx;
/* was static in system_information.c */
extern int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts);
uint8_t ca[20];
/* has to be called before generate_ma_for_ts to
set bts->si_common.cell_alloc */
generate_cell_chan_list(ca, trx->bts);
llist_for_each_entry(cur_trx, &trx->bts->trx_list, list) {
int i;
for (i = 0; i < ARRAY_SIZE(cur_trx->ts); i++)
generate_ma_for_ts(&cur_trx->ts[i]);
}
}
case S_INP_TEI_UP:
if (isd->link_type == E1INP_SIGN_RSL)
bootstrap_rsl(trx);
break;
case S_L_INP_TEI_DN:
LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx);
case S_INP_TEI_DN:
LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx);
if (isd->link_type == E1INP_SIGN_OML)
osmo_counter_inc(trx->bts->network->stats.bts.oml_fail);
@@ -499,7 +440,7 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *),
return rc;
osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
rc = bootstrap_bts(bts);
@@ -507,7 +448,14 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *),
LOGP(DNM, LOGL_FATAL, "Error bootstrapping BTS\n");
return rc;
}
rc = e1_reconfig_bts(bts);
switch (bts->type) {
case GSM_BTS_TYPE_NANOBTS:
case GSM_BTS_TYPE_HSL_FEMTO:
break;
default:
rc = e1_reconfig_bts(bts);
break;
}
if (rc < 0) {
LOGP(DNM, LOGL_FATAL, "Error enabling E1 input driver\n");
return rc;

View File

@@ -21,13 +21,11 @@
#include <openbsc/bsc_msc.h>
#include <openbsc/debug.h>
#include <osmocom/abis/ipaccess.h>
#include <openbsc/ipaccess.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/tlv.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <errno.h>

View File

@@ -30,7 +30,7 @@
#include <osmocom/core/linuxlist.h>
#include <openbsc/gsm_data.h>
#include <osmocom/abis/e1_input.h>
#include <openbsc/e1_input.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_om2000.h>
#include <osmocom/core/utils.h>
@@ -52,14 +52,6 @@
#include "../../bscconfig.h"
#define NETWORK_STR "Configure the GSM network\n"
#define CODE_CMD_STR "Code commands\n"
#define NAME_CMD_STR "Name Commands\n"
#define NAME_STR "Name to use\n"
#define LCHAN_NR_STR "Logical Channel Number\n"
/* FIXME: this should go to some common file */
static const struct value_string gprs_ns_timer_strs[] = {
{ 0, "tns-block" },
@@ -263,9 +255,6 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
bts->oml_tei, VTY_NEWLINE);
else if (bts->type == GSM_BTS_TYPE_HSL_FEMTO)
vty_out(vty, " Serial Number: %lu%s", bts->hsl.serno, VTY_NEWLINE);
else if (bts->type == GSM_BTS_TYPE_NOKIA_SITE)
vty_out(vty, " Skip Reset: %d%s",
bts->nokia.skip_reset, VTY_NEWLINE);
vty_out(vty, " NM State: ");
net_dump_nmstate(vty, &bts->mo.nm_state);
vty_out(vty, " Site Mgr NM State: ");
@@ -448,8 +437,6 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
VTY_NEWLINE);
vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
if (bts->tz_bts_specific != 0)
vty_out(vty, " timezone %d %d%s", bts->tzhr, bts->tzmn, VTY_NEWLINE);
vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
vty_out(vty, " cell reselection hysteresis %u%s",
bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
@@ -511,7 +498,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
get_value_string(osmo_sitype_strs, i), VTY_NEWLINE);
vty_out(vty, " system-information %s static %s%s",
get_value_string(osmo_sitype_strs, i),
osmo_hexdump_nospc(bts->si_buf[i], sizeof(bts->si_buf[i])),
osmo_osmo_hexdump_nospc(bts->si_buf[i], sizeof(bts->si_buf[i])),
VTY_NEWLINE);
}
}
@@ -519,16 +506,10 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
case GSM_BTS_TYPE_NANOBTS:
vty_out(vty, " ip.access unit_id %u %u%s",
bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
vty_out(vty, " oml ip.access stream_id %u line %u%s",
bts->oml_tei, bts->oml_e1_link.e1_nr, VTY_NEWLINE);
vty_out(vty, " oml ip.access stream_id %u%s", bts->oml_tei, VTY_NEWLINE);
break;
case GSM_BTS_TYPE_HSL_FEMTO:
vty_out(vty, " hsl serial-number %lu%s", bts->hsl.serno, VTY_NEWLINE);
vty_out(vty, " oml hsl line %u%s",
bts->oml_e1_link.e1_nr, VTY_NEWLINE);
break;
case GSM_BTS_TYPE_NOKIA_SITE:
vty_out(vty, " nokia_site skip-reset %d%s", bts->nokia.skip_reset, VTY_NEWLINE);
break;
default:
config_write_e1_link(vty, &bts->oml_e1_link, " oml ");
@@ -903,47 +884,6 @@ static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan)
VTY_NEWLINE);
}
static int dump_lchan_trx_ts(struct gsm_bts_trx_ts *ts, struct vty *vty,
void (*dump_cb)(struct vty *, struct gsm_lchan *))
{
int lchan_nr;
for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; lchan_nr++) {
struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
if ((lchan->type == GSM_LCHAN_NONE) && (lchan->state == LCHAN_S_NONE))
continue;
dump_cb(vty, lchan);
}
return CMD_SUCCESS;
}
static int dump_lchan_trx(struct gsm_bts_trx *trx, struct vty *vty,
void (*dump_cb)(struct vty *, struct gsm_lchan *))
{
int ts_nr;
for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
dump_lchan_trx_ts(ts, vty, dump_cb);
}
return CMD_SUCCESS;
}
static int dump_lchan_bts(struct gsm_bts *bts, struct vty *vty,
void (*dump_cb)(struct vty *, struct gsm_lchan *))
{
int trx_nr;
for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_nr);
dump_lchan_trx(trx, vty, dump_cb);
}
return CMD_SUCCESS;
}
static int lchan_summary(struct vty *vty, int argc, const char **argv,
void (*dump_cb)(struct vty *, struct gsm_lchan *))
{
@@ -963,9 +903,6 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
return CMD_WARNING;
}
bts = gsm_bts_num(net, bts_nr);
if (argc == 1)
return dump_lchan_bts(bts, vty, dump_cb);
}
if (argc >= 2) {
trx_nr = atoi(argv[1]);
@@ -975,9 +912,6 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
return CMD_WARNING;
}
trx = gsm_bts_trx_num(bts, trx_nr);
if (argc == 2)
return dump_lchan_trx(trx, vty, dump_cb);
}
if (argc >= 3) {
ts_nr = atoi(argv[2]);
@@ -987,9 +921,6 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
return CMD_WARNING;
}
ts = &trx->ts[ts_nr];
if (argc == 3)
return dump_lchan_trx_ts(ts, vty, dump_cb);
}
if (argc >= 4) {
lchan_nr = atoi(argv[3]);
@@ -1002,11 +933,21 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv,
dump_cb(vty, lchan);
return CMD_SUCCESS;
}
for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
bts = gsm_bts_num(net, bts_nr);
dump_lchan_bts(bts, vty, dump_cb);
for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
trx = gsm_bts_trx_num(bts, trx_nr);
for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
ts = &trx->ts[ts_nr];
for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN;
lchan_nr++) {
lchan = &ts->lchan[lchan_nr];
if (lchan->type == GSM_LCHAN_NONE)
continue;
dump_cb(vty, lchan);
}
}
}
}
return CMD_SUCCESS;
@@ -1018,7 +959,7 @@ DEFUN(show_lchan,
"show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
SHOW_STR "Display information about a logical channel\n"
"BTS Number\n" "TRX Number\n" "Timeslot Number\n"
LCHAN_NR_STR)
"Logical Channel Number\n")
{
return lchan_summary(vty, argc, argv, lchan_dump_full_vty);
@@ -1028,13 +969,125 @@ DEFUN(show_lchan_summary,
show_lchan_summary_cmd,
"show lchan summary [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
SHOW_STR "Display information about a logical channel\n"
"Short summary\n"
"BTS Number\n" "TRX Number\n" "Timeslot Number\n"
LCHAN_NR_STR)
"Logical Channel Number\n")
{
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
}
static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
{
vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
}
DEFUN(show_e1drv,
show_e1drv_cmd,
"show e1_driver",
SHOW_STR "Display information about available E1 drivers\n")
{
struct e1inp_driver *drv;
llist_for_each_entry(drv, &e1inp_driver_list, list)
e1drv_dump_vty(vty, drv);
return CMD_SUCCESS;
}
static void e1line_dump_vty(struct vty *vty, struct e1inp_line *line)
{
vty_out(vty, "E1 Line Number %u, Name %s, Driver %s%s",
line->num, line->name ? line->name : "",
line->driver->name, VTY_NEWLINE);
}
DEFUN(show_e1line,
show_e1line_cmd,
"show e1_line [line_nr]",
SHOW_STR "Display information about a E1 line\n"
"E1 Line Number\n")
{
struct e1inp_line *line;
if (argc >= 1) {
int num = atoi(argv[0]);
llist_for_each_entry(line, &e1inp_line_list, list) {
if (line->num == num) {
e1line_dump_vty(vty, line);
return CMD_SUCCESS;
}
}
return CMD_WARNING;
}
llist_for_each_entry(line, &e1inp_line_list, list)
e1line_dump_vty(vty, line);
return CMD_SUCCESS;
}
static void e1ts_dump_vty(struct vty *vty, struct e1inp_ts *ts)
{
if (ts->type == E1INP_TS_TYPE_NONE)
return;
vty_out(vty, "E1 Timeslot %2u of Line %u is Type %s%s",
ts->num, ts->line->num, e1inp_tstype_name(ts->type),
VTY_NEWLINE);
}
DEFUN(show_e1ts,
show_e1ts_cmd,
"show e1_timeslot [line_nr] [ts_nr]",
SHOW_STR "Display information about a E1 timeslot\n"
"E1 Line Number\n" "E1 Timeslot Number\n")
{
struct e1inp_line *line = NULL;
struct e1inp_ts *ts;
int ts_nr;
if (argc == 0) {
llist_for_each_entry(line, &e1inp_line_list, list) {
for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
ts = &line->ts[ts_nr];
e1ts_dump_vty(vty, ts);
}
}
return CMD_SUCCESS;
}
if (argc >= 1) {
int num = atoi(argv[0]);
struct e1inp_line *l;
llist_for_each_entry(l, &e1inp_line_list, list) {
if (l->num == num) {
line = l;
break;
}
}
if (!line) {
vty_out(vty, "E1 line %s is invalid%s",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
}
if (argc >= 2) {
ts_nr = atoi(argv[1]);
if (ts_nr >= NUM_E1_TS) {
vty_out(vty, "E1 timeslot %s is invalid%s",
argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
ts = &line->ts[ts_nr];
e1ts_dump_vty(vty, ts);
return CMD_SUCCESS;
} else {
for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
ts = &line->ts[ts_nr];
e1ts_dump_vty(vty, ts);
}
return CMD_SUCCESS;
}
return CMD_SUCCESS;
}
static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag)
{
vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE);
@@ -1080,6 +1133,8 @@ DEFUN(show_paging,
return CMD_SUCCESS;
}
#define NETWORK_STR "Configure the GSM network\n"
DEFUN(cfg_net,
cfg_net_cmd,
"network", NETWORK_STR)
@@ -1090,13 +1145,11 @@ DEFUN(cfg_net,
return CMD_SUCCESS;
}
DEFUN(cfg_net_ncc,
cfg_net_ncc_cmd,
"network country code <1-999>",
"Set the GSM network country code\n"
"Country commands\n"
CODE_CMD_STR
"Network Country Code to use\n")
"Set the GSM network country code")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1108,10 +1161,7 @@ DEFUN(cfg_net_ncc,
DEFUN(cfg_net_mnc,
cfg_net_mnc_cmd,
"mobile network code <0-999>",
"Set the GSM mobile network code\n"
"Network Commands\n"
CODE_CMD_STR
"Mobile Network Code to use\n")
"Set the GSM mobile network code")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1123,7 +1173,7 @@ DEFUN(cfg_net_mnc,
DEFUN(cfg_net_name_short,
cfg_net_name_short_cmd,
"short name NAME",
"Set the short GSM network name\n" NAME_CMD_STR NAME_STR)
"Set the short GSM network name")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1134,7 +1184,7 @@ DEFUN(cfg_net_name_short,
DEFUN(cfg_net_name_long,
cfg_net_name_long_cmd,
"long name NAME",
"Set the long GSM network name\n" NAME_CMD_STR NAME_STR)
"Set the long GSM network name")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -1251,13 +1301,11 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd,
#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
#define HO_AVG_COUNT_STR "Amount to use for Averaging\n"
DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
"handover window rxlev averaging <1-10>",
HO_WIN_RXLEV_STR
"How many RxLev measurements are used for averaging\n"
HO_AVG_COUNT_STR)
"How many RxLev measurements are used for averaging")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
@@ -1267,8 +1315,7 @@ DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
"handover window rxqual averaging <1-10>",
HO_WIN_RXQUAL_STR
"How many RxQual measurements are used for averaging\n"
HO_AVG_COUNT_STR)
"How many RxQual measurements are used for averaging")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
@@ -1277,9 +1324,8 @@ DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
"handover window rxlev neighbor averaging <1-10>",
HO_WIN_RXLEV_STR "Neighbor\n"
"How many RxQual measurements are used for averaging\n"
HO_AVG_COUNT_STR)
HO_WIN_RXLEV_STR
"How many RxQual measurements are used for averaging")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
@@ -1289,8 +1335,7 @@ DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
"handover power budget interval <1-99>",
HO_PBUDGET_STR
"How often to check if we have a better cell (SACCH frames)\n"
"Interval\n" "Number\n")
"How often to check if we have a better cell (SACCH frames)")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.pwr_interval = atoi(argv[0]);
@@ -1300,8 +1345,7 @@ DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
"handover power budget hysteresis <0-999>",
HO_PBUDGET_STR
"How many dB does a neighbor to be stronger to become a HO candidate\n"
"Hysteresis\n" "Number\n")
"How many dB does a neighbor to be stronger to become a HO candidate")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
@@ -1311,8 +1355,7 @@ DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
"handover maximum distance <0-9999>",
HANDOVER_STR
"How big is the maximum timing advance before HO is forced\n"
"Distance\n" "Number\n")
"How big is the maximum timing advance before HO is forced")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.max_distance = atoi(argv[0]);
@@ -1322,10 +1365,7 @@ DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
DEFUN(cfg_net_pag_any_tch,
cfg_net_pag_any_tch_cmd,
"paging any use tch (0|1)",
"Assign a TCH when receiving a Paging Any request\n"
"Any Channel\n" "Use\n" "TCH\n"
"Do not use TCH for Paging Request Any\n"
"Do use TCH for Paging Request Any\n")
"Assign a TCH when receiving a Paging Any request")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->pag_any_tch = atoi(argv[0]);
@@ -1338,7 +1378,7 @@ DEFUN(cfg_net_pag_any_tch,
cfg_net_T##number##_cmd, \
"timer t" #number " <0-65535>", \
"Configure GSM Timers\n" \
doc "Timer Value\n") \
doc) \
{ \
struct gsm_network *gsmnet = gsmnet_from_vty(vty); \
int value = atoi(argv[0]); \
@@ -1353,24 +1393,24 @@ DEFUN(cfg_net_pag_any_tch,
return CMD_SUCCESS; \
}
DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.\n")
DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n")
DECLARE_TIMER(3105, "Currently not used.\n")
DECLARE_TIMER(3107, "Currently not used.\n")
DECLARE_TIMER(3109, "Currently not used.\n")
DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n")
DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n")
DECLARE_TIMER(3115, "Currently not used.\n")
DECLARE_TIMER(3117, "Currently not used.\n")
DECLARE_TIMER(3119, "Currently not used.\n")
DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT\n")
DECLARE_TIMER(3141, "Currently not used.\n")
DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.")
DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.")
DECLARE_TIMER(3105, "Currently not used.")
DECLARE_TIMER(3107, "Currently not used.")
DECLARE_TIMER(3109, "Currently not used.")
DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.")
DECLARE_TIMER(3113, "Set the time to try paging a subscriber.")
DECLARE_TIMER(3115, "Currently not used.")
DECLARE_TIMER(3117, "Currently not used.")
DECLARE_TIMER(3119, "Currently not used.")
DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT")
DECLARE_TIMER(3141, "Currently not used.")
DEFUN(cfg_net_dtx,
cfg_net_dtx_cmd,
"dtx-used (0|1)",
"Enable the usage of DTX.\n"
"DTX is disabled\n" "DTX is enabled\n")
"DTX is enabled/disabled")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->dtx_enabled = atoi(argv[0]);
@@ -1426,7 +1466,7 @@ DEFUN(cfg_bts,
DEFUN(cfg_bts_type,
cfg_bts_type_cmd,
"type TYPE",
"Set the BTS type\n" "Type\n")
"Set the BTS type\n")
{
struct gsm_bts *bts = vty->index;
int rc;
@@ -1441,7 +1481,7 @@ DEFUN(cfg_bts_type,
DEFUN(cfg_bts_band,
cfg_bts_band_cmd,
"band BAND",
"Set the frequency band of this BTS\n" "Frequency band\n")
"Set the frequency band of this BTS\n")
{
struct gsm_bts *bts = vty->index;
int band = gsm_band_parse(argv[0]);
@@ -1537,31 +1577,6 @@ DEFUN(cfg_bts_bsic,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_timezone,
cfg_bts_timezone_cmd,
"timezone <-19-19> (0|15|30|45)",
"Set the Timezone Offset of this BTS\n")
{
struct gsm_bts *bts = vty->index;
int tzhr = atoi(argv[0]);
int tzmn = atoi(argv[1]);
bts->tzhr = tzhr;
bts->tzmn = tzmn;
bts->tz_bts_specific=1;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_no_timezone,
cfg_bts_no_timezone_cmd,
"no timezone",
"disable bts specific timezone\n")
{
struct gsm_bts *bts = vty->index;
bts->tz_bts_specific=0;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_unit_id,
cfg_bts_unit_id_cmd,
@@ -1600,34 +1615,17 @@ DEFUN(cfg_bts_serno,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_nokia_site_skip_reset,
cfg_bts_nokia_site_skip_reset_cmd,
"nokia_site skip-reset (0|1)",
"Skip the reset step during bootstrap process of this BTS\n")
{
struct gsm_bts *bts = vty->index;
if (bts->type != GSM_BTS_TYPE_NOKIA_SITE) {
vty_out(vty, "%% BTS is not of Nokia *Site type%s", VTY_NEWLINE);
return CMD_WARNING;
}
bts->nokia.skip_reset = atoi(argv[0]);
return CMD_SUCCESS;
}
#define OML_STR "Organization & Maintenance Link\n"
#define IPA_STR "ip.access Specific Options\n"
DEFUN(cfg_bts_stream_id,
cfg_bts_stream_id_cmd,
"oml ip.access stream_id <0-255> line E1_LINE",
"oml ip.access stream_id <0-255>",
OML_STR IPA_STR
"Set the ip.access Stream ID of the OML link of this BTS\n")
{
struct gsm_bts *bts = vty->index;
int stream_id = atoi(argv[0]), linenr = atoi(argv[1]);
int stream_id = atoi(argv[0]);
if (!is_ipaccess_bts(bts)) {
vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE);
@@ -1635,27 +1633,6 @@ DEFUN(cfg_bts_stream_id,
}
bts->oml_tei = stream_id;
/* This is used by e1inp_bind_ops callback for each BTS model. */
bts->oml_e1_link.e1_nr = linenr;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_hsl_oml,
cfg_bts_hsl_oml_cmd,
"oml hsl line E1_LINE",
OML_STR "HSL femto Specific Options"
"Set OML link of this HSL femto BTS\n")
{
struct gsm_bts *bts = vty->index;
int linenr = atoi(argv[0]);
if (!(bts->type == GSM_BTS_TYPE_HSL_FEMTO)) {
vty_out(vty, "%% BTS is not of HSL type%s", VTY_NEWLINE);
return CMD_WARNING;
}
bts->oml_e1_link.e1_nr = linenr;
return CMD_SUCCESS;
}
@@ -2240,7 +2217,7 @@ DEFUN(cfg_bts_neigh_mode, cfg_bts_neigh_mode_cmd,
}
DEFUN(cfg_bts_neigh, cfg_bts_neigh_cmd,
"neighbor-list (add|del) arfcn <0-1023>",
"neighbor-list (add|del) arfcn <0-1024>",
"Neighbor List\n" "Add to manual neighbor list\n"
"Delete from manual neighbor list\n" "ARFCN of neighbor\n"
"ARFCN of neighbor\n")
@@ -2264,7 +2241,7 @@ DEFUN(cfg_bts_neigh, cfg_bts_neigh_cmd,
}
DEFUN(cfg_bts_si5_neigh, cfg_bts_si5_neigh_cmd,
"si5 neighbor-list (add|del) arfcn <0-1023>",
"si5 neighbor-list (add|del) arfcn <0-1024>",
"SI5 Neighbor List\n" "Add to manual SI5 neighbor list\n"
"Delete from SI5 manual neighbor list\n" "ARFCN of neighbor\n"
"ARFCN of neighbor\n")
@@ -2322,7 +2299,7 @@ DEFUN(cfg_trx,
DEFUN(cfg_trx_arfcn,
cfg_trx_arfcn_cmd,
"arfcn <0-1023>",
"arfcn <0-1024>",
"Set the ARFCN for this TRX\n")
{
int arfcn = atoi(argv[0]);
@@ -2701,6 +2678,10 @@ int bsc_vty_init(const struct log_info *cat)
install_element_ve(&show_lchan_summary_cmd);
install_element_ve(&logging_fltr_imsi_cmd);
install_element_ve(&show_e1drv_cmd);
install_element_ve(&show_e1line_cmd);
install_element_ve(&show_e1ts_cmd);
install_element_ve(&show_paging_cmd);
logging_vty_add_cmds(cat);
@@ -2758,12 +2739,8 @@ int bsc_vty_init(const struct log_info *cat)
install_element(BTS_NODE, &cfg_bts_tsc_cmd);
install_element(BTS_NODE, &cfg_bts_bsic_cmd);
install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
install_element(BTS_NODE, &cfg_bts_timezone_cmd);
install_element(BTS_NODE, &cfg_bts_no_timezone_cmd);
install_element(BTS_NODE, &cfg_bts_serno_cmd);
install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd);
install_element(BTS_NODE, &cfg_bts_stream_id_cmd);
install_element(BTS_NODE, &cfg_bts_hsl_oml_cmd);
install_element(BTS_NODE, &cfg_bts_oml_e1_cmd);
install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd);
install_element(BTS_NODE, &cfg_bts_challoc_cmd);

View File

@@ -26,10 +26,10 @@
#include <openbsc/gsm_data.h>
#include <openbsc/abis_om2000.h>
#include <openbsc/abis_nm.h>
#include <osmocom/abis/e1_input.h>
#include <openbsc/e1_input.h>
#include <openbsc/signal.h>
#include <osmocom/abis/lapd.h>
#include "../libabis/input/lapd.h"
static void bootstrap_om_bts(struct gsm_bts *bts)
{
@@ -70,9 +70,9 @@ static void start_sabm_in_line(struct e1inp_line *line, int start)
llist_for_each_entry(link, &ts->sign.sign_links, list) {
if (start)
lapd_sap_start(ts->lapd, link->tei, link->sapi);
lapd_sap_start(ts->driver.dahdi.lapd, link->tei, link->sapi);
else
lapd_sap_stop(ts->lapd, link->tei, link->sapi);
lapd_sap_stop(ts->driver.dahdi.lapd, link->tei, link->sapi);
}
}
}
@@ -83,7 +83,7 @@ static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
{
struct gsm_bts *bts;
if (subsys != SS_L_GLOBAL)
if (subsys != SS_GLOBAL)
return 0;
switch (signal) {
@@ -103,11 +103,11 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
{
struct input_signal_data *isd = signal_data;
if (subsys != SS_L_INPUT)
if (subsys != SS_INPUT)
return 0;
switch (signal) {
case S_L_INP_TEI_UP:
case S_INP_TEI_UP:
switch (isd->link_type) {
case E1INP_SIGN_OML:
if (isd->trx->bts->type != GSM_BTS_TYPE_RBS2000)
@@ -119,19 +119,22 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
break;
}
break;
case S_L_INP_LINE_INIT:
case S_L_INP_LINE_NOALARM:
if (strcasecmp(isd->line->driver->name, "DAHDI")
&& strcasecmp(isd->line->driver->name, "MISDN_LAPD"))
case S_INP_LINE_INIT:
/* Right now Ericsson RBS are only supported on DAHDI */
if (strcasecmp(isd->line->driver->name, "DAHDI"))
break;
start_sabm_in_line(isd->line, 1);
break;
case S_L_INP_LINE_ALARM:
if (strcasecmp(isd->line->driver->name, "DAHDI")
&& strcasecmp(isd->line->driver->name, "MISDN_LAPD"))
case S_INP_LINE_ALARM:
if (strcasecmp(isd->line->driver->name, "DAHDI"))
break;
start_sabm_in_line(isd->line, 0);
break;
case S_INP_LINE_NOALARM:
if (strcasecmp(isd->line->driver->name, "DAHDI"))
break;
start_sabm_in_line(isd->line, 1);
break;
}
return 0;
@@ -241,18 +244,12 @@ static void config_write_bts(struct vty *vty, struct gsm_bts *bts)
static int bts_model_rbs2k_start(struct gsm_network *net);
static void bts_model_rbs2k_e1line_bind_ops(struct e1inp_line *line)
{
e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
}
static struct gsm_bts_model model_rbs2k = {
.type = GSM_BTS_TYPE_RBS2000,
.name = "rbs2000",
.start = bts_model_rbs2k_start,
.oml_rcvmsg = &abis_om2k_rcvmsg,
.config_write_bts = &config_write_bts,
.e1line_bind_ops = &bts_model_rbs2k_e1line_bind_ops,
};
static int bts_model_rbs2k_start(struct gsm_network *net)
@@ -263,8 +260,8 @@ static int bts_model_rbs2k_start(struct gsm_network *net)
gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_HOPPING);
gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_HSCSD);
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL);
osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
osmo_signal_register_handler(SS_GLOBAL, gbl_sig_cb, NULL);
osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
return 0;

View File

@@ -28,18 +28,13 @@
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
#include <osmocom/core/logging.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/abis/ipaccess.h>
#include <openbsc/e1_input.h>
static int bts_model_hslfemto_start(struct gsm_network *net);
static void bts_model_hslfemto_e1line_bind_ops(struct e1inp_line *line);
static struct gsm_bts_model model_hslfemto = {
.type = GSM_BTS_TYPE_HSL_FEMTO,
.start = bts_model_hslfemto_start,
.e1line_bind_ops = &bts_model_hslfemto_e1line_bind_ops,
.nm_att_tlvdef = {
.def = {
/* no HSL specific OML attributes that we know of */
@@ -103,20 +98,20 @@ static int hslfemto_bootstrap_om(struct gsm_bts *bts)
msg = hsl_alloc_msgb();
cur = msgb_put(msg, sizeof(l1_msg));
memcpy(msg->data, l1_msg, sizeof(l1_msg));
msg->dst = bts->c0->rsl_link;
msg->trx = bts->c0;
abis_rsl_sendmsg(msg);
#if 1
msg = hsl_alloc_msgb();
cur = msgb_put(msg, sizeof(conn_trau_msg));
memcpy(msg->data, conn_trau_msg, sizeof(conn_trau_msg));
msg->dst = bts->c0->rsl_link;
msg->trx = bts->c0;
abis_rsl_sendmsg(msg);
#endif
msg = hsl_alloc_msgb();
cur = msgb_put(msg, sizeof(conn_trau_msg2));
memcpy(msg->data, conn_trau_msg2, sizeof(conn_trau_msg2));
msg->dst = bts->c0->rsl_link;
msg->trx = bts->c0;
abis_rsl_sendmsg(msg);
*((uint16_t *)oml_arfcn_bsic+10) = htons(bts->c0->arfcn);
@@ -125,8 +120,8 @@ static int hslfemto_bootstrap_om(struct gsm_bts *bts)
msg = hsl_alloc_msgb();
cur = msgb_put(msg, sizeof(oml_arfcn_bsic));
memcpy(msg->data, oml_arfcn_bsic, sizeof(oml_arfcn_bsic));
msg->dst = bts->c0->rsl_link;
abis_sendmsg(msg);
msg->trx = bts->c0;
_abis_nm_sendmsg(msg, 0);
/* Delay the OPSTART until after SI have been set via RSL */
//abis_nm_opstart(bts, NM_OC_BTS, 255, 255, 255);
@@ -140,11 +135,11 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
{
struct input_signal_data *isd = signal_data;
if (subsys != SS_L_INPUT)
if (subsys != SS_INPUT)
return 0;
switch (signal) {
case S_L_INP_TEI_UP:
case S_INP_TEI_UP:
switch (isd->link_type) {
case E1INP_SIGN_OML:
if (isd->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO)
@@ -156,8 +151,6 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
return 0;
}
static struct gsm_network *hsl_gsmnet;
static int bts_model_hslfemto_start(struct gsm_network *net)
{
model_hslfemto.features.data = &model_hslfemto._features_data[0];
@@ -166,147 +159,13 @@ static int bts_model_hslfemto_start(struct gsm_network *net)
gsm_btsmodel_set_feature(&model_hslfemto, BTS_FEAT_GPRS);
gsm_btsmodel_set_feature(&model_hslfemto, BTS_FEAT_EGPRS);
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
hsl_gsmnet = net;
return 0;
/* Call A-bis input driver, start socket for OML and RSL. */
return hsl_setup(net);
}
int bts_model_hslfemto_init(void)
{
return gsm_bts_model_register(&model_hslfemto);
}
#define OML_UP 0x0001
#define RSL_UP 0x0002
struct gsm_bts *find_bts_by_serno(struct gsm_network *net, uint64_t serno)
{
struct gsm_bts *bts;
llist_for_each_entry(bts, &net->bts_list, list) {
if (bts->type != GSM_BTS_TYPE_HSL_FEMTO)
continue;
if (serno == bts->hsl.serno)
return bts;
}
return NULL;
}
/* This function is called once the OML/RSL link becomes up. */
static struct e1inp_sign_link *
hsl_sign_link_up(void *unit_data, struct e1inp_line *line,
enum e1inp_sign_type type)
{
struct hsl_unit *dev = unit_data;
struct gsm_bts *bts;
bts = find_bts_by_serno(hsl_gsmnet, dev->serno);
if (!bts) {
LOGP(DLINP, LOGL_ERROR, "Unable to find BTS config for "
"serial number %lx\n", dev->serno);
return NULL;
}
DEBUGP(DLINP, "Identified HSL BTS Serial Number %lx\n", dev->serno);
/* we shouldn't hardcode it, but HSL femto also hardcodes it... */
bts->oml_tei = 255;
bts->c0->rsl_tei = 0;
bts->oml_link = e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML-1],
E1INP_SIGN_OML, bts->c0,
bts->oml_tei, 0);
bts->c0->rsl_link = e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML-1],
E1INP_SIGN_RSL, bts->c0,
bts->c0->rsl_tei, 0);
e1inp_event(&line->ts[E1INP_SIGN_OML-1], S_L_INP_TEI_UP, 255, 0);
e1inp_event(&line->ts[E1INP_SIGN_OML-1], S_L_INP_TEI_UP, 0, 0);
bts->ip_access.flags |= OML_UP;
bts->ip_access.flags |= (RSL_UP << 0);
return bts->oml_link;
}
void hsl_drop_oml(struct gsm_bts *bts)
{
struct e1inp_line *line;
if (!bts->oml_link)
return;
line = bts->oml_link->ts->line;
e1inp_sign_link_destroy(bts->oml_link);
bts->oml_link = NULL;
e1inp_sign_link_destroy(bts->c0->rsl_link);
bts->c0->rsl_link = NULL;
bts->ip_access.flags = 0;
}
static void hsl_sign_link_down(struct e1inp_line *line)
{
/* No matter what link went down, we close both signal links. */
struct e1inp_ts *ts = &line->ts[E1INP_SIGN_OML-1];
struct e1inp_sign_link *link;
llist_for_each_entry(link, &ts->sign.sign_links, list) {
struct gsm_bts *bts = link->trx->bts;
hsl_drop_oml(bts);
/* Yes, we only use the first element of the list. */
break;
}
}
/* This function is called if we receive one OML/RSL message. */
static int hsl_sign_link(struct msgb *msg)
{
int ret = 0;
struct e1inp_sign_link *link = msg->dst;
struct e1inp_ts *e1i_ts = link->ts;
switch (link->type) {
case E1INP_SIGN_OML:
if (!(link->trx->bts->ip_access.flags & OML_UP)) {
e1inp_event(e1i_ts, S_L_INP_TEI_UP,
link->tei, link->sapi);
link->trx->bts->ip_access.flags |= OML_UP;
}
ret = abis_nm_rcvmsg(msg);
break;
case E1INP_SIGN_RSL:
if (!(link->trx->bts->ip_access.flags &
(RSL_UP << link->trx->nr))) {
e1inp_event(e1i_ts, S_L_INP_TEI_UP,
link->tei, link->sapi);
link->trx->bts->ip_access.flags |=
(RSL_UP << link->trx->nr);
}
ret = abis_rsl_rcvmsg(msg);
break;
default:
LOGP(DLINP, LOGL_ERROR, "Unknown signal link type %d\n",
link->type);
msgb_free(msg);
break;
}
return ret;
}
static struct e1inp_line_ops hsl_e1inp_line_ops = {
.cfg = {
.ipa = {
.addr = "0.0.0.0",
.role = E1INP_LINE_R_BSC,
},
},
.sign_link_up = hsl_sign_link_up,
.sign_link_down = hsl_sign_link_down,
.sign_link = hsl_sign_link,
};
static void bts_model_hslfemto_e1line_bind_ops(struct e1inp_line *line)
{
e1inp_line_bind_ops(line, &hsl_e1inp_line_ops);
}

View File

@@ -24,7 +24,6 @@ int bts_init(void)
bts_model_rbs2k_init();
bts_model_nanobts_init();
bts_model_hslfemto_init();
bts_model_nokia_site_init();
/* Your new BTS here. */
return 0;
}

View File

@@ -26,27 +26,15 @@
#include <openbsc/gsm_data.h>
#include <openbsc/signal.h>
#include <openbsc/abis_nm.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/debug.h>
#include <osmocom/abis/subchan_demux.h>
#include <osmocom/abis/ipaccess.h>
#include <osmocom/core/logging.h>
#include <openbsc/e1_input.h> /* for ipaccess_setup() */
static int bts_model_nanobts_start(struct gsm_network *net);
static void bts_model_nanobts_e1line_bind_ops(struct e1inp_line *line);
static struct gsm_bts_model model_nanobts = {
.type = GSM_BTS_TYPE_NANOBTS,
.name = "nanobts",
.start = bts_model_nanobts_start,
.oml_rcvmsg = &abis_nm_rcvmsg,
.e1line_bind_ops = bts_model_nanobts_e1line_bind_ops,
.nm_att_tlvdef = {
.def = {
/* ip.access specifics */
@@ -364,8 +352,7 @@ static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd)
/* We skip NSVC1 since we only use NSVC0 */
if (nsvc->id == 1)
break;
if ((new_state->availability == NM_AVSTATE_OFF_LINE) ||
(new_state->availability == NM_AVSTATE_DEPENDENCY)) {
if (new_state->availability == NM_AVSTATE_OFF_LINE) {
abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
nsvc->id, 0xff,
nanobts_attr_nsvc0,
@@ -386,8 +373,7 @@ static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd)
static int sw_activ_rep(struct msgb *mb)
{
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct e1inp_sign_link *sign_link = mb->dst;
struct gsm_bts *bts = sign_link->trx->bts;
struct gsm_bts *bts = mb->trx->bts;
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
if (!trx)
@@ -453,8 +439,6 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal,
return 0;
}
static struct gsm_network *ipaccess_gsmnet;
static int bts_model_nanobts_start(struct gsm_network *net)
{
model_nanobts.features.data = &model_nanobts._features_data[0];
@@ -465,182 +449,11 @@ static int bts_model_nanobts_start(struct gsm_network *net)
osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
ipaccess_gsmnet = net;
return 0;
/* Call A-bis input driver, start server sockets for OML and RSL. */
return ipaccess_setup(net);
}
int bts_model_nanobts_init(void)
{
return gsm_bts_model_register(&model_nanobts);
}
#define OML_UP 0x0001
#define RSL_UP 0x0002
static struct gsm_bts *
find_bts_by_unitid(struct gsm_network *net, uint16_t site_id, uint16_t bts_id)
{
struct gsm_bts *bts;
llist_for_each_entry(bts, &net->bts_list, list) {
if (!is_ipaccess_bts(bts))
continue;
if (bts->ip_access.site_id == site_id &&
bts->ip_access.bts_id == bts_id)
return bts;
}
return NULL;
}
/* These are exported because they are used by the VTY interface. */
void ipaccess_drop_rsl(struct gsm_bts_trx *trx)
{
if (!trx->rsl_link)
return;
e1inp_sign_link_destroy(trx->rsl_link);
trx->rsl_link = NULL;
}
void ipaccess_drop_oml(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
if (!bts->oml_link)
return;
e1inp_sign_link_destroy(bts->oml_link);
bts->oml_link = NULL;
/* we have issues reconnecting RSL, drop everything. */
llist_for_each_entry(trx, &bts->trx_list, list)
ipaccess_drop_rsl(trx);
bts->ip_access.flags = 0;
}
/* This function is called once the OML/RSL link becomes up. */
static struct e1inp_sign_link *
ipaccess_sign_link_up(void *unit_data, struct e1inp_line *line,
enum e1inp_sign_type type)
{
struct gsm_bts *bts;
struct ipaccess_unit *dev = unit_data;
struct e1inp_sign_link *sign_link = NULL;
bts = find_bts_by_unitid(ipaccess_gsmnet, dev->site_id, dev->bts_id);
if (!bts) {
LOGP(DLINP, LOGL_ERROR, "Unable to find BTS configuration for "
" %u/%u/%u, disconnecting\n", dev->site_id,
dev->bts_id, dev->trx_id);
return NULL;
}
DEBUGP(DLINP, "Identified BTS %u/%u/%u\n",
dev->site_id, dev->bts_id, dev->trx_id);
switch(type) {
case E1INP_SIGN_OML:
/* remove old OML signal link for this BTS. */
ipaccess_drop_oml(bts);
/* create new OML link. */
sign_link = bts->oml_link =
e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML - 1],
E1INP_SIGN_OML, bts->c0,
bts->oml_tei, 0);
break;
case E1INP_SIGN_RSL: {
struct e1inp_ts *ts;
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, dev->trx_id);
/* no OML link set yet? give up. */
if (!bts->oml_link)
return NULL;
/* remove old RSL link for this TRX. */
ipaccess_drop_rsl(trx);
/* set new RSL link for this TRX. */
line = bts->oml_link->ts->line;
ts = &line->ts[E1INP_SIGN_RSL + dev->trx_id - 1];
e1inp_ts_config_sign(ts, line);
sign_link = trx->rsl_link =
e1inp_sign_link_create(ts, E1INP_SIGN_RSL,
trx, trx->rsl_tei, 0);
trx->rsl_link->ts->sign.delay = 0;
break;
}
default:
break;
}
return sign_link;
}
static void ipaccess_sign_link_down(struct e1inp_line *line)
{
/* No matter what link went down, we close both signal links. */
struct e1inp_ts *ts = &line->ts[E1INP_SIGN_OML-1];
struct e1inp_sign_link *link;
llist_for_each_entry(link, &ts->sign.sign_links, list) {
struct gsm_bts *bts = link->trx->bts;
ipaccess_drop_oml(bts);
/* Yes, we only use the first element of the list. */
break;
}
}
/* This function is called if we receive one OML/RSL message. */
static int ipaccess_sign_link(struct msgb *msg)
{
int ret = 0;
struct e1inp_sign_link *link = msg->dst;
struct e1inp_ts *e1i_ts = link->ts;
switch (link->type) {
case E1INP_SIGN_RSL:
if (!(link->trx->bts->ip_access.flags &
(RSL_UP << link->trx->nr))) {
e1inp_event(e1i_ts, S_L_INP_TEI_UP,
link->tei, link->sapi);
link->trx->bts->ip_access.flags |=
(RSL_UP << link->trx->nr);
}
ret = abis_rsl_rcvmsg(msg);
break;
case E1INP_SIGN_OML:
if (!(link->trx->bts->ip_access.flags & OML_UP)) {
e1inp_event(e1i_ts, S_L_INP_TEI_UP,
link->tei, link->sapi);
link->trx->bts->ip_access.flags |= OML_UP;
}
ret = abis_nm_rcvmsg(msg);
break;
default:
LOGP(DLINP, LOGL_ERROR, "Unknown signal link type %d\n",
link->type);
msgb_free(msg);
break;
}
return ret;
}
/* not static, ipaccess-config needs it. */
struct e1inp_line_ops ipaccess_e1inp_line_ops = {
.cfg = {
.ipa = {
.addr = "0.0.0.0",
.role = E1INP_LINE_R_BSC,
},
},
.sign_link_up = ipaccess_sign_link_up,
.sign_link_down = ipaccess_sign_link_down,
.sign_link = ipaccess_sign_link,
};
static void bts_model_nanobts_e1line_bind_ops(struct e1inp_line *line)
{
e1inp_line_bind_ops(line, &ipaccess_e1inp_line_ops);
}

File diff suppressed because it is too large Load Diff

View File

@@ -25,22 +25,16 @@
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/abis_nm.h>
#include <osmocom/abis/e1_input.h>
#include <openbsc/e1_input.h>
#include <openbsc/signal.h>
static int bts_model_bs11_start(struct gsm_network *net);
static void bts_model_bs11_e1line_bind_ops(struct e1inp_line *line)
{
e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
}
static struct gsm_bts_model model_bs11 = {
.type = GSM_BTS_TYPE_BS11,
.name = "bs11",
.start = bts_model_bs11_start,
.oml_rcvmsg = &abis_nm_rcvmsg,
.e1line_bind_ops = bts_model_bs11_e1line_bind_ops,
.nm_att_tlvdef = {
.def = {
[NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TLV },
@@ -548,7 +542,7 @@ static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
{
struct gsm_bts *bts;
if (subsys != SS_L_GLOBAL)
if (subsys != SS_GLOBAL)
return 0;
switch (signal) {
@@ -568,11 +562,11 @@ static int inp_sig_cb(unsigned int subsys, unsigned int signal,
{
struct input_signal_data *isd = signal_data;
if (subsys != SS_L_INPUT)
if (subsys != SS_INPUT)
return 0;
switch (signal) {
case S_L_INP_TEI_UP:
case S_INP_TEI_UP:
switch (isd->link_type) {
case E1INP_SIGN_OML:
if (isd->trx->bts->type == GSM_BTS_TYPE_BS11)
@@ -592,8 +586,8 @@ static int bts_model_bs11_start(struct gsm_network *net)
gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HOPPING);
gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HSCSD);
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL);
osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
osmo_signal_register_handler(SS_GLOBAL, gbl_sig_cb, NULL);
return 0;
}

View File

@@ -30,7 +30,6 @@
#include <openbsc/abis_nm.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/debug.h>
#include <openbsc/rtp_proxy.h>
#include <openbsc/signal.h>
#include <osmocom/core/talloc.h>
@@ -310,12 +309,6 @@ void lchan_free(struct gsm_lchan *lchan)
osmo_signal_dispatch(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, &sig);
}
if (lchan->abis_ip.rtp_socket) {
LOGP(DRLL, LOGL_ERROR, "%s RTP Proxy Socket remained open.\n",
gsm_lchan_name(lchan));
rtp_socket_free(lchan->abis_ip.rtp_socket);
lchan->abis_ip.rtp_socket = NULL;
}
/* stop the timer */
osmo_timer_del(&lchan->T3101);
@@ -344,8 +337,8 @@ void lchan_free(struct gsm_lchan *lchan)
lchan->conn = NULL;
}
lchan->sacch_deact = 0;
lchan->release_mode = 0;
lchan->sach_deact = 0;
lchan->release_reason = 0;
/* FIXME: ts_free() the timeslot, if we're the last logical
* channel using it */
@@ -369,11 +362,6 @@ void lchan_reset(struct gsm_lchan *lchan)
lchan->type = GSM_LCHAN_NONE;
lchan->state = LCHAN_S_NONE;
if (lchan->abis_ip.rtp_socket) {
rtp_socket_free(lchan->abis_ip.rtp_socket);
lchan->abis_ip.rtp_socket = NULL;
}
}
/* release the next allocated SAPI or return 0 */
@@ -389,7 +377,7 @@ static int _lchan_release_next_sapi(struct gsm_lchan *lchan)
link_id = sapi;
if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H)
link_id |= 0x40;
rsl_release_request(lchan, link_id, lchan->release_mode);
rsl_release_request(lchan, link_id, lchan->release_reason);
return 0;
}
@@ -403,12 +391,12 @@ static void _lchan_handle_release(struct gsm_lchan *lchan)
if (_lchan_release_next_sapi(lchan) == 0)
return;
if (lchan->sacch_deact) {
if (lchan->sach_deact) {
gsm48_send_rr_release(lchan);
return;
}
rsl_release_request(lchan, 0, lchan->release_mode);
rsl_release_request(lchan, 0, lchan->release_reason);
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
}
@@ -424,14 +412,14 @@ int rsl_lchan_rll_release(struct gsm_lchan *lchan, uint8_t link_id)
}
/* Consider releasing the channel now */
int lchan_release(struct gsm_lchan *lchan, int sacch_deact, int mode)
int lchan_release(struct gsm_lchan *lchan, int sach_deact, int reason)
{
DEBUGP(DRLL, "%s starting release sequence\n", gsm_lchan_name(lchan));
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
lchan->conn = NULL;
lchan->release_mode = mode;
lchan->sacch_deact = sacch_deact;
lchan->release_reason = reason;
lchan->sach_deact = sach_deact;
_lchan_handle_release(lchan);
return 1;
}

View File

@@ -24,14 +24,13 @@
#include <netinet/in.h>
#include <openbsc/gsm_data.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/abis/trau_frame.h>
#include <openbsc/e1_input.h>
#include <openbsc/trau_frame.h>
#include <openbsc/trau_mux.h>
#include <openbsc/misdn.h>
#include <osmocom/abis/ipaccess.h>
#include <openbsc/ipaccess.h>
#include <osmocom/core/talloc.h>
#include <openbsc/debug.h>
#include <openbsc/abis_rsl.h>
#define SAPI_L2ML 0
#define SAPI_OML 62
@@ -47,17 +46,17 @@ int e1_reconfig_ts(struct gsm_bts_trx_ts *ts)
struct e1inp_line *line;
struct e1inp_ts *e1_ts;
DEBUGP(DLMI, "e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr);
DEBUGP(DMI, "e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr);
if (!e1_link->e1_ts) {
LOGP(DLINP, LOGL_ERROR, "TS (%u/%u/%u) without E1 timeslot?\n",
LOGP(DINP, LOGL_ERROR, "TS (%u/%u/%u) without E1 timeslot?\n",
ts->nr, ts->trx->nr, ts->trx->bts->nr);
return 0;
}
line = e1inp_line_find(e1_link->e1_nr);
line = e1inp_line_get(e1_link->e1_nr);
if (!line) {
LOGP(DLINP, LOGL_ERROR, "TS (%u/%u/%u) referring to "
LOGP(DINP, LOGL_ERROR, "TS (%u/%u/%u) referring to "
"non-existing E1 line %u\n", ts->nr, ts->trx->nr,
ts->trx->bts->nr, e1_link->e1_nr);
return -ENOMEM;
@@ -67,7 +66,7 @@ int e1_reconfig_ts(struct gsm_bts_trx_ts *ts)
case GSM_PCHAN_TCH_F:
case GSM_PCHAN_TCH_H:
e1_ts = &line->ts[e1_link->e1_ts-1];
e1inp_ts_config_trau(e1_ts, line, subch_cb);
e1inp_ts_config(e1_ts, line, E1INP_TS_TYPE_TRAU);
subch_demux_activate(&e1_ts->trau.demux, e1_link->e1_ts_ss);
break;
default:
@@ -86,28 +85,28 @@ int e1_reconfig_trx(struct gsm_bts_trx *trx)
int i;
if (!e1_link->e1_ts) {
LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link without "
LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link without "
"timeslot?\n", trx->bts->nr, trx->nr);
return -EINVAL;
}
/* RSL Link */
line = e1inp_line_find(e1_link->e1_nr);
line = e1inp_line_get(e1_link->e1_nr);
if (!line) {
LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link referring "
LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link referring "
"to non-existing E1 line %u\n", trx->bts->nr,
trx->nr, e1_link->e1_nr);
return -ENOMEM;
}
sign_ts = &line->ts[e1_link->e1_ts-1];
e1inp_ts_config_sign(sign_ts, line);
e1inp_ts_config(sign_ts, line, E1INP_TS_TYPE_SIGN);
/* Ericsson RBS have a per-TRX OML link in parallel to RSL */
if (trx->bts->type == GSM_BTS_TYPE_RBS2000) {
struct e1inp_sign_link *oml_link;
oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, trx,
trx->rsl_tei, SAPI_OML);
if (!oml_link) {
LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) OML link creation "
LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) OML link creation "
"failed\n", trx->bts->nr, trx->nr);
return -ENOMEM;
}
@@ -118,7 +117,7 @@ int e1_reconfig_trx(struct gsm_bts_trx *trx)
rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
trx, trx->rsl_tei, SAPI_RSL);
if (!rsl_link) {
LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link creation "
LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link creation "
"failed\n", trx->bts->nr, trx->nr);
return -ENOMEM;
}
@@ -132,33 +131,6 @@ int e1_reconfig_trx(struct gsm_bts_trx *trx)
return 0;
}
/* this is the generic callback for all ISDN-based BTS. */
static int bts_isdn_sign_link(struct msgb *msg)
{
int ret = -EINVAL;
struct e1inp_sign_link *link = msg->dst;
struct gsm_bts *bts;
log_set_context(BSC_CTX_BTS, link->trx->bts);
switch (link->type) {
case E1INP_SIGN_OML:
bts = link->trx->bts;
ret = bts->model->oml_rcvmsg(msg);
break;
case E1INP_SIGN_RSL:
ret = abis_rsl_rcvmsg(msg);
break;
default:
LOGP(DLMI, LOGL_ERROR, "unknown link type %u\n", link->type);
break;
}
return ret;
}
struct e1inp_line_ops bts_isdn_e1inp_line_ops = {
.sign_link = bts_isdn_sign_link,
};
int e1_reconfig_bts(struct gsm_bts *bts)
{
struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
@@ -167,40 +139,27 @@ int e1_reconfig_bts(struct gsm_bts *bts)
struct e1inp_sign_link *oml_link;
struct gsm_bts_trx *trx;
DEBUGP(DLMI, "e1_reconfig_bts(%u)\n", bts->nr);
DEBUGP(DMI, "e1_reconfig_bts(%u)\n", bts->nr);
line = e1inp_line_find(e1_link->e1_nr);
if (!line) {
LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to "
"non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
return -ENOMEM;
}
if (!bts->model->e1line_bind_ops) {
LOGP(DLINP, LOGL_ERROR, "no callback to bind E1 line operations\n");
return -EINVAL;
}
if (!line->ops)
bts->model->e1line_bind_ops(line);
/* skip signal link initialization, this is done later for these BTS. */
if (bts->type == GSM_BTS_TYPE_NANOBTS ||
bts->type == GSM_BTS_TYPE_HSL_FEMTO)
return e1inp_line_update(line);
/* OML link */
if (!e1_link->e1_ts) {
LOGP(DLINP, LOGL_ERROR, "BTS %u OML link without timeslot?\n",
LOGP(DINP, LOGL_ERROR, "BTS %u OML link without timeslot?\n",
bts->nr);
return -EINVAL;
}
/* OML link */
line = e1inp_line_get(e1_link->e1_nr);
if (!line) {
LOGP(DINP, LOGL_ERROR, "BTS %u OML link referring to "
"non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
return -ENOMEM;
}
sign_ts = &line->ts[e1_link->e1_ts-1];
e1inp_ts_config_sign(sign_ts, line);
e1inp_ts_config(sign_ts, line, E1INP_TS_TYPE_SIGN);
oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
bts->c0, bts->oml_tei, SAPI_OML);
if (!oml_link) {
LOGP(DLINP, LOGL_ERROR, "BTS %u OML link creation failed\n",
LOGP(DINP, LOGL_ERROR, "BTS %u OML link creation failed\n",
bts->nr);
return -ENOMEM;
}
@@ -301,3 +260,37 @@ int e1_config(struct gsm_bts *bts, int cardnr, int release_l2)
return mi_setup(cardnr, line, release_l2);
}
#endif
/* configure pseudo E1 line in ip.access style and connect to BTS */
int ia_config_connect(struct gsm_bts *bts, struct sockaddr_in *sin)
{
struct e1inp_line *line;
struct e1inp_ts *sign_ts, *rsl_ts;
struct e1inp_sign_link *oml_link, *rsl_link;
line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
if (!line)
return -ENOMEM;
/* create E1 timeslots for signalling and TRAU frames */
e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_SIGN);
/* create signalling links for TS1 */
sign_ts = &line->ts[1-1];
rsl_ts = &line->ts[2-1];
oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
bts->c0, 0xff, 0);
rsl_link = e1inp_sign_link_create(rsl_ts, E1INP_SIGN_RSL,
bts->c0, 0, 0);
/* create back-links from bts/trx */
bts->oml_link = oml_link;
bts->c0->rsl_link = rsl_link;
/* default port at BTS for incoming connections is 3006 */
if (sin->sin_port == 0)
sin->sin_port = htons(3006);
return ipaccess_connect(line, sin);
}

View File

@@ -44,7 +44,7 @@ int ipacc_rtp_direct = 1;
static int gsm48_sendmsg(struct msgb *msg)
{
if (msg->lchan)
msg->dst = msg->lchan->ts->trx->rsl_link;
msg->trx = msg->lchan->ts->trx;
msg->l3h = msg->data;
return rsl_data_request(msg, 0);

View File

@@ -39,6 +39,7 @@
#include <openbsc/signal.h>
#include <osmocom/core/talloc.h>
#include <openbsc/transaction.h>
#include <openbsc/rtp_proxy.h>
struct bsc_handover {
struct llist_head list;

View File

@@ -74,12 +74,16 @@ static int freq_list_bmrel_set_arfcn(uint8_t *chan_list, unsigned int arfcn)
if (arfcn == min_arfcn)
return 0;
if (((arfcn - min_arfcn) & 1023) > 111) {
if (arfcn < min_arfcn) {
LOGP(DRR, LOGL_ERROR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn);
return -EINVAL;
}
if (arfcn > min_arfcn + 111) {
LOGP(DRR, LOGL_ERROR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn);
return -EINVAL;
}
bitno = (arfcn - min_arfcn) & 1023;
bitno = (arfcn - min_arfcn);
byte = bitno / 8;
bit = bitno % 8;
@@ -90,22 +94,18 @@ static int freq_list_bmrel_set_arfcn(uint8_t *chan_list, unsigned int arfcn)
/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
const struct gsm_bts *bts, int bis, int ter)
const struct gsm_bts *bts)
{
int i, rc, min = -1, max = -1, pgsm = 0;
int i, rc, min = 1024, max = -1;
memset(chan_list, 0, 16);
if (bts->band == GSM_BAND_900
&& bts->c0->arfcn >= 1 && bts->c0->arfcn <= 124)
pgsm = 1;
/* P-GSM-only handsets only support 'bit map 0 format' */
if (!bis && !ter && pgsm) {
/* GSM900-only handsets only support 'bit map 0 format' */
if (bts->band == GSM_BAND_900) {
chan_list[0] = 0;
for (i = 0; i < bv->data_len*8; i++) {
if (i >= 1 && i <= 124
&& bitvec_get_bit_pos(bv, i)) {
if (bitvec_get_bit_pos(bv, i)) {
rc = freq_list_bm0_set_arfcn(chan_list, i);
if (rc < 0)
return rc;
@@ -118,30 +118,10 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
chan_list[0] = 0x8e;
for (i = 0; i < bv->data_len*8; i++) {
/* in case of SI2 or SI5 allow all neighbours in same band
* in case of SI*bis, allow neighbours in same band ouside pgsm
* in case of SI*ter, allow neighbours in different bands
*/
if (bitvec_get_bit_pos(bv, i)
&& ((!bis && !ter && gsm_arfcn2band(i) == bts->band)
|| (bis && pgsm && gsm_arfcn2band(i) == bts->band && (i < 1 || i > 124))
|| (ter && gsm_arfcn2band(i) != bts->band))) {
/* 955..1023 < 0..885 */
if (min < 0)
if (bitvec_get_bit_pos(bv, i)) {
if (i < min)
min = i;
if (i >= 955 && min < 955)
min = i;
if (i >= 955 && min >= 955 && i < min)
min = i;
if (i < 955 && min < 955 && i < min)
min = i;
if (max < 0)
max = i;
if (i < 955 && max >= 955)
max = i;
if (i >= 955 && max >= 955 && i > max)
max = i;
if (i < 955 && max < 955 && i > max)
if (i > max)
max = i;
}
}
@@ -152,7 +132,7 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
return 0;
}
if (((max - min) & 1023) > 111) {
if ((max - min) > 111) {
LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, "
"distance > 111\n", min, max);
return -EINVAL;
@@ -163,11 +143,7 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
chan_list[2] = (min & 1) << 7;
for (i = 0; i < bv->data_len*8; i++) {
/* see notes above */
if (bitvec_get_bit_pos(bv, i)
&& ((!bis && !ter && gsm_arfcn2band(i) == bts->band)
|| (bis && pgsm && gsm_arfcn2band(i) == bts->band && (i < 1 || i > 124))
|| (ter && gsm_arfcn2band(i) != bts->band))) {
if (bitvec_get_bit_pos(bv, i)) {
rc = freq_list_bmrel_set_arfcn(chan_list, i);
if (rc < 0)
return rc;
@@ -178,7 +154,7 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
}
/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
/* static*/ int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts)
static int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
struct bitvec *bv = &bts->si_common.cell_alloc;
@@ -202,12 +178,11 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv,
}
/* then we generate a GSM 04.08 frequency list from the bitvec */
return bitvec2freq_list(chan_list, bv, bts, 0, 0);
return bitvec2freq_list(chan_list, bv, bts);
}
/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts,
int si5, int bis, int ter)
static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts, int si5)
{
struct gsm_bts *cur_bts;
struct bitvec *bv;
@@ -231,28 +206,7 @@ static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts,
}
/* then we generate a GSM 04.08 frequency list from the bitvec */
return bitvec2freq_list(chan_list, bv, bts, bis, ter);
}
static int list_arfcn(uint8_t *chan_list, uint8_t mask, char *text)
{
int n = 0, i;
struct gsm_sysinfo_freq freq[1024];
memset(freq, 0, sizeof(freq));
gsm48_decode_freq_list(freq, chan_list, 16, 0xce, 1);
for (i = 0; i < 1024; i++) {
if (freq[i].mask) {
if (!n)
LOGP(DRR, LOGL_INFO, "%s", text);
LOGPC(DRR, LOGL_INFO, " %d", i);
n++;
}
}
if (n)
LOGPC(DRR, LOGL_INFO, "\n");
return n;
return bitvec2freq_list(chan_list, bv, bts);
}
static int generate_si1(uint8_t *output, struct gsm_bts *bts)
@@ -271,7 +225,6 @@ static int generate_si1(uint8_t *output, struct gsm_bts *bts)
rc = generate_cell_chan_list(si1->cell_channel_description, bts);
if (rc < 0)
return rc;
list_arfcn(si1->cell_channel_description, 0xce, "Serving cell:");
si1->rach_control = bts->si_common.rach_control;
@@ -294,11 +247,9 @@ static int generate_si2(uint8_t *output, struct gsm_bts *bts)
si2->header.skip_indicator = 0;
si2->header.system_information = GSM48_MT_RR_SYSINFO_2;
rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts, 0, 0, 0);
rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts, 0);
if (rc < 0)
return rc;
list_arfcn(si2->bcch_frequency_list, 0xce,
"Neighbour cells in same band:");
si2->ncc_permitted = bts->si_common.ncc_permitted;
si2->rach_control = bts->si_common.rach_control;
@@ -306,65 +257,6 @@ static int generate_si2(uint8_t *output, struct gsm_bts *bts)
return sizeof(*si2);
}
static int generate_si2bis(uint8_t *output, struct gsm_bts *bts)
{
int rc;
struct gsm48_system_information_type_2bis *si2b =
(struct gsm48_system_information_type_2bis *) output;
int n;
memset(si2b, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
si2b->header.l2_plen = (22 << 2) | 1;
si2b->header.rr_protocol_discriminator = GSM48_PDISC_RR;
si2b->header.skip_indicator = 0;
si2b->header.system_information = GSM48_MT_RR_SYSINFO_2bis;
rc = generate_bcch_chan_list(si2b->bcch_frequency_list, bts, 0, 1, 0);
if (rc < 0)
return rc;
n = list_arfcn(si2b->bcch_frequency_list, 0xce,
"Neighbour cells in same band, but outside P-GSM:");
if (n) {
/* indicate in SI2 and SI2bis: there is an extension */
struct gsm48_system_information_type_2 *si2 =
(struct gsm48_system_information_type_2 *)
bts->si_buf[SYSINFO_TYPE_2];
si2->bcch_frequency_list[0] |= 0x20;
si2b->bcch_frequency_list[0] |= 0x20;
} else
bts->si_valid &= ~(1 << SYSINFO_TYPE_2bis);
si2b->rach_control = bts->si_common.rach_control;
return sizeof(*si2b);
}
static int generate_si2ter(uint8_t *output, struct gsm_bts *bts)
{
int rc;
struct gsm48_system_information_type_2ter *si2t =
(struct gsm48_system_information_type_2ter *) output;
int n;
memset(si2t, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
si2t->header.l2_plen = (22 << 2) | 1;
si2t->header.rr_protocol_discriminator = GSM48_PDISC_RR;
si2t->header.skip_indicator = 0;
si2t->header.system_information = GSM48_MT_RR_SYSINFO_2ter;
rc = generate_bcch_chan_list(si2t->ext_bcch_frequency_list, bts, 0, 0, 1);
if (rc < 0)
return rc;
n = list_arfcn(si2t->ext_bcch_frequency_list, 0x8e,
"Neighbour cells in different band:");
if (!n)
bts->si_valid &= ~(1 << SYSINFO_TYPE_2ter);
return sizeof(*si2t);
}
static struct gsm48_si_ro_info si_info = {
.selection_params = {
.present = 0,
@@ -411,13 +303,6 @@ static int generate_si3(uint8_t *output, struct gsm_bts *bts)
si3->cell_sel_par = bts->si_common.cell_sel_par;
si3->rach_control = bts->si_common.rach_control;
if ((bts->si_valid & (1 << SYSINFO_TYPE_2ter))) {
LOGP(DRR, LOGL_INFO, "SI 2ter is included.\n");
si_info.si2ter_indicator = 1;
} else {
si_info.si2ter_indicator = 0;
}
/* SI3 Rest Octets (10.5.2.34), containing
CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME
Power Offset, 2ter Indicator, Early Classmark Sending,
@@ -484,92 +369,9 @@ static int generate_si5(uint8_t *output, struct gsm_bts *bts)
si5->rr_protocol_discriminator = GSM48_PDISC_RR;
si5->skip_indicator = 0;
si5->system_information = GSM48_MT_RR_SYSINFO_5;
rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts, 1, 0, 0);
rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts, 1);
if (rc < 0)
return rc;
list_arfcn(si5->bcch_frequency_list, 0xce,
"Neighbour cells in same band:");
/* 04.08 9.1.37: L2 Pseudo Length of 18 */
return l2_plen;
}
static int generate_si5bis(uint8_t *output, struct gsm_bts *bts)
{
struct gsm48_system_information_type_5bis *si5b;
int rc, l2_plen = 18;
int n;
memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* ip.access nanoBTS needs l2_plen!! */
switch (bts->type) {
case GSM_BTS_TYPE_NANOBTS:
case GSM_BTS_TYPE_HSL_FEMTO:
*output++ = (l2_plen << 2) | 1;
l2_plen++;
break;
default:
break;
}
si5b = (struct gsm48_system_information_type_5bis *) output;
/* l2 pseudo length, not part of msg: 18 */
si5b->rr_protocol_discriminator = GSM48_PDISC_RR;
si5b->skip_indicator = 0;
si5b->system_information = GSM48_MT_RR_SYSINFO_5bis;
rc = generate_bcch_chan_list(si5b->bcch_frequency_list, bts, 1, 1, 0);
if (rc < 0)
return rc;
n = list_arfcn(si5b->bcch_frequency_list, 0xce,
"Neighbour cells in same band, but outside P-GSM:");
if (n) {
/* indicate in SI5 and SI5bis: there is an extension */
struct gsm48_system_information_type_5 *si5 =
(struct gsm48_system_information_type_5 *)
bts->si_buf[SYSINFO_TYPE_5];
si5->bcch_frequency_list[0] |= 0x20;
si5b->bcch_frequency_list[0] |= 0x20;
} else
bts->si_valid &= ~(1 << SYSINFO_TYPE_5bis);
/* 04.08 9.1.37: L2 Pseudo Length of 18 */
return l2_plen;
}
static int generate_si5ter(uint8_t *output, struct gsm_bts *bts)
{
struct gsm48_system_information_type_5ter *si5t;
int rc, l2_plen = 18;
int n;
memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* ip.access nanoBTS needs l2_plen!! */
switch (bts->type) {
case GSM_BTS_TYPE_NANOBTS:
case GSM_BTS_TYPE_HSL_FEMTO:
*output++ = (l2_plen << 2) | 1;
l2_plen++;
break;
default:
break;
}
si5t = (struct gsm48_system_information_type_5ter *) output;
/* l2 pseudo length, not part of msg: 18 */
si5t->rr_protocol_discriminator = GSM48_PDISC_RR;
si5t->skip_indicator = 0;
si5t->system_information = GSM48_MT_RR_SYSINFO_5ter;
rc = generate_bcch_chan_list(si5t->bcch_frequency_list, bts, 1, 0, 1);
if (rc < 0)
return rc;
n = list_arfcn(si5t->bcch_frequency_list, 0x8e,
"Neighbour cells in different band:");
if (!n)
bts->si_valid &= ~(1 << SYSINFO_TYPE_5ter);
/* 04.08 9.1.37: L2 Pseudo Length of 18 */
return l2_plen;
@@ -618,7 +420,7 @@ static struct gsm48_si13_info si13_default = {
.t3192 = 200,
.drx_timer_max = 3,
.bs_cv_max = 15,
.ext_info_present = 0,
.ext_info_present = 1,
.ext_info = {
/* The values below are just guesses ! */
.egprs_supported = 0,
@@ -678,13 +480,9 @@ typedef int (*gen_si_fn_t)(uint8_t *output, struct gsm_bts *bts);
static const gen_si_fn_t gen_si_fn[_MAX_SYSINFO_TYPE] = {
[SYSINFO_TYPE_1] = &generate_si1,
[SYSINFO_TYPE_2] = &generate_si2,
[SYSINFO_TYPE_2bis] = &generate_si2bis,
[SYSINFO_TYPE_2ter] = &generate_si2ter,
[SYSINFO_TYPE_3] = &generate_si3,
[SYSINFO_TYPE_4] = &generate_si4,
[SYSINFO_TYPE_5] = &generate_si5,
[SYSINFO_TYPE_5bis] = &generate_si5bis,
[SYSINFO_TYPE_5ter] = &generate_si5ter,
[SYSINFO_TYPE_6] = &generate_si6,
[SYSINFO_TYPE_13] = &generate_si13,
};

View File

@@ -1,6 +1,6 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
noinst_LIBRARIES = libcommon.a

View File

@@ -86,11 +86,12 @@ enum node_type bsc_vty_go_parent(struct vty *vty)
case PGROUP_NODE:
vty->node = NAT_NODE;
break;
case MSC_NODE:
vty->node = CONFIG_NODE;
break;
case TRUNK_NODE:
vty->node = MGCP_NODE;
break;
case MSC_NODE:
case MNCC_INT_NODE:
default:
vty->node = CONFIG_NODE;
}
@@ -150,6 +151,7 @@ gDEFUN(ournode_exit,
case NS_NODE:
case BSSGP_NODE:
case NAT_NODE:
case BSC_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
@@ -160,7 +162,6 @@ gDEFUN(ournode_exit,
vty->index = NULL;
break;
case MSC_NODE:
case MNCC_INT_NODE:
vty->node = CONFIG_NODE;
break;
case TRUNK_NODE:
@@ -197,7 +198,7 @@ gDEFUN(ournode_end,
case NAT_BSC_NODE:
case PGROUP_NODE:
case MSC_NODE:
case MNCC_INT_NODE:
case BSC_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
vty->index = NULL;

View File

@@ -95,6 +95,26 @@ static const struct log_info_cat default_categories[] = {
.description = "Radio Measurement Processing",
.enabled = 0, .loglevel = LOGL_NOTICE,
},
[DMI] = {
.name = "DMI",
.description = "A-bis Input Driver for Signalling",
.enabled = 0, .loglevel = LOGL_NOTICE,
},
[DMIB] = {
.name = "DMIB",
.description = "A-bis Input Driver for B-Channels (voice)",
.enabled = 0, .loglevel = LOGL_NOTICE,
},
[DMUX] = {
.name = "DMUX",
.description = "A-bis B-Subchannel TRAU Frame Multiplex",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DINP] = {
.name = "DINP",
.description = "A-bis Intput Subsystem",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
[DSCCP] = {
.name = "DSCCP",
.description = "SCCP Protocol",

View File

@@ -86,6 +86,7 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
}
/* Init back pointer */
net->bsc_data->auto_off_timeout = -1;
net->bsc_data->network = net;
INIT_LLIST_HEAD(&net->bsc_data->mscs);
@@ -187,7 +188,6 @@ static const struct value_string bts_types[] = {
{ GSM_BTS_TYPE_NANOBTS, "nanobts" },
{ GSM_BTS_TYPE_RBS2000, "rbs2000" },
{ GSM_BTS_TYPE_HSL_FEMTO, "hsl_femto" },
{ GSM_BTS_TYPE_NOKIA_SITE, "nokia_site" },
{ 0, NULL }
};
@@ -341,14 +341,13 @@ int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type)
bts->oml_tei = 0xff;
bts->c0->nominal_power = 23;
break;
case GSM_BTS_TYPE_BS11:
case GSM_BTS_TYPE_UNKNOWN:
break;
case GSM_BTS_TYPE_RBS2000:
INIT_LLIST_HEAD(&bts->rbs2000.is.conn_groups);
INIT_LLIST_HEAD(&bts->rbs2000.con.conn_groups);
break;
case GSM_BTS_TYPE_BS11:
case GSM_BTS_TYPE_UNKNOWN:
case GSM_BTS_TYPE_NOKIA_SITE:
break;
}
return 0;
@@ -395,6 +394,8 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ
INIT_LLIST_HEAD(&bts->abis_queue);
INIT_LLIST_HEAD(&bts->loc_list);
return bts;
}

View File

@@ -245,7 +245,7 @@ void gsm_bts_mo_reset(struct gsm_bts *bts)
}
}
struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num)
struct gsm_bts_trx *gsm_bts_trx_num(struct gsm_bts *bts, int num)
{
struct gsm_bts_trx *trx;
@@ -262,7 +262,7 @@ struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num)
static char ts2str[255];
char *gsm_trx_name(const struct gsm_bts_trx *trx)
char *gsm_trx_name(struct gsm_bts_trx *trx)
{
snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d)",
trx->bts->nr, trx->nr);
@@ -271,7 +271,7 @@ char *gsm_trx_name(const struct gsm_bts_trx *trx)
}
char *gsm_ts_name(const struct gsm_bts_trx_ts *ts)
char *gsm_ts_name(struct gsm_bts_trx_ts *ts)
{
snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)",
ts->trx->bts->nr, ts->trx->nr, ts->nr);
@@ -279,7 +279,7 @@ char *gsm_ts_name(const struct gsm_bts_trx_ts *ts)
return ts2str;
}
char *gsm_lchan_name(const struct gsm_lchan *lchan)
char *gsm_lchan_name(struct gsm_lchan *lchan)
{
struct gsm_bts_trx_ts *ts = lchan->ts;
@@ -292,7 +292,7 @@ char *gsm_lchan_name(const struct gsm_lchan *lchan)
/* obtain the MO structure for a given object instance */
struct gsm_abis_mo *
gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
const struct abis_om_obj_inst *obj_inst)
struct abis_om_obj_inst *obj_inst)
{
struct gsm_bts_trx *trx;
struct gsm_abis_mo *mo = NULL;
@@ -373,7 +373,7 @@ gsm_objclass2mo(struct gsm_bts *bts, uint8_t obj_class,
/* obtain the gsm_nm_state data structure for a given object instance */
struct gsm_nm_state *
gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
const struct abis_om_obj_inst *obj_inst)
struct abis_om_obj_inst *obj_inst)
{
struct gsm_abis_mo *mo;
@@ -387,7 +387,7 @@ gsm_objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
/* obtain the in-memory data structure of a given object instance */
void *
gsm_objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
const struct abis_om_obj_inst *obj_inst)
struct abis_om_obj_inst *obj_inst)
{
struct gsm_bts_trx *trx;
void *obj = NULL;

View File

@@ -54,11 +54,9 @@ int make_sock(struct osmo_fd *bfd, int proto,
case IPPROTO_UDP:
type = SOCK_DGRAM;
break;
#ifdef IPPROTO_GRE
case IPPROTO_GRE:
type = SOCK_RAW;
break;
#endif
default:
return -EINVAL;
}
@@ -70,7 +68,7 @@ int make_sock(struct osmo_fd *bfd, int proto,
bfd->priv_nr = priv_nr;
if (bfd->fd < 0) {
LOGP(DLINP, LOGL_ERROR, "could not create socket.\n");
LOGP(DINP, LOGL_ERROR, "could not create socket.\n");
return -EIO;
}
@@ -86,7 +84,7 @@ int make_sock(struct osmo_fd *bfd, int proto,
ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
LOGP(DLINP, LOGL_ERROR, "could not bind socket %s\n",
LOGP(DINP, LOGL_ERROR, "could not bind socket %s\n",
strerror(errno));
close(bfd->fd);
return -EIO;

Some files were not shown because too many files have changed in this diff Show More