From 08f95b2ac7f377f98f83761b52027b88824d7a64 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 13 Oct 2008 09:02:02 +0200 Subject: initial import of gssm-v0.1.1a --- gssm/AUTHORS | 4 + gssm/ChangeLog | 0 gssm/LICENSE | 34 + gssm/Makefile.am | 3 + gssm/Makefile.common | 2 + gssm/NEWS | 0 gssm/README | 247 +++ gssm/TODO | 1 + gssm/bootstrap | 7 + gssm/config/Makefile.am | 61 + gssm/config/acx_pthread.m4 | 190 +++ gssm/config/bnv_have_qt.m4 | 404 +++++ gssm/config/cppunit.m4 | 80 + gssm/config/gr_as.m4 | 34 + gssm/config/gr_boost.m4 | 70 + gssm/config/gr_check_mc4020.m4 | 37 + gssm/config/gr_check_shm_open.m4 | 29 + gssm/config/gr_check_usrp.m4 | 32 + gssm/config/gr_doxygen.m4 | 56 + gssm/config/gr_gprof.m4 | 72 + gssm/config/gr_omnithread.m4 | 51 + gssm/config/gr_pwin32.m4 | 146 ++ gssm/config/gr_python.m4 | 104 ++ gssm/config/gr_scripting.m4 | 30 + gssm/config/gr_set_md_cpu.m4 | 41 + gssm/config/gr_swig.m4 | 85 + gssm/config/gr_sysv_shm.m4 | 36 + gssm/config/lf_cc.m4 | 42 + gssm/config/lf_cxx.m4 | 121 ++ gssm/config/lf_warnings.m4 | 128 ++ gssm/config/lf_x11.m4 | 39 + gssm/config/mkstemp.m4 | 89 ++ gssm/config/onceonly.m4 | 63 + gssm/config/pkg.m4 | 68 + gssm/config/usrp_fusb_tech.m4 | 54 + gssm/config/usrp_libusb.m4 | 38 + gssm/config/usrp_sdcc.m4 | 67 + gssm/configure.ac | 101 ++ gssm/patch/wireshark-0.99.5-gssm.patch | 2669 ++++++++++++++++++++++++++++++++ gssm/src/Makefile.am | 4 + gssm/src/lib/Makefile.am | 44 + gssm/src/lib/buffer.h | 4 + gssm/src/lib/burst_types.h | 217 +++ gssm/src/lib/bursts.cc | 153 ++ gssm/src/lib/bursts.h | 10 + gssm/src/lib/cch.cc | 460 ++++++ gssm/src/lib/cch.h | 42 + gssm/src/lib/display.cc | 46 + gssm/src/lib/display.h | 4 + gssm/src/lib/gsm_constants.h | 76 + gssm/src/lib/gssm.i | 28 + gssm/src/lib/gssm_sink.cc | 764 +++++++++ gssm/src/lib/gssm_sink.h | 125 ++ gssm/src/lib/gssm_state.h | 9 + gssm/src/lib/rr_decode.cc | 236 +++ gssm/src/lib/rr_decode.h | 4 + gssm/src/lib/rrm.h | 22 + gssm/src/lib/sch.cc | 320 ++++ gssm/src/lib/sch.h | 3 + gssm/src/lib/tun.cc | 125 ++ gssm/src/lib/tun.h | 4 + gssm/src/mktun/Makefile.am | 7 + gssm/src/mktun/mktun.c | 125 ++ gssm/src/python/file_gssm.py | 45 + gssm/src/python/file_stats.py | 46 + gssm/src/python/gssm_stats.py | 85 + gssm/src/python/gssm_usrp.py | 63 + 67 files changed, 8406 insertions(+) create mode 100644 gssm/AUTHORS create mode 100644 gssm/ChangeLog create mode 100644 gssm/LICENSE create mode 100644 gssm/Makefile.am create mode 100644 gssm/Makefile.common create mode 100644 gssm/NEWS create mode 100644 gssm/README create mode 100644 gssm/TODO create mode 100755 gssm/bootstrap create mode 100644 gssm/config/Makefile.am create mode 100644 gssm/config/acx_pthread.m4 create mode 100644 gssm/config/bnv_have_qt.m4 create mode 100644 gssm/config/cppunit.m4 create mode 100644 gssm/config/gr_as.m4 create mode 100644 gssm/config/gr_boost.m4 create mode 100644 gssm/config/gr_check_mc4020.m4 create mode 100644 gssm/config/gr_check_shm_open.m4 create mode 100644 gssm/config/gr_check_usrp.m4 create mode 100644 gssm/config/gr_doxygen.m4 create mode 100644 gssm/config/gr_gprof.m4 create mode 100644 gssm/config/gr_omnithread.m4 create mode 100644 gssm/config/gr_pwin32.m4 create mode 100644 gssm/config/gr_python.m4 create mode 100644 gssm/config/gr_scripting.m4 create mode 100644 gssm/config/gr_set_md_cpu.m4 create mode 100644 gssm/config/gr_swig.m4 create mode 100644 gssm/config/gr_sysv_shm.m4 create mode 100644 gssm/config/lf_cc.m4 create mode 100644 gssm/config/lf_cxx.m4 create mode 100644 gssm/config/lf_warnings.m4 create mode 100644 gssm/config/lf_x11.m4 create mode 100644 gssm/config/mkstemp.m4 create mode 100644 gssm/config/onceonly.m4 create mode 100644 gssm/config/pkg.m4 create mode 100644 gssm/config/usrp_fusb_tech.m4 create mode 100644 gssm/config/usrp_libusb.m4 create mode 100644 gssm/config/usrp_sdcc.m4 create mode 100644 gssm/configure.ac create mode 100644 gssm/patch/wireshark-0.99.5-gssm.patch create mode 100644 gssm/src/Makefile.am create mode 100644 gssm/src/lib/Makefile.am create mode 100644 gssm/src/lib/buffer.h create mode 100644 gssm/src/lib/burst_types.h create mode 100644 gssm/src/lib/bursts.cc create mode 100644 gssm/src/lib/bursts.h create mode 100644 gssm/src/lib/cch.cc create mode 100644 gssm/src/lib/cch.h create mode 100644 gssm/src/lib/display.cc create mode 100644 gssm/src/lib/display.h create mode 100644 gssm/src/lib/gsm_constants.h create mode 100644 gssm/src/lib/gssm.i create mode 100644 gssm/src/lib/gssm_sink.cc create mode 100644 gssm/src/lib/gssm_sink.h create mode 100644 gssm/src/lib/gssm_state.h create mode 100644 gssm/src/lib/rr_decode.cc create mode 100644 gssm/src/lib/rr_decode.h create mode 100644 gssm/src/lib/rrm.h create mode 100644 gssm/src/lib/sch.cc create mode 100644 gssm/src/lib/sch.h create mode 100644 gssm/src/lib/tun.cc create mode 100644 gssm/src/lib/tun.h create mode 100644 gssm/src/mktun/Makefile.am create mode 100644 gssm/src/mktun/mktun.c create mode 100755 gssm/src/python/file_gssm.py create mode 100755 gssm/src/python/file_stats.py create mode 100755 gssm/src/python/gssm_stats.py create mode 100755 gssm/src/python/gssm_usrp.py diff --git a/gssm/AUTHORS b/gssm/AUTHORS new file mode 100644 index 0000000..5d2553d --- /dev/null +++ b/gssm/AUTHORS @@ -0,0 +1,4 @@ +Josh Lackey + +The functions mm_demod() and quad_demod() are dervied from the corresponding +functions in the GNU Radio project. diff --git a/gssm/ChangeLog b/gssm/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/gssm/LICENSE b/gssm/LICENSE new file mode 100644 index 0000000..db9d807 --- /dev/null +++ b/gssm/LICENSE @@ -0,0 +1,34 @@ +Copyright (c) 2007, Joshua Lackey (jl@thre.at) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Threat Security nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-- + +The functions mm_demod() and quad_demod() in gssm_sink.cc are derived from the +corresponding functions in the GNU Radio project. + diff --git a/gssm/Makefile.am b/gssm/Makefile.am new file mode 100644 index 0000000..90b432f --- /dev/null +++ b/gssm/Makefile.am @@ -0,0 +1,3 @@ +include $(top_srcdir)/Makefile.common + +SUBDIRS = src diff --git a/gssm/Makefile.common b/gssm/Makefile.common new file mode 100644 index 0000000..ec4ab08 --- /dev/null +++ b/gssm/Makefile.common @@ -0,0 +1,2 @@ +grincludedir = $(includedir)/gnuradio +swigincludedir = $(grincludedir)/swig diff --git a/gssm/NEWS b/gssm/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/gssm/README b/gssm/README new file mode 100644 index 0000000..370a0a1 --- /dev/null +++ b/gssm/README @@ -0,0 +1,247 @@ +gssm -- Groupe Special (Software) Mobile + + or + +gssm -- The Global Software System for Mobile communications + +--- + +SUMMARY + +This package monitors GSM base station control channels. It uses the USRP +and various daughterboards to capture live data, GNU Radio and custom +modules to demodulate and decode the GSM packets, and Wireshark to display +the data. + +Get it here: http://thre.at/gsm. + +Talk about it here: gsm-subscribe@lists.segfault.net. + +More here: http://wiki.thc.org/gsm. + +--- + +WHAT + +This package monitors GSM base station control channels. It uses the USRP +and various daughterboards to capture live data, GNU Radio and custom +modules to demodulate and decode the GSM packets, and Wireshark to display +the data. + +This version of gssm decodes most of the control channels. The control +channels contain the information necessary for a mobile to communicate with +a base station. The control channels which gssm currently decodes are: + + FCCH The frequency correction channel. + SCH The synchronization channel. + BCCH The broadcast control channel. + PCH The paging channel. Downlink only, used to page mobiles. + AGCH The access grant channel. Downlink only, used to allocate + an SDCCH or directly a TCH. + SACCH Slow associated control channel. + SDCCH Stand-alone dedicated control channel. + +gssm displays the decoded data using Wireshark. Not only does this give us a +very nice graphical front end to examine the dissected packets, but Wireshark +already has quite a bit of code to dissect GSM data. Unfortunately, the +current implementation of Wireshark does not dissect packets unique to the +wireless interface. Up to now, there was no reason to include code to dissect +these packets. I include a patch for wireshark-0.99.5 which adds (partial) Um +packet dissection capability and a new custom ethertype to interface with the +USRP. + +While gssm has basic functionality now, it really is alpha-quality software +and there are a number of enhancements which must be made before it becomes +truly useful. + + 1. The Mueller and Muller clock recovery method doesn't always + handle the quarter-bits present in a GSM burst. A more reliable + method must be implemented. Until then, this software will suffer + from a large number of receive errors even with a high + signal-to-noise ratio. + + 2. Wireshark dissects most GSM packets except those specific to + the Um interface, the wireless interface between the mobile and + the BTS, the Base Transciever Station. + + a. I've only implemented a small portion of the Um + interface. Much more work must be done to complete this. + + b. Only the Bbis frame type is implemented. When packets + arrive in Wireshark which are "malformed" or with strange + protocol descriptors, it is because they were sent using + some other frame type. + + c. The interface between gssm and Wireshark is extremely + hacky, to say the least. It would be nice to eventually + standardize a GNU Radio interface for Wireshark. I also want + to clean up my Um interface and submit that there as well. + + 3. You need to find your local GSM tower by hand. Once you've + found it, you need to edit the python script and enter the + information by hand. It would be very nice if this information was + automatically generated. + + 4. The code is designed to support all frequency bands but I + haven't implemented anything but U.S. support. + + 5. This code is receive-only and currently can only monitor tower + to mobile transmissions. + + 6. Lots more. + +--- + +WHERE + +This code is being adopted by the GSM Scanner Project and will be used as +the base for further improvements. Questions and suggestions can certainly +be sent to me, but they also should be directed to the mailing list -- +gsm-subscribe@lists.segfault.net. Also, check out the wiki at +http://wiki.thc.org/gsm. + +The current version of the code can be found here: http://thre.at/gsm. +Updates and bug-fixes will be found at the GSM Scanner Project, +http://wiki.thc.org/gsm. + +--- + +HOW + +First, you must install the gssm package. + +1. First install GNU Radio. Any relatively recent GNU Radio build + should work. I've been testing on revision 5220. + +2. Now build gssm. It should be as simple to install as: + + jl@hackphoo ~ $ cd ~/src/gssm + jl@hackphoo ~/src/gssm $ ./bootstrap && ./configure && make && sudo make install + [...] + jl@hackphoo ~/src/gssm $ + +3. Get the latest version of Wireshark and apply the patch in the + patch directory and then build Wireshark as usual. Note that the + current version of this patch is for wireshark-0.99.5 and may not + apply cleanly to newer versions. + + jl@hackphoo ~ $ cd ~/src/wireshark-0.99.5 + jl@hackphoo ~/src/wireshark-0.99.5 $ patch -p1 < ~/src/gssm/patch/wireshark-0.99.5-gssm.patch + patching file epan/dissectors/packet-gsm_a.c + jl@hackphoo ~/src/wireshark-0.99.5 $ ./configure && make && sudo make install + [...] + jl@hackphoo ~/src/wireshark-0.99.5 $ + +4. gssm uses a TUN interface to send packets to Wireshark. You must + have the tun.ko kernel module loaded. + + jl@hackphoo:~$ lsmod | grep tun + tun 12032 0 + jl@hackphoo:~$ + + If the tun.ko kernel module is not loaded, you can try and load it + by hand. + + jl@hackphoo:~$ lsmod | grep tun + jl@hackphoo:~$ sudo modprobe tun + jl@hackphoo:~$ lsmod | grep tun + tun 12032 0 + jl@hackphoo:~$ + + If that doesn't work and you get a "FATAL: Module tun not found", + you are most likely going to have to rebuild your kernel and make + sure that you enable support for the TUN device. + + It appears that Ubuntu 7.04 supports the TUN device by default. + +5. It is possible to configure the TUN device so that any user, or + users in a certain group, can create and delete interfaces. + Unfortunately, it appears that no matter who creates the + interfaces only root can mark these interfaces up. + + Rather than require gssm to run as root, we instead use another + simpler program to create the interface and mark it up. This + program, mktun, was installed with gssm. + + jl@hackphoo:~$ /usr/local/bin/mktun --help + note: you must be root (except perhaps to delete the interface) + usage: mktun [--help | -h] | [--delete | -d] + jl@hackphoo:~$ sudo /usr/local/bin/mktun gsm + jl@hackphoo:~$ ifconfig + [...] + + gsm Link encap:Ethernet HWaddr 22:07:3F:7F:6A:EC + inet6 addr: fe80::2007:3fff:fe7f:6aec/64 Scope:Link + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:33324 errors:0 dropped:0 overruns:0 frame:0 + TX packets:0 errors:0 dropped:6 overruns:0 carrier:0 + collisions:0 txqueuelen:500 + RX bytes:1199664 (1.1 MiB) TX bytes:0 (0.0 b) + + [...] + jl@hackphoo:~$ + + You can always delete the interface when you want to get rid of it. + + jl@hackphoo:~$ sudo /usr/local/bin/mktun -d gsm + jl@hackphoo:~$ ifconfig | grep gsm + jl@hackphoo:~$ + +Now, demod some traffic. + +1. Since this program doesn't scan the GSM frequency ranges for you, you + must locate your closest tower by hand. There are instructions on how + to do this at http://wiki.thc.org/gsm. + + Essentially, use usrp_fft.py in the GSM frequency ranges + (http://en.wikipedia.org/wiki/GSM_frequency_ranges) and look for a peak + roughly 300kHz wide. The main channel on a base station, channel 0, + does not use frequency hopping so the peak of the signal you are + looking for should be constant. + + The M&M clock recovery occasionally fails to synchronize with bursts + and so you need a fairly strong signal to get good results with the + current code. Look for signals that are at least 20dB above the noise + floor. (!) + +2. The USRP daughterboards have a frequency offset error which differs + from board to board. Normally this error ranges from 4kHz to 32kHz. + The current code will demodulate data with offsets up to 32kHz but will + perform much better if you compensate for the offset. + + The GSM Scanner Project has a matlab script which will locate your + offset. This doesn't help if you don't own matlab. Currently, the + easiest alternative method is as follows. + + a. Use usrp_fft.py and set the decimation rate to 112. When + the frequency correction burst is transmitted it forms a peak + in the signal 62.5kHz above the center of the channel. + + b. Locate the 62.5kHz peak and eyeball the offset. You should + be able to estimate the offset within 10kHz or so. + +3. Enter in the frequency and the offset above into the script + gssm-v0.1/src/python/gssm_usrp.py. + +4. Start Wireshark and monitor the gsm interface. + +5. Start the gssm_usrp.py script. + + You should see a bunch of errors start flying by. This is expected + even when we aren't receiving bad data because of the fairly brain-dead + way the code determines if channels have data. Any data displayed in + Wireshark has been successfully Viterbi decoded and has survived a FIRE + parity check and is therefore, with extremely high-probability, valid. + So, don't worry about all the errors. There aren't really that many + and it doesn't affect the valid data anyway. + + If it is displayed incorrectly in Wireshark it is because I haven't + implemented frame types besides Bbis. + + You can expand most of the packets you see and you can use the + Wireshark filter functionality on quite a few of the GSM information + elements. + +6. Notice obvious errors. Write code to fix the errors. Send us patches. + + diff --git a/gssm/TODO b/gssm/TODO new file mode 100644 index 0000000..c3ca5b4 --- /dev/null +++ b/gssm/TODO @@ -0,0 +1 @@ +Lots. diff --git a/gssm/bootstrap b/gssm/bootstrap new file mode 100755 index 0000000..a725425 --- /dev/null +++ b/gssm/bootstrap @@ -0,0 +1,7 @@ +rm -rf config.cache autom4te*.cache + +aclocal -I config +autoconf +autoheader +libtoolize --automake +automake --add-missing diff --git a/gssm/config/Makefile.am b/gssm/config/Makefile.am new file mode 100644 index 0000000..ad85978 --- /dev/null +++ b/gssm/config/Makefile.am @@ -0,0 +1,61 @@ +# +# Copyright 2001 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +include $(top_srcdir)/Makefile.common + +# Install m4 macros in this directory +m4datadir = $(datadir)/aclocal + +# List your m4 macros here +m4macros = \ + acx_pthread.m4 \ + bnv_have_qt.m4 \ + cppunit.m4 \ + gr_as.m4 \ + gr_boost.m4 \ + gr_check_usrp.m4 \ + gr_check_mc4020.m4 \ + gr_check_shm_open.m4 \ + gr_doxygen.m4 \ + gr_gprof.m4 \ + gr_omnithread.m4 \ + gr_pwin32.m4 \ + gr_python.m4 \ + gr_scripting.m4 \ + gr_set_md_cpu.m4 \ + gr_swig.m4 \ + gr_sysv_shm.m4 \ + lf_cc.m4 \ + lf_cxx.m4 \ + lf_warnings.m4 \ + lf_x11.m4 \ + mkstemp.m4 \ + onceonly.m4 \ + pkg.m4 \ + usrp_fusb_tech.m4 \ + usrp_libusb.m4 \ + usrp_sdcc.m4 + + +# Don't install m4 macros anymore +# m4data_DATA = $(m4macros) + +EXTRA_DIST = $(m4macros) diff --git a/gssm/config/acx_pthread.m4 b/gssm/config/acx_pthread.m4 new file mode 100644 index 0000000..d318ab0 --- /dev/null +++ b/gssm/config/acx_pthread.m4 @@ -0,0 +1,190 @@ +dnl Available from the GNU Autoconf Macro Archive at: +dnl http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html +dnl +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/gssm/config/bnv_have_qt.m4 b/gssm/config/bnv_have_qt.m4 new file mode 100644 index 0000000..1469bfb --- /dev/null +++ b/gssm/config/bnv_have_qt.m4 @@ -0,0 +1,404 @@ +dnl Available from the GNU Autoconf Macro Archive at: +dnl http://www.gnu.org/software/ac-archive/htmldoc/bnv_have_qt.html +dnl +AC_DEFUN([BNV_HAVE_QT], +[ + dnl THANKS! This code includes bug fixes by: + dnl Tim McClarren. + + AC_REQUIRE([AC_PROG_CXX]) + AC_REQUIRE([AC_PATH_X]) + AC_REQUIRE([AC_PATH_XTRA]) + + AC_MSG_CHECKING(for Qt) + + AC_ARG_WITH([Qt-dir], + [ --with-Qt-dir=DIR DIR is equal to \$QTDIR if you have followed the + installation instructions of Trolltech. Header + files are in DIR/include, binary utilities are + in DIR/bin and the library is in DIR/lib]) + AC_ARG_WITH([Qt-include-dir], + [ --with-Qt-include-dir=DIR + Qt header files are in DIR]) + AC_ARG_WITH([Qt-bin-dir], + [ --with-Qt-bin-dir=DIR Qt utilities such as moc and uic are in DIR]) + AC_ARG_WITH([Qt-lib-dir], + [ --with-Qt-lib-dir=DIR The Qt library is in DIR]) + AC_ARG_WITH([Qt-lib], + [ --with-Qt-lib=LIB Use -lLIB to link with the Qt library]) + if test x"$with_Qt_dir" = x"no" || + test x"$with_Qt_include-dir" = x"no" || + test x"$with_Qt_bin_dir" = x"no" || + test x"$with_Qt_lib_dir" = x"no" || + test x"$with_Qt_lib" = x"no"; then + # user disabled Qt. Leave cache alone. + have_qt="User disabled Qt." + else + # "yes" is a bogus option + if test x"$with_Qt_dir" = xyes; then + with_Qt_dir= + fi + if test x"$with_Qt_include_dir" = xyes; then + with_Qt_include_dir= + fi + if test x"$with_Qt_bin_dir" = xyes; then + with_Qt_bin_dir= + fi + if test x"$with_Qt_lib_dir" = xyes; then + with_Qt_lib_dir= + fi + if test x"$with_Qt_lib" = xyes; then + with_Qt_lib= + fi + # No Qt unless we discover otherwise + have_qt=no + # Check whether we are requested to link with a specific version + if test x"$with_Qt_lib" != x; then + bnv_qt_lib="$with_Qt_lib" + fi + # Check whether we were supplied with an answer already + if test x"$with_Qt_dir" != x; then + have_qt=yes + bnv_qt_dir="$with_Qt_dir" + bnv_qt_include_dir="$with_Qt_dir/include" + bnv_qt_bin_dir="$with_Qt_dir/bin" + bnv_qt_lib_dir="$with_Qt_dir/lib" + # Only search for the lib if the user did not define one already + if test x"$bnv_qt_lib" = x; then + bnv_qt_lib="`ls $bnv_qt_lib_dir/libqt* | sed -n 1p | + sed s@$bnv_qt_lib_dir/lib@@ | [sed s@[.].*@@]`" + fi + bnv_qt_LIBS="-L$bnv_qt_lib_dir -l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + else + # Use cached value or do search, starting with suggestions from + # the command line + AC_CACHE_VAL(bnv_cv_have_qt, + [ + # We are not given a solution and there is no cached value. + bnv_qt_dir=NO + bnv_qt_include_dir=NO + bnv_qt_lib_dir=NO + if test x"$bnv_qt_lib" = x; then + bnv_qt_lib=NO + fi + BNV_PATH_QT_DIRECT + if test "$bnv_qt_dir" = NO || + test "$bnv_qt_include_dir" = NO || + test "$bnv_qt_lib_dir" = NO || + test "$bnv_qt_lib" = NO; then + # Problem with finding complete Qt. Cache the known absence of Qt. + bnv_cv_have_qt="have_qt=no" + else + # Record where we found Qt for the cache. + bnv_cv_have_qt="have_qt=yes \ + bnv_qt_dir=$bnv_qt_dir \ + bnv_qt_include_dir=$bnv_qt_include_dir \ + bnv_qt_bin_dir=$bnv_qt_bin_dir \ + bnv_qt_LIBS=\"$bnv_qt_LIBS\"" + fi + ])dnl + eval "$bnv_cv_have_qt" + fi # all $bnv_qt_* are set + fi # $have_qt reflects the system status + if test x"$have_qt" = xyes; then + QT_CXXFLAGS="-I$bnv_qt_include_dir" + QT_DIR="$bnv_qt_dir" + QT_LIBS="$bnv_qt_LIBS" + # If bnv_qt_dir is defined, utilities are expected to be in the + # bin subdirectory + if test x"$bnv_qt_dir" != x; then + if test -x "$bnv_qt_dir/bin/uic"; then + QT_UIC="$bnv_qt_dir/bin/uic" + else + # Old versions of Qt don't have uic + QT_UIC= + fi + QT_MOC="$bnv_qt_dir/bin/moc" + else + # Or maybe we are told where to look for the utilities + if test x"$bnv_qt_bin_dir" != x; then + if test -x "$bnv_qt_bin_dir/uic"; then + QT_UIC="$bnv_qt_bin_dir/uic" + else + # Old versions of Qt don't have uic + QT_UIC= + fi + QT_MOC="$bnv_qt_bin_dir/moc" + else + # Last possibility is that they are in $PATH + QT_UIC="`which uic`" + QT_MOC="`which moc`" + fi + fi + # All variables are defined, report the result + AC_MSG_RESULT([$have_qt: + QT_CXXFLAGS=$QT_CXXFLAGS + QT_DIR=$QT_DIR + QT_LIBS=$QT_LIBS + QT_UIC=$QT_UIC + QT_MOC=$QT_MOC]) + else + # Qt was not found + QT_CXXFLAGS= + QT_DIR= + QT_LIBS= + QT_UIC= + QT_MOC= + AC_MSG_RESULT($have_qt) + fi + AC_SUBST(QT_CXXFLAGS) + AC_SUBST(QT_DIR) + AC_SUBST(QT_LIBS) + AC_SUBST(QT_UIC) + AC_SUBST(QT_MOC) + + #### Being paranoid: + if test x"$have_qt" = xyes; then + AC_MSG_CHECKING(correct functioning of Qt installation) + AC_CACHE_VAL(bnv_cv_qt_test_result, + [ + cat > bnv_qt_test.h << EOF +#include +class Test : public QObject +{ +Q_OBJECT +public: + Test() {} + ~Test() {} +public slots: + void receive() {} +signals: + void send(); +}; +EOF + + cat > bnv_qt_main.$ac_ext << EOF +#include "bnv_qt_test.h" +#include +int main( int argc, char **argv ) +{ + QApplication app( argc, argv ); + Test t; + QObject::connect( &t, SIGNAL(send()), &t, SLOT(receive()) ); +} +EOF + + bnv_cv_qt_test_result="failure" + bnv_try_1="$QT_MOC bnv_qt_test.h -o moc_bnv_qt_test.$ac_ext >/dev/null 2>bnv_qt_test_1.out" + AC_TRY_EVAL(bnv_try_1) + bnv_err_1=`grep -v '^ *+' bnv_qt_test_1.out | grep -v "^bnv_qt_test.h\$"` + if test x"$bnv_err_1" != x; then + echo "$bnv_err_1" >&AC_FD_CC + echo "configure: could not run $QT_MOC on:" >&AC_FD_CC + cat bnv_qt_test.h >&AC_FD_CC + else + bnv_try_2="$CXX $QT_CXXFLAGS -c $CXXFLAGS -o moc_bnv_qt_test.o moc_bnv_qt_test.$ac_ext >/dev/null 2>bnv_qt_test_2.out" + AC_TRY_EVAL(bnv_try_2) + bnv_err_2=`grep -v '^ *+' bnv_qt_test_2.out | grep -v "^bnv_qt_test.{$ac_ext}\$"` + if test x"$bnv_err_2" != x; then + echo "$bnv_err_2" >&AC_FD_CC + echo "configure: could not compile:" >&AC_FD_CC + cat bnv_qt_test.$ac_ext >&AC_FD_CC + else + bnv_try_3="$CXX $QT_CXXFLAGS -c $CXXFLAGS -o bnv_qt_main.o bnv_qt_main.$ac_ext >/dev/null 2>bnv_qt_test_3.out" + AC_TRY_EVAL(bnv_try_3) + bnv_err_3=`grep -v '^ *+' bnv_qt_test_3.out | grep -v "^bnv_qt_main.{$ac_ext}\$"` + if test x"$bnv_err_3" != x; then + echo "$bnv_err_3" >&AC_FD_CC + echo "configure: could not compile:" >&AC_FD_CC + cat bnv_qt_main.$ac_ext >&AC_FD_CC + else + bnv_try_4="$CXX $QT_LIBS $LIBS -o bnv_qt_main bnv_qt_main.o moc_bnv_qt_test.o >/dev/null 2>bnv_qt_test_4.out" + AC_TRY_EVAL(bnv_try_4) + bnv_err_4=`grep -v '^ *+' bnv_qt_test_4.out` + if test x"$bnv_err_4" != x; then + echo "$bnv_err_4" >&AC_FD_CC + else + bnv_cv_qt_test_result="success" + fi + fi + fi + fi + ])dnl AC_CACHE_VAL bnv_cv_qt_test_result + AC_MSG_RESULT([$bnv_cv_qt_test_result]); + if test x"$bnv_cv_qt_test_result" = "xfailure"; then + # working Qt was not found + QT_CXXFLAGS= + QT_DIR= + QT_LIBS= + QT_UIC= + QT_MOC= + have_qt=no + AC_MSG_WARN([Failed to find matching components of a complete + Qt installation. Try using more options, + see ./configure --help.]) + fi + + rm -f bnv_qt_test.h moc_bnv_qt_test.$ac_ext moc_bnv_qt_test.o \ + bnv_qt_main.$ac_ext bnv_qt_main.o bnv_qt_main \ + bnv_qt_test_1.out bnv_qt_test_2.out bnv_qt_test_3.out bnv_qt_test_4.out + fi +]) + +dnl Internal subroutine of BNV_HAVE_QT +dnl Set bnv_qt_dir bnv_qt_include_dir bnv_qt_bin_dir bnv_qt_lib_dir bnv_qt_lib +dnl Copyright 2001 Bastiaan N. Veelo +AC_DEFUN([BNV_PATH_QT_DIRECT], +[ + ## Binary utilities ## + if test x"$with_Qt_bin_dir" != x; then + bnv_qt_bin_dir=$with_Qt_bin_dir + fi + ## Look for header files ## + if test x"$with_Qt_include_dir" != x; then + bnv_qt_include_dir="$with_Qt_include_dir" + else + # The following header file is expected to define QT_VERSION. + qt_direct_test_header=qglobal.h + # Look for the header file in a standard set of common directories. + bnv_include_path_list=" + /usr/include + `ls -dr /usr/include/qt* 2>/dev/null` + `ls -dr /usr/lib/qt*/include 2>/dev/null` + `ls -dr /usr/local/qt*/include 2>/dev/null` + `ls -dr /opt/qt*/include 2>/dev/null` + " + for bnv_dir in $bnv_include_path_list; do + if test -r "$bnv_dir/$qt_direct_test_header"; then + bnv_dirs="$bnv_dirs $bnv_dir" + fi + done + # Now look for the newest in this list + bnv_prev_ver=0 + for bnv_dir in $bnv_dirs; do + bnv_this_ver=`egrep -w '#define QT_VERSION' $bnv_dir/$qt_direct_test_header | sed s/'#define QT_VERSION'//` + if expr $bnv_this_ver '>' $bnv_prev_ver > /dev/null; then + bnv_qt_include_dir=$bnv_dir + bnv_prev_ver=$bnv_this_ver + fi + done + fi dnl Found header files. + + # Are these headers located in a traditional Trolltech installation? + # That would be $bnv_qt_include_dir stripped from its last element: + bnv_possible_qt_dir=`dirname $bnv_qt_include_dir` + if test -x $bnv_possible_qt_dir/bin/moc && + ls $bnv_possible_qt_dir/lib/libqt* > /dev/null; then + # Then the rest is a piece of cake + bnv_qt_dir=$bnv_possible_qt_dir + bnv_qt_bin_dir="$bnv_qt_dir/bin" + bnv_qt_lib_dir="$bnv_qt_dir/lib" + # Only look for lib if the user did not supply it already + if test x"$bnv_qt_lib" = xNO; then + bnv_qt_lib="`ls $bnv_qt_lib_dir/libqt* | sed -n 1p | + sed s@$bnv_qt_lib_dir/lib@@ | [sed s@[.].*@@]`" + fi + bnv_qt_LIBS="-L$bnv_qt_lib_dir -l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + else + # There is no valid definition for $QTDIR as Trolltech likes to see it + bnv_qt_dir= + ## Look for Qt library ## + if test x"$with_Qt_lib_dir" != x; then + bnv_qt_lib_dir="$with_Qt_lib_dir" + # Only look for lib if the user did not supply it already + if test x"$bnv_qt_lib" = xNO; then + bnv_qt_lib="`ls $bnv_qt_lib_dir/libqt* | sed -n 1p | + sed s@$bnv_qt_lib_dir/lib@@ | [sed s@[.].*@@]`" + fi + bnv_qt_LIBS="-L$bnv_qt_lib_dir -l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + else + # Normally, when there is no traditional Trolltech installation, + # the library is installed in a place where the linker finds it + # automatically. + # If the user did not define the library name, try with qt + if test x"$bnv_qt_lib" = xNO; then + bnv_qt_lib=qt + fi + qt_direct_test_header=qapplication.h + qt_direct_test_main=" + int argc; + char ** argv; + QApplication app(argc,argv); + " + # See if we find the library without any special options. + # Don't add top $LIBS permanently yet + bnv_save_LIBS="$LIBS" + LIBS="-l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + bnv_qt_LIBS="$LIBS" + bnv_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="-I$bnv_qt_include_dir" + AC_TRY_LINK([#include <$qt_direct_test_header>], + $qt_direct_test_main, + [ + # Success. + # We can link with no special library directory. + bnv_qt_lib_dir= + ], [ + # That did not work. Try the multi-threaded version + echo "Non-critical error, please neglect the above." >&AC_FD_CC + bnv_qt_lib=qt-mt + LIBS="-l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + AC_TRY_LINK([#include <$qt_direct_test_header>], + $qt_direct_test_main, + [ + # Success. + # We can link with no special library directory. + bnv_qt_lib_dir= + ], [ + # That did not work. Try the OpenGL version + echo "Non-critical error, please neglect the above." >&AC_FD_CC + bnv_qt_lib=qt-gl + LIBS="-l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + AC_TRY_LINK([#include <$qt_direct_test_header>], + $qt_direct_test_main, + [ + # Succes. + # We can link with no special library directory. + bnv_qt_lib_dir= + ], [ + # That did not work. Maybe a library version I don't know about? + echo "Non-critical error, please neglect the above." >&AC_FD_CC + # Look for some Qt lib in a standard set of common directories. + bnv_dir_list=" + `echo $bnv_qt_includes | sed ss/includess` + /lib + /usr/lib + /usr/local/lib + /opt/lib + `ls -dr /usr/lib/qt* 2>/dev/null` + `ls -dr /usr/local/qt* 2>/dev/null` + `ls -dr /opt/qt* 2>/dev/null` + " + for bnv_dir in $bnv_dir_list; do + if ls $bnv_dir/libqt*; then + # Gamble that it's the first one... + bnv_qt_lib="`ls $bnv_dir/libqt* | sed -n 1p | + sed s@$bnv_dir/lib@@ | sed s/[.].*//`" + bnv_qt_lib_dir="$bnv_dir" + break + fi + done + # Try with that one + LIBS="-l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + AC_TRY_LINK([#include <$qt_direct_test_header>], + $qt_direct_test_main, + [ + # Succes. + # We can link with no special library directory. + bnv_qt_lib_dir= + ], [ + # Leave bnv_qt_lib_dir defined + ]) + ]) + ]) + ]) + if test x"$bnv_qt_lib_dir" != x; then + bnv_qt_LIBS="-l$bnv_qt_lib_dir $LIBS" + else + bnv_qt_LIBS="$LIBS" + fi + LIBS="$bnv_save_LIBS" + CXXFLAGS="$bnv_save_CXXFLAGS" + fi dnl $with_Qt_lib_dir was not given + fi dnl Done setting up for non-traditional Trolltech installation +]) diff --git a/gssm/config/cppunit.m4 b/gssm/config/cppunit.m4 new file mode 100644 index 0000000..0991d51 --- /dev/null +++ b/gssm/config/cppunit.m4 @@ -0,0 +1,80 @@ +dnl +dnl AM_PATH_CPPUNIT(MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl +AC_DEFUN([AM_PATH_CPPUNIT], +[ + +AC_ARG_WITH(cppunit-prefix,[ --with-cppunit-prefix=PFX Prefix where CppUnit is installed (optional)], + cppunit_config_prefix="$withval", cppunit_config_prefix="") +AC_ARG_WITH(cppunit-exec-prefix,[ --with-cppunit-exec-prefix=PFX Exec prefix where CppUnit is installed (optional)], + cppunit_config_exec_prefix="$withval", cppunit_config_exec_prefix="") + + if test x$cppunit_config_exec_prefix != x ; then + cppunit_config_args="$cppunit_config_args --exec-prefix=$cppunit_config_exec_prefix" + if test x${CPPUNIT_CONFIG+set} != xset ; then + CPPUNIT_CONFIG=$cppunit_config_exec_prefix/bin/cppunit-config + fi + fi + if test x$cppunit_config_prefix != x ; then + cppunit_config_args="$cppunit_config_args --prefix=$cppunit_config_prefix" + if test x${CPPUNIT_CONFIG+set} != xset ; then + CPPUNIT_CONFIG=$cppunit_config_prefix/bin/cppunit-config + fi + fi + + AC_PATH_PROG(CPPUNIT_CONFIG, cppunit-config, no) + cppunit_version_min=$1 + + AC_MSG_CHECKING(for Cppunit - version >= $cppunit_version_min) + no_cppunit="" + if test "$CPPUNIT_CONFIG" = "no" ; then + no_cppunit=yes + else + CPPUNIT_CFLAGS=`$CPPUNIT_CONFIG --cflags` + CPPUNIT_LIBS=`$CPPUNIT_CONFIG --libs` + cppunit_version=`$CPPUNIT_CONFIG --version` + + cppunit_major_version=`echo $cppunit_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + cppunit_minor_version=`echo $cppunit_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + cppunit_micro_version=`echo $cppunit_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + cppunit_major_min=`echo $cppunit_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + cppunit_minor_min=`echo $cppunit_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + cppunit_micro_min=`echo $cppunit_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + cppunit_version_proper=`expr \ + $cppunit_major_version \> $cppunit_major_min \| \ + $cppunit_major_version \= $cppunit_major_min \& \ + $cppunit_minor_version \> $cppunit_minor_min \| \ + $cppunit_major_version \= $cppunit_major_min \& \ + $cppunit_minor_version \= $cppunit_minor_min \& \ + $cppunit_micro_version \>= $cppunit_micro_min ` + + if test "$cppunit_version_proper" = "1" ; then + AC_MSG_RESULT([$cppunit_major_version.$cppunit_minor_version.$cppunit_micro_version]) + else + AC_MSG_RESULT(no) + no_cppunit=yes + fi + fi + + if test "x$no_cppunit" = x ; then + ifelse([$2], , :, [$2]) + else + CPPUNIT_CFLAGS="" + CPPUNIT_LIBS="" + ifelse([$3], , :, [$3]) + fi + + AC_SUBST(CPPUNIT_CFLAGS) + AC_SUBST(CPPUNIT_LIBS) +]) + + + diff --git a/gssm/config/gr_as.m4 b/gssm/config/gr_as.m4 new file mode 100644 index 0000000..a069547 --- /dev/null +++ b/gssm/config/gr_as.m4 @@ -0,0 +1,34 @@ +# Figure out how to run the assembler. -*- Autoconf -*- + +# serial 2 + +# Copyright 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# I just copy and renamed this from automake-1.6.3 so we should work +# under both 1.4-p6 and later. -eb + +# GR_PROG_AS +# ---------- +AC_DEFUN([GR_PROG_AS], +[# By default we simply use the C compiler to build assembly code. +AC_REQUIRE([AC_PROG_CC]) +: ${CCAS='$(CC)'} +# Set ASFLAGS if not already set. +: ${CCASFLAGS='$(CFLAGS)'} +AC_SUBST(CCAS) +AC_SUBST(CCASFLAGS)]) diff --git a/gssm/config/gr_boost.m4 b/gssm/config/gr_boost.m4 new file mode 100644 index 0000000..dc44219 --- /dev/null +++ b/gssm/config/gr_boost.m4 @@ -0,0 +1,70 @@ +dnl +dnl Copyright 2004 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +AC_DEFUN([GR_REQUIRE_BOOST_INCLUDES], +[ + AC_LANG_PUSH(C++) + gr_boost_include_dir= + AC_ARG_WITH([boost-include-dir], + AC_HELP_STRING([--with-boost-include-dir=], + [path to boost c++ include files]), + [ + # "yes" and "no" are bogus answers + if test x"$with_boost_include_dir" == xyes || + test x"$with_boost_include_dir" == xno; then + gr_boost_include_dir= + else + gr_boost_include_dir=$with_boost_include_dir + fi + ]) + echo "gr_boost_include_dir = $gr_boost_include_dir" + if test x$gr_boost_include_dir != x; then + # if user specified a directory, then we use it + OLD_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -I$gr_boost_include_dir" + AC_CHECK_HEADER([boost/shared_ptr.hpp], + [BOOST_CFLAGS="-I$gr_boost_include_dir"], + [AC_MSG_ERROR( + [Failed to locate boost/shared_ptr.hpp. +Try using --with-boost-include-dir=])]) + CPPFLAGS=$OLD_CPPFLAGS + else + # is the header in the default place? + AC_CHECK_HEADER([boost/shared_ptr.hpp], + [BOOST_CFLAGS=""], + [ # nope, look one more place + # wipe out cached value. KLUDGE: AC should have API for this + unset AS_TR_SH([ac_cv_header_boost/shared_ptr.hpp]) + p=/usr/local/include/boost-1_31 + OLD_CPPFLAGS=$CPP_FLAGS + CPPFLAGS="$CPPFLAGS -I$p" + AC_CHECK_HEADER([boost/shared_ptr.hpp], + [BOOST_CFLAGS="-I$p"], + [AC_MSG_ERROR( + [Failed to locate boost/shared_ptr.hpp. +Try using --with-boost-include-dir=])]) + CPPFLAGS=$OLD_CPPFLAGS + ]) + + fi + AC_LANG_POP + AC_SUBST(BOOST_CFLAGS) +]) diff --git a/gssm/config/gr_check_mc4020.m4 b/gssm/config/gr_check_mc4020.m4 new file mode 100644 index 0000000..0c4318e --- /dev/null +++ b/gssm/config/gr_check_mc4020.m4 @@ -0,0 +1,37 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +AC_DEFUN([GR_CHECK_MC4020],[ + AC_MSG_CHECKING([for mc4020 A/D driver include file]) + AC_COMPILE_IFELSE([ +#include +int main (int argc, char **argv) +{ + return 0; +} +],[HAVE_MC4020=yes + AC_DEFINE(HAVE_MC4020,[1],[Define if you have a Measurement Computing PCI-DAS4020/12 A/D])], + [HAVE_MC4020=no]) + + AC_MSG_RESULT($HAVE_MC4020) + AM_CONDITIONAL(HAVE_MC4020, test x$HAVE_MC4020 = xyes) +]) + diff --git a/gssm/config/gr_check_shm_open.m4 b/gssm/config/gr_check_shm_open.m4 new file mode 100644 index 0000000..27c9ee6 --- /dev/null +++ b/gssm/config/gr_check_shm_open.m4 @@ -0,0 +1,29 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. + +AC_DEFUN([GR_CHECK_SHM_OPEN], +[ + SHM_OPEN_LIBS="" + save_LIBS="$LIBS" + AC_SEARCH_LIBS([shm_open], [rt], [SHM_OPEN_LIBS="$LIBS"]) + AC_CHECK_FUNCS([shm_open]) + LIBS="$save_LIBS" + AC_SUBST(SHM_OPEN_LIBS) +]) diff --git a/gssm/config/gr_check_usrp.m4 b/gssm/config/gr_check_usrp.m4 new file mode 100644 index 0000000..b818a69 --- /dev/null +++ b/gssm/config/gr_check_usrp.m4 @@ -0,0 +1,32 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +dnl Check for Universal Software Radio Peripheral + +AC_DEFUN([GR_CHECK_USRP],[ + PKG_CHECK_MODULES(USRP, usrp >= 0.2, + [HAVE_USRP=yes + AC_DEFINE(HAVE_USRP,[1],[Define if you have a USRP])], + [HAVE_USRP=no]) + + AM_CONDITIONAL(HAVE_USRP, test x$HAVE_USRP = xyes) +]) + diff --git a/gssm/config/gr_doxygen.m4 b/gssm/config/gr_doxygen.m4 new file mode 100644 index 0000000..b40b1ea --- /dev/null +++ b/gssm/config/gr_doxygen.m4 @@ -0,0 +1,56 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +AC_DEFUN([GR_CHECK_DOXYGEN],[ + AC_ARG_ENABLE(doxygen, [ --enable-doxygen enable documentation generation with doxygen (auto)]) + AC_ARG_ENABLE(dot, [ --enable-dot use 'dot' to generate graphs in doxygen (auto)]) + AC_ARG_ENABLE(html-docs, [ --enable-html-docs enable HTML generation with doxygen (yes)], [], [ enable_html_docs=yes]) + AC_ARG_ENABLE(latex-docs, [ --enable-latex-docs enable LaTeX doc generation with doxygen (no)], [], [ enable_latex_docs=no]) + + if test "x$enable_doxygen" = xno; then + enable_doc=no + else + AC_PATH_PROG(DOXYGEN, doxygen, , $PATH) + if test x$DOXYGEN = x; then + if test "x$enable_doxygen" = xyes; then + AC_MSG_ERROR([could not find doxygen]) + fi + enable_doc=no + else + enable_doc=yes + AC_PATH_PROG(DOT, dot, , $PATH) + fi + fi + + AM_CONDITIONAL(DOC, test x$enable_doc = xyes) + + if test x$DOT = x; then + if test "x$enable_dot" = xyes; then + AC_MSG_ERROR([could not find dot]) + fi + enable_dot=no + else + enable_dot=yes + fi + AC_SUBST(enable_dot) + AC_SUBST(enable_html_docs) + AC_SUBST(enable_latex_docs) +]) diff --git a/gssm/config/gr_gprof.m4 b/gssm/config/gr_gprof.m4 new file mode 100644 index 0000000..cc50508 --- /dev/null +++ b/gssm/config/gr_gprof.m4 @@ -0,0 +1,72 @@ +dnl +dnl Copyright 2002 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +dnl FIXME probably need to add linker flag too... + +AC_DEFUN([GR_SET_GPROF],[ + dnl Check for --with-gprof + AC_MSG_CHECKING([whether user wants gprof]) + AC_ARG_WITH(gprof, + [ --with-gprof Turn on gprof profiling], + [], [ with_gprof=no ]) + AC_MSG_RESULT($with_gprof) + + dnl gprof profiling flags for the two main compilers + cc_profiling_flags="-pg" + cxx_profiling_flags="-pg" + ld_profiling_flags="-pg" + if test $with_gprof = yes + then + if test -n "${CC}" + then + LF_CHECK_CC_FLAG($cc_profiling_flags) + fi + if test -n "${CXX}" + then + LF_CHECK_CXX_FLAG($cxx_profiling_flags) + fi + fi +]) + +AC_DEFUN([GR_SET_PROF],[ + dnl Check for --with-prof + AC_MSG_CHECKING([whether user wants prof]) + AC_ARG_WITH(prof, + [ --with-prof Turn on prof profiling], + [], [ with_prof=no ]) + AC_MSG_RESULT($with_prof) + + dnl prof profiling flags for the two main compilers + cc_profiling_flags="-p" + cxx_profiling_flags="-p" + ld_profiling_flags="-p" + if test $with_prof = yes + then + if test -n "${CC}" + then + LF_CHECK_CC_FLAG($cc_profiling_flags) + fi + if test -n "${CXX}" + then + LF_CHECK_CXX_FLAG($cxx_profiling_flags) + fi + fi +]) diff --git a/gssm/config/gr_omnithread.m4 b/gssm/config/gr_omnithread.m4 new file mode 100644 index 0000000..7c3150b --- /dev/null +++ b/gssm/config/gr_omnithread.m4 @@ -0,0 +1,51 @@ +# Check for Omnithread (pthread/NT) thread support. -*- Autoconf -*- + +# Copyright 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([GR_OMNITHREAD], +[ + # Check first for POSIX + ACX_PTHREAD( + [ ot_posix="yes" + AC_DEFINE(OMNITHREAD_POSIX,[1],[Define to 1 to enable pthread]) + ],[ + # If no POSIX support found, then check for NT threads + AC_MSG_CHECKING([for NT threads]) + + AC_LINK_IFELSE([ + #include + #include + int main() { InitializeCriticalSection(NULL); return 0; } + ], + [ + ot_nt="yes" + AC_DEFINE(OMNITHREAD_NT,[1],[Define to 1 to enable NT thread]) + ], + [AC_MSG_FAILURE([GNU Radio requires POSIX threads. pthreads not found.])] + ) + AC_MSG_RESULT(yes) + ]) + AM_CONDITIONAL(OMNITHREAD_POSIX, test "x$ot_posix" = xyes) + AM_CONDITIONAL(OMNITHREAD_NT, test "x$ot_nt" = xyes) + + save_LIBS="$LIBS" + AC_SEARCH_LIBS([clock_gettime], [rt], [PTHREAD_LIBS="$PTHREAD_LIBS $LIBS"]) + AC_CHECK_FUNCS([clock_gettime gettimeofday nanosleep]) + LIBS="$save_LIBS" +]) + diff --git a/gssm/config/gr_pwin32.m4 b/gssm/config/gr_pwin32.m4 new file mode 100644 index 0000000..5f748af --- /dev/null +++ b/gssm/config/gr_pwin32.m4 @@ -0,0 +1,146 @@ +# Check for (mingw)win32 POSIX replacements. -*- Autoconf -*- + +# Copyright 2003,2004,2005 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio 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, or (at your option) +# any later version. +# +# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + + +AC_DEFUN([GR_PWIN32], +[ +AC_REQUIRE([AC_HEADER_TIME]) +AC_CHECK_HEADERS([sys/types.h fcntl.h io.h]) +AC_CHECK_HEADERS([windows.h]) +AC_CHECK_HEADERS([winioctl.h winbase.h], [], [], [ + #if HAVE_WINDOWS_H + #include + #endif +]) + +AC_CHECK_FUNCS([getopt usleep gettimeofday nanosleep rand srand random srandom sleep sigaction]) +AC_CHECK_TYPES([struct timezone, struct timespec, ssize_t],[],[],[ + #if HAVE_SYS_TYPES_H + # include + #endif + #if TIME_WITH_SYS_TIME + # include + # include + #else + # if HAVE_SYS_TIME_H + # include + # else + # include + # endif + #endif +]) + +dnl Checks for replacements +AC_REPLACE_FUNCS([getopt usleep gettimeofday]) + + +AC_MSG_CHECKING(for Sleep) +AC_TRY_LINK([ #include + #include + ], [ Sleep(0); ], + [AC_DEFINE(HAVE_SSLEEP,1,[Define to 1 if you have win32 Sleep]) + AC_MSG_RESULT(yes)], + AC_MSG_RESULT(no) + ) + +dnl Under Win32, mkdir prototype in io.h has only one arg +AC_MSG_CHECKING(whether mkdir accepts only one arg) +AC_TRY_COMPILE([#include + #include + #include ], [ + mkdir("") + ], [ AC_MSG_RESULT(yes) + AC_DEFINE(MKDIR_TAKES_ONE_ARG,[],[Define if mkdir accepts only one arg]) ], + [ AC_MSG_RESULT(no) + ]) + +AH_BOTTOM( +[ +/* Define missing prototypes, implemented in replacement lib */ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_GETOPT +int getopt (int argc, char * const argv[], const char * optstring); +extern char * optarg; +extern int optind, opterr, optopt; +#endif + +#ifndef HAVE_USLEEP +int usleep(unsigned long usec); /* SUSv2 */ +#endif + +#ifndef HAVE_NANOSLEEP +#ifndef HAVE_STRUCT_TIMESPEC +#if HAVE_SYS_TYPES_H +# include /* need time_t */ +#endif +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif +static inline int nanosleep(const struct timespec *req, struct timespec *rem) { return usleep(req->tv_sec*1000000+req->tv_nsec/1000); } +#endif + +#if defined(HAVE_SSLEEP) && !defined(HAVE_SLEEP) +#ifdef HAVE_WINBASE_H +#include +#include +#endif +/* TODO: what about SleepEx? */ +static inline unsigned int sleep (unsigned int nb_sec) { Sleep(nb_sec*1000); return 0; } +#endif + +#ifndef HAVE_GETTIMEOFDAY +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifndef HAVE_STRUCT_TIMEZONE +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; +#endif +int gettimeofday(struct timeval *tv, struct timezone *tz); +#endif + +#if !defined(HAVE_RANDOM) && defined(HAVE_RAND) +#include +static inline long int random (void) { return rand(); } +#endif + +#if !defined(HAVE_SRANDOM) && defined(HAVE_SRAND) +static inline void srandom (unsigned int seed) { srand(seed); } +#endif + +#ifndef HAVE_SSIZE_T +typedef size_t ssize_t; +#endif + +#ifdef __cplusplus +} +#endif +]) + + +]) diff --git a/gssm/config/gr_python.m4 b/gssm/config/gr_python.m4 new file mode 100644 index 0000000..957d557 --- /dev/null +++ b/gssm/config/gr_python.m4 @@ -0,0 +1,104 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +# PYTHON_DEVEL() +# +# Checks for Python and tries to get the include path to 'Python.h'. +# It provides the $(PYTHON_CPPFLAGS) output variable. +AC_DEFUN([PYTHON_DEVEL],[ + AC_REQUIRE([AM_PATH_PYTHON]) + + # Check for Python include path + AC_MSG_CHECKING([for Python include path]) + if test -z "$PYTHON" ; then + AC_MSG_ERROR([cannot find Python path]) + fi + + python_path=${PYTHON%/bin*} + for i in "$python_path/include/python$PYTHON_VERSION/" "$python_path/include/python/" "$python_path/" ; do + python_path=`find $i -type f -name Python.h -print` + if test -n "$python_path" ; then + break + fi + done + for i in $python_path ; do + python_path=${python_path%/Python.h} + break + done + AC_MSG_RESULT([$python_path]) + if test -z "$python_path" ; then + AC_MSG_ERROR([cannot find Python include path]) + fi + + AC_SUBST(PYTHON_CPPFLAGS,[-I$python_path]) + + # Check for Python headers usability + python_save_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS" + AC_CHECK_HEADERS([Python.h], [], + [AC_MSG_ERROR([cannot find usable Python headers])]) + CPPFLAGS="$python_save_CPPFLAGS" + + # Check for Python library path + AC_MSG_CHECKING([for Python library path]) + python_path=`echo $PYTHON | sed "s,/bin.*$,,"` + for i in "$python_path/lib/python$PYTHON_VERSION/config/" "$python_path/lib/python$PYTHON_VERSION/" "$python_path/lib/python/config/" "$python_path/lib/python/" "$python_path/" "$python_path/libs" ; do + python_path=`find $i -type f -name libpython$PYTHON_VERSION.* -print | sed "1q"` + if test -n "$python_path" ; then + break + fi + done + python_path=`echo $python_path | sed "s,/libpython.*$,,"` + if test -z "$python_path" ; then + AC_MSG_WARN(cannot find Python library path) + fi + AC_MSG_RESULT([$python_path]) + + AC_SUBST([PYTHON_LDFLAGS],["-L$python_path -lpython$PYTHON_VERSION"]) + # + python_site=`echo $python_path | sed "s/config/site-packages/"` + AC_SUBST([PYTHON_SITE_PKG],[$python_site]) + # + # libraries which must be linked in when embedding + # + AC_MSG_CHECKING(python extra libraries) + PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \ + conf = distutils.sysconfig.get_config_var; \ + print conf('LOCALMODLIBS')+' '+conf('LIBS')" + AC_MSG_RESULT($PYTHON_EXTRA_LIBS)` + AC_SUBST(PYTHON_EXTRA_LIBS) + + + # Check for Python library usability + python_save_LIBS=$LIBS + python_save_CPPFLAGS=$CPPFLAGS + LIBS="$LIBS $PYTHON_LDFLAGS $PYTHON_EXTRA_LIBS" + CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS" + + AC_MSG_CHECKING(Python headers and library usability) + AC_TRY_LINK([ #include ], [ PyArg_Parse(NULL, NULL); ], + [AC_MSG_RESULT(yes)], + [AC_MSG_WARN(no dev lib, crossing fingers) + AC_SUBST([PYTHON_LDFLAGS],[""])]) + + CPPFLAGS="$python_save_CPPFLAGS" + LIBS="$python_save_LIBS" +]) diff --git a/gssm/config/gr_scripting.m4 b/gssm/config/gr_scripting.m4 new file mode 100644 index 0000000..7f3abde --- /dev/null +++ b/gssm/config/gr_scripting.m4 @@ -0,0 +1,30 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +AC_DEFUN([GR_SCRIPTING],[ + AC_REQUIRE([AC_PROG_LN_S]) + AC_REQUIRE([AC_PROG_CXX]) + AC_REQUIRE([AC_PROG_LIBTOOL]) + + SWIG_PROG(1.3.23) + SWIG_ENABLE_CXX + SWIG_PYTHON +]) diff --git a/gssm/config/gr_set_md_cpu.m4 b/gssm/config/gr_set_md_cpu.m4 new file mode 100644 index 0000000..e53eeaf --- /dev/null +++ b/gssm/config/gr_set_md_cpu.m4 @@ -0,0 +1,41 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +AC_DEFUN([GR_SET_MD_CPU],[ + AC_REQUIRE([AC_CANONICAL_TARGET]) + AC_ARG_WITH(md-cpu, + [ --with-md-cpu=ARCH set machine dependent speedups (auto)], + [cf_with_md_cpu="$withval"], + [cf_with_md_cpu="$target_cpu"]) + + AC_MSG_CHECKING([for machine dependent speedups]) + case "$cf_with_md_cpu" in + x86 | i[[3-7]]86) MD_CPU=x86 ;; +# sparc) MD_CPU=sparc ;; + *) MD_CPU=generic ;; + esac + AC_MSG_RESULT($MD_CPU) + AC_SUBST(MD_CPU) + + AM_CONDITIONAL(MD_CPU_x86, test $MD_CPU = x86) + AM_CONDITIONAL(MD_CPU_generic, test $MD_CPU = generic) +]) + diff --git a/gssm/config/gr_swig.m4 b/gssm/config/gr_swig.m4 new file mode 100644 index 0000000..a587c6d --- /dev/null +++ b/gssm/config/gr_swig.m4 @@ -0,0 +1,85 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +# SWIG_PROG([required-version]) +# +# Checks for the SWIG program. If found you can (and should) call SWIG via $(SWIG). +# You can use the optional first argument to check if the version of the available SWIG +# is greater or equal to the value of the argument. It should have the format: +# N[.N[.N]] (N is a number between 0 and 999. Only the first N is mandatory.) +AC_DEFUN([SWIG_PROG],[ + AC_REQUIRE([AC_PROG_MAKE_SET]) + AC_CHECK_PROG(SWIG,swig,[`which swig`]) + if test -z "$SWIG" ; then + AC_MSG_ERROR([Cannot find 'swig' program. SWIG version >= $1 required]) + SWIG=false + elif test -n "$1" ; then + AC_MSG_CHECKING([for SWIG version]) + swig_version=`$SWIG -version 2>&1 | \ + awk '/^SWIG Version [[0-9]+\.[0-9]+\.[0-9]]+.*$/ { split($[3],a,"[[^.0-9]]"); print a[[1]] }'` + AC_MSG_RESULT([$swig_version]) + if test -n "$swig_version" ; then + swig_version=`echo $swig_version | \ + awk '{ split($[1],a,"\."); print [a[1]*1000000+a[2]*1000+a[3]] }' 2>/dev/null` + swig_required_version=`echo $1 | \ + awk '{ split($[1],a,"\."); print [a[1]*1000000+a[2]*1000+a[3]] }' 2>/dev/null` + if test $swig_required_version -gt $swig_version ; then + AC_MSG_ERROR([SWIG version >= $1 required]) + fi + else + AC_MSG_ERROR([cannot determine SWIG version]) + fi + fi +]) + +# SWIG_ENABLE_CXX() +# +# Enable swig C++ support. This effects all invocations of $(SWIG). +AC_DEFUN([SWIG_ENABLE_CXX],[ + AC_REQUIRE([SWIG_PROG]) + AC_REQUIRE([AC_PROG_CXX]) + if test "$SWIG" != "false" ; then + SWIG="$SWIG -c++" + fi +]) + +# SWIG_PYTHON([use-shadow-classes]) +# +# Checks for Python and provides the $(SWIG_PYTHON_CPPFLAGS), +# $(SWIG_PYTHON_LIB) and $(SWIG_PYTHON_OPT) output variables. +# $(SWIG_PYTHON_OPT) contains all necessary swig options to generate +# code for Python. If you need multi module support use +# $(SWIG_PYTHON_LIB) (provided by the SWIG_MULTI_MODULE_SUPPORT() +# macro) to link against the appropriate library. It contains the +# SWIG Python runtime library that is needed by the type check system +# for example. + +AC_DEFUN([SWIG_PYTHON],[ + AC_REQUIRE([SWIG_PROG]) + AC_REQUIRE([PYTHON_DEVEL]) + if test "$SWIG" != "false" ; then + AC_SUBST(SWIG_PYTHON_LIB,[-lswigpy]) +dnl test ! "x$1" = "xno" && swig_shadow=" -shadow" || swig_shadow="" +dnl AC_SUBST(SWIG_PYTHON_OPT,[-python$swig_shadow]) + AC_SUBST(SWIG_PYTHON_OPT,[-python]) + fi + AC_SUBST(SWIG_PYTHON_CPPFLAGS,[$PYTHON_CPPFLAGS]) +]) diff --git a/gssm/config/gr_sysv_shm.m4 b/gssm/config/gr_sysv_shm.m4 new file mode 100644 index 0000000..5e11e49 --- /dev/null +++ b/gssm/config/gr_sysv_shm.m4 @@ -0,0 +1,36 @@ +# Check for IPC System V shm support. -*- Autoconf -*- + +# Copyright 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([GR_SYSV_SHM], +[ + AC_LANG_SAVE + AC_LANG_C + + AC_CHECK_HEADERS([sys/ipc.h sys/shm.h]) + + save_LIBS="$LIBS" + AC_SEARCH_LIBS(shmat, [cygipc ipc], + [ IPC_LIBS="$LIBS" ], + [ AC_MSG_WARN([SystemV IPC support not found. ]) ] + ) + LIBS="$save_LIBS" + + AC_LANG_RESTORE + AC_SUBST(IPC_LIBS) +]) diff --git a/gssm/config/lf_cc.m4 b/gssm/config/lf_cc.m4 new file mode 100644 index 0000000..f9bd715 --- /dev/null +++ b/gssm/config/lf_cc.m4 @@ -0,0 +1,42 @@ +dnl Autoconf support for C++ +dnl Copyright (C) 1988 Eleftherios Gkioulekas +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a configuration +dnl script generated by Autoconf, you may include it under the same +dnl distribution terms that you use for the rest of that program. + +# ------------------------------------------------------------------------- +# Use this macro to configure your C compiler +# When called the macro does the following things: +# 1. It finds an appropriate C compiler. +# If you passed the flag --with-cc=foo then it uses that +# particular compiler +# 2. Check whether the compiler works. +# 3. Checks whether the compiler accepts the -g +# ------------------------------------------------------------------------- + +AC_DEFUN([LF_CONFIGURE_CC],[ + dnl Sing the song + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_PROG_CPP])dnl + AC_REQUIRE([AC_AIX])dnl + AC_REQUIRE([AC_ISC_POSIX])dnl + AC_REQUIRE([AC_MINIX])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl +]) + diff --git a/gssm/config/lf_cxx.m4 b/gssm/config/lf_cxx.m4 new file mode 100644 index 0000000..8ade1fb --- /dev/null +++ b/gssm/config/lf_cxx.m4 @@ -0,0 +1,121 @@ +dnl Autoconf support for C++ +dnl Copyright (C) 1988 Eleftherios Gkioulekas +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a configuration +dnl script generated by Autoconf, you may include it under the same +dnl distribution terms that you use for the rest of that program. + +# ----------------------------------------------------------------- +# This macro should be called to configure your C++ compiler. +# When called, the macro does the following things: +# 1. It finds an appropriate C++ compiler +# If you passed the flag --with-cxx=foo, then it uses that +# particular compiler +# 2. Checks whether the compiler accepts the -g +# ------------------------------------------------------------------ + +AC_DEFUN([LF_CONFIGURE_CXX],[ + AC_REQUIRE([AC_PROG_CXX])dnl + AC_REQUIRE([AC_PROG_CXXCPP])dnl + LF_CXX_PORTABILITY +]) + +# ----------------------------------------------------------------------- +# This macro tests the C++ compiler for various portability problem. +# 1. Defines CXX_HAS_NO_BOOL if the compiler does not support the bool +# data type +# 2. Defines CXX_HAS_BUGGY_FOR_LOOPS if the compiler has buggy +# scoping for the for-loop +# 3. Defines USE_ASSERT if the user wants to use assertions +# ----------------------------------------------------------------------- + + +AC_DEFUN([LF_CXX_PORTABILITY],[ + + dnl + dnl Check for common C++ portability problems + dnl + + dnl AC_LANG_PUSH + dnl AC_LANG_CPLUSPLUS + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + + dnl Check whether we have bool + AC_MSG_CHECKING(whether C++ has bool) + AC_TRY_RUN([main() { bool b1=true; bool b2=false; }], + [ AC_MSG_RESULT(yes) ], + [ AC_MSG_RESULT(no) + AC_DEFINE(CXX_HAS_NO_BOOL,[],[Define if C++ is missing bool type]) ], + [ AC_MSG_WARN(Don't cross-compile)] + ) + + dnl Test whether C++ has buggy for-loops + AC_MSG_CHECKING(whether C++ has buggy scoping in for-loops) + AC_TRY_COMPILE([#include ], [ + for (int i=0;i<10;i++) { } + for (int i=0;i<10;i++) { } +], [ AC_MSG_RESULT(no) ], + [ AC_MSG_RESULT(yes) + AC_DEFINE(CXX_HAS_BUGGY_FOR_LOOPS,[],[Define if for loop scoping is broken]) ]) + + dnl Test whether the user wants to enable assertions + AC_MSG_CHECKING(whether user wants assertions) + AC_ARG_ENABLE(assert, + [ --disable-assert don't use cpp.h assert], + [ AC_DEFINE(NDEBUG,[],[Define to disable asserts (don't doit!)]) + AC_MSG_RESULT(no) ], + [ AC_MSG_RESULT(yes) ], + ) + + dnl Test whether C++ has std::isnan + AC_MSG_CHECKING(whether C++ has std::isnan) + AC_TRY_COMPILE([#include ], [ + std::isnan(0); +], [ AC_MSG_RESULT(yes) + AC_DEFINE(CXX_HAS_STD_ISNAN,[],[Define if has std::isnan]) ], + [ AC_MSG_RESULT(no) ]) + + dnl Done with the portability checks + dnl AC_LANG_POP([C++]) + AC_LANG_RESTORE +]) + +AH_BOTTOM([// Workaround for compilers with buggy for-loop scoping +// That's quite a few compilers actually including recent versions of +// Dec Alpha cxx, HP-UX CC and SGI CC. +// The trivial "if" statement provides the correct scoping to the +// for loop + +#ifdef CXX_HAS_BUGGY_FOR_LOOPS +#undef for +#define for if(1) for +#endif +]) + +AH_BOTTOM([// If the C++ compiler we use doesn't have bool, then +// the following is a near-perfect work-around. +// You must make sure your code does not depend on "int" and "bool" +// being two different types, in overloading for instance. + +#ifdef CXX_HAS_NO_BOOL +#define bool int +#define true 1 +#define false 0 +#endif +]) diff --git a/gssm/config/lf_warnings.m4 b/gssm/config/lf_warnings.m4 new file mode 100644 index 0000000..0ebb97e --- /dev/null +++ b/gssm/config/lf_warnings.m4 @@ -0,0 +1,128 @@ +dnl Copyright (C) 1988 Eleftherios Gkioulekas +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a configuration +dnl script generated by Autoconf, you may include it under the same +dnl distribution terms that you use for the rest of that program. + +# -------------------------------------------------------------------------- +# Check whether the C++ compiler accepts a certain flag +# If it does it adds the flag to CXXFLAGS +# If it does not then it returns an error to lf_ok +# Usage: +# LF_CHECK_CXX_FLAG(-flag1 -flag2 -flag3 ...) +# ------------------------------------------------------------------------- + +AC_DEFUN([LF_CHECK_CXX_FLAG],[ + echo 'void f(){}' > conftest.cc + for i in $1 + do + AC_MSG_CHECKING([whether $CXX accepts $i]) + if test -z "`${CXX} $i -c conftest.cc 2>&1`" + then + CXXFLAGS="${CXXFLAGS} $i" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + done + rm -f conftest.cc conftest.o +]) + +# -------------------------------------------------------------------------- +# Check whether the C compiler accepts a certain flag +# If it does it adds the flag to CFLAGS +# If it does not then it returns an error to lf_ok +# Usage: +# LF_CHECK_CC_FLAG(-flag1 -flag2 -flag3 ...) +# ------------------------------------------------------------------------- + +AC_DEFUN([LF_CHECK_CC_FLAG],[ + echo 'void f(){}' > conftest.c + for i in $1 + do + AC_MSG_CHECKING([whether $CC accepts $i]) + if test -z "`${CC} $i -c conftest.c 2>&1`" + then + CFLAGS="${CFLAGS} $i" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + done + rm -f conftest.c conftest.o +]) + +# -------------------------------------------------------------------------- +# Check whether the Fortran compiler accepts a certain flag +# If it does it adds the flag to FFLAGS +# If it does not then it returns an error to lf_ok +# Usage: +# LF_CHECK_F77_FLAG(-flag1 -flag2 -flag3 ...) +# ------------------------------------------------------------------------- + +AC_DEFUN([LF_CHECK_F77_FLAG],[ + cat << EOF > conftest.f +c....:++++++++++++++++++++++++ + PROGRAM MAIN + PRINT*,'Hello World!' + END +EOF + for i in $1 + do + AC_MSG_CHECKING([whether $F77 accepts $i]) + if test -z "`${F77} $i -c conftest.f 2>&1`" + then + FFLAGS="${FFLAGS} $i" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + done + rm -f conftest.f conftest.o +]) + +# ---------------------------------------------------------------------- +# Provide the configure script with an --with-warnings option that +# turns on warnings. Call this command AFTER you have configured ALL your +# compilers. +# ---------------------------------------------------------------------- + +AC_DEFUN([LF_SET_WARNINGS],[ + dnl Check for --with-warnings + AC_MSG_CHECKING([whether user wants warnings]) + AC_ARG_WITH(warnings, + [ --with-warnings Turn on warnings], + [ lf_warnings=yes ], [ lf_warnings=no ]) + lf_warnings=yes # hard code for now -eb + AC_MSG_RESULT($lf_warnings) + + dnl Warnings for the two main compilers + cc_warning_flags="-Wall" + cxx_warning_flags="-Wall -Woverloaded-virtual" + if test $lf_warnings = yes + then + if test -n "${CC}" + then + LF_CHECK_CC_FLAG($cc_warning_flags) + fi + if test -n "${CXX}" + then + LF_CHECK_CXX_FLAG($cxx_warning_flags) + fi + fi +]) diff --git a/gssm/config/lf_x11.m4 b/gssm/config/lf_x11.m4 new file mode 100644 index 0000000..3bd19f2 --- /dev/null +++ b/gssm/config/lf_x11.m4 @@ -0,0 +1,39 @@ +dnl Copyright (C) 1988 Eleftherios Gkioulekas +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a configuration +dnl script generated by Autoconf, you may include it under the same +dnl distribution terms that you use for the rest of that program. + + +#----------------------------------------------------------------------- +# This macro searches for Xlib and when it finds it it adds the +# appropriate flags to CXXFLAGS and export the link sequence to +# the variable XLIB. +# In your configure.in file add: +# LF_PATH_XLIB +# In your Makefile.am add +# program_LDADD = .... $(XLIB) +#------------------------------------------------------------------------ + +AC_DEFUN([LF_PATH_XLIB],[ + AC_PATH_XTRA + CXXFLAGS="$CXXFLAGS $X_CFLAGS" + XLIB="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" + AC_SUBST(XLIB) +]) + diff --git a/gssm/config/mkstemp.m4 b/gssm/config/mkstemp.m4 new file mode 100644 index 0000000..4af0f0a --- /dev/null +++ b/gssm/config/mkstemp.m4 @@ -0,0 +1,89 @@ +#serial 4 + +# On some hosts (e.g., HP-UX 10.20, SunOS 4.1.4, Solaris 2.5.1), mkstemp has a +# silly limit that it can create no more than 26 files from a given template. +# Other systems lack mkstemp altogether. +# On OSF1/Tru64 V4.0F, the system-provided mkstemp function can create +# only 32 files per process. +# On systems like the above, arrange to use the replacement function. +AC_DEFUN([UTILS_FUNC_MKSTEMP], +[dnl + AC_REPLACE_FUNCS(mkstemp) + if test $ac_cv_func_mkstemp = no; then + utils_cv_func_mkstemp_limitations=yes + else + AC_CACHE_CHECK([for mkstemp limitations], + utils_cv_func_mkstemp_limitations, + [ + AC_TRY_RUN([ +# include + int main () + { + int i; + for (i = 0; i < 70; i++) + { + char template[] = "conftestXXXXXX"; + int fd = mkstemp (template); + if (fd == -1) + exit (1); + close (fd); + } + exit (0); + } + ], + utils_cv_func_mkstemp_limitations=no, + utils_cv_func_mkstemp_limitations=yes, + utils_cv_func_mkstemp_limitations=yes + ) + ] + ) + fi + + if test $utils_cv_func_mkstemp_limitations = yes; then + AC_LIBOBJ(mkstemp) + AC_LIBOBJ(tempname) + AC_DEFINE(mkstemp, rpl_mkstemp, + [Define to rpl_mkstemp if the replacement function should be used.]) + gl_PREREQ_MKSTEMP + jm_PREREQ_TEMPNAME + fi +]) + +# Prerequisites of lib/mkstemp.c. +AC_DEFUN([gl_PREREQ_MKSTEMP], +[ + AH_BOTTOM( + [ + #ifndef HAVE_MKSTEMP + #ifdef __cplusplus + extern "C" { + #endif + int rpl_mkstemp (char *templ); + #ifdef __cplusplus + } + #endif + #endif + ]) +]) + +# Prerequisites of lib/tempname.c. +AC_DEFUN([jm_PREREQ_TEMPNAME], +[ + AC_REQUIRE([AC_HEADER_STAT]) + AC_CHECK_HEADERS_ONCE(fcntl.h sys/time.h unistd.h) + AC_CHECK_HEADERS(stdint.h) + AC_CHECK_FUNCS(__secure_getenv gettimeofday lstat) + AC_CHECK_DECLS_ONCE(getenv) + # AC_REQUIRE([jm_AC_TYPE_UINTMAX_T]) + + dnl Under Win32, mkdir prototype in io.h has only one arg + AC_MSG_CHECKING(whether mkdir accepts only one arg) + AC_TRY_COMPILE([#include + #include + #include ], [ + mkdir("") + ], [ AC_MSG_RESULT(yes) + AC_DEFINE(MKDIR_TAKES_ONE_ARG,[],[Define if mkdir accepts only one arg]) ], + [ AC_MSG_RESULT(no) + ]) +]) diff --git a/gssm/config/onceonly.m4 b/gssm/config/onceonly.m4 new file mode 100644 index 0000000..f6fec37 --- /dev/null +++ b/gssm/config/onceonly.m4 @@ -0,0 +1,63 @@ +# onceonly.m4 serial 3 +dnl Copyright (C) 2002, 2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl This file defines some "once only" variants of standard autoconf macros. +dnl AC_CHECK_HEADERS_ONCE like AC_CHECK_HEADERS +dnl AC_CHECK_FUNCS_ONCE like AC_CHECK_FUNCS +dnl AC_CHECK_DECLS_ONCE like AC_CHECK_DECLS +dnl AC_REQUIRE([AC_HEADER_STDC]) like AC_HEADER_STDC +dnl The advantage is that the check for each of the headers/functions/decls +dnl will be put only once into the 'configure' file. It keeps the size of +dnl the 'configure' file down, and avoids redundant output when 'configure' +dnl is run. +dnl The drawback is that the checks cannot be conditionalized. If you write +dnl if some_condition; then gl_CHECK_HEADERS(stdlib.h); fi +dnl inside an AC_DEFUNed function, the gl_CHECK_HEADERS macro call expands to +dnl empty, and the check will be inserted before the body of the AC_DEFUNed +dnl function. + +dnl Autoconf version 2.57 or newer is recommended. +AC_PREREQ(2.54) + +# AC_CHECK_HEADERS_ONCE(HEADER1 HEADER2 ...) is a once-only variant of +# AC_CHECK_HEADERS(HEADER1 HEADER2 ...). +AC_DEFUN([AC_CHECK_HEADERS_ONCE], [ + : + AC_FOREACH([gl_HEADER_NAME], [$1], [ + AC_DEFUN([gl_CHECK_HEADER_]m4_quote(translit(defn([gl_HEADER_NAME]), + [-./], [___])), [ + AC_CHECK_HEADERS(gl_HEADER_NAME) + ]) + AC_REQUIRE([gl_CHECK_HEADER_]m4_quote(translit(gl_HEADER_NAME, + [-./], [___]))) + ]) +]) + +# AC_CHECK_FUNCS_ONCE(FUNC1 FUNC2 ...) is a once-only variant of +# AC_CHECK_FUNCS(FUNC1 FUNC2 ...). +AC_DEFUN([AC_CHECK_FUNCS_ONCE], [ + : + AC_FOREACH([gl_FUNC_NAME], [$1], [ + AC_DEFUN([gl_CHECK_FUNC_]defn([gl_FUNC_NAME]), [ + AC_CHECK_FUNCS(defn([gl_FUNC_NAME])) + ]) + AC_REQUIRE([gl_CHECK_FUNC_]defn([gl_FUNC_NAME])) + ]) +]) + +# AC_CHECK_DECLS_ONCE(DECL1 DECL2 ...) is a once-only variant of +# AC_CHECK_DECLS(DECL1, DECL2, ...). +AC_DEFUN([AC_CHECK_DECLS_ONCE], [ + : + AC_FOREACH([gl_DECL_NAME], [$1], [ + AC_DEFUN([gl_CHECK_DECL_]defn([gl_DECL_NAME]), [ + AC_CHECK_DECLS(defn([gl_DECL_NAME])) + ]) + AC_REQUIRE([gl_CHECK_DECL_]defn([gl_DECL_NAME])) + ]) +]) diff --git a/gssm/config/pkg.m4 b/gssm/config/pkg.m4 new file mode 100644 index 0000000..770f062 --- /dev/null +++ b/gssm/config/pkg.m4 @@ -0,0 +1,68 @@ +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + dnl If PKG_CONFIG_PATH is not already set, add /usr/local/lib/pkgconfig. + dnl If it's set, assume the user knows what they're doing. + dnl This should help avoid failures while looking for fftw3f + if test -z "$PKG_CONFIG_PATH"; then + export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" + fi + + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + + AC_MSG_CHECKING($1_INCLUDEDIR) + $1_INCLUDEDIR=`$PKG_CONFIG --variable=includedir "$2"` + AC_MSG_RESULT($$1_INCLUDEDIR) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + AC_SUBST($1_INCLUDEDIR) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + diff --git a/gssm/config/usrp_fusb_tech.m4 b/gssm/config/usrp_fusb_tech.m4 new file mode 100644 index 0000000..573c175 --- /dev/null +++ b/gssm/config/usrp_fusb_tech.m4 @@ -0,0 +1,54 @@ +dnl +dnl Copyright 2003 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +AC_DEFUN([USRP_SET_FUSB_TECHNIQUE],[ + AC_REQUIRE([AC_CANONICAL_TARGET]) + AC_ARG_WITH(fusb-tech, + [ --with-fusb-tech=OS set fast usb technique (auto)], + [cf_with_fusb_tech="$withval"], + [cf_with_fusb_tech="$target_os"]) + + + AC_CHECK_HEADER([linux/usbdevice_fs.h], + [x_have_usbdevice_fs_h=yes], + [x_have_usbdevice_fs_h=no]) + + AC_MSG_CHECKING([for fast usb technique to use]) + case "$cf_with_fusb_tech" in + linux*) if test x${x_have_usbdevice_fs_h} = xyes; + then + FUSB_TECH=linux + else + FUSB_TECH=generic + fi ;; + + darwin*) FUSB_TECH=darwin ;; + *) FUSB_TECH=generic ;; + esac + + AC_MSG_RESULT($FUSB_TECH) + AC_SUBST(FUSB_TECH) + + AM_CONDITIONAL(FUSB_TECH_darwin, test $FUSB_TECH = darwin) + AM_CONDITIONAL(FUSB_TECH_generic, test $FUSB_TECH = generic) + AM_CONDITIONAL(FUSB_TECH_linux, test $FUSB_TECH = linux) +]) + diff --git a/gssm/config/usrp_libusb.m4 b/gssm/config/usrp_libusb.m4 new file mode 100644 index 0000000..27f8c2a --- /dev/null +++ b/gssm/config/usrp_libusb.m4 @@ -0,0 +1,38 @@ +# Check for libusb support. -*- Autoconf -*- + +# Copyright 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([USRP_LIBUSB], +[ + AC_LANG_PUSH(C) + + AC_CHECK_HEADERS([usb.h], + [], + [ AC_MSG_ERROR([USRP requires libusb. usb.h not found, stop. See http://libusb.sf.net]) ] + ) + + save_LIBS="$LIBS" + AC_SEARCH_LIBS(usb_bulk_write, [usb], + [ USB_LIBS="$LIBS" ], + [ AC_MSG_ERROR([USRP requires libusb. usb_bulk_write not found, stop. See http://libusb.sf.net]) ] + ) + LIBS="$save_LIBS" + + AC_LANG_POP + AC_SUBST(USB_LIBS) +]) diff --git a/gssm/config/usrp_sdcc.m4 b/gssm/config/usrp_sdcc.m4 new file mode 100644 index 0000000..81c255a --- /dev/null +++ b/gssm/config/usrp_sdcc.m4 @@ -0,0 +1,67 @@ +# Check for sdcc support. -*- Autoconf -*- + +# Copyright 2004 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([USRP_SDCC], +[ + AC_CHECK_PROG(XCC, sdcc, sdcc -mmcs51 --no-xinit-opt,no) + AC_CHECK_PROG(XAS, asx8051, asx8051 -plosgff,no) + + if test "$XCC" = "no" -o "$XAS" = "no" ; then + AC_MSG_ERROR([USRP requires sdcc. sdcc not found, stop. See http://sdcc.sf.net]) + fi + + sdcc_version_min=$1 + + sdcc_version=`sdcc --version 2>&1 | \ + sed 's/\(SDCC.* \)\([[0-9]]*\.[[0-9]]*\.[[0-9]]*\)\( .*$\)/\2/'` + + AC_MSG_CHECKING([sdcc_version "$sdcc_version"]) + + sdcc_major_version=`echo $sdcc_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + sdcc_minor_version=`echo $sdcc_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + sdcc_micro_version=`echo $sdcc_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + sdcc_major_min=`echo $sdcc_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + sdcc_minor_min=`echo $sdcc_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + sdcc_micro_min=`echo $sdcc_version_min | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + sdcc_version_proper=`expr \ + "$sdcc_major_version" \> "$sdcc_major_min" \| \ + "$sdcc_major_version" \= "$sdcc_major_min" \& \ + "$sdcc_minor_version" \> "$sdcc_minor_min" \| \ + "$sdcc_major_version" \= "$sdcc_major_min" \& \ + "$sdcc_minor_version" \= "$sdcc_minor_min" \& \ + "$sdcc_micro_version" \>= "$sdcc_micro_min" ` + + if test "$sdcc_version_proper" = "1" ; then + AC_MSG_RESULT([$sdcc_major_version.$sdcc_minor_version.$sdcc_micro_version]) + else + AC_MSG_ERROR([USRP requires sdcc >= $sdcc_version_min. sdcc not found, stop. See http://sdcc.sf.net]) + fi + + AC_SUBST(XCC) + AC_SUBST(XAS) + +]) diff --git a/gssm/configure.ac b/gssm/configure.ac new file mode 100644 index 0000000..7ce1181 --- /dev/null +++ b/gssm/configure.ac @@ -0,0 +1,101 @@ +dnl +dnl Copyright 2004 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +dnl Boston, MA 02111-1307, USA. +dnl + +AC_INIT +AC_PREREQ(2.57) +AC_CONFIG_SRCDIR([src/lib/gssm.i]) +AM_CONFIG_HEADER(config.h) +AC_CANONICAL_TARGET([]) +AM_INIT_AUTOMAKE(gssm, 0.0) + +dnl disable maintainer rules: e.g., rebuilding configure, makefile.in's unless +dnl user explicitly specifies --enable-maintainer-mode +dnl AM_MAINTAINER_MODE + +dnl LF_CONFIGURE_CC +LF_CONFIGURE_CXX +LF_SET_WARNINGS +GR_SET_GPROF +GR_SET_PROF +GR_PROG_AS +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_INSTALL + +AC_LIBTOOL_WIN32_DLL +AC_ENABLE_SHARED dnl do build shared libraries +AC_DISABLE_STATIC dnl don't build static libraries +AC_PROG_LIBTOOL + +dnl locate python, swig, +GR_SCRIPTING + +dnl check for threads (mandatory) +GR_OMNITHREAD + +dnl CFLAGS="${CFLAGS} $PTHREAD_CFLAGS" +dnl CXXFLAGS="${CXXFLAGS} $PTHREAD_CFLAGS" +CFLAGS="-O3 $PTHREAD_CFLAGS" +CXXFLAGS="-O3 $PTHREAD_CFLAGS" + +if test "x$CXX_FOR_BUILD" = x +then + CXX_FOR_BUILD=${CXX} +fi +AC_SUBST(CXX_FOR_BUILD) + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h limits.h strings.h sys/ioctl.h sys/time.h unistd.h) +AC_CHECK_HEADERS(sys/mman.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_SIZE_T +AC_HEADER_TIME + +dnl Checks for library functions. +AC_CHECK_FUNCS([]) + +dnl check for mingw +GR_PWIN32 + +PKG_CHECK_MODULES(GNURADIO_CORE, gnuradio-core >= 2) +LIBS="$LIBS $GNURADIO_CORE_LIBS" + +dnl Define where to find boost includes +dnl defines BOOST_CFLAGS +GR_REQUIRE_BOOST_INCLUDES + +STD_DEFINES_AND_INCLUDES="$GNURADIO_CORE_CFLAGS $BOOST_CFLAGS" +AC_SUBST(STD_DEFINES_AND_INCLUDES) + +AC_CONFIG_FILES([\ + Makefile \ + config/Makefile \ + src/Makefile \ + src/lib/Makefile \ + src/mktun/Makefile \ + ]) + +AC_OUTPUT diff --git a/gssm/patch/wireshark-0.99.5-gssm.patch b/gssm/patch/wireshark-0.99.5-gssm.patch new file mode 100644 index 0000000..655b909 --- /dev/null +++ b/gssm/patch/wireshark-0.99.5-gssm.patch @@ -0,0 +1,2669 @@ +*** wireshark-0.99.5/epan/dissectors/packet-gsm_a.c 2007-02-01 15:00:39.000000000 -0800 +--- wireshark-0.99.5-gssm/epan/dissectors/packet-gsm_a.c 2007-05-31 00:24:56.000000000 -0700 +*************** +*** 567,575 **** + /* [3] 10.5.2.8b Channel Request Description 2 */ + /* Pos 20 */ + { 0x00, "Cipher Mode Setting" }, /* [3] 10.5.2.9 */ +! /* [3] 10.5.2.10 Cipher Response +! * [3] 10.5.2.11 Control Channel Description +! * [3] 10.5.2.11a DTM Information Details */ + { 0x00, "Dynamic ARFCN Mapping" }, /* [3] 10.5.2.11b */ + { 0x00, "Frequency Channel Sequence" }, /* [3] 10.5.2.12 */ + { 0x00, "Frequency List" }, /* 10.5.2.13 */ +--- 567,576 ---- + /* [3] 10.5.2.8b Channel Request Description 2 */ + /* Pos 20 */ + { 0x00, "Cipher Mode Setting" }, /* [3] 10.5.2.9 */ +! /* [3] 10.5.2.10 Cipher Response */ +! {0x00, "Control Channel Description"}, /* [3] 10.5.2.11 Control Channel Description */ // jl +! /* [3] 10.5.2.11 Control Channel Description */ +! /* [3] 10.5.2.11a DTM Information Details */ + { 0x00, "Dynamic ARFCN Mapping" }, /* [3] 10.5.2.11b */ + { 0x00, "Frequency Channel Sequence" }, /* [3] 10.5.2.12 */ + { 0x00, "Frequency List" }, /* 10.5.2.13 */ +*************** +*** 594,633 **** + { 0x00, "MultiRate configuration" }, /* [3] 10.5.2.21aa */ + /* Pos 30 */ + { 0x00, "Multislot Allocation" }, /* [3] 10.5.2.21b */ +! /* + * [3] 10.5.2.21c NC mode +! * [3] 10.5.2.22 Neighbour Cell Description + * [3] 10.5.2.22a Neighbour Cell Description 2 + * [3] 10.5.2.22b (void) + * [3] 10.5.2.22c NT/N Rest Octets +! * [3] 10.5.2.23 P1 Rest Octets + * [3] 10.5.2.24 P2 Rest Octets + * [3] 10.5.2.25 P3 Rest Octets +! * [3] 10.5.2.25a Packet Channel Description +! * [3] 10.5.2.25b Dedicated mode or TBF + * [3] 10.5.2.25c RR Packet Uplink Assignment + * [3] 10.5.2.25d RR Packet Downlink Assignment +! * [3] 10.5.2.26 Page Mode + * [3] 10.5.2.26a (void) + * [3] 10.5.2.26b (void) + * [3] 10.5.2.26c (void) + * [3] 10.5.2.26d (void) +- * [3] 10.5.2.27 NCC Permitted + */ + { 0x00, "Power Command" }, /* 10.5.2.28 */ + { 0x00, "Power Command and access type" }, /* 10.5.2.28a */ +! /* +! * [3] 10.5.2.29 RACH Control Parameters +! * [3] 10.5.2.30 Request Reference +! */ +! { 0x00, "RR Cause" }, /* 10.5.2.31 */ + { 0x00, "Synchronization Indication" }, /* 10.5.2.39 */ +! /* [3] 10.5.2.32 SI 1 Rest Octets + * [3] 10.5.2.33 SI 2bis Rest Octets + * [3] 10.5.2.33a SI 2ter Rest Octets + * [3] 10.5.2.33b SI 2quater Rest Octets +! * [3] 10.5.2.34 SI 3 Rest Octets +! * [3] 10.5.2.35 SI 4 Rest Octets + * [3] 10.5.2.35a SI 6 Rest Octets + * [3] 10.5.2.36 SI 7 Rest Octets + * [3] 10.5.2.37 SI 8 Rest Octets +--- 595,643 ---- + { 0x00, "MultiRate configuration" }, /* [3] 10.5.2.21aa */ + /* Pos 30 */ + { 0x00, "Multislot Allocation" }, /* [3] 10.5.2.21b */ +! /* + * [3] 10.5.2.21c NC mode +! */ +! {0x00, "Neighbor Cell Description"}, /* [3] 10.5.2.22 Neighbour Cell Description */ // jl +! /* + * [3] 10.5.2.22a Neighbour Cell Description 2 + * [3] 10.5.2.22b (void) + * [3] 10.5.2.22c NT/N Rest Octets +! */ +! {0x00, "P1 Rest Octets"}, /* [3] 10.5.2.23 P1 Rest Octets */ // jl +! /* + * [3] 10.5.2.24 P2 Rest Octets + * [3] 10.5.2.25 P3 Rest Octets +! */ +! {0x00, "Packet Channel Description"}, /* [3] 10.5.2.25a Packet Channel Description */ // jl +! {0x00, "Dedicated Mode or TBF" }, /* [3] 10.5.2.25b Dedicated mode or TBF */ // jl +! /* + * [3] 10.5.2.25c RR Packet Uplink Assignment + * [3] 10.5.2.25d RR Packet Downlink Assignment +! */ +! {0x00, "Page Mode"}, /* [3] 10.5.2.26 Page Mode */ // jl +! /* + * [3] 10.5.2.26a (void) + * [3] 10.5.2.26b (void) + * [3] 10.5.2.26c (void) + * [3] 10.5.2.26d (void) + */ ++ {0x00, "NCC Permitted"}, /* [3] 10.5.2.27 NCC Permitted */ // jl + { 0x00, "Power Command" }, /* 10.5.2.28 */ + { 0x00, "Power Command and access type" }, /* 10.5.2.28a */ +! {0x00, "RACH Control Parameters"}, /* [3] 10.5.2.29 RACH Control Parameters */ // jl +! {0x00, "Request Reference"}, /* [3] 10.5.2.30 Request Reference */ // jl +! { 0x00, "RR Cause" }, /* 10.5.2.31 */ + { 0x00, "Synchronization Indication" }, /* 10.5.2.39 */ +! {0x00, "SI 1 Rest Octets"}, /* [3] 10.5.2.32 SI 1 Rest Octets */ // jl +! /* + * [3] 10.5.2.33 SI 2bis Rest Octets + * [3] 10.5.2.33a SI 2ter Rest Octets + * [3] 10.5.2.33b SI 2quater Rest Octets +! */ +! {0x00, "SI 3 Rest Octets"}, /* [3] 10.5.2.34 SI 3 Rest Octets */ // jl +! {0x00, "SI 4 Rest Octets"}, /* [3] 10.5.2.35 SI 4 Rest Octets */ // jl +! /* + * [3] 10.5.2.35a SI 6 Rest Octets + * [3] 10.5.2.36 SI 7 Rest Octets + * [3] 10.5.2.37 SI 8 Rest Octets +*************** +*** 1057,1062 **** +--- 1067,1093 ---- + #define DTAP_SS_IEI_MASK 0x3f + + /* Initialize the protocol and registered fields */ ++ static int hf_gsm_a_rr_rach_cp_max_retrans = -1; // jl ++ static int hf_gsm_a_rr_rach_cp_tx_integer = -1; // jl ++ static int hf_gsm_a_rr_rach_cp_cell_bar_access = -1; // jl ++ static int hf_gsm_a_rr_rach_cp_re = -1; // jl ++ static int hf_gsm_a_rr_rach_cp_ec = -1; // jl ++ static int hf_gsm_a_rr_si_1_rest_octets = -1; // jl ++ ++ static int hf_gsm_a_rr_neigh_cell_dsc_ext = -1; // jl ++ static int hf_gsm_a_rr_neigh_cell_dsc_ba = -1; // jl ++ ++ static int hf_gsm_a_rr_cc_dsc_mscr = -1; // jl ++ static int hf_gsm_a_rr_cc_dsc_att = -1; // jl ++ static int hf_gsm_a_rr_cc_dsc_cbq3 = -1; // jl ++ static int hf_gsm_a_rr_cc_dsc_ccch = -1; // jl ++ ++ static int hf_gsm_a_rr_co_bcch_dn_ind = -1; // jl ++ static int hf_gsm_a_rr_co_bcch_pwrc = -1; // jl ++ static int hf_gsm_a_rr_co_bcch_dtx = -1; // jl ++ ++ static int hf_gsm_a_rr_dm_or_tbf = -1; // jl ++ + static int proto_a_bssmap = -1; + static int proto_a_dtap = -1; + static int proto_a_rp = -1; +*************** +*** 3211,3220 **** + * [3] 10.5.2.1e Cell selection indicator after release of all TCH and SDCCH IE + */ + DE_RR_CELL_DSC, /* 10.5.2.2 RR Cell Description */ + /* +- * [3] 10.5.2.3 Cell Options (BCCH) + * [3] 10.5.2.3a Cell Options (SACCH) +! * [3] 10.5.2.4 Cell Selection Parameters + * [3] 10.5.2.4a (void) + */ + DE_RR_CH_DSC, /* [3] 10.5.2.5 Channel Description */ +--- 3242,3254 ---- + * [3] 10.5.2.1e Cell selection indicator after release of all TCH and SDCCH IE + */ + DE_RR_CELL_DSC, /* 10.5.2.2 RR Cell Description */ ++ DE_RR_CO_BCCH, /* [3] 10.5.2.3 Cell Options (BCCH) */ // jl ++ + /* + * [3] 10.5.2.3a Cell Options (SACCH) +! */ +! DE_RR_CELL_SEL_PARAM, /* [3] 10.5.2.4 Cell Selection Parameters */ // jl +! /* + * [3] 10.5.2.4a (void) + */ + DE_RR_CH_DSC, /* [3] 10.5.2.5 Channel Description */ +*************** +*** 3230,3237 **** + * [3] 10.5.2.8b Channel Request Description 2 */ + /* Pos 20 */ + DE_RR_CIP_MODE_SET, /* [3] 10.5.2.9 Cipher Mode Setting */ +! /* [3] 10.5.2.10 Cipher Response +! * [3] 10.5.2.11 Control Channel Description + * [3] 10.5.2.11a DTM Information Details */ + DE_RR_DYN_ARFCN_MAP, /* [3] 10.5.2.11b Dynamic ARFCN Mapping */ + DE_RR_FREQ_CH_SEQ, /* [3] 10.5.2.12 Frequency Channel Sequence */ +--- 3264,3275 ---- + * [3] 10.5.2.8b Channel Request Description 2 */ + /* Pos 20 */ + DE_RR_CIP_MODE_SET, /* [3] 10.5.2.9 Cipher Mode Setting */ +! /* +! * [3] 10.5.2.10 Cipher Response +! */ +! DE_RR_CC_DSC, /* [3] 10.5.2.11 Control Channel Description */ // jl +! +! /* + * [3] 10.5.2.11a DTM Information Details */ + DE_RR_DYN_ARFCN_MAP, /* [3] 10.5.2.11b Dynamic ARFCN Mapping */ + DE_RR_FREQ_CH_SEQ, /* [3] 10.5.2.12 Frequency Channel Sequence */ +*************** +*** 3245,3252 **** + */ + + DE_RR_HO_REF, /* 10.5.2.15 Handover Reference */ + /* +- * [3] 10.5.2.16 IA Rest Octets + * [3] 10.5.2.17 IAR Rest Octets + * [3] 10.5.2.18 IAX Rest Octets + * [3] 10.5.2.19 L2 Pseudo Length +--- 3283,3290 ---- + */ + + DE_RR_HO_REF, /* 10.5.2.15 Handover Reference */ ++ DE_RR_IA_REST_OCTETS, /* [3] 10.5.2.16 IA Rest Octets */ // jl + /* + * [3] 10.5.2.17 IAR Rest Octets + * [3] 10.5.2.18 IAX Rest Octets + * [3] 10.5.2.19 L2 Pseudo Length +*************** +*** 3261,3298 **** + + /* + * [3] 10.5.2.21c NC mode +! * [3] 10.5.2.22 Neighbour Cell Description + * [3] 10.5.2.22a Neighbour Cell Description 2 + * [3] 10.5.2.22b (void) + * [3] 10.5.2.22c NT/N Rest Octets + * [3] 10.5.2.23 P1 Rest Octets + * [3] 10.5.2.24 P2 Rest Octets + * [3] 10.5.2.25 P3 Rest Octets +! * [3] 10.5.2.25a Packet Channel Description +! * [3] 10.5.2.25b Dedicated mode or TBF + * [3] 10.5.2.25c RR Packet Uplink Assignment + * [3] 10.5.2.25d RR Packet Downlink Assignment +! * [3] 10.5.2.26 Page Mode + * [3] 10.5.2.26a (void) + * [3] 10.5.2.26b (void) + * [3] 10.5.2.26c (void) + * [3] 10.5.2.26d (void) +- * [3] 10.5.2.27 NCC Permitted + */ + DE_RR_POW_CMD, /* 10.5.2.28 Power Command */ + DE_RR_POW_CMD_AND_ACC_TYPE, /* 10.5.2.28a Power Command and access type */ +! /* +! * [3] 10.5.2.29 RACH Control Parameters +! * [3] 10.5.2.30 Request Reference +! */ +! DE_RR_CAUSE, /* 10.5.2.31 RR Cause */ + DE_RR_SYNC_IND, /* 10.5.2.39 Synchronization Indication */ +! /* [3] 10.5.2.32 SI 1 Rest Octets + * [3] 10.5.2.33 SI 2bis Rest Octets + * [3] 10.5.2.33a SI 2ter Rest Octets + * [3] 10.5.2.33b SI 2quater Rest Octets +! * [3] 10.5.2.34 SI 3 Rest Octets +! * [3] 10.5.2.35 SI 4 Rest Octets + * [3] 10.5.2.35a SI 6 Rest Octets + * [3] 10.5.2.36 SI 7 Rest Octets + * [3] 10.5.2.37 SI 8 Rest Octets +--- 3299,3346 ---- + + /* + * [3] 10.5.2.21c NC mode +! */ +! DE_RR_NEIGH_CELL_DSC, /* [3] 10.5.2.22 Neighbour Cell Description */ // jl +! /* + * [3] 10.5.2.22a Neighbour Cell Description 2 + * [3] 10.5.2.22b (void) + * [3] 10.5.2.22c NT/N Rest Octets ++ */ ++ DE_RR_P1_REST_OCTETS, /* [3] 10.5.2.23 P1 Rest Octets */ // jl ++ /* + * [3] 10.5.2.23 P1 Rest Octets + * [3] 10.5.2.24 P2 Rest Octets + * [3] 10.5.2.25 P3 Rest Octets +! */ +! DE_RR_PCD, /* [3] 10.5.2.25a Packet Channel Description */ // jl +! DE_RR_DM_OR_TBF, /* [3] 10.5.2.25b Dedicated mode or TBF */ // jl +! /* + * [3] 10.5.2.25c RR Packet Uplink Assignment + * [3] 10.5.2.25d RR Packet Downlink Assignment +! */ +! DE_RR_PAGE_MODE, /* [3] 10.5.2.26 Page Mode */ // jl +! /* + * [3] 10.5.2.26a (void) + * [3] 10.5.2.26b (void) + * [3] 10.5.2.26c (void) + * [3] 10.5.2.26d (void) + */ ++ DE_RR_NCC_PERMITTED, /* [3] 10.5.2.27 NCC Permitted */ // jl + DE_RR_POW_CMD, /* 10.5.2.28 Power Command */ + DE_RR_POW_CMD_AND_ACC_TYPE, /* 10.5.2.28a Power Command and access type */ +! DE_RR_RACH_CP, /* [3] 10.5.2.29 RACH Control Parameters */ // jl +! DE_RR_REQ_REF, /* [3] 10.5.2.30 Request Reference */ // jl +! DE_RR_CAUSE, /* 10.5.2.31 RR Cause */ + DE_RR_SYNC_IND, /* 10.5.2.39 Synchronization Indication */ +! DE_RR_SI_1_REST_OCTETS, /* [3] 10.5.2.32 SI 1 Rest Octets */ // jl +! /* + * [3] 10.5.2.33 SI 2bis Rest Octets + * [3] 10.5.2.33a SI 2ter Rest Octets + * [3] 10.5.2.33b SI 2quater Rest Octets +! */ +! DE_RR_SI_3_REST_OCTETS, /* [3] 10.5.2.34 SI 3 Rest Octets */ // jl +! DE_RR_SI_4_REST_OCTETS, /* [3] 10.5.2.35 SI 4 Rest Octets */ // jl +! /* + * [3] 10.5.2.35a SI 6 Rest Octets + * [3] 10.5.2.36 SI 7 Rest Octets + * [3] 10.5.2.37 SI 8 Rest Octets +*************** +*** 3463,3480 **** + de_cell_id(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string, int string_len) + { + guint32 curr_offset; + +! curr_offset = offset; + +- curr_offset += + /* 0x02 CI */ +! be_cell_id_aux(tvb, tree, offset, len, add_string, string_len, 0x02); + + /* no length check possible */ + + return(curr_offset - offset); + } + + /* + * [3] 10.5.1.3 + */ +--- 3511,3631 ---- + de_cell_id(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string, int string_len) + { + guint32 curr_offset; ++ proto_item *item; ++ proto_tree *subtree; + +! curr_offset = offset; +! +! item = proto_tree_add_text(tree, tvb, curr_offset, 2, gsm_dtap_elem_strings[DE_CELL_ID].strptr); +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_CELL_ID]); + + /* 0x02 CI */ +! curr_offset += be_cell_id_aux(tvb, subtree, offset, len, add_string, string_len, 0x02); + + /* no length check possible */ + + return(curr_offset - offset); + } + ++ ++ // jl -- got this list somewhere off the net... ++ typedef struct mcc_mnc_name_s { ++ char *mcc; ++ char *mnc; ++ char *name; ++ } mcc_mnc_name_t; ++ ++ static mcc_mnc_name_t mcc_mnc_names[] = { ++ {"310", "110", "Wireless 2000 PCS"}, ++ {"310", "020", "Union Telephone"}, ++ {"310", "260", "T-Mobile"}, ++ {"310", "030", "Centennial"}, ++ {"310", "310", "T-Mobile"}, ++ {"310", "040", "Concho Wireless"}, ++ {"310", "460", "Simmetry"}, ++ {"310", "070", "Highland Cellular"}, ++ {"310", "080", "Corr Wireless"}, ++ {"310", "090", "Edge Wireless"}, ++ {"310", "100", "Plateau Wireless"}, ++ {"310", "170", "T-Mobile (formerly Cingular Wireless CA/NV)"}, ++ {"310", "180", "West Central"}, ++ {"310", "190", "Alaska Wireless"}, ++ {"310", "320", "Cellular One"}, ++ {"310", "340", "WestLink"}, ++ {"310", "390", "Yorkville"}, ++ {"310", "410", "Cingular Wireless"}, ++ {"310", "420", "Cincinnati Bell"}, ++ {"310", "430", "Alaska DigiTel"}, ++ {"310", "440", "Cellular One"}, ++ {"310", "450", "Viaero Wireless"}, ++ {"310", "460", "Simmetry (formerly OneLink PCS)"}, ++ {"310", "490", "SunCom"}, ++ {"310", "500", "Alltel (formerly PSC Wireless - GA/AL region only)"}, ++ {"310", "530", "West VA Wireless"}, ++ {"310", "540", "Oklahoma Western"}, ++ {"310", "560", "Cellular One DCS"}, ++ {"310", "590", "Western Wireless (now parto of Alltel)"}, ++ {"310", "610", "Epic Touch"}, ++ {"310", "620", "Coleman Telecomm"}, ++ {"310", "630", "AmeriLink PCS"}, ++ {"310", "640", "Einstein PCS"}, ++ {"310", "680", "Cellular One DCS (Dobson. Formerly NPI Wireless)"}, ++ {"310", "690", "Immix Wireless"}, ++ {"310", "740", "Telemetrix"}, ++ {"310", "760", "Panhandle Telecomm"}, ++ {"310", "770", "Iowa Wireless"}, ++ {"310", "790", "PinPoint Wireless"}, ++ {"310", "830", "Caprock Cellular"}, ++ {"310", "870", "Kaplan"}, ++ {"310", "880", "Advantage Cellular"}, ++ {"310", "890", "RCC/Unicell"}, ++ {"310", "900", "Texas Cellular"}, ++ {"310", "910", "First Cellular"}, ++ {"310", "940", "Digital Cellular"}, ++ {"310", "950", "XIT Wireless"}, ++ {"310", "980", "Cingular Wireless (not in commercial use)"}, ++ {"310", "990", "Cingular Wireless (not in commercial use)"}, ++ {"311", "000", "Mid-Tex Cellular"}, ++ {"311", "030", "Indigo Wireless"}, ++ {"311", "040", "Commnet Wireless"}, ++ {"311", "050", "Wilkes Cellular"}, ++ {"311", "070", "Easterbrooke"}, ++ {"311", "080", "Pine Cellular"}, ++ {"311", "090", "Siouxland PCS"}, ++ {"311", "110", "High Plains Wireless"}, ++ {"311", "130", "Cell One Amarillo"}, ++ {"311", "140", "Sprocket (aka MBO Wireless)"}, ++ {"311", "150", "Wilkes Cellular"}, ++ {"311", "160", "Cellular One DCS (Dobson. Formerly EMW)"}, ++ {"311", "170", "PetroCom"}, ++ {"311", "180", "Cingular Wireless (not in commercial use)"}, ++ {"311", "190", "Cellular Properties Inc (aka CellOne East Central IL)"}, ++ {"311", "210", "Farmers Cellular"}, ++ {"311", "250", "USA i CAN"}, ++ {"310", "110", "Wireless 2000 PCS (no longer in business)"}, ++ {"310", "150", "Cingular Wireless (SE GA/SC/NC/E TN. Consolidated with 310-410)"}, ++ {"310", "160", "T-Mobile (consolidated with 310-260. Formerly Omnipoint)"}, ++ {"310", "200", "T-Mobile (consolidated with 310-260)"}, ++ {"310", "210", "T-Mobile (consolidated with 310-260)"}, ++ {"310", "220", "T-Mobile (consolidated with 310-260)"}, ++ {"310", "230", "T-Mobile (consolidated with 310-260)"}, ++ {"310", "240", "T-Mobile (consolidated with 310-260)"}, ++ {"310", "250", "T-Mobile (consolidated with 310-260)"}, ++ {"310", "260", "T-Mobile (consolidated with 310-260)"}, ++ {"310", "270", "T-Mobile (consolidated with 310-260. Former Powertel)"}, ++ {"310", "310", "T-Mobile (consolidated with 310-260. Former Aerial)"}, ++ {"310", "350", "Carolina Phone (No longer in business)"}, ++ {"310", "380", "Cingular Wireless (formerly AT&T Wireless)"}, ++ {"310", "400", "Minnesota Southern (never actually used)"}, ++ {"310", "580", "T-Mobile (consolidated with 310-260. Former PCS One)"}, ++ {"310", "660", "T-Mobile (consolidated with 310-260. Former DigiPH)"}, ++ {"310", "670", "Wireless 2000 PCS (No longer in business)"}, ++ {"310", "780", "AirLink PCS (No longer in business)"}, ++ {"310", "800", "T-Mobile (consolidated with 310-260)"}, ++ {0, 0, 0} ++ }; ++ ++ + /* + * [3] 10.5.1.3 + */ +*************** +*** 3485,3493 **** + guint16 value; + guint32 curr_offset; + proto_tree *subtree; +! proto_item *item; + gchar mcc[4]; + gchar mnc[4]; + + len = len; + curr_offset = offset; +--- 3636,3646 ---- + guint16 value; + guint32 curr_offset; + proto_tree *subtree; +! proto_item *item, *item_name; + gchar mcc[4]; + gchar mnc[4]; ++ mcc_mnc_name_t *mmn = &mcc_mnc_names[0]; ++ + + len = len; + curr_offset = offset; +*************** +*** 3506,3516 **** + mcc_mnc_aux(octs, mcc, mnc); + + +! proto_tree_add_text(subtree, + tvb, curr_offset, 3, + "Mobile Country Code (MCC): %s, Mobile Network Code (MNC): %s", + mcc, + mnc); + + curr_offset += 3; + +--- 3659,3676 ---- + mcc_mnc_aux(octs, mcc, mnc); + + +! item_name = proto_tree_add_text(subtree, + tvb, curr_offset, 3, + "Mobile Country Code (MCC): %s, Mobile Network Code (MNC): %s", + mcc, + mnc); ++ while(mmn->name) { ++ if((!strncmp(mcc, mmn->mcc, 3)) && (!strncmp(mnc, mmn->mnc, 3))) { ++ proto_item_append_text(item_name, " -- %s", mmn->name); ++ break; ++ } ++ mmn++; ++ } + + curr_offset += 3; + +*************** +*** 4051,4071 **** + guint8 oct,bit,byte; + guint16 arfcn; + proto_item *item; +! + + len = len; + curr_offset = offset; + + oct = tvb_get_guint8(tvb, curr_offset); + + /* FORMAT-ID, Format Identifier (part of octet 3)*/ +! proto_tree_add_item(tree, hf_gsm_a_rr_format_id, tvb, curr_offset, 1, FALSE); + /* Cell Channel Description */ + + if ((oct & 0xc0) == 0x00) + { + /* bit map 0 */ +! item = proto_tree_add_text(tree,tvb, curr_offset, 16,"list of ARFCN for hopping = "); + bit = 4; + arfcn = 125; + for (byte = 0;byte <= 15;byte++) +--- 4211,4237 ---- + guint8 oct,bit,byte; + guint16 arfcn; + proto_item *item; +! proto_tree *subtree; + + len = len; + curr_offset = offset; + ++ item = proto_tree_add_text(tree, tvb, curr_offset, 16, gsm_dtap_elem_strings[DE_RR_CELL_CH_DSC].strptr); ++ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_CELL_CH_DSC]); ++ + oct = tvb_get_guint8(tvb, curr_offset); + ++ // mask out "spare" bits which can be used for other channel lists -- jl ++ oct = oct & 0xcf; ++ + /* FORMAT-ID, Format Identifier (part of octet 3)*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_format_id, tvb, curr_offset, 1, FALSE); + /* Cell Channel Description */ + + if ((oct & 0xc0) == 0x00) + { + /* bit map 0 */ +! item = proto_tree_add_text(subtree,tvb, curr_offset, 16,"list of ARFCN for hopping = "); + bit = 4; + arfcn = 125; + for (byte = 0;byte <= 15;byte++) +*************** +*** 4086,4117 **** + else if ((oct & 0xf8) == 0x80) + { + /* 1024 range */ +! proto_tree_add_text(tree,tvb, curr_offset, 16,"Cell Channel Description (1024 range) (Not decoded)"); + curr_offset = curr_offset + 16; + } + else if ((oct & 0xfe) == 0x88) + { + /* 512 range */ +! proto_tree_add_text(tree,tvb, curr_offset, 16,"Cell Channel Description (512 range) (Not decoded)"); + curr_offset = curr_offset + 16; + } + else if ((oct & 0xfe) == 0x8a) + { + /* 256 range */ +! proto_tree_add_text(tree,tvb, curr_offset, 16,"Cell Channel Description (256 range) (Not decoded)"); + curr_offset = curr_offset + 16; + } + else if ((oct & 0xfe) == 0x8c) + { + /* 128 range */ +! proto_tree_add_text(tree,tvb, curr_offset, 16,"Cell Channel Description (128 range) (Not decoded)"); + curr_offset = curr_offset + 16; + } + else if ((oct & 0xfe) == 0x8e) + { + /* variable bit map */ + arfcn = ((oct & 0x01) << 9) | (tvb_get_guint8(tvb, curr_offset+1) << 1) | ((tvb_get_guint8(tvb, curr_offset + 2) & 0x80) >> 7); +! item = proto_tree_add_text(tree,tvb, curr_offset, 16,"list of ARFCN for hopping = %d",arfcn); + curr_offset = curr_offset + 2; + bit = 7; + for (byte = 0;byte <= 13;byte++) +--- 4252,4283 ---- + else if ((oct & 0xf8) == 0x80) + { + /* 1024 range */ +! proto_tree_add_text(subtree,tvb, curr_offset, 16,"Cell Channel Description (1024 range) (Not decoded)"); + curr_offset = curr_offset + 16; + } + else if ((oct & 0xfe) == 0x88) + { + /* 512 range */ +! proto_tree_add_text(subtree,tvb, curr_offset, 16,"Cell Channel Description (512 range) (Not decoded)"); + curr_offset = curr_offset + 16; + } + else if ((oct & 0xfe) == 0x8a) + { + /* 256 range */ +! proto_tree_add_text(subtree,tvb, curr_offset, 16,"Cell Channel Description (256 range) (Not decoded)"); + curr_offset = curr_offset + 16; + } + else if ((oct & 0xfe) == 0x8c) + { + /* 128 range */ +! proto_tree_add_text(subtree,tvb, curr_offset, 16,"Cell Channel Description (128 range) (Not decoded)"); + curr_offset = curr_offset + 16; + } + else if ((oct & 0xfe) == 0x8e) + { + /* variable bit map */ + arfcn = ((oct & 0x01) << 9) | (tvb_get_guint8(tvb, curr_offset+1) << 1) | ((tvb_get_guint8(tvb, curr_offset + 2) & 0x80) >> 7); +! item = proto_tree_add_text(subtree,tvb, curr_offset, 16,"list of ARFCN for hopping = %d",arfcn); + curr_offset = curr_offset + 2; + bit = 7; + for (byte = 0;byte <= 13;byte++) +*************** +*** 4172,4181 **** + + return(curr_offset - offset); + } +! /* + * [3] 10.5.2.3 Cell Options (BCCH) + * [3] 10.5.2.3a Cell Options (SACCH) + * [3] 10.5.2.4 Cell Selection Parameters + * [3] 10.5.2.4a MAC Mode and Channel Coding Requested + * [3] 10.5.2.5 Channel Description + */ +--- 4338,4545 ---- + + return(curr_offset - offset); + } +! +! +! /* // jl + * [3] 10.5.2.3 Cell Options (BCCH) ++ * ++ * DN-IND, Dynamic ARFCN mapping indicator (octet 2) Note 4 ++ * 87654321 ++ * 0....... Dynamic ARFCN mapping is not used by the PLMN ++ * 1....... Dynamic ARFCN mapping is used by the PLMN ++ * ++ * PWRC Power control indicator (octet 2) Note 1 ++ * 87654321 ++ * .0...... PWRC is not set ++ * .1...... PWRC is set ++ * ++ * DTX, DTX indicator (octet 2) Note 3 ++ * 65 ++ * ..00.... The MSs may use uplink discontinuous transmission ++ * ..01.... The MSs shall use uplink discontinuous transmission ++ * ..10.... The MS shall not use uplink discontinuous transmission ++ * ++ * RADIO-LINK_TIMEOUT (octet 2) Note 2 ++ * 4321 ++ * ....0000 4 ++ * ....0001 8 ++ * ....0010 12 ++ * ++ * ....1110 60 ++ * ....1111 64 ++ * ++ * NOTE 1: The precise meaning of the PWRC parameter can be found in 3GPP TS 45.008. ++ * NOTE 2: The precise meaning of RADIO-LINK-TIMEOUT parameter can be found in 3GPP TS 45.008. ++ * NOTE 3: The DTX indicator field is not related to the use of downlink discontinuous transmission. ++ * NOTE 4: Dynamic ARFCN mapping is specified in 3GPP TS 45.005. ++ */ ++ static const value_string gsm_a_rr_co_bcch_dn_ind_vals[] = { ++ {0, "Dynamic ARFCN mapping is not used by the PLMN"}, ++ {1, "Dynamic ARFCN mapping is used by the PLMN"}, ++ {0, 0} ++ }; ++ ++ static const value_string gsm_a_rr_co_bcch_pwrc_vals[] = { ++ {0, "PWRC is not set"}, ++ {1, "PWRC is set"}, ++ {0, 0} ++ }; ++ ++ static const value_string gsm_a_rr_co_bcch_dtx_vals[] = { ++ {0, "The MSs may use uplink discontinuous transmission"}, ++ {1, "The MSs shall use uplink discontinuous transmission"}, ++ {2, "The MSs shall not use uplink discontinuous transmission"}, ++ {0, 0} ++ }; ++ ++ ++ static guint8 de_rr_co_bcch(tvbuff_t *tvb, proto_tree *tree, ++ guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) { ++ ++ guint32 curr_offset; ++ guint8 oct; ++ int rl_timeout; ++ proto_tree *subtree; ++ proto_item *item; ++ ++ len = len; ++ curr_offset = offset; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, 1, gsm_dtap_elem_strings[DE_RR_CO_BCCH].strptr); ++ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_CO_BCCH]); ++ proto_tree_add_item(subtree, hf_gsm_a_rr_co_bcch_dn_ind, tvb, curr_offset, 1, FALSE); ++ proto_tree_add_item(subtree, hf_gsm_a_rr_co_bcch_pwrc, tvb, curr_offset, 1, FALSE); ++ proto_tree_add_item(subtree, hf_gsm_a_rr_co_bcch_dtx, tvb, curr_offset, 1, FALSE); ++ ++ oct = tvb_get_guint8(tvb, curr_offset); ++ rl_timeout = ((oct & 0xf) + 1) * 4; ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "radio-link timeout %d", rl_timeout); ++ ++ curr_offset++; ++ ++ return curr_offset - offset; ++ } ++ ++ ++ /* + * [3] 10.5.2.3a Cell Options (SACCH) ++ */ ++ ++ /* // jl + * [3] 10.5.2.4 Cell Selection Parameters ++ * ++ * CELL-RESELECT-HYSTERESIS (octet 2) ++ * The usage of this information is defined in 3GPP TS 45.008 ++ * ++ * 8 7 6 ++ * 0 0 0 0 dB RXLEV hysteresis for LA re-selection ++ * 0 0 1 2 dB RXLEV hysteresis for LA re-selection ++ * 0 1 0 4 dB RXLEV hysteresis for LA re-selection ++ * 0 1 1 6 dB RXLEV hysteresis for LA re-selection ++ * 1 0 0 8 dB RXLEV hysteresis for LA re-selection ++ * 1 0 1 10 dB RXLEV hysteresis for LA re-selection ++ * 1 1 0 12 dB RXLEV hysteresis for LA re-selection ++ * 1 1 1 14 dB RXLEV hysteresis for LA re-selection ++ * ++ * MS-TXPWR-MAX-CCH (octet 2) ++ * Bits 5 - 1: ++ * The MS-TXPWR-MAX-CCH field is coded as the binary representation ++ * of the "power control level" in 3GPP TS 45.005 corresponding to ++ * the maximum TX power level an MS may use when accessing on a ++ * Control Channel CCH. This value shall be used by the Mobile ++ * Station according to 3GPP TS 45.008. ++ * ++ * Range: 0 to 31. ++ * ++ * ACS, ADDITIONAL RESELECT PARAM IND (octet 3) ++ * Bit 8: In System Information type 3 message: ++ * 0 System information type 16 and 17 are not broadcast on the BCCH. ++ * 1 System information type 16 and 17 are broadcast on the ++ * BCCH. A mobile station which does not support System ++ * information type 16 and 17 may consider this bit as "0". ++ * ++ * In System Information type 4 message: ++ * 0 The SI 4 rest octets, if present, and SI 7 and SI 8 rest octets, if ++ * so indicated in the SI 4 rest octets shall be used to derive the value ++ * of PI and possibly C2 parameters and/or other parameters ++ * 1 The value of PI and possibly C2 parameters and/or other parameters ++ * in a System information type 7 or type 8 message shall be used ++ * ++ * NECI: HALF RATE SUPPORT (octet 3) ++ * Bit 7: ++ * 0 New establishment causes are not supported ++ * 1 New establishment causes are supported ++ * ++ * RXLEV-ACCESS-MIN (octet 3) ++ * Bits 6 - 1: ++ * The RXLEV-ACCESS-MIN field is coded as the binary representation ++ * of the minimum received signal level at the MS for which it is ++ * permitted to access the system. ++ * ++ * Range: 0 to 63. (See 3GPP TS 45.008). ++ */ ++ static guint8 de_rr_cell_sel_param(tvbuff_t *tvb, proto_tree *tree, ++ guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) { ++ ++ guint32 curr_offset; ++ guint8 oct; ++ proto_tree *subtree; ++ proto_item *item; ++ int crh, mtmc, acs, hrs, ram; ++ ++ len = len; ++ curr_offset = offset; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, 2, gsm_dtap_elem_strings[DE_RR_CELL_SEL_PARAM].strptr); ++ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_CELL_SEL_PARAM]); ++ ++ oct = tvb_get_guint8(tvb, curr_offset); ++ ++ // CELL-RESELECT-HYSTERESIS ++ crh = ((oct & 0xe0) >> 5) * 2; ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "Cell Reselect Hysteresis: %d dB RXLEV hysteresis for LA re-selection", crh); ++ ++ // MS-TXPWR-MAX-CCH (octet 2) ++ mtmc = (oct & 0x1f); ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "Maximum TX power level an MS may use when accessing on a Control Channel CCH: %d", mtmc); ++ ++ curr_offset++; ++ oct = tvb_get_guint8(tvb, curr_offset); ++ ++ // ACS, System Information Type 3 ++ acs = (oct & 0x80) >> 7; ++ item = proto_tree_add_text(subtree, tvb, curr_offset, 1, "In System Information Type 3: "); ++ if(!acs) ++ proto_item_append_text(item, "System Information Types 16 and 17 are not broadcast on the BCCH"); ++ else ++ proto_item_append_text(item, "System Information Types 16 and 17 are broadcast on the BCCH"); ++ ++ item = proto_tree_add_text(subtree, tvb, curr_offset, 1, "In System Information Type 4: "); ++ if(!acs) ++ proto_item_append_text(item, "The SI 4, SI 7, and SI 8 rest octets shall be used to derive the value of PI and possibly C2 parameters"); ++ else ++ proto_item_append_text(item, "The value of PI and possibly C2 parameters in a System Information Type 7 or 8 message shall be used"); ++ ++ // NECI: HALF RATE SUPPORT (octet 3) ++ hrs = (oct & 0x40) >> 6; ++ item = proto_tree_add_text(subtree, tvb, curr_offset, 1, "Half Rate Support: "); ++ if(!hrs) ++ proto_item_append_text(item, "New establishment causes are not supported"); ++ else ++ proto_item_append_text(item, "New establishment causes are supported"); ++ ++ // RXLEV-ACCESS-MIN (octet 3) ++ ram = oct & 0x3f; ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "RXLEV-ACCESS-MIN: Minimum received signal level at the MS for which it is permitted to access " ++ "the system: %d", ram); ++ ++ curr_offset++; ++ ++ return curr_offset - offset; ++ } ++ ++ ++ /* + * [3] 10.5.2.4a MAC Mode and Channel Coding Requested + * [3] 10.5.2.5 Channel Description + */ +*************** +*** 4207,4212 **** +--- 4571,4578 ---- + } + else + { ++ subchannel = 0; ++ str = ""; + if ((oct8 & 0xf0) == 0x10) + { + str = "TCH/H + ACCHs, Subchannel"; +*************** +*** 4309,4314 **** +--- 4675,4682 ---- + } + else + { ++ subchannel = 0; ++ str = ""; + if ((oct8 & 0xf0) == 0x10) + { + str = "TCH/H + ACCHs, Subchannel"; +*************** +*** 4517,4534 **** + guint8 + de_rr_chnl_needed(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) + { +! guint32 curr_offset; + +! len = len; +! curr_offset = offset; +! +! proto_tree_add_item(tree, hf_gsm_a_rr_chnl_needed_ch1, tvb, curr_offset, 1, FALSE); +! proto_tree_add_item(tree, hf_gsm_a_rr_chnl_needed_ch2, tvb, curr_offset, 1, FALSE); + + curr_offset = curr_offset + 1; + +! return(curr_offset - offset); + } + /* + * [3] 10.5.2.8a Channel Request Description + * [3] 10.5.2.8b Channel Request Description 2 +--- 4885,4910 ---- + guint8 + de_rr_chnl_needed(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) + { +! proto_tree *subtree; +! proto_item *item; +! guint32 curr_offset; + +! len = len; +! curr_offset = offset; +! +! item = proto_tree_add_text(tree, tvb, curr_offset, 1, gsm_dtap_elem_strings[DE_RR_CHNL_NEEDED].strptr); +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_CHNL_NEEDED]); +! proto_tree_add_item(subtree, hf_gsm_a_rr_chnl_needed_ch1, tvb, curr_offset, 1, FALSE); +! proto_tree_add_item(subtree, hf_gsm_a_rr_chnl_needed_ch2, tvb, curr_offset, 1, FALSE); +! +! // we're assuming that this is the second half octet, so go +! // ahead and increase curr_offset. + + curr_offset = curr_offset + 1; + +! return(curr_offset - offset); + } ++ + /* + * [3] 10.5.2.8a Channel Request Description + * [3] 10.5.2.8b Channel Request Description 2 +*************** +*** 4573,4579 **** + } + /* + * [3] 10.5.2.10 Cipher Response +! * [3] 10.5.2.11 Control Channel Description + * [3] 10.5.2.11a DTM Information Details + */ + /* +--- 4949,5079 ---- + } + /* + * [3] 10.5.2.10 Cipher Response +! */ +! +! +! /* +! * [3] 10.5.2.11 Control Channel Description // jl +! */ +! +! static const true_false_string gsm_a_rr_cc_dsc_mscr_tfs = { +! "MSC is Release 1999 onwards.", +! "MSC is Release 1998 or older." +! }; +! +! static const true_false_string gsm_a_rr_cc_dsc_att_tfs = { +! "MSs in the cell shall apply IMSI attach and detach procedure.", +! "MSs in the cell are not allowed to apply IMSI attach and detach " +! "procedure." +! }; +! +! static const value_string gsm_a_rr_cc_dsc_cbq3_vals[] = { +! {0, "Iu mode not supported."}, +! {1, "Iu mode capable MSs barred."}, +! {2, "Iu mode supported, cell not barred."}, +! {3, "Iu mode supported, cell not barred. The network shall not use " +! "this value."}, +! {0, 0} +! }; +! +! static const value_string gsm_a_rr_cc_dsc_ccch_vals[] = { +! {0, "1 basic physical channel used for CCCH, not combined with " +! "SDCCHs"}, +! {1, "1 basic physical channel used for CCCH, combined with SDCCHs"}, +! {2, "2 basic physical channels used for CCCH, not combined with " +! "SDCCHs"}, +! {3, "reserved"}, +! {4, "3 basic physical channels used for CCCH, not combined with " +! "SDCCHs"}, +! {5, "reserved"}, +! {6, "4 basic physical channels used for CCCH, not combined with " +! "SDCCHs"}, +! {7, "reserved"}, +! {0, 0} +! }; +! +! static guint8 de_rr_cc_dsc(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) { +! +! guint32 curr_offset; +! guint8 oct; +! guint curr_len; +! proto_tree *subtree; +! proto_item *item; +! int bsagblksres, ccchconf, bspamfrms, psch; +! float t3212; +! +! curr_offset = offset; +! curr_len = len; +! +! item = proto_tree_add_text(tree, tvb, curr_offset, 3, +! gsm_dtap_elem_strings[DE_RR_CC_DSC].strptr); +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_CC_DSC]); +! +! proto_tree_add_item(subtree, hf_gsm_a_rr_cc_dsc_mscr, tvb, curr_offset, +! 1, FALSE); +! proto_tree_add_item(subtree, hf_gsm_a_rr_cc_dsc_att, tvb, curr_offset, +! 1, FALSE); +! +! oct = tvb_get_guint8(tvb, curr_offset); +! +! // BS-AG-BLKS-RES +! bsagblksres = (oct & 0x38) >> 3; +! +! // CCCH-CONF +! ccchconf = (oct & 7); +! +! item = proto_tree_add_text(subtree, tvb, curr_offset, 1, +! "BS-AG-BLKS-RES: "); +! +! if((ccchconf == 1) && (bsagblksres > 2)) +! proto_item_append_text(item, "reserved"); +! else +! proto_item_append_text(item, "%d", bsagblksres); +! +! proto_tree_add_item(subtree, hf_gsm_a_rr_cc_dsc_ccch, tvb, curr_offset, +! 1, FALSE); +! +! curr_offset++; curr_len--; +! proto_tree_add_item(subtree, hf_gsm_a_rr_cc_dsc_cbq3, tvb, curr_offset, +! 1, FALSE); +! +! oct = tvb_get_guint8(tvb, curr_offset); +! +! // BS-PA-MFRMS +! bspamfrms = (oct & 0x7) + 2; +! proto_tree_add_text(subtree, tvb, curr_offset, 1, "BS-PA-MFRMS: %d " +! "multiframes period for transmission of PAGING REQUEST messages " +! "to the same paging subgroup", bspamfrms); +! +! curr_offset++; curr_len--; +! oct = tvb_get_guint8(tvb, curr_offset); +! +! // T3212 +! t3212 = (float)oct / 10.0; +! item = proto_tree_add_text(subtree, tvb, curr_offset, 1, "T3212 " +! "timeout value: "); +! if(oct) +! proto_item_append_text(item, "%.1f hours (%d minutes)", +! t3212, (int)oct * 6); +! else +! proto_item_append_text(item, "infinite (periodic updating " +! "shall not be used within the cell)"); +! +! item = proto_tree_add_text(subtree, tvb, curr_offset - 2, 2, +! "The number of different paging subchannels on the CCCH is "); +! if(ccchconf == 1) +! psch = MAX(1, (3 - bsagblksres)) * bspamfrms; +! else +! psch = (9 - bsagblksres) * bspamfrms; +! proto_item_append_text(item, "%d", psch); +! +! curr_offset++; curr_len--; +! +! return curr_offset - offset; +! } +! +! +! /* + * [3] 10.5.2.11a DTM Information Details + */ + /* +*************** +*** 4755,4762 **** +--- 5255,5288 ---- + + return(curr_offset - offset); + } ++ ++ + /* + * [3] 10.5.2.16 IA Rest Octets ++ * ++ * XXX not done ++ */ ++ static guint8 de_rr_ia_rest_octets(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) ++ { ++ guint32 curr_offset; ++ guint curr_len; ++ // proto_tree *subtree; ++ proto_item *item; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, curr_len, gsm_dtap_elem_strings[DE_RR_IA_REST_OCTETS].strptr); ++ // subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_IA_REST_OCTETS]); ++ ++ // len is -1 for mandatory, so can't increase by this. ++ // curr_offset += curr_len; ++ ++ return curr_offset - offset; ++ } ++ ++ ++ /* + * [3] 10.5.2.17 IAR Rest Octets + * [3] 10.5.2.18 IAX Rest Octets + * [3] 10.5.2.19 L2 Pseudo Length +*************** +*** 4900,4925 **** + return(curr_offset - offset); + + } + /* + * [3] 10.5.2.21c NC mode +! * [3] 10.5.2.22 Neighbour Cell Description + * [3] 10.5.2.22a Neighbour Cell Description 2 + * [3] 10.5.2.22b (void) + * [3] 10.5.2.22c NT/N Rest Octets + * [3] 10.5.2.23 P1 Rest Octets + * [3] 10.5.2.24 P2 Rest Octets + * [3] 10.5.2.25 P3 Rest Octets + * [3] 10.5.2.25a Packet Channel Description + * [3] 10.5.2.25b Dedicated mode or TBF + * [3] 10.5.2.25c RR Packet Uplink Assignment + * [3] 10.5.2.25d RR Packet Downlink Assignment + * [3] 10.5.2.26 Page Mode + * [3] 10.5.2.26a (void) + * [3] 10.5.2.26b (void) + * [3] 10.5.2.26c (void) + * [3] 10.5.2.26d (void) +- * [3] 10.5.2.27 NCC Permitted + */ + /* + * [3] 10.5.2.28 Power Command + * +--- 5426,5786 ---- + return(curr_offset - offset); + + } ++ ++ + /* + * [3] 10.5.2.21c NC mode +! */ +! +! +! /* +! * [3] 10.5.2.22 Neighbour Cell Description // jl +! * +! * The purpose of the Neighbour Cell Description information +! * element is to provide the absolute radio frequency channel +! * numbers of the BCCH carriers to be monitored by the mobile +! * stations in the cell. +! * +! * The Neighbour Cell Description information element is coded as +! * the Cell Channel Description information element, as specified +! * in sub-clause 10.5.2.1b, with the exception of bits 5 and 6 of +! * octet 2. Figure 10.5.2.22.1 and table 10.5.2.22.1: contains the +! * difference of specifications. +! */ +! +! static const true_false_string gsm_a_rr_neigh_cell_dsc_ext_tfs = { +! "The information element carries only a part of the BA", +! "The information element carries the complete BA" +! }; +! +! static const true_false_string gsm_a_rr_neigh_cell_dsc_ba_tfs = { +! "Base Allocation for SACCH", +! "Base Allocation for BCCH" +! }; +! +! static guint8 de_rr_neigh_cell_dsc(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) +! { +! guint32 curr_offset; +! guint curr_len; +! proto_tree *subtree; +! proto_item *item; +! +! curr_offset = offset; +! curr_len = len; +! +! item = proto_tree_add_text(tree, tvb, curr_offset, 16, +! gsm_dtap_elem_strings[DE_RR_NEIGH_CELL_DSC].strptr); +! subtree = proto_item_add_subtree(item, +! ett_gsm_dtap_elem[DE_RR_NEIGH_CELL_DSC]); +! +! proto_tree_add_item(subtree, hf_gsm_a_rr_neigh_cell_dsc_ext, tvb, +! curr_offset, 1, FALSE); +! proto_tree_add_item(subtree, hf_gsm_a_rr_neigh_cell_dsc_ba, tvb, +! curr_offset, 1, FALSE); +! +! return de_rr_cell_ch_dsc(tvb, tree, curr_offset, curr_len, add_string, +! string_len); +! } +! +! +! /* + * [3] 10.5.2.22a Neighbour Cell Description 2 + * [3] 10.5.2.22b (void) + * [3] 10.5.2.22c NT/N Rest Octets ++ */ ++ ++ ++ /* // jl + * [3] 10.5.2.23 P1 Rest Octets ++ * ++ * XXX not done ++ */ ++ static guint8 de_rr_p1_rest_octets(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) ++ { ++ guint32 curr_offset; ++ guint curr_len; ++ // proto_tree *subtree; ++ proto_item *item; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, curr_len, gsm_dtap_elem_strings[DE_RR_P1_REST_OCTETS].strptr); ++ // subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_P1_REST_OCTETS]); ++ ++ // mandatory elements get len == -1, so we can't increase this ++ // curr_offset += curr_len; ++ return curr_offset - offset; ++ } ++ ++ ++ /* + * [3] 10.5.2.24 P2 Rest Octets + * [3] 10.5.2.25 P3 Rest Octets ++ */ ++ ++ ++ /* // jl + * [3] 10.5.2.25a Packet Channel Description ++ * ++ * < Packet Channel Description > ::= ++ * < Channel type : bit (5) > ++ * < TN : bit (3) > ++ * < TSC : bit (3) > ++ * { 0 ++ * { 0 ++ * < spare bit > ++ * < ARFCN : bit (10) > -- non-hopping RF channel configuraion ++ * | 1 ++ * < spare bit > ++ * < MAIO : bit (6) > -- indirect encoding of hopping RF channel configuration ++ * < MA_NUMBER_IND : bit > ++ * { 0 ++ * < spare bits : bit (2) > ++ * | 1 ++ * < CHANGE_MARK_1 : bit (2) > ++ * } ++ * } ++ * | 1 ++ * < MAIO : bit (6) > -- direct encoding of hopping RF channel configuration ++ * < HSN : bit (6) > ++ * }; ++ * ++ * 5 + 3 + 3 + 1 + 12 = 24 ++ */ ++ static guint8 de_rr_pcd(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, char *add_string _U_, int string_len _U_) { ++ ++ guint32 curr_offset; ++ guint curr_len; ++ proto_tree *subtree; ++ proto_item *item; ++ int val, v; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, 3, gsm_dtap_elem_strings[DE_RR_PCD].strptr); ++ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_PCD]); ++ ++ val = tvb_get_ntoh24(tvb, curr_offset); ++ ++ // channel type ++ other_decode_bitfield_value(a_bigbuf, val, 0x1f0000, 24); ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "%s : Channel Type: %x", a_bigbuf, (val >> 16) & 0x1f); ++ ++ // TN ++ other_decode_bitfield_value(a_bigbuf, val, 0xe00000, 24); ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "%s : Timeslot Number: %d", a_bigbuf, ((val >> 16) & 0xe0) >> 5); ++ ++ curr_offset++; ++ curr_len--; ++ ++ // TSC ++ other_decode_bitfield_value(a_bigbuf, val, 0x700, 24); ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "%s : Training Sequence Code: %d", a_bigbuf, (val >> 8) & 0x7); ++ ++ if(!(val & 0x800)) { ++ if(!(val & 0x1000)) { ++ other_decode_bitfield_value(a_bigbuf, val, 0xc0ff, 24); ++ v = ((val & 0xc000) >> 6) | (val & 0xff); ++ proto_tree_add_text(subtree, tvb, curr_offset, 2, "%s : RF Channel Number: %d", a_bigbuf, v); ++ ++ curr_offset += 2; ++ curr_len -= 2; ++ } else { ++ other_decode_bitfield_value(a_bigbuf, val, 0xc00f, 24); ++ v = ((val & 0xc000) >> 10) | (val & 0x0f); ++ proto_tree_add_text(subtree, tvb, curr_offset, 2, "%s : Mobile Allocation Index Offset: %d", a_bigbuf, v); ++ ++ curr_offset++; ++ curr_len--; ++ ++ other_decode_bitfield_value(a_bigbuf, val, 0x10, 24); ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "%s : MA_NUMBER = %d", a_bigbuf, (val & 0x10)? 15 : 14); ++ ++ if(val & 0x20) { ++ other_decode_bitfield_value(a_bigbuf, val, 0xc0, 24); ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "%s : CHANGE_MARK_1 = %d", a_bigbuf, (val & 0xc0) >> 6); ++ ++ curr_offset++; ++ curr_len--; ++ } ++ } ++ } else { ++ other_decode_bitfield_value(a_bigbuf, val, 0xf003, 24); ++ v = ((val & 0xf000) >> 10) | (val & 0x3); ++ proto_tree_add_text(subtree, tvb, curr_offset, 2, "%s : Mobile Allocation Index Offset: %d", a_bigbuf, v); ++ ++ curr_offset++; ++ curr_len--; ++ ++ other_decode_bitfield_value(a_bigbuf, val, 0xfc, 24); ++ proto_tree_add_text(subtree, tvb, curr_offset, 1, "%s : Hopping Sequence Number: %d", a_bigbuf, (val & 0xfc) >> 2); ++ ++ curr_offset++; ++ curr_len--; ++ } ++ ++ return curr_offset - offset; ++ } ++ ++ ++ /* // jl ++ * + * [3] 10.5.2.25b Dedicated mode or TBF ++ */ ++ static const value_string gsm_a_rr_dm_or_tbf_vals[] = { ++ {0, "This message assigns a dedicated resource"}, ++ {2, "Not Used (error)"}, ++ {4, "Not Used (error)"}, ++ {6, "Not Used (error)"}, ++ {1, "This message assigns an uplink TBF or is the second message of two in a two-message assignment of an uplink or downlink TBF"}, ++ {3, "This message assigns a downlink TBF to the mobile station identified in the IA Rest Octets IE"}, ++ {5, "This message is the first message of two in a two-message assignment of an uplink TBF"}, ++ {7, "This message is the first message of two in a two-message assignment of a downlink TBF to the mobile station identified in the IA Rest Octets IE"}, ++ {0, 0} ++ }; ++ ++ static int ia_dedicated_mode_resource = 0; ++ static int ia_tbf = 0; ++ ++ static guint8 de_rr_dm_or_tbf(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) { ++ ++ guint32 curr_offset; ++ guint curr_len; ++ proto_tree *subtree; ++ proto_item *item; ++ guint8 oct; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, 1, gsm_dtap_elem_strings[DE_RR_DM_OR_TBF].strptr); ++ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_DM_OR_TBF]); ++ ++ proto_tree_add_item(subtree, hf_gsm_a_rr_dm_or_tbf, tvb, curr_offset, 1, FALSE); ++ oct = tvb_get_guint8(tvb, curr_offset); ++ if(!(oct & 0x10)) ++ ia_dedicated_mode_resource = 1; ++ else ++ ia_tbf = 1; ++ ++ // XXX assuming 2nd half of the octet, increasing curr_offset ++ curr_offset++; ++ curr_len--; ++ ++ return curr_offset - offset; ++ } ++ ++ ++ /* + * [3] 10.5.2.25c RR Packet Uplink Assignment + * [3] 10.5.2.25d RR Packet Downlink Assignment ++ */ ++ ++ /* // jl + * [3] 10.5.2.26 Page Mode ++ * ++ * PM (octet 1) ++ * 2 1 ++ * 0 0 Normal paging. ++ * 0 1 Extended paging. ++ * 1 0 Paging reorganization. ++ * 1 1 Same as before. ++ * ++ * NOTE: The value "same as before" has been defined instead of ++ * "reserved" to allow the use of this coding with another meaning in an ++ * upwards compatible way in later phases of the GSM system. ++ */ ++ static guint8 de_rr_page_mode(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) { ++ ++ guint32 curr_offset; ++ guint curr_len; ++ proto_tree *subtree; ++ proto_item *item; ++ guint8 oct; ++ int pm; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, 1, gsm_dtap_elem_strings[DE_RR_PAGE_MODE].strptr); ++ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_PAGE_MODE]); ++ ++ /* ++ * XXX ++ * ++ * The page mode IE is a half octet. We're assuming that it ++ * comes in the bottom half octet. (That is, we assume that it ++ * is the first message at the start of an octet boundary.) ++ */ ++ oct = tvb_get_guint8(tvb, curr_offset); ++ pm = (oct & 3); ++ item = proto_tree_add_text(subtree, tvb, curr_offset, 1, "Page Mode: "); ++ switch(pm) { ++ case 0: ++ proto_item_append_text(item, "Normal paging"); ++ break; ++ case 1: ++ proto_item_append_text(item, "Extended paging"); ++ break; ++ case 2: ++ proto_item_append_text(item, "Paging reorganization"); ++ break; ++ case 3: ++ proto_item_append_text(item, "Same as before"); ++ break; ++ } ++ ++ // we didn't really grab the whole octet, so curr_offset ++ // is not increased. ++ ++ return curr_offset - offset; ++ } ++ ++ ++ /* + * [3] 10.5.2.26a (void) + * [3] 10.5.2.26b (void) + * [3] 10.5.2.26c (void) + * [3] 10.5.2.26d (void) + */ ++ ++ ++ /* // jl ++ * [3] 10.5.2.27 NCC Permitted ++ * ++ * The NCC permitted field is coded as a bit map, i.e. bit N is ++ * coded with a "0" if the BCCH carrier with NCC = N - 1 is not ++ * permitted for monitoring and with a "1" if the BCCH carrier with ++ * NCC = N - 1 is permitted for monitoring; N = 1, 2, .., 8. ++ */ ++ static guint8 de_rr_ncc_permitted(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) ++ { ++ guint32 curr_offset; ++ guint curr_len; ++ proto_tree *subtree; ++ proto_item *item; ++ guint8 oct; ++ int bit; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, 1, gsm_dtap_elem_strings[DE_RR_NCC_PERMITTED].strptr); ++ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_NCC_PERMITTED]); ++ ++ item = proto_tree_add_text(subtree, tvb, curr_offset, 1, "Allowed NCC on BCCH carriers:"); ++ oct = tvb_get_guint8(tvb, curr_offset++); ++ ++ for(bit = 0; bit < 8; bit++) ++ if(oct & (1 << bit)) ++ proto_item_append_text(item, " %d", bit); ++ ++ return curr_offset - offset; ++ } ++ ++ + /* + * [3] 10.5.2.28 Power Command + * +*************** +*** 4978,5049 **** + proto_item *item; + guint32 curr_offset; + +! len = len; +! curr_offset = offset; + +! item = +! proto_tree_add_text(tree, +! tvb, curr_offset, 1, +! gsm_dtap_elem_strings[DE_RR_POW_CMD].strptr); + +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_POW_CMD]); + +! proto_tree_add_item(subtree, hf_gsm_a_b8spare, tvb, curr_offset, 1, FALSE); +! /*EPC mode */ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_epc, tvb, curr_offset, 1, FALSE); +! /*FPC_EPC*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_fpcepc, tvb, curr_offset, 1, FALSE); +! /*POWER LEVEL*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_powlev, tvb, curr_offset, 1, FALSE); +! +! curr_offset = curr_offset + 1; + +! return(curr_offset - offset); + } + + /* +! * [3] 10.5.2.28a Power Command and access type + */ +! static guint8 +! de_rr_pow_cmd_and_acc_type(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) +! { +! proto_tree *subtree; +! proto_item *item; +! guint32 curr_offset; + +! len = len; +! curr_offset = offset; + +! item = +! proto_tree_add_text(tree, +! tvb, curr_offset, 1, +! gsm_dtap_elem_strings[DE_RR_POW_CMD_AND_ACC_TYPE].strptr); + +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_POW_CMD_AND_ACC_TYPE]); + +! /*ATC */ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_atc, tvb, curr_offset, 1, FALSE); +! /*EPC mode */ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_epc, tvb, curr_offset, 1, FALSE); +! /*FPC_EPC*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_fpcepc, tvb, curr_offset, 1, FALSE); +! /*POWER LEVEL*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_powlev, tvb, curr_offset, 1, FALSE); +! +! curr_offset = curr_offset + 1; + +! return(curr_offset - offset); + } +! /* +! * [3] 10.5.2.29 RACH Control Parameters +! * [3] 10.5.2.30 Request Reference +! */ + + /* + * [3] 10.5.2.31 + */ +! guint8 +! de_rr_cause(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) + { + guint32 curr_offset; + +--- 5839,6099 ---- + proto_item *item; + guint32 curr_offset; + +! len = len; +! curr_offset = offset; +! +! item = +! proto_tree_add_text(tree, +! tvb, curr_offset, 1, +! gsm_dtap_elem_strings[DE_RR_POW_CMD].strptr); +! +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_POW_CMD]); +! +! proto_tree_add_item(subtree, hf_gsm_a_b8spare, tvb, curr_offset, 1, FALSE); +! /*EPC mode */ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_epc, tvb, curr_offset, 1, FALSE); +! /*FPC_EPC*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_fpcepc, tvb, curr_offset, 1, FALSE); +! /*POWER LEVEL*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_powlev, tvb, curr_offset, 1, FALSE); +! +! curr_offset = curr_offset + 1; +! +! return(curr_offset - offset); +! } +! +! /* +! * [3] 10.5.2.28a Power Command and access type +! */ +! static guint8 +! de_rr_pow_cmd_and_acc_type(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) +! { +! proto_tree *subtree; +! proto_item *item; +! guint32 curr_offset; +! +! len = len; +! curr_offset = offset; +! +! item = +! proto_tree_add_text(tree, +! tvb, curr_offset, 1, +! gsm_dtap_elem_strings[DE_RR_POW_CMD_AND_ACC_TYPE].strptr); +! +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_POW_CMD_AND_ACC_TYPE]); +! +! /*ATC */ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_atc, tvb, curr_offset, 1, FALSE); +! /*EPC mode */ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_epc, tvb, curr_offset, 1, FALSE); +! /*FPC_EPC*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_fpcepc, tvb, curr_offset, 1, FALSE); +! /*POWER LEVEL*/ +! proto_tree_add_item(subtree, hf_gsm_a_rr_pow_cmd_powlev, tvb, curr_offset, 1, FALSE); +! +! curr_offset = curr_offset + 1; +! +! return(curr_offset - offset); +! } +! +! +! /* +! * [3] 10.5.2.29 RACH Control Parameters +! * +! * Max retrans, Maximum number of retransmissions (octet 2) +! * +! * Bits +! * 8 7 +! * 0 0 Maximum 1 retransmission +! * 0 1 Maximum 2 retransmissions +! * 1 0 Maximum 4 retransmissions +! * 1 1 Maximum 7 retransmissions +! */ +! static const value_string gsm_a_rr_rach_cp_max_retrans_vals[] = { +! {0, "Maximum 1 retransmission"}, +! {1, "Maximum 2 retransmissions"}, +! {2, "Maximum 4 retransmissions"}, +! {3, "Maximum 7 retransmissions"}, +! {0, 0}, +! }; +! +! +! /* +! * Tx-integer, Number of slots to spread transmission (octet 2) +! * +! * Bits +! * 6 5 4 3 +! * 0 0 0 0 3 slots used to spread transmission +! * 0 0 0 1 4 slots used to spread transmission +! * 0 0 1 0 5 slots used to spread transmission +! * 0 0 1 1 6 slots used to spread transmission +! * 0 1 0 0 7 slots used to spread transmission +! * 0 1 0 1 8 slots used to spread transmission +! * 0 1 1 0 9 slots used to spread transmission +! * 0 1 1 1 10 slots used to spread transmission +! * 1 0 0 0 11 slots used to spread transmission +! * 1 0 0 1 12 slots used to spread transmission +! * 1 0 1 0 14 slots used to spread transmission +! * 1 0 1 1 16 slots used to spread transmission +! * 1 1 0 0 20 slots used to spread transmission +! * 1 1 0 1 25 slots used to spread transmission +! * 1 1 1 0 32 slots used to spread transmission +! * 1 1 1 1 50 slots used to spread transmission +! */ +! static const value_string gsm_a_rr_rach_cp_tx_integer_vals[] = { +! {0, "3 slots used to spread transmission"}, +! {1, "4 slots used to spread transmission"}, +! {2, "5 slots used to spread transmission"}, +! {3, "6 slots used to spread transmission"}, +! {4, "7 slots used to spread transmission"}, +! {5, "8 slots used to spread transmission"}, +! {6, "9 slots used to spread transmission"}, +! {7, "10 slots used to spread transmission"}, +! {8, "11 slots used to spread transmission"}, +! {9, "12 slots used to spread transmission"}, +! {10, "14 slots used to spread transmission"}, +! {11, "16 slots used to spread transmission"}, +! {12, "20 slots used to spread transmission"}, +! {13, "25 slots used to spread transmission"}, +! {14, "32 slots used to spread transmission"}, +! {15, "50 slots used to spread transmission"}, +! {0, 0}, +! }; +! +! /* +! * CELL_BAR_ACCESS, Cell Barred for Access (octet 2) +! * +! * Bit 2 +! * 0 The cell is not barred, see 3GPP TS 23.022 +! * 1 The cell is barred, see 3GPP TS 23.022 +! */ +! static const true_false_string gsm_a_rr_rach_cp_cell_bar_access_tfs = { +! "The cell is barred, see 3GPP TS 23.022", +! "The cell is not barred, see 3GPP TS 23.022" +! }; +! +! static const value_string gsm_a_rr_rach_cp_cell_bar_access_vals[] = { +! {0, "The cell is not barred"}, +! {1, "The cell is barred"}, +! {0, 0}, +! }; +! +! /* +! * RE, Call reestablishment allowed (octet 2) +! * +! * Bit 1 +! * 0 Call Reestablishment allowed in the cell +! * 1 Call Reestablishment not allowed in the cell +! */ +! static const true_false_string gsm_a_rr_rach_cp_re_tfs = { +! "Call Reestablishment not allowed in the cell", +! "Call Reestablishment allowed in the cell" +! }; +! +! static const value_string gsm_a_rr_rach_cp_re_vals[] = { +! {0, "Call Reestablishment is allowed in the cell"}, +! {1, "Call Reestablishment is not allowed in the cell"}, +! {0, 0}, +! }; +! +! /* +! * EC Emergency Call allowed (octet 3 bit 3) +! * +! * Bit 3 +! * 0 Emergency call allowed in the cell to all MSs +! * 1 Emergency call not allowed in the cell except for the MSs that belong to one of the classes between 11 to 15. +! */ +! static const true_false_string gsm_a_rr_rach_cp_ec_tfs = { +! "Emergency call not allowed in the cell except for the MSs that belong to one of the classes between 11 to 15.", +! "Emergency call allowed in the cell to all MSs" +! }; +! +! static const value_string gsm_a_rr_rach_cp_ec_vals[] = { +! {0, "Emergency call allowed in the cell to all MSs"}, +! {1, "Emergency call not allowed in the cell except for the MSs that belong to one of the classes between 11 and 15"}, +! {0, 0}, +! }; +! +! /* AC CN, Access Control Class N (octet 3 (except bit 3) and octet 4) +! * +! * For a mobile station with AC C = N access is not barred if the AC CN bit is coded with a "0"; N = 0, 1, .. 9,11, .., 15. +! */ +! +! static guint8 de_rr_rach_cp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) { + +! proto_tree *subtree; +! proto_item *item; +! guint16 accn; +! guint32 curr_offset; +! guint curr_len; +! guint bit; + +! curr_len = len; +! curr_offset = offset; + +! item = proto_tree_add_text(tree, tvb, curr_offset, 3, gsm_dtap_elem_strings[DE_RR_RACH_CP].strptr); +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_RACH_CP]); + +! proto_tree_add_item(subtree, hf_gsm_a_rr_rach_cp_max_retrans, tvb, curr_offset, 1, FALSE); +! proto_tree_add_item(subtree, hf_gsm_a_rr_rach_cp_tx_integer, tvb, curr_offset, 1, FALSE); +! proto_tree_add_item(subtree, hf_gsm_a_rr_rach_cp_cell_bar_access, tvb, curr_offset, 1, FALSE); +! proto_tree_add_item(subtree, hf_gsm_a_rr_rach_cp_re, tvb, curr_offset, 1, FALSE); +! proto_tree_add_item(subtree, hf_gsm_a_rr_rach_cp_ec, tvb, curr_offset + 1, 1, FALSE); +! +! curr_offset++; +! accn = tvb_get_ntohs(tvb, curr_offset); +! item = proto_tree_add_text(subtree, tvb, curr_offset, 2, "Access Classes not barred:"); +! bit = 16; +! while(bit-- > 0) +! if(bit != 10) +! if((accn & (1 << bit)) == 0) +! proto_item_append_text(item, " %d", bit); +! +! curr_offset += 2; +! return curr_offset - offset; + } + ++ + /* +! * [3] 10.5.2.30 Request Reference + */ +! static guint8 de_rr_req_ref(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) { + +! proto_tree *subtree; +! proto_item *item; +! guint32 curr_offset; +! guint curr_len; +! int v, t1p, t2, t3; + +! curr_len = len; +! curr_offset = offset; + +! item = proto_tree_add_text(tree, tvb, curr_offset, 3, gsm_dtap_elem_strings[DE_RR_REQ_REF].strptr); +! subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_REQ_REF]); + +! v = tvb_get_guint8(tvb, curr_offset); +! proto_tree_add_text(subtree, tvb, curr_offset, 1, "Random Access Information: %x", v); + +! curr_offset++; +! curr_len--; +! +! v = tvb_get_ntohs(tvb, curr_offset); +! t1p = (v & 0xf800) >> 11; +! t3 = ((v & 0x700) >> 5) | ((v & 0xe0) >> 5); +! t2 = v & 0x1f; +! proto_tree_add_text(subtree, tvb, curr_offset, 2, "FN modulo 42432: %d", 51 * ((t3 - t2) % 26) + t3 + 51 * 26 * t1p); +! +! curr_offset += 2; +! curr_len -= 2; +! +! return curr_offset - offset; + } +! + + /* + * [3] 10.5.2.31 + */ +! guint8 de_rr_cause(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) + { + guint32 curr_offset; + +*************** +*** 5056,5068 **** + + return(curr_offset - offset); + } + /* +- * [3] 10.5.2.32 SI 1 Rest Octets + * [3] 10.5.2.33 SI 2bis Rest Octets + * [3] 10.5.2.33a SI 2ter Rest Octets + * [3] 10.5.2.33b SI 2quater Rest Octets + * [3] 10.5.2.34 SI 3 Rest Octets + * [3] 10.5.2.35 SI 4 Rest Octets + * [3] 10.5.2.35a SI 6 Rest Octets + * [3] 10.5.2.36 SI 7 Rest Octets + * [3] 10.5.2.37 SI 8 Rest Octets +--- 6106,6288 ---- + + return(curr_offset - offset); + } ++ ++ ++ /* ++ * [4] 10.5.2.32 SI 1 Rest Octets ++ * ++ * NCH Position (5 bits) | Band Indicator | Spare ++ * ++ * NCH Position on the CCCH ++ * ++ * The values in the NCH Position field indicates the block ++ * number of the CCCH block which is used for the first NCH ++ * block and the number of blocks used for the NCH. (The ++ * block numbering corresponds to table 5 in clause 7 of ++ * 3GPP TS 45.002) The absence of the NCH position field ++ * indicates that there is no NCH in the cell/on the ++ * carrying CCCH slot The following coding applies if 1 or ++ * more basic physical channels are used for CCCH, not ++ * combined with SDCCHs. ++ * ++ * Value # blocks # of 1 block ++ * 00000 1 0 ++ * 00001 1 1 ++ * 00010 1 2 ++ * 00011 1 3 ++ * 00100 1 4 ++ * 00101 1 5 ++ * 00110 1 6 ++ * 00111 2 0 ++ * 01000 2 1 ++ * 01001 2 2 ++ * 01010 2 3 ++ * 01011 2 4 ++ * 01100 2 5 ++ * 01101 3 0 ++ * 01110 3 1 ++ * 01111 3 2 ++ * 10000 3 3 ++ * 10001 3 4 ++ * 10010 4 0 ++ * 10011 4 1 ++ * 10100 4 2 ++ * 10101 4 3 ++ * 10110 5 0 ++ * 10111 5 1 ++ * 11000 5 2 ++ * 11001 6 0 ++ * 11010 6 1 ++ * 11011 7 0 ++ * ++ * Other values are reserved for future use. A mobile ++ * station receiving a reserved value shall behave as if ++ * the NCH position was not present ++ * ++ * Band Indicator ++ * ++ * 0 ARFCN indicates 1800 band ++ * 1 ARFCN indicates 1900 band ++ */ ++ static const value_string gsm_a_rr_si_1_rest_octets_vals[] = { ++ {0x0, "NCH position on the CCCH: 1 block starting at block 0"}, ++ {0x1, "NCH position on the CCCH: 1 block starting at block 1"}, ++ {0x2, "NCH position on the CCCH: 1 block starting at block 2"}, ++ {0x3, "NCH position on the CCCH: 1 block starting at block 3"}, ++ {0x4, "NCH position on the CCCH: 1 block starting at block 4"}, ++ {0x5, "NCH position on the CCCH: 1 block starting at block 5"}, ++ {0x6, "NCH position on the CCCH: 1 block starting at block 6"}, ++ {0x7, "NCH position on the CCCH: 2 blocks starting at block 0"}, ++ {0x8, "NCH position on the CCCH: 2 blocks starting at block 1"}, ++ {0x9, "NCH position on the CCCH: 2 blocks starting at block 2"}, ++ {0xa, "NCH position on the CCCH: 2 blocks starting at block 3"}, ++ {0xb, "NCH position on the CCCH: 2 blocks starting at block 4"}, ++ {0xc, "NCH position on the CCCH: 2 blocks starting at block 5"}, ++ {0xd, "NCH position on the CCCH: 3 blocks starting at block 0"}, ++ {0xe, "NCH position on the CCCH: 3 blocks starting at block 1"}, ++ {0xf, "NCH position on the CCCH: 3 blocks starting at block 2"}, ++ {0x10, "NCH position on the CCCH: 3 blocks starting at block 3"}, ++ {0x11, "NCH position on the CCCH: 3 blocks starting at block 4"}, ++ {0x12, "NCH position on the CCCH: 4 blocks starting at block 0"}, ++ {0x13, "NCH position on the CCCH: 4 blocks starting at block 1"}, ++ {0x14, "NCH position on the CCCH: 4 blocks starting at block 2"}, ++ {0x15, "NCH position on the CCCH: 4 blocks starting at block 3"}, ++ {0x16, "NCH position on the CCCH: 5 blocks starting at block 0"}, ++ {0x17, "NCH position on the CCCH: 5 blocks starting at block 1"}, ++ {0x18, "NCH position on the CCCH: 5 blocks starting at block 2"}, ++ {0x19, "NCH position on the CCCH: 6 blocks starting at block 0"}, ++ {0x1a, "NCH position on the CCCH: 6 blocks starting at block 1"}, ++ {0x1b, "NCH position on the CCCH: 7 blocks starting at block 0"}, ++ {0, 0}, ++ }; ++ ++ static guint8 de_rr_si_1_rest_octets(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) ++ { ++ proto_tree *subtree; ++ proto_item *item; ++ guint32 curr_offset; ++ guint curr_len; ++ guint8 oct; ++ ++ curr_len = len; ++ curr_offset = offset; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, 1, gsm_dtap_elem_strings[DE_RR_SI_1_REST_OCTETS].strptr); ++ subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_SI_1_REST_OCTETS]); ++ proto_tree_add_item(subtree, hf_gsm_a_rr_si_1_rest_octets, tvb, curr_offset, 1, FALSE); ++ ++ // ??? oct = tvb_get_guint8(tvb, curr_offset) & 0x4; ++ oct = tvb_get_guint8(tvb, curr_offset) & 0x20; ++ ++ item = proto_tree_add_text(subtree, tvb, curr_offset, 1, "ARFCN: "); ++ if(!oct) ++ proto_item_append_text(item, "1800 band"); ++ else ++ proto_item_append_text(item, "1900 band"); ++ ++ curr_offset++; ++ ++ return curr_offset - offset; ++ } ++ ++ + /* + * [3] 10.5.2.33 SI 2bis Rest Octets + * [3] 10.5.2.33a SI 2ter Rest Octets + * [3] 10.5.2.33b SI 2quater Rest Octets ++ */ ++ ++ /* // jl + * [3] 10.5.2.34 SI 3 Rest Octets ++ * ++ * XXX not done ++ */ ++ static guint8 de_rr_si_3_rest_octets(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) ++ { ++ proto_item *item; ++ // proto_tree *subtree; ++ guint32 curr_offset; ++ guint curr_len; ++ ++ curr_len = len; ++ curr_offset = offset; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, 4, gsm_dtap_elem_strings[DE_RR_SI_3_REST_OCTETS].strptr); ++ // subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_SI_3_REST_OCTETS]); ++ ++ curr_offset += 4; ++ ++ return curr_offset - offset; ++ } ++ ++ ++ /* // jl + * [3] 10.5.2.35 SI 4 Rest Octets ++ * ++ * XXX not done ++ */ ++ static guint8 de_rr_si_4_rest_octets(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len, gchar *add_string _U_, int string_len _U_) ++ { ++ // proto_tree *subtree; ++ proto_item *item; ++ guint32 curr_offset; ++ guint curr_len; ++ ++ curr_len = len; ++ curr_offset = offset; ++ ++ item = proto_tree_add_text(tree, tvb, curr_offset, curr_len, gsm_dtap_elem_strings[DE_RR_SI_4_REST_OCTETS].strptr); ++ // subtree = proto_item_add_subtree(item, ett_gsm_dtap_elem[DE_RR_SI_4_REST_OCTETS]); ++ ++ // len is -1 on mandatory elements, so we can't increase by ++ // this. ++ //curr_offset += curr_len; ++ ++ return curr_offset - offset; ++ } ++ ++ ++ /* + * [3] 10.5.2.35a SI 6 Rest Octets + * [3] 10.5.2.36 SI 7 Rest Octets + * [3] 10.5.2.37 SI 8 Rest Octets +*************** +*** 12736,12745 **** + * [3] 10.5.2.1e Cell selection indicator after release of all TCH and SDCCH IE + */ + de_rr_cell_dsc, /* 10.5.2.2 RR Cell Description */ + /* +- * [3] 10.5.2.3 Cell Options (BCCH) + * [3] 10.5.2.3a Cell Options (SACCH) +! * [3] 10.5.2.4 Cell Selection Parameters + * [3] 10.5.2.4a (void) + */ + de_rr_ch_dsc, /* [3] 10.5.2.5 Channel Description */ +--- 13956,13967 ---- + * [3] 10.5.2.1e Cell selection indicator after release of all TCH and SDCCH IE + */ + de_rr_cell_dsc, /* 10.5.2.2 RR Cell Description */ ++ de_rr_co_bcch, /* [3] 10.5.2.3 Cell Options (BCCH) */ + /* + * [3] 10.5.2.3a Cell Options (SACCH) +! */ +! de_rr_cell_sel_param, /* [3] 10.5.2.4 Cell Selection Parameters */ +! /* + * [3] 10.5.2.4a (void) + */ + de_rr_ch_dsc, /* [3] 10.5.2.5 Channel Description */ +*************** +*** 12757,12765 **** + * [3] 10.5.2.8b Channel Request Description 2 */ + /* Pos 20 */ + de_rr_cip_mode_set, /* [3] 10.5.2.9 Cipher Mode Setting */ +! /* [3] 10.5.2.10 Cipher Response +! * [3] 10.5.2.11 Control Channel Description +! * [3] 10.5.2.11a DTM Information Details */ + de_rr_dyn_arfcn_map, /* [3] 10.5.2.11b Dynamic ARFCN Mapping */ + de_rr_freq_ch_seq, /* [3] 10.5.2.12 Frequency Channel Sequence */ + de_rr_freq_list, /* [3] 10.5.2.13 Frequency List */ +--- 13979,13987 ---- + * [3] 10.5.2.8b Channel Request Description 2 */ + /* Pos 20 */ + de_rr_cip_mode_set, /* [3] 10.5.2.9 Cipher Mode Setting */ +! /* [3] 10.5.2.10 Cipher Response */ +! de_rr_cc_dsc, /* [3] 10.5.2.11 Control Channel Description */ +! /* [3] 10.5.2.11a DTM Information Details */ + de_rr_dyn_arfcn_map, /* [3] 10.5.2.11b Dynamic ARFCN Mapping */ + de_rr_freq_ch_seq, /* [3] 10.5.2.12 Frequency Channel Sequence */ + de_rr_freq_list, /* [3] 10.5.2.13 Frequency List */ +*************** +*** 12771,12778 **** + * [3] 10.5.2.14e Enhanced DTM CS Release Indication + */ + de_rr_ho_ref, /* 10.5.2.15 Handover Reference */ + /* +- * [3] 10.5.2.16 IA Rest Octets + * [3] 10.5.2.17 IAR Rest Octets + * [3] 10.5.2.18 IAX Rest Octets + * [3] 10.5.2.19 L2 Pseudo Length +--- 13993,14000 ---- + * [3] 10.5.2.14e Enhanced DTM CS Release Indication + */ + de_rr_ho_ref, /* 10.5.2.15 Handover Reference */ ++ de_rr_ia_rest_octets, /* [3] 10.5.2.16 IA Rest Octets */ + /* + * [3] 10.5.2.17 IAR Rest Octets + * [3] 10.5.2.18 IAX Rest Octets + * [3] 10.5.2.19 L2 Pseudo Length +*************** +*** 12786,12823 **** + de_rr_mult_all, /* [3] 10.5.2.21b Multislot Allocation */ + /* + * [3] 10.5.2.21c NC mode +! * [3] 10.5.2.22 Neighbour Cell Description + * [3] 10.5.2.22a Neighbour Cell Description 2 + * [3] 10.5.2.22b (void) + * [3] 10.5.2.22c NT/N Rest Octets +! * [3] 10.5.2.23 P1 Rest Octets + * [3] 10.5.2.24 P2 Rest Octets + * [3] 10.5.2.25 P3 Rest Octets +! * [3] 10.5.2.25a Packet Channel Description +! * [3] 10.5.2.25b Dedicated mode or TBF + * [3] 10.5.2.25c RR Packet Uplink Assignment + * [3] 10.5.2.25d RR Packet Downlink Assignment +! * [3] 10.5.2.26 Page Mode + * [3] 10.5.2.26a (void) + * [3] 10.5.2.26b (void) + * [3] 10.5.2.26c (void) + * [3] 10.5.2.26d (void) +- * [3] 10.5.2.27 NCC Permitted +- */ +- de_rr_pow_cmd, /* 10.5.2.28 Power Command */ +- de_rr_pow_cmd_and_acc_type, /* 10.5.2.28a Power Command and access type */ +- /* +- * [3] 10.5.2.29 RACH Control Parameters +- * [3] 10.5.2.30 Request Reference + */ +! de_rr_cause, /* 10.5.2.31 RR Cause */ +! de_rr_sync_ind, /* 10.5.2.39 Synchronization Indication */ + /* [3] 10.5.2.32 SI 1 Rest Octets + * [3] 10.5.2.33 SI 2bis Rest Octets + * [3] 10.5.2.33a SI 2ter Rest Octets + * [3] 10.5.2.33b SI 2quater Rest Octets +! * [3] 10.5.2.34 SI 3 Rest Octets +! * [3] 10.5.2.35 SI 4 Rest Octets + * [3] 10.5.2.35a SI 6 Rest Octets + * [3] 10.5.2.36 SI 7 Rest Octets + * [3] 10.5.2.37 SI 8 Rest Octets +--- 14008,14054 ---- + de_rr_mult_all, /* [3] 10.5.2.21b Multislot Allocation */ + /* + * [3] 10.5.2.21c NC mode +! */ +! de_rr_neigh_cell_dsc, /* [3] 10.5.2.22 Neighbour Cell Description */ // jl +! /* + * [3] 10.5.2.22a Neighbour Cell Description 2 + * [3] 10.5.2.22b (void) + * [3] 10.5.2.22c NT/N Rest Octets +! */ +! de_rr_p1_rest_octets, /* [3] 10.5.2.23 P1 Rest Octets */ // jl +! /* + * [3] 10.5.2.24 P2 Rest Octets + * [3] 10.5.2.25 P3 Rest Octets +! */ +! de_rr_pcd, /* [3] 10.5.2.25a Packet Channel Description */ +! de_rr_dm_or_tbf, /* [3] 10.5.2.25b Dedicated mode or TBF */ +! /* + * [3] 10.5.2.25c RR Packet Uplink Assignment + * [3] 10.5.2.25d RR Packet Downlink Assignment +! */ +! de_rr_page_mode, /* [3] 10.5.2.26 Page Mode */ // jl +! /* + * [3] 10.5.2.26a (void) + * [3] 10.5.2.26b (void) + * [3] 10.5.2.26c (void) + * [3] 10.5.2.26d (void) + */ +! de_rr_ncc_permitted, /* [3] 10.5.2.27 NCC Permitted */ +! de_rr_pow_cmd, /* [3] 10.5.2.28 Power Command */ +! de_rr_pow_cmd_and_acc_type, /* [3] 10.5.2.28a Power Command and access type */ +! de_rr_rach_cp, /* [3] 10.5.2.29 RACH Control Parameters */ // jl +! de_rr_req_ref, /* [3] 10.5.2.30 Request Reference */ +! de_rr_cause, /* [3] 10.5.2.31 RR Cause */ +! de_rr_sync_ind, /* [3] 10.5.2.39 Synchronization Indication */ +! de_rr_si_1_rest_octets, /* [3] 10.5.2.32 SI 1 Rest Octets */ + /* [3] 10.5.2.32 SI 1 Rest Octets + * [3] 10.5.2.33 SI 2bis Rest Octets + * [3] 10.5.2.33a SI 2ter Rest Octets + * [3] 10.5.2.33b SI 2quater Rest Octets +! */ +! de_rr_si_3_rest_octets, /* [3] 10.5.2.34 SI 3 Rest Octets */ +! de_rr_si_4_rest_octets, /* [3] 10.5.2.35 SI 4 Rest Octets */ +! /* + * [3] 10.5.2.35a SI 6 Rest Octets + * [3] 10.5.2.36 SI 7 Rest Octets + * [3] 10.5.2.37 SI 8 Rest Octets +*************** +*** 15275,15280 **** +--- 16506,16556 ---- + + EXTRANEOUS_DATA_CHECK(curr_len, 0); + } ++ ++ ++ /* // jl ++ * ++ * 44.018 9.1.18 Immediate Assignment ++ * ++ * 10.5.2.26 Page Mode M V .5 ++ * 10.5.2.25b Dedicated Mode or TBF M V .5 ++ * 10.5.2.5 Channel Description C V 3 ++ * 10.5.2.25a Packet Channel Description C V 3 ++ * 10.5.2.30 Request Reference M V 3 ++ * 10.5.2.40 Timing Advance M V 1 ++ * 10.5.2.21 Mobile Allocation M LV 1-9 ++ * 10.5.2.38 Starting Time O TV 3 (0x7c) ++ * 10.5.2.16 IA Rest Octets M V 0-11 ++ */ ++ ++ void dtap_rr_immediate_assignment(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) { ++ ++ guint32 curr_offset; ++ guint32 consumed; ++ guint curr_len; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_PAGE_MODE); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_DM_OR_TBF); ++ if(ia_dedicated_mode_resource) { ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_CELL_CH_DSC); ++ ia_dedicated_mode_resource = 0; ++ } else if(ia_tbf) { ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_PCD); ++ ia_tbf = 0; ++ } ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_REQ_REF); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_TIMING_ADV); ++ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_RR_MOB_ALL, " - Immediate Assignment Mobile Allocation"); ++ ELEM_OPT_TV(0x7c, BSSAP_PDU_TYPE_DTAP, DE_RR_STARTING_TIME, " - Immediate Assignment Starting Time"); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_IA_REST_OCTETS); ++ ++ // EXTRANEOUS_DATA_CHECK(curr_len, 0); ++ } ++ ++ + /* 3GPP TS 24.008 version 4.7.0 Release 4 + * [3] 9.1.15 + */ +*************** +*** 15404,15409 **** +--- 16680,16715 ---- + EXTRANEOUS_DATA_CHECK(len, curr_offset - offset); + + } ++ ++ ++ /* // jl ++ * 44.018 9.1.22 Paging Request Type 1 ++ * ++ * 10.5.2.26 Page Mode M V .5 ++ * 10.5.2.8 Channels Needed M V .5 ++ * 10.5.1.4 Mobile Identity 1 M LV 2 - 9 ++ * 10.5.1.4 Mobile Identity 2 O TLV 3 - 10 (0x17) ++ * 10.5.2.23 P1 Rest Octets M V 0-17 ++ */ ++ static void dtap_rr_paging_req_1(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) { ++ ++ guint32 curr_offset; ++ guint32 consumed; ++ guint curr_len; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_PAGE_MODE); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_CHNL_NEEDED); ++ ELEM_MAND_LV(BSSAP_PDU_TYPE_DTAP, DE_MID, " 1"); ++ ELEM_OPT_TLV(0x17, BSSAP_PDU_TYPE_DTAP, DE_MID, " 2"); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_P1_REST_OCTETS); ++ ++ // EXTRANEOUS_DATA_CHECK(curr_len, 0); ++ } ++ ++ + /* + * [4] 9.1.25 + */ +*************** +*** 15498,15503 **** +--- 16804,16930 ---- + EXTRANEOUS_DATA_CHECK(curr_len, 0); + } + ++ ++ /* ++ * 44.018 9.1.31 System Information Type 1 ++ * ++ * 10.5.2.19 L2 pseudo length M V 1 ++ * 10.2 RR Protocol Discriminator M V .5 ++ * 10.3.1 Skip Indicator M V .5 ++ * 10.4 System Information Type 1 Message Type M V 1 ++ * 10.5.2.1b Cell Channel Description M V 16 ++ * 10.5.2.29 RACH Control Parameters M V 3 ++ * 10.5.2.32 SI 1 Rest Octects M V 1 ++ */ ++ static void dtap_rr_system_information_1(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) { ++ ++ guint32 curr_offset; ++ guint32 consumed; ++ guint curr_len; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_CELL_CH_DSC); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_RACH_CP); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_SI_1_REST_OCTETS); ++ ++ EXTRANEOUS_DATA_CHECK(curr_len, 0); ++ } ++ ++ ++ /* ++ * 44.018 9.1.32 System Information Type 2 ++ * ++ * ++ * 10.5.2.19 L2 pseudo length M V 1 ++ * 10.2 RR Protocol Discriminator M V .5 ++ * 10.3.1 Skip Indicator M V .5 ++ * 10.4 System Information Type 1 Message Type M V 1 ++ * 10.5.2.22 BCCH Frequency List Neighbor Cell Desc M V 16 ++ * 10.5.2.27 NCC Permitted M V 1 ++ * 10.5.2.29 RACH Control Parameters M V 3 ++ */ ++ static void dtap_rr_system_information_2(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) { ++ ++ guint32 curr_offset; ++ guint32 consumed; ++ guint curr_len; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_NEIGH_CELL_DSC); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_NCC_PERMITTED); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_RACH_CP); ++ ++ EXTRANEOUS_DATA_CHECK(curr_len, 0); ++ } ++ ++ ++ /* ++ * 44.018 9.1.35 System Information Type 3 ++ * ++ * 10.5.1.1 Cell Identity M V 2 ++ * 10.5.1.3 Location Area Identification M V 5 ++ * 10.5.2.11 Control Channel Description M V 3 ++ * 10.5.2.3 Cell Options BCCH M V 1 ++ * 10.5.2.4 Cell Selection Parameters M V 2 ++ * 10.5.2.29 RACH Control Parameters M V 3 ++ * 10.5.2.34 SI 3 Rest Octets M V 4 ++ */ ++ static void dtap_rr_system_information_3(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) { ++ ++ guint32 curr_offset; ++ guint32 consumed; ++ guint curr_len; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_CELL_ID); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_LAI); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_CC_DSC); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_CO_BCCH); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_CELL_SEL_PARAM); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_RACH_CP); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_SI_3_REST_OCTETS); ++ ++ EXTRANEOUS_DATA_CHECK(curr_len, 0); ++ } ++ ++ ++ /* ++ * 44.018 9.1.36 System Information Type 4 ++ * ++ * 10.5.1.3 Location Area Identification M V 5 ++ * 10.5.2.4 Cell Selection Parameters M V 2 ++ * 10.5.2.29 RACH Control Parameters M V 3 ++ * 10.5.2.5 CBCH Channel Description O TV 4 (64) ++ * 10.5.2.21 CBCH Mobile Allocation C TLV 3-6 (72) ++ * 10.5.2.35 SI 4 Rest Octets M V 0-10 ++ */ ++ static void dtap_rr_system_information_4(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) { ++ ++ guint32 curr_offset; ++ guint32 consumed; ++ guint curr_len; ++ ++ curr_offset = offset; ++ curr_len = len; ++ ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_LAI); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_CELL_SEL_PARAM); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_RACH_CP); ++ ELEM_OPT_TV(0x64, BSSAP_PDU_TYPE_DTAP, DE_RR_CH_DSC, "CBCH Channel Description"); ++ // next is actually conditional ++ ELEM_OPT_TLV(0x72, BSSAP_PDU_TYPE_DTAP, DE_RR_MOB_ALL, "CBCH Mobile Allocation"); ++ ELEM_MAND_V(BSSAP_PDU_TYPE_DTAP, DE_RR_SI_4_REST_OCTETS); ++ ++ // EXTRANEOUS_DATA_CHECK(curr_len, 0); ++ } ++ ++ + /* + * [4] 9.3.1 + */ +*************** +*** 17738,17744 **** + static void (*dtap_msg_rr_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = { + NULL, /* RR Initialisation Request */ + NULL, /* Additional Assignment */ +! NULL, /* Immediate Assignment */ + NULL, /* Immediate Assignment Extended */ + NULL, /* Immediate Assignment Reject */ + +--- 19165,19171 ---- + static void (*dtap_msg_rr_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint32 offset, guint len) = { + NULL, /* RR Initialisation Request */ + NULL, /* Additional Assignment */ +! dtap_rr_immediate_assignment, /* Immediate Assignment */ + NULL, /* Immediate Assignment Extended */ + NULL, /* Immediate Assignment Reject */ + +*************** +*** 17771,17777 **** + NULL, /* Partial Release */ + NULL, /* Partial Release Complete */ + +! NULL, /* Paging Request Type 1 */ + NULL, /* Paging Request Type 2 */ + NULL, /* Paging Request Type 3 */ + dtap_rr_paging_resp, /* Paging Response */ +--- 19198,19204 ---- + NULL, /* Partial Release */ + NULL, /* Partial Release Complete */ + +! dtap_rr_paging_req_1, /* Paging Request Type 1 */ + NULL, /* Paging Request Type 2 */ + NULL, /* Paging Request Type 3 */ + dtap_rr_paging_resp, /* Paging Response */ +*************** +*** 17788,17797 **** + NULL, /* Inter System to cdma2000 Handover Command */ + + NULL, /* System Information Type 8 */ +! NULL, /* System Information Type 1 */ +! NULL, /* System Information Type 2 */ +! NULL, /* System Information Type 3 */ +! NULL, /* System Information Type 4 */ + NULL, /* System Information Type 5 */ + NULL, /* System Information Type 6 */ + NULL, /* System Information Type 7 */ +--- 19215,19224 ---- + NULL, /* Inter System to cdma2000 Handover Command */ + + NULL, /* System Information Type 8 */ +! dtap_rr_system_information_1, /* System Information Type 1 */ // jl +! dtap_rr_system_information_2, /* System Information Type 2 */ // jl +! dtap_rr_system_information_3, /* System Information Type 3 */ // jl +! dtap_rr_system_information_4, /* System Information Type 4 */ // jl + NULL, /* System Information Type 5 */ + NULL, /* System Information Type 6 */ + NULL, /* System Information Type 7 */ +*************** +*** 18203,18212 **** +--- 19630,19649 ---- + return; + } + ++ /* ++ * XXX assuming GNU Radio input ++ */ ++ if(check_col(pinfo->cinfo, COL_PROTOCOL)) ++ col_set_str(pinfo->cinfo, COL_PROTOCOL, "GSM"); ++ if(check_col(pinfo->cinfo, COL_INFO)) ++ col_clear(pinfo->cinfo, COL_INFO); ++ ++ /* XXX orig + if (check_col(pinfo->cinfo, COL_INFO)) + { + col_append_str(pinfo->cinfo, COL_INFO, "(DTAP) "); + } ++ */ + + /* + * set tap record pointer +*************** +*** 18460,18465 **** +--- 19897,20061 ---- + + static hf_register_info hf[] = + { ++ // jl ++ { ++ &hf_gsm_a_rr_rach_cp_max_retrans, ++ { ++ "Maximum number of retransmissions", ++ "gsm_a.rr.rach_cp.max_retrans", FT_UINT8, ++ BASE_HEX, ++ VALS(gsm_a_rr_rach_cp_max_retrans_vals), ++ 0xc0, "Maximum number of retransmissions", ++ HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_rach_cp_tx_integer, ++ { ++ "Number of slots to spread transmissions", ++ "gsm_a.rr.rach_cp.tx_integer", FT_UINT8, ++ BASE_HEX, ++ VALS(gsm_a_rr_rach_cp_tx_integer_vals), ++ 0x3c, "Tx-integer, Number of slots to " ++ "spread tranmissions", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_rach_cp_cell_bar_access, ++ { ++ "Cell Barred for Access", ++ "gsm_a.rr.rach_cp.cell_bar_access", ++ FT_UINT8, 1, ++ VALS( ++ &gsm_a_rr_rach_cp_cell_bar_access_vals), ++ 0x2, ++ "CELL_BAR_ACCESS, Cell Barred for Access", ++ HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_rach_cp_re, ++ { ++ "Call reestablishment allowed", ++ "gsm_a.rr.rach_cp.re", FT_UINT8, 1, ++ VALS(&gsm_a_rr_rach_cp_re_vals), 0x1, ++ "RE, Call reestablishment allowed", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_si_1_rest_octets, ++ { ++ "SI 1 Rest Octets", ++ "gsm_a.rr.si_1.rest_octets", FT_UINT8, ++ BASE_HEX, ++ VALS(gsm_a_rr_si_1_rest_octets_vals), 0x1f, ++ "SI 1 Rest Octets", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_neigh_cell_dsc_ext, ++ { ++ "Extension Indication", ++ "gsm_a.rr.neigh_cell_dsc.ext", FT_BOOLEAN, ++ 1, TFS(&gsm_a_rr_neigh_cell_dsc_ext_tfs), ++ 0x20, "Extension Indication", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_neigh_cell_dsc_ba, ++ { ++ "BACCH allocation sequence number indication", ++ "gsm_a.rr.neigh_cell_dsc.ba", FT_BOOLEAN, 1, ++ TFS(&gsm_a_rr_neigh_cell_dsc_ba_tfs), 0x10, ++ "BACCH allocation sequence number " ++ "indication", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_cc_dsc_mscr, ++ { ++ "MSC Release", "gsm_a.rr.cc_dsc.mscr", ++ FT_BOOLEAN, 1, ++ TFS(&gsm_a_rr_cc_dsc_mscr_tfs), 0x80, ++ "MSC Release", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_cc_dsc_att, ++ { ++ "Attach-detach allowed", "gsm_a.rr.cc_dsc.att", ++ FT_BOOLEAN, 1, ++ TFS(&gsm_a_rr_cc_dsc_att_tfs), 0x40, ++ "Attach-detach allowed", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_cc_dsc_cbq3, ++ { ++ "Cell Bar Qualify 3", "gsm_a.rr.cc_dsc.cbq3", ++ FT_UINT8, BASE_HEX, ++ VALS(gsm_a_rr_cc_dsc_cbq3_vals), 0x60, ++ "Cell Bar Qualify 3", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_cc_dsc_ccch, ++ { ++ "CCCH Configuration", "gsm_a.rr.cc_dsc.ccch", ++ FT_UINT8, BASE_HEX, ++ VALS(gsm_a_rr_cc_dsc_ccch_vals), 0x7, ++ "CCCH Configuration", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_co_bcch_dn_ind, ++ { ++ "DN-IND Dynamic ARFCN mapping indicator", "gsm_a.rr.co_bcch.dn_ind", ++ FT_UINT8, BASE_HEX, VALS(gsm_a_rr_co_bcch_dn_ind_vals), 0x80, ++ "Dynamic ARFCN mapping indicator", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_co_bcch_pwrc, ++ { ++ "PWRC Power Control indicator", "gsm_a.rr.co_bcch.pwrc", ++ FT_UINT8, BASE_HEX, VALS(gsm_a_rr_co_bcch_pwrc_vals), 0x40, ++ "Power Control indicator", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_co_bcch_dtx, ++ { ++ "DTX indicator", "gsm_a.rr.co_bcch.dtx", ++ FT_UINT8, BASE_HEX, VALS(gsm_a_rr_co_bcch_dtx_vals), 0x30, ++ "DTX indicator", HFILL ++ } ++ }, ++ // jl ++ { ++ &hf_gsm_a_rr_dm_or_tbf, ++ { ++ "Dedicated Mode or Temporary Block Flow", "gsm_a.rr.dm_or_tbf", ++ FT_UINT8, BASE_HEX, VALS(gsm_a_rr_dm_or_tbf_vals), 0x70, // assuming this is the 2nd IE in octet ++ "Dedicated Mode or TBF", HFILL ++ } ++ }, ++ ++ // ---------------------------------- ++ + { &hf_gsm_a_bssmap_msg_type, + { "BSSMAP Message Type", "gsm_a.bssmap_msgtype", + FT_UINT8, BASE_HEX, VALS(gsm_a_bssmap_msg_strings), 0x0, +*************** +*** 18875,18880 **** +--- 20471,20488 ---- + FT_UINT8,BASE_DEC, VALS(gsm_a_gmm_cn_spec_drs_cycle_len_coef_strings), 0xf0, + "CN Specific DRX cycle length coefficient", HFILL } + }, ++ ++ // jl ++ { ++ &hf_gsm_a_rr_rach_cp_ec, ++ { ++ "Emergency Call allowed", "gsm_a.rr.rach_cp_ec", ++ FT_BOOLEAN, 1, TFS(&gsm_a_rr_rach_cp_ec_tfs), 0x4, ++ "EC, Emergency Call allowed", HFILL ++ } ++ }, ++ // ++ + { &hf_gsm_a_rr_RR_cause, + { "RR cause value","gsm_a.rr.RRcause", + FT_UINT8,BASE_DEC, VALS(gsm_a_rr_RR_cause_vals), 0x0, +*************** +*** 19338,19343 **** +--- 20946,20955 ---- + dissector_add("bssap.pdu_type", BSSAP_PDU_TYPE_DTAP, dtap_handle); + dissector_add("ranap.nas_pdu", BSSAP_PDU_TYPE_DTAP, dtap_handle); + dissector_add("llcgprs.sapi", 1 , dtap_handle); ++ ++ // GNU Radio ++ dissector_add("ethertype", 0xfed5, dtap_handle); ++ + data_handle = find_dissector("data"); + } + diff --git a/gssm/src/Makefile.am b/gssm/src/Makefile.am new file mode 100644 index 0000000..afa6595 --- /dev/null +++ b/gssm/src/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/Makefile.common + +SUBDIRS = lib mktun +DIST_SUBDIRS = lib mktun diff --git a/gssm/src/lib/Makefile.am b/gssm/src/lib/Makefile.am new file mode 100644 index 0000000..be3775c --- /dev/null +++ b/gssm/src/lib/Makefile.am @@ -0,0 +1,44 @@ +# $Id: Makefile.am,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +include $(top_srcdir)/Makefile.common + +ourpythondir = $(pythondir) +ourlibdir = $(pyexecdir) + +INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) + +SWIGCPPPYTHONARGS = -c++ -python $(PYTHON_CPPFLAGS) -I$(swigincludedir) -I$(grincludedir) + +LOCAL_IFILES = gssm.i +NON_LOCAL_IFILES = $(GNURADIO_CORE_INCLUDEDIR)/swig/gnuradio.i +ALL_IFILES = $(LOCAL_IFILES) $(NON_LOCAL_IFILES) + +BUILT_SOURCES = gssm_glue.cc gssm.py + +ourpython_PYTHON = gssm.py + +ourlib_LTLIBRARIES = _gssm.la + +# source files that go into the shared library +_gssm_la_SOURCES = \ + gssm_glue.cc \ + gssm_sink.cc \ + bursts.cc \ + sch.cc \ + cch.cc \ + rr_decode.cc \ + tun.cc \ + display.cc + +_gssm_la_LDFLAGS = -module -avoid-version + +_gssm_la_LIBADD = $(PYTHON_LDFLAGS) -lstdc++ + +gssm_glue.cc gssm.py: gssm.i $(ALL_IFILES) + $(SWIG) $(SWIGCPPPYTHONARGS) -module gssm -o gssm_glue.cc $< + +grinclude_HEADERS = gssm_sink.h + +swiginclude_HEADERS = $(LOCAL_IFILES) + +MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc diff --git a/gssm/src/lib/buffer.h b/gssm/src/lib/buffer.h new file mode 100644 index 0000000..038cba6 --- /dev/null +++ b/gssm/src/lib/buffer.h @@ -0,0 +1,4 @@ +#pragma once + +static const int BUFFER_QD_SIZE = 16384; +static const int BUFFER_MM_SIZE = 16384; diff --git a/gssm/src/lib/burst_types.h b/gssm/src/lib/burst_types.h new file mode 100644 index 0000000..fc8fa4a --- /dev/null +++ b/gssm/src/lib/burst_types.h @@ -0,0 +1,217 @@ +// $Id: burst_types.h,v 1.2 2007-07-07 16:31:42 jl Exp $ + +#pragma once + +#include "gsm_constants.h" + +static const int TB_LEN = 3; +static const int TB_OS1 = 0; +static const int TB_OS2 = 145; +static const unsigned char tail_bits[TB_LEN] = {0, 0, 0}; + +/* + * The normal burst is used to carry information on traffic and control + * channels. + */ +static const int N_TSC_NUM = 8; // number of training sequence codes +static const int N_TSC_CODE_LEN = 26; // length of tsc +static const int N_TSC_OS = 61; // tsc offset +static const int N_EDATA_LEN_1 = 58; // length of first data section +static const int N_EDATA_OS_1 = 3; // offset of first data section +static const int N_EDATA_LEN_2 = 58; // length of second data section +static const int N_EDATA_OS_2 = 87; // offset of second data section +static const unsigned char n_tsc[N_TSC_NUM][N_TSC_CODE_LEN] = { +/* 0 */ { + 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1 + }, +/* 1 */ { + 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, + 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1 + }, +/* 2 */ { + 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, + 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0 + }, +/* 3 */ { + 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0 + }, +/* 4 */ { + 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1 + }, +/* 5 */ { + 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, + 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0 + }, +/* 6 */ { + 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1 + }, +/* 7 */ { + 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0 + } +}; + + +/* + * The frequency correction burst is used for frequency synchronization + * of the mobile. This is broadcast in TS0 together with the SCH and + * BCCH. + * + * Modulating the bits below causes a spike at 62.5kHz above (below for + * COMPACT) the center frequency. One can use this spike with a narrow + * band filter to accurately determine the center of the channel. + */ +static const int FC_CODE_LEN = 142; +static const int FC_OS = 3; +static const unsigned char fc_fb[FC_CODE_LEN] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const unsigned char fc_fb_de[TB_LEN + FC_CODE_LEN + TB_LEN] = { + 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1 +}; + +static const unsigned char fc_compact_fb[FC_CODE_LEN] = { + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0 +}; + + +/* + * The synchronization burst is used for time synchronization of the + * mobile. The bits given below were chosen for their correlation + * properties. The synchronization channel (SCH) contains a long + * training sequence (given below) and carries the TDMA frame number and + * base station identity code. It is broadcast in TS0 in the frame + * following the frequency correction burst. + */ +static const int SB_CODE_LEN = 64; +static const int SB_ETS_OS = 42; +static const int SB_EDATA_LEN_1 = 39; +static const int SB_EDATA_OS_1 = 3; +static const int SB_EDATA_LEN_2 = 39; +static const int SB_EDATA_OS_2 = 106; +static const unsigned char sb_etsc[SB_CODE_LEN] = { + 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, + 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1 +}; + +static const unsigned char sb_cts_etsc[SB_CODE_LEN] = { + 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1 +}; + +static const unsigned char sb_compact_etsc[SB_CODE_LEN] = { + 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, + 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, + 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0 +}; + + +/* + * A base tranceiver station must transmit a burst in every timeslot of + * every TDMA frame in channel C0. The dummy burst will be transmitted + * on all timeslots of all TDMA frames for which no other channel + * requires a burst to be transmitted. + */ +static const int D_CODE_LEN = 142; +static const int D_MB_OS = 3; +static const unsigned char d_mb[D_CODE_LEN] = { + 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, + 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, + 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, + 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, + 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 +}; + + +/* + * The access burst is used for random access from a mobile. + */ +static const int AB_ETB_CODE_LEN = 8; +static const int AB_ETB_OS = 0; +static const unsigned char ab_etb[AB_ETB_CODE_LEN] = { + 0, 0, 1, 1, 1, 0, 1, 0 +}; + +static const int AB_SSB_CODE_LEN = 41; +static const int AB_SSB_OS = 8; +static const unsigned char ab_ssb[AB_SSB_CODE_LEN] = { + 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, + 0, 0, 1, 1, 1, 1, 0, 0, 0 +}; + +static const unsigned char ab_ts1_ssb[AB_SSB_CODE_LEN] = { + 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, + 0, 0, 1, 0, 0, 1, 1, 0, 1 +}; + +static const unsigned char ab_ts2_ssb[AB_SSB_CODE_LEN] = { + 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, + 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, + 1, 0, 1, 1, 1, 0, 1, 1, 1 +}; + + +typedef enum { + burst_n_0, + burst_n_1, + burst_n_2, + burst_n_3, + burst_n_4, + burst_n_5, + burst_n_6, + burst_n_7, + burst_fc, + burst_fc_c, + burst_s, + burst_s_cts, + burst_s_c, + burst_d, + burst_a, + burst_a_ts1, + burst_a_ts2, + burst_not_a_burst +} burst_t; + +static const int N_BURST_TYPES = ((int)(burst_not_a_burst) + 1); diff --git a/gssm/src/lib/bursts.cc b/gssm/src/lib/bursts.cc new file mode 100644 index 0000000..cd35382 --- /dev/null +++ b/gssm/src/lib/bursts.cc @@ -0,0 +1,153 @@ +// $Id: bursts.cc,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#include +#include +#include +#include +#include "burst_types.h" + +void display_burst_type(burst_t t) { + + switch(t) { + case burst_n_0: + case burst_n_1: + case burst_n_2: + case burst_n_3: + case burst_n_4: + case burst_n_5: + case burst_n_6: + case burst_n_7: + printf("normal burst %d", t); + break; + case burst_fc: + printf("frequency correction burst"); + break; + case burst_fc_c: + printf("frequency correction burst (COMPACT)"); + break; + case burst_s: + printf("synchronization burst"); + break; + case burst_s_cts: + printf("synchronization burst (CTS)"); + break; + case burst_s_c: + printf("synchronization burst (COMPACT)"); + break; + case burst_d: + printf("dummy burst"); + break; + case burst_a: + printf("access burst"); + break; + case burst_a_ts1: + printf("access burst (TS1)"); + break; + case burst_a_ts2: + printf("access burst (TS2)"); + break; + default: + printf("unknown burst type"); + break; + } +} + + +static int burst_diff(const unsigned char *b1, const unsigned char *b2, + unsigned int l) { + + int d = 0; + unsigned int i; + + for(i = 0; i < l; i++) + d += (b1[i] ^ b2[i]); + return d; +} + + +int search_fc(unsigned char *buf) { + + return !(burst_diff(buf + TB_OS1, tail_bits, TB_LEN) + + burst_diff(buf + TB_OS2, tail_bits, TB_LEN) + + burst_diff(buf + FC_OS, fc_fb, FC_CODE_LEN)); +} + + +int is_dummy_burst(const unsigned char *buf) { + + int i; + + for(i = 0; i < D_CODE_LEN; i++) + if(buf[i + D_MB_OS] != d_mb[i]) + return 0; + return 1; +} + + +burst_t search_burst(unsigned char *buf, int max_burst_errors, int *rmin_o) { + + int i, d_burst[N_BURST_TYPES], t_d, d_min, rmin; + burst_t bt_min; + + for(i = 0; i < N_BURST_TYPES; i++) + d_burst[i] = max_burst_errors + 1; + + // access burst (uplink only) + t_d = burst_diff(buf + AB_ETB_OS, ab_etb, AB_ETB_CODE_LEN); + d_burst[(int)burst_a] = + t_d + burst_diff(buf + AB_SSB_OS, ab_ssb, AB_SSB_CODE_LEN); + + d_burst[(int)burst_a_ts1] = + t_d + burst_diff(buf + AB_SSB_OS, ab_ts1_ssb, AB_SSB_CODE_LEN); + + d_burst[(int)burst_a_ts2] = + t_d + burst_diff(buf + AB_SSB_OS, ab_ts2_ssb, AB_SSB_CODE_LEN); + + // check tail bits + t_d = + burst_diff(buf + TB_OS1, tail_bits, TB_LEN) + + burst_diff(buf + TB_OS2, tail_bits, TB_LEN); + + // normal bursts + for(i = 0; i < N_TSC_NUM; i++) + d_burst[(int)burst_n_0 + i] = + t_d + burst_diff(buf + N_TSC_OS, n_tsc[i], N_TSC_CODE_LEN); + + // frequency correction + d_burst[(int)burst_fc] = + t_d + burst_diff(buf + FC_OS, fc_fb, FC_CODE_LEN); + + d_burst[(int)burst_fc_c] = + t_d + burst_diff(buf + FC_OS, fc_compact_fb, FC_CODE_LEN); + + // synchronization burst + d_burst[(int)burst_s] = + t_d + burst_diff(buf + SB_ETS_OS, sb_etsc, SB_CODE_LEN); + + d_burst[(int)burst_s_cts] = + t_d + burst_diff(buf + SB_ETS_OS, sb_cts_etsc, SB_CODE_LEN); + + d_burst[(int)burst_s_c] = + t_d + burst_diff(buf + SB_ETS_OS, sb_compact_etsc, SB_CODE_LEN); + + // dummy + d_burst[(int)burst_d] = + t_d + burst_diff(buf + D_MB_OS, d_mb, D_CODE_LEN); + + d_burst[(int)burst_not_a_burst] = max_burst_errors; + + rmin = BURST_LENGTH; + d_min = max_burst_errors + 1; + bt_min = burst_not_a_burst; + for(i = 0; i < N_BURST_TYPES; i++) { + if(d_burst[i] < d_min) { + bt_min = (burst_t)i; + d_min = d_burst[i]; + } + if((d_burst[i] < rmin) && ((burst_t)i != burst_not_a_burst)) + rmin = d_burst[i]; + } + if(rmin_o) + *rmin_o = rmin; + return bt_min; +} diff --git a/gssm/src/lib/bursts.h b/gssm/src/lib/bursts.h new file mode 100644 index 0000000..c8a5096 --- /dev/null +++ b/gssm/src/lib/bursts.h @@ -0,0 +1,10 @@ +// $Id: bursts.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#pragma once + +#include "burst_types.h" + +void display_burst_type(burst_t); +burst_t search_burst(unsigned char *, int, int *); +int search_fc(unsigned char *); +int is_dummy_burst(const unsigned char *); diff --git a/gssm/src/lib/cch.cc b/gssm/src/lib/cch.cc new file mode 100644 index 0000000..5659440 --- /dev/null +++ b/gssm/src/lib/cch.cc @@ -0,0 +1,460 @@ +// $Id: cch.cc,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#include +#include +#include +#include +#include + +#include +#include + +#include "burst_types.h" +#include "cch.h" + +/* + * GSM SACCH -- Slow Associated Control Channel + * + * These messages are encoded exactly the same as on the BCCH. + * (Broadcast Control Channel.) + * + * Input: 184 bits + * + * 1. Add parity and flushing bits. + * 2. Convolutional encode. + * 3. Interleave. + * 4. Map on bursts. + */ + + +/* + * Parity (FIRE) for the GSM SACCH channel. + * + * g(x) = (x^23 + 1)(x^17 + x^3 + 1) + * = x^40 + x^26 + x^23 + x^17 + x^3 + 1 + */ + +static const unsigned char parity_polynomial[PARITY_SIZE + 1] = { + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, + 1 +}; + +// remainder after dividing data polynomial by g(x) +static const unsigned char parity_remainder[PARITY_SIZE] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 +}; + + +/* +static void parity_encode(unsigned char *d, unsigned char *p) { + + int i; + unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q; + + memcpy(buf, d, DATA_BLOCK_SIZE); + memset(buf + DATA_BLOCK_SIZE, 0, PARITY_SIZE); + + for(q = buf; q < buf + DATA_BLOCK_SIZE; q++) + if(*q) + for(i = 0; i < PARITY_SIZE + 1; i++) + q[i] ^= parity_polynomial[i]; + for(i = 0; i < PARITY_SIZE; i++) + p[i] = !buf[DATA_BLOCK_SIZE + i]; +} + */ + + +static int parity_check(unsigned char *d) { + + unsigned int i; + unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q; + + memcpy(buf, d, DATA_BLOCK_SIZE + PARITY_SIZE); + + for(q = buf; q < buf + DATA_BLOCK_SIZE; q++) + if(*q) + for(i = 0; i < PARITY_SIZE + 1; i++) + q[i] ^= parity_polynomial[i]; + return memcmp(buf + DATA_BLOCK_SIZE, parity_remainder, PARITY_SIZE); +} + + +/* + * Convolutional encoding and Viterbi decoding for the GSM SACCH channel. + */ + +/* + * Convolutional encoding: + * + * G_0 = 1 + x^3 + x^4 + * G_1 = 1 + x + x^3 + x^4 + * + * i.e., + * + * c_{2k} = u_k + u_{k - 3} + u_{k - 4} + * c_{2k + 1} = u_k + u_{k - 1} + u_{k - 3} + u_{k - 4} + */ +#define K 5 +#define MAX_ERROR (2 * CONV_INPUT_SIZE + 1) + + +/* + * Given the current state and input bit, what are the output bits? + * + * encode[current_state][input_bit] + */ +static const unsigned int encode[1 << (K - 1)][2] = { + {0, 3}, {3, 0}, {3, 0}, {0, 3}, + {0, 3}, {3, 0}, {3, 0}, {0, 3}, + {1, 2}, {2, 1}, {2, 1}, {1, 2}, + {1, 2}, {2, 1}, {2, 1}, {1, 2} +}; + + +/* + * Given the current state and input bit, what is the next state? + * + * next_state[current_state][input_bit] + */ +static const unsigned int next_state[1 << (K - 1)][2] = { + {0, 8}, {0, 8}, {1, 9}, {1, 9}, + {2, 10}, {2, 10}, {3, 11}, {3, 11}, + {4, 12}, {4, 12}, {5, 13}, {5, 13}, + {6, 14}, {6, 14}, {7, 15}, {7, 15} +}; + + +/* + * Given the previous state and the current state, what input bit caused + * the transition? If it is impossible to transition between the two + * states, the value is 2. + * + * prev_next_state[previous_state][current_state] + */ +static const unsigned int prev_next_state[1 << (K - 1)][1 << (K - 1)] = { + { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2}, + { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2}, + { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2}, + { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2}, + { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2}, + { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2}, + { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2}, + { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2}, + { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2}, + { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2}, + { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2}, + { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2}, + { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2}, + { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2}, + { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1}, + { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1} +}; + + +static inline unsigned int hamming_distance2(unsigned int w) { + + return (w & 1) + !!(w & 2); +} + + +/* +static void conv_encode(unsigned char *data, unsigned char *output) { + + unsigned int i, state = 0, o; + + // encode data + for(i = 0; i < CONV_INPUT_SIZE; i++) { + o = encode[state][data[i]]; + state = next_state[state][data[i]]; + *output++ = !!(o & 2); + *output++ = o & 1; + } +} + */ + + +static int conv_decode(unsigned char *output, unsigned char *data) { + + int i, t; + unsigned int rdata, state, nstate, b, o, distance, accumulated_error, + min_state, min_error, cur_state; + + unsigned int ae[1 << (K - 1)]; + unsigned int nae[1 << (K - 1)]; // next accumulated error + unsigned int state_history[1 << (K - 1)][CONV_INPUT_SIZE + 1]; + + // initialize accumulated error, assume starting state is 0 + for(i = 0; i < (1 << (K - 1)); i++) + ae[i] = nae[i] = MAX_ERROR; + ae[0] = 0; + + // build trellis + for(t = 0; t < CONV_INPUT_SIZE; t++) { + + // get received data symbol + rdata = (data[2 * t] << 1) | data[2 * t + 1]; + + // for each state + for(state = 0; state < (1 << (K - 1)); state++) { + + // make sure this state is possible + if(ae[state] >= MAX_ERROR) + continue; + + // find all states we lead to + for(b = 0; b < 2; b++) { + + // get next state given input bit b + nstate = next_state[state][b]; + + // find output for this transition + o = encode[state][b]; + + // calculate distance from received data + distance = hamming_distance2(rdata ^ o); + + // choose surviving path + accumulated_error = ae[state] + distance; + if(accumulated_error < nae[nstate]) { + + // save error for surviving state + nae[nstate] = accumulated_error; + + // update state history + state_history[nstate][t + 1] = state; + } + } + } + + // get accumulated error ready for next time slice + for(i = 0; i < (1 << (K - 1)); i++) { + ae[i] = nae[i]; + nae[i] = MAX_ERROR; + } + } + + // the final state is the state with the fewest errors + min_state = (unsigned int)-1; + min_error = MAX_ERROR; + for(i = 0; i < (1 << (K - 1)); i++) { + if(ae[i] < min_error) { + min_state = i; + min_error = ae[i]; + } + } + + // trace the path + cur_state = min_state; + for(t = CONV_INPUT_SIZE; t >= 1; t--) { + min_state = cur_state; + cur_state = state_history[cur_state][t]; // get previous + output[t - 1] = prev_next_state[cur_state][min_state]; + } + + // return the number of errors detected (hard-decision) + return min_error; +} + + +/* + * GSM SACCH interleaving and burst mapping + * + * Interleaving: + * + * Given 456 coded input bits, form 4 blocks of 114 bits: + * + * i(B, j) = c(n, k) k = 0, ..., 455 + * n = 0, ..., N, N + 1, ... + * B = B_0 + 4n + (k mod 4) + * j = 2(49k mod 57) + ((k mod 8) div 4) + * + * Mapping on Burst: + * + * e(B, j) = i(B, j) + * e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56 + * e(B, 57) = h_l(B) + * e(B, 58) = h_n(B) + * + * Where h_l(B) and h_n(B) are bits in burst B indicating flags. + */ + +/* +static void interleave(unsigned char *data, unsigned char *iBLOCK) { + + int j, k, B; + + // for each bit in input data + for(k = 0; k < CONV_SIZE; k++) { + B = k % 4; + j = 2 * ((49 * k) % 57) + ((k % 8) / 4); + iBLOCK[B * iBLOCK_SIZE + j] = data[k]; + } +} + */ + + +static void decode_interleave(unsigned char *data, unsigned char *iBLOCK) { + + int j, k, B; + + for(k = 0; k < CONV_SIZE; k++) { + B = k % 4; + j = 2 * ((49 * k) % 57) + ((k % 8) / 4); + data[k] = iBLOCK[B * iBLOCK_SIZE + j]; + } +} + + +/* +static void burstmap(unsigned char *iBLOCK, unsigned char *eBLOCK, + unsigned char hl, unsigned char hn) { + + int j; + + for(j = 0; j < 57; j++) { + eBLOCK[j] = iBLOCK[j]; + eBLOCK[j + 59] = iBLOCK[j + 57]; + } + eBLOCK[57] = hl; + eBLOCK[58] = hn; +} + */ + + +static void decode_burstmap(unsigned char *iBLOCK, unsigned char *eBLOCK, + unsigned char *hl, unsigned char *hn) { + + int j; + + for(j = 0; j < 57; j++) { + iBLOCK[j] = eBLOCK[j]; + iBLOCK[j + 57] = eBLOCK[j + 59]; + } + *hl = eBLOCK[57]; + *hn = eBLOCK[58]; +} + + +/* + * Transmitted bits are sent least-significant first. + */ +static int compress_bits(unsigned char *dbuf, unsigned int dbuf_len, + unsigned char *sbuf, unsigned int sbuf_len) { + + unsigned int i, j, c, pos = 0; + + if(dbuf_len < ((sbuf_len + 7) >> 3)) + return -1; + + for(i = 0; i < sbuf_len; i += 8) { + for(j = 0, c = 0; (j < 8) && (i + j < sbuf_len); j++) + c |= (!!sbuf[i + j]) << j; + dbuf[pos++] = c & 0xff; + } + return pos; +} + + +int get_ns_l3_len(unsigned char *data, unsigned int datalen) { + + if((data[0] & 3) != 1) { + fprintf(stderr, "error: get_ns_l3_len: pseudo-length reserved " + "bits bad (%2.2x)\n", data[0] & 3); + return -1; + } + return (data[0] >> 2); +} + + +static unsigned char *decode_sacch(unsigned char *e0, unsigned char *e1, + unsigned char *e2, unsigned char *e3, unsigned int *datalen) { + + int errors, len, data_size = (DATA_BLOCK_SIZE + 7) >> 3; + unsigned char conv_data[CONV_SIZE], iBLOCK[BLOCKS][iBLOCK_SIZE], + hl, hn, decoded_data[PARITY_OUTPUT_SIZE], *data; + + if(!(data = (unsigned char *)malloc(data_size))) { + throw std::runtime_error("error: decode_cch: malloc"); + } + + if(datalen) + *datalen = 0; + + // unmap the bursts + decode_burstmap(iBLOCK[0], e0, &hl, &hn); // XXX ignore stealing bits + decode_burstmap(iBLOCK[1], e1, &hl, &hn); + decode_burstmap(iBLOCK[2], e2, &hl, &hn); + decode_burstmap(iBLOCK[3], e3, &hl, &hn); + + // remove interleave + decode_interleave(conv_data, (unsigned char *)iBLOCK); + + // Viterbi decode + errors = conv_decode(decoded_data, conv_data); + + // check parity + if(errors || parity_check(decoded_data)) { + // fprintf(stderr, "error: sacch: parity error (%d)\n", errors); + return 0; + } + if((len = compress_bits(data, data_size, decoded_data, + DATA_BLOCK_SIZE)) < 0) { + fprintf(stderr, "error: compress_bits\n"); + return 0; + } + if((unsigned int)len < data_size) { + fprintf(stderr, "error: buf too small (%d < %d)\n", + sizeof(data), len); + return 0; + } + + if(datalen) + *datalen = (unsigned int)len; + return data; +} + + +/* + * decode_cch + * + * Decode a "common" control channel. Most control channels use + * the same burst, interleave, Viterbi and parity configuration. + * The documentation for the control channels defines SACCH first + * and then just keeps referring to that. + * + * The current (investigated) list is as follows: + * + * BCCH Norm + * BCCH Ext + * PCH + * AGCH + * CBCH (SDCCH/4) + * CBCH (SDCCH/8) + * SDCCH/4 + * SACCH/C4 + * SDCCH/8 + * SACCH/C8 + * + * We provide two functions, one for where all four bursts are + * contiguous, and one where they aren't. + */ +unsigned char *decode_cch(unsigned char *e0, unsigned char *e1, + unsigned char *e2, unsigned char *e3, unsigned int *datalen) { + + return decode_sacch(e0, e1, e2, e3, datalen); +} + + +unsigned char *decode_cch(unsigned char *e, unsigned int *datalen) { + + return decode_sacch(e, e + eBLOCK_SIZE, e + 2 * eBLOCK_SIZE, + e + 3 * eBLOCK_SIZE, datalen); +} diff --git a/gssm/src/lib/cch.h b/gssm/src/lib/cch.h new file mode 100644 index 0000000..bb1d629 --- /dev/null +++ b/gssm/src/lib/cch.h @@ -0,0 +1,42 @@ +// $Id: cch.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +/* + * decode_cch + * + * Decode a "common" control channel. Most control channels use + * the same burst, interleave, Viterbi and parity configuration. + * The documentation for the control channels defines SACCH first + * and then just keeps referring to that. + * + * The current (investigated) list is as follows: + * + * BCCH Norm + * BCCH Ext + * PCH + * AGCH + * CBCH (SDCCH/4) + * CBCH (SDCCH/8) + * SDCCH/4 + * SACCH/C4 + * SDCCH/8 + * SACCH/C8 + * + * We provide two functions, one for where all four bursts are + * contiguous, and one where they aren't. + */ + +#define DATA_BLOCK_SIZE 184 +#define PARITY_SIZE 40 +#define FLUSH_BITS_SIZE 4 +#define PARITY_OUTPUT_SIZE (DATA_BLOCK_SIZE + PARITY_SIZE + FLUSH_BITS_SIZE) + +#define CONV_INPUT_SIZE PARITY_OUTPUT_SIZE +#define CONV_SIZE (2 * CONV_INPUT_SIZE) + +#define BLOCKS 4 +#define iBLOCK_SIZE (CONV_SIZE / BLOCKS) +#define eBLOCK_SIZE (iBLOCK_SIZE + 2) + +unsigned char *decode_cch(unsigned char *, unsigned char *, unsigned char *, + unsigned char *, unsigned int *); +unsigned char *decode_cch(unsigned char *, unsigned int *); diff --git a/gssm/src/lib/display.cc b/gssm/src/lib/display.cc new file mode 100644 index 0000000..086b48a --- /dev/null +++ b/gssm/src/lib/display.cc @@ -0,0 +1,46 @@ +// $Id: display.cc,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#include +#include + + +void dump_raw(unsigned char *buf, unsigned int len) { + + unsigned int i; + + for(i = 0; i < len; i++) { + printf("%2.2x", buf[i]); + if(!((i + 1) % 4)) + printf(" "); + } + printf("\n"); +} + + +void display_raw(unsigned char *buf, unsigned int len) { + + unsigned int i, j, c; + unsigned long long v; + + for(i = 0; i < len; i += 64) { + v = 0; + for(j = 0; (j < 64) && (i + j < len); j++) { + printf("%d", buf[i + j]); + if(!((j + 1) % 4)) + printf(" "); + v = (v << 1) | buf[i + j]; + } + for(; j < 64; j++) { + printf(" "); + if(!((j + 1) % 4)) + printf(" "); + v <<= 1; + } + printf("\t"); + for(j = 0; j < 8; j++) { + c = (v >> (8 * (7 - j))) & 0xff; + printf("%2.2x ", c); + } + printf("\n"); + } +} diff --git a/gssm/src/lib/display.h b/gssm/src/lib/display.h new file mode 100644 index 0000000..cacd931 --- /dev/null +++ b/gssm/src/lib/display.h @@ -0,0 +1,4 @@ +// $Id: display.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +void dump_raw(unsigned char *, unsigned int); +void display_raw(unsigned char *, unsigned int); diff --git a/gssm/src/lib/gsm_constants.h b/gssm/src/lib/gsm_constants.h new file mode 100644 index 0000000..6f4f07e --- /dev/null +++ b/gssm/src/lib/gsm_constants.h @@ -0,0 +1,76 @@ +// $Id: gsm_constants.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#pragma once + +static const double QN_TIME = 12.0l / 13.0l / 1000000.0l; +static const double BN_TIME = 4.0l * QN_TIME; +static const double TN_TIME = 156.25l * BN_TIME; +static const double FN_TIME = 8.0l * TN_TIME; + +static const double GSM_RATE = 812500.0l / 3.0l; +static const int MAX_FN = 26 * 51 * 2048; + +static const int BURST_LENGTH = 156; + + +/* + * frequency correction: + * tn = 0 fnm51 = 0 + * + * sync: + * tn = 0 fnm51 = 1 + * tn = 0 fnm51 = 11 + * tn = 0 fnm51 = 21 + * tn = 0 fnm51 = 31 + * tn = 0 fnm51 = 41 + * + * bcch: + * tn = 0 fnm51 = 2, 3, 4, 5 + * tn = 2 fnm51 = 2, 3, 4, 5 + * tn = 4 fnm51 = 2, 3, 4, 5 + * tn = 6 fnm51 = 2, 3, 4, 5 + * + * bcch_ext: + * tn = 0 fnm51 = 6, 7, 8, 9 + * tn = 2 fnm51 = 6, 7, 8, 9 + * tn = 4 fnm51 = 6, 7, 8, 9 + * tn = 6 fnm51 = 6, 7, 8, 9 + * + * pch and agch: + * tn = 0 fnm51 = 6, 7, 8, 9 + * tn = 0 fnm51 = 12, 13, 14, 15 + * tn = 0 fnm51 = 16, 17, 18, 19 + * tn = 0 fnm51 = 22, 23, 24, 25 + * tn = 0 fnm51 = 26, 27, 28, 29 + * tn = 0 fnm51 = 32, 33, 34, 35 + * tn = 0 fnm51 = 36, 37, 38, 39 + * tn = 0 fnm51 = 42, 43, 44, 45 + * tn = 0 fnm51 = 46, 47, 48, 49 + * tn = 2 fnm51 = 6, 7, 8, 9 + * tn = 2 fnm51 = 12, 13, 14, 15 + * tn = 2 fnm51 = 16, 17, 18, 19 + * tn = 2 fnm51 = 22, 23, 24, 25 + * tn = 2 fnm51 = 26, 27, 28, 29 + * tn = 2 fnm51 = 32, 33, 34, 35 + * tn = 2 fnm51 = 36, 37, 38, 39 + * tn = 2 fnm51 = 42, 43, 44, 45 + * tn = 2 fnm51 = 46, 47, 48, 49 + * tn = 4 fnm51 = 6, 7, 8, 9 + * tn = 4 fnm51 = 12, 13, 14, 15 + * tn = 4 fnm51 = 16, 17, 18, 19 + * tn = 4 fnm51 = 22, 23, 24, 25 + * tn = 4 fnm51 = 26, 27, 28, 29 + * tn = 4 fnm51 = 32, 33, 34, 35 + * tn = 4 fnm51 = 36, 37, 38, 39 + * tn = 4 fnm51 = 42, 43, 44, 45 + * tn = 4 fnm51 = 46, 47, 48, 49 + * tn = 6 fnm51 = 6, 7, 8, 9 + * tn = 6 fnm51 = 12, 13, 14, 15 + * tn = 6 fnm51 = 16, 17, 18, 19 + * tn = 6 fnm51 = 22, 23, 24, 25 + * tn = 6 fnm51 = 26, 27, 28, 29 + * tn = 6 fnm51 = 32, 33, 34, 35 + * tn = 6 fnm51 = 36, 37, 38, 39 + * tn = 6 fnm51 = 42, 43, 44, 45 + * tn = 6 fnm51 = 46, 47, 48, 49 + */ diff --git a/gssm/src/lib/gssm.i b/gssm/src/lib/gssm.i new file mode 100644 index 0000000..fbac240 --- /dev/null +++ b/gssm/src/lib/gssm.i @@ -0,0 +1,28 @@ +// $Id: gssm.i,v 1.2 2007-07-07 16:31:42 jl Exp $ + +%include "exception.i" +%import "gnuradio.i" + +%{ +#include "gnuradio_swig_bug_workaround.h" +#include "gssm_sink.h" +#include +%} + + +GR_SWIG_BLOCK_MAGIC(gssm, sink); +gssm_sink_sptr gssm_make_sink(double); + +class gssm_sink : public gr_sync_block { + +public: + int d_search_fc_count; + int d_found_fc_count; + int d_valid_s; + int d_invalid_s; + + void stats(); + +private: + gssm_sink(double); +}; diff --git a/gssm/src/lib/gssm_sink.cc b/gssm/src/lib/gssm_sink.cc new file mode 100644 index 0000000..307e3c8 --- /dev/null +++ b/gssm/src/lib/gssm_sink.cc @@ -0,0 +1,764 @@ +/* + * $Id: gssm_sink.cc,v 1.2 2007-07-07 16:31:42 jl Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#include "gssm_sink.h" +#include "gsm_constants.h" +#include "burst_types.h" +#include "bursts.h" +#include "sch.h" +#include "cch.h" +#include "gssm_state.h" +#include "tun.h" +#include "rr_decode.h" +#include "display.h" +#include "buffer.h" + + +gssm_sink_sptr gssm_make_sink(double sps) { + + return gssm_sink_sptr(new gssm_sink(sps)); +} + + +static const char *chan_name = "gsm"; // GSM TUN interface name + + +gssm_sink::gssm_sink(double sps) : + gr_sync_block("gssm_sink", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(0, 0, 0)) { + + if((d_tunfd = mktun(chan_name, d_ether_addr)) == -1) { + fprintf(stderr, "warning: was not able to open TUN device, " + "disabling Wireshark interface\n"); + // throw std::runtime_error("cannot open TUN device"); + } + + // allocate memory for physical channel to logical channel mapping + if(!(d_phy_buf = (unsigned char *)malloc(8 * 51 * eBLOCK_SIZE))) { + perror("malloc"); + close(d_tunfd); + throw std::runtime_error("cannot allocate buffer memory"); + } + + // allocate memory to specify which physical data is present + if(!(d_phy_ind = (int *)malloc(8 * 51 * sizeof(int)))) { + perror("malloc"); + close(d_tunfd); + throw std::runtime_error("cannot allocate index memory"); + } + memset(d_phy_ind, 0, 8 * 51 * sizeof(int)); + + // buffers to hold quadrature demod and clock recovery output + d_buf_qd = gr_make_buffer(BUFFER_QD_SIZE, sizeof(float)); + d_qd_reader = gr_buffer_add_reader(d_buf_qd, 0); + d_buf_mm = gr_make_buffer(BUFFER_MM_SIZE, sizeof(float)); + d_mm_reader = gr_buffer_add_reader(d_buf_mm, 0); + + // indicate to clock recovery that we are not sync'ed + d_bitno = -1; + + // set samples per second and symbol + d_sps = sps; + d_samples_per_symbol = d_sps / GSM_RATE; + + // initial program state + d_state = state_fc; + + // initial base station synchronization + d_tn = -1; + d_fn = -1; + d_bsic = -1; + + // stats + d_search_fc_count = d_found_fc_count = d_valid_s = d_invalid_s = + d_invalid_s_1 = d_valid_bcch = d_invalid_bcch = d_valid_ia = + d_invalid_ia = d_valid_sdcch4 = d_invalid_sdcch4 = + d_valid_sacchc4 = d_invalid_sacchc4 = d_valid_sdcch8 = + d_invalid_sdcch8 = d_valid_sacchc8 = d_invalid_sacchc8 = 0; + + // interpolator + d_interp = new gri_mmse_fir_interpolator(); + + // M&M clock recovery + reset_clock(); + + // set quad demod constants + d_qd_last = 0; + d_qd_gain = M_PI_2l / d_samples_per_symbol; // rate at quad demod + + // we always want multiples of the burst length + set_output_multiple( + (int)ceil((BURST_LENGTH + 1) * d_samples_per_symbol) + + d_interp->ntaps() + 10); +} + + +gssm_sink::~gssm_sink() { + + // close TUN interface + close(d_tunfd); + + // free phy memory + free(d_phy_buf); + free(d_phy_ind); +} + + +int gssm_sink::check_logical_channel(int b1, int b2, int b3, int b4) { + + int r = 0; + unsigned int data_len; + unsigned char *data; + + if(d_phy_ind[b1] && d_phy_ind[b2] && d_phy_ind[b3] && + d_phy_ind[b4]) { + // channel data present + data = decode_cch( + d_phy_buf + b1 * eBLOCK_SIZE, + d_phy_buf + b2 * eBLOCK_SIZE, + d_phy_buf + b3 * eBLOCK_SIZE, + d_phy_buf + b4 * eBLOCK_SIZE, + &data_len); + if(data) { + write_interface(d_tunfd, data + 1, data_len - 1, + d_ether_addr); + + // since we decoded this data, clear present flag + d_phy_ind[b1] = d_phy_ind[b2] = d_phy_ind[b3] = + d_phy_ind[b4] = 0; + + free(data); + + return 0; + } + return -1; + } + + return -2; // channel data not present +} + + +void gssm_sink::check_logical_channels() { + + int o, o_s, ts, rl, fn_s; + + // do we have complete data for various logical channels? + + // BCCH Norm + rl = 51; + fn_s = 2; + for(ts = 0; ts < 8; ts += 2) { + o = ts * rl + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: BCCH Norm (%d, %d)\n", ts, + fn_s); + } + + // BCCH Ext + rl = 51; + fn_s = 6; + for(ts = 0; ts < 8; ts += 2) { + o = ts * rl + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: BCCH Ext (%d, %d)\n", ts, + fn_s); + } + + // PCH, AGCH, SDCCH, SACCHC4 + rl = 51; + for(ts = 0; ts < 8; ts += 2) { + o_s = ts * rl; + + fn_s = 6; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + + fn_s = 12; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + + fn_s = 16; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + + fn_s = 22; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + + fn_s = 26; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + + fn_s = 32; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + + fn_s = 36; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + + fn_s = 42; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + + fn_s = 46; + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: PCH, AGCH (%d, %d)\n", ts, + fn_s); + } + + // SDCCH8 + rl = 51; + for(ts = 0; ts < 8; ts++) { + o_s = ts * rl; + for(fn_s = 0; fn_s < 32; fn_s += 4) { + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: SDCCH8 (%d, %d)\n", + ts, fn_s); + } + } + + // SACCHC8 + // XXX ignoring subchannel numbers + rl = 51; + for(ts = 0; ts < 8; ts++) { + o_s = ts * rl; + for(fn_s = 32; fn_s < 48; fn_s += 4) { + o = o_s + fn_s; + if(check_logical_channel(o, o + 1, o + 2, o + 3) == -1) + fprintf(stderr, "error: SACCH8 (%d, %d)\n", + ts, fn_s); + } + } + +} + + +void gssm_sink::next_timeslot() { + + d_tn++; + if(d_tn >= 8) { + d_tn %= 8; + d_fn = (d_fn + 1) % MAX_FN; + d_fnm51 = d_fn % 51; + d_fnm102 = d_fn % 102; + } +} + + +static void differential_decode(const unsigned char *in, unsigned char *out) { + + int i; + unsigned char is = 1; + + for(i = 0; i < BURST_LENGTH; i++) + is = out[i] = !in[i] ^ is; +} + + +static void differential_decode(const float *in, unsigned char *out) { + + int i; + unsigned char is = 1; + + for(i = 0; i < BURST_LENGTH; i++) + is = out[i] = (in[i] < 0) ^ is; +} + + +static const unsigned int MAX_INVALID_S = 10; +//static const unsigned int MAX_INVALID_S = 1; + +int gssm_sink::check_num_invalid_s() { + + if(d_invalid_s - d_invalid_s_1 >= MAX_INVALID_S) { + d_invalid_s_1 = d_invalid_s; + memset(d_phy_ind, 0, 8 * 51 * sizeof(int)); + + return 1; + } + return 0; +} + + +int gssm_sink::handle_sch(const unsigned char *buf, int *fn, int *bsic) { + + int ret; + + if(ret = !decode_sch(buf, fn, bsic)) { + d_valid_s++; + d_invalid_s_1 = d_invalid_s; + } else { + d_invalid_s++; + } + return ret; +} + + +/* + * search_s + * + * Searches for the synchronization packet. We assume that we have + * just seen the frequency correction packet. Hence: + * + * 1. We first enter with tn = 1. + * 2. The sync burst is the next burst in this channel. + */ +int gssm_sink::search_state_s(const float *in, int nitems) { + + int i, imax, wl; + unsigned char buf[BURST_LENGTH]; + float fbuf[BURST_LENGTH]; + + // assume that we are at the start of a burst + + imax = nitems - (int)ceil((BURST_LENGTH + 1) * d_samples_per_symbol) - + d_interp->ntaps() - (int)d_mu; + + for(i = 0; i < imax;) { + wl = BURST_LENGTH; + i += mm_demod(in + i, nitems - i, fbuf, wl); + if(!d_tn) { + differential_decode(fbuf, buf); + if(handle_sch(buf, &d_fn, &d_bsic)) { + + d_fnm51 = d_fn % 51; + d_fnm102 = d_fn % 102; + + next_timeslot(); + + d_state = state_data; + + return i; + } else if(check_num_invalid_s()) { + reset_state(); + return 0; + } + } + next_timeslot(); + } + return i; +} + + +static int is_sch(int tn, int fnm51) { + + return ((!tn) && ((fnm51 == 1) || (fnm51 == 11) || (fnm51 == 21) || + (fnm51 == 31) || (fnm51 == 41))); +} + + +void gssm_sink::search_sch(const unsigned char *buf) { + + int fn, bsic; + + if(is_sch(d_tn, d_fnm51)) { + if(handle_sch(buf, &fn, &bsic)) { + if(d_fn != fn) { + fprintf(stderr, "error: lost sync " + "(%d != %d [%d])\n", fn, d_fn, fn - d_fn); + d_fn = fn; + d_fnm51 = fn % 51; + d_fnm102 = fn % 102; + } + if(d_bsic != bsic) { + fprintf(stderr, "warning: bsic changed " + "(%d -> %d)\n", d_bsic, bsic); + d_bsic = bsic; + } + + } else { + if(check_num_invalid_s()) { + reset_state(); + } + } + } +} + + +int gssm_sink::search_state_data(const float *in, int nitems) { + + int i, imax, wl; + unsigned int offset, offset_i; + unsigned char buf[BURST_LENGTH]; + float fbuf[BURST_LENGTH]; + + imax = nitems - (int)ceil((BURST_LENGTH + 1) * d_samples_per_symbol) - + d_interp->ntaps() - (int)d_mu; + + for(i = 0; i < imax;) { + wl = BURST_LENGTH; + i += mm_demod(in + i, nitems - i, fbuf, wl); + + differential_decode(fbuf, buf); + + /* + for(int ii = 0; ii < BURST_LENGTH; ii++) + printf("%f\n", fbuf[ii]); + */ + + /* + if(is_sch(d_tn, d_fnm51)) + printf("S"); + else + printf(" "); + printf("%2d:%d: ", d_fnm51, d_tn); + for(int ii = 0; ii < BURST_LENGTH; ii++) + printf("%d", buf[ii]); + printf("\n"); + */ + + /* + if((buf[0] == 1) || (buf[1] == 1) || (buf[2] == 1)) + printf("%2d:%d: %d%d%d:%d%d%d %f %f %f : %f %f %f\n", + d_fnm51, d_tn, buf[0], buf[1], buf[2], buf[145], + buf[146], buf[147], fbuf[0], fbuf[1], fbuf[2], + fbuf[145], fbuf[146], fbuf[147]); + */ + + search_sch(buf); + if(d_state != state_data) + return 0; + + if(!is_dummy_burst(buf)) { + offset_i = (d_tn * 51 + (d_fn % 51)); + offset = offset_i * eBLOCK_SIZE; + memcpy(d_phy_buf + offset, buf + N_EDATA_OS_1, + N_EDATA_LEN_1); + memcpy(d_phy_buf + offset + N_EDATA_LEN_1, + buf + N_EDATA_OS_2, N_EDATA_LEN_2); + d_phy_ind[offset_i] = 1; + } + + // check_logical_channels(); + + if((!d_tn) && (!d_fnm51)) { + check_logical_channels(); + memset(d_phy_ind, 0, 8 * 51 * sizeof(int)); + } + + next_timeslot(); + } + return i; +} + + +static int slice(float f) { + + return (f >= 0); +} + + +int gssm_sink::mm_demod(const float *in, int nitems, float *out, int &nitems_out) { + int i, o; + float mm_val, v, f; + + f = floor(d_mu); + i = (int)f; + d_mu -= f; + + for(o = 0; (i < nitems - d_interp->ntaps()) && (o < nitems_out); o++) { + /* + * Produce output sample interpolated by d_mu where d_mu + * represents the normalized distance between the first and + * second sample of the given sequence. + * + * For example, d_mu = 0.5 interpolates a sample halfway + * in-between the current sample and the next. + */ + v = d_interp->interpolate(&in[i], d_mu); + + // adjust how fast and in which direction we modify omega + mm_val = slice(d_last_sample) * v - slice(v) * d_last_sample; + + // write output + // out[o] = (d_last_sample = v) >= 0; // hard decision + out[o] = d_last_sample = v; // soft decision + + // adjust the sample time for the next symbol + d_omega = d_omega + d_gain_omega * mm_val; + + // don't allow it to exceed extrema + if(d_omega > d_max_omega) + d_omega = d_max_omega; + else if(d_omega < d_min_omega) + d_omega = d_min_omega; + + // advance to next symbol + d_mu += d_omega + d_gain_mu * mm_val; + + // if we're sync'ed + if(d_bitno > -1) { + d_bitno++; + + // skip the quarter-bit at the end of a burst + if(d_bitno >= BURST_LENGTH) { + d_mu += d_omega / 4.0l; + d_bitno = 0; + } + } + + // d_mu is now the number of samples to the next symbol + f = floor(d_mu); + i += (int)f; // integer advance + d_mu -= f; // fractional advance + } + + // we may have advanced past the buffer + i -= (int)f; + d_mu += f; + + nitems_out = o; + + return i; // returns number consumed +} + + +int gssm_sink::quad_demod(const gr_complex *in, int nitems, float *out, int &nitems_out) { + + int r, M; + gr_complex product; + + M = std::min(nitems, nitems_out); + for(r = 0; r < M; r++) { + product = in[r] * conj(d_qd_last); + d_qd_last = in[r]; + out[r] = d_qd_gain * gr_fast_atan2f(imag(product), real(product)); + } + + nitems_out = r; + return r; // returns number consumed +} + + +int gssm_sink::process_input(const gr_complex *in, const int nitems) { + + float *w; + const float *r; + int wl, rl, rrl, ret; + + w = (float *)d_buf_qd->write_pointer(); + wl = d_buf_qd->space_available(); + ret = quad_demod(in, nitems, w, wl); + d_buf_qd->update_write_pointer(wl); + + r = (const float *)d_qd_reader->read_pointer(); + rl = d_qd_reader->items_available(); + w = (float *)d_buf_mm->write_pointer(); + wl = d_buf_mm->space_available(); + rrl = mm_demod(r, rl, w, wl); + d_qd_reader->update_read_pointer(rrl); + d_buf_mm->update_write_pointer(wl); + + return ret; +} + + +void gssm_sink::flush_buffers() { + + d_qd_reader->update_read_pointer(d_qd_reader->items_available()); + d_mm_reader->update_read_pointer(d_mm_reader->items_available()); +} + + +void gssm_sink::save_clock() { + + d_mu_bak = d_mu; + d_omega_bak = d_omega; + d_last_sample_bak = d_last_sample; +} + + +void gssm_sink::restore_clock() { + + d_mu = d_mu_bak; + d_omega = d_omega_bak; + d_last_sample = d_last_sample_bak; +} + + +void gssm_sink::reset_state() { + + d_state = state_fc; + d_bitno = -1; + flush_buffers(); + d_tn = -1; + d_fn = -1; + d_fnm51 = -1; + d_fnm102 = -1; + d_bsic = -1; + + reset_clock(); +} + + +void gssm_sink::reset_clock() { + + // M&M clock recovery + d_mu = 0.0; + d_gain_mu = 0.01; + d_omega = d_samples_per_symbol; + //d_omega_relative_limit = 0.01; + d_omega_relative_limit = 0.3; + d_max_omega = d_omega * (1.0 + d_omega_relative_limit); + d_min_omega = d_omega * (1.0 - d_omega_relative_limit); + d_gain_omega = 0.25 * d_gain_mu * d_gain_mu; +} + + +/* + * search_fc + * + * Searches for the frequency correction burst. + */ +int gssm_sink::search_state_fc(const float *in, int nitems) { + + int i, j, slen = sizeof(fc_fb_de) / sizeof(*fc_fb_de), + imax, c, nbits; + float w[BURST_LENGTH]; + double f; + const unsigned char *s = fc_fb_de; + + f = floor(d_mu); + i = (int)f; + d_mu -= f; + + imax = nitems - (int)ceil((BURST_LENGTH + 1) * d_samples_per_symbol) - + d_interp->ntaps() - i; + + while(i < imax) { + + // update stats + d_search_fc_count++; + + // save current clock parameters + save_clock(); + + // calculate burst + nbits = BURST_LENGTH; + c = mm_demod(in + i, nitems - i, w, nbits); + + // compare fixed and tail bits + for(j = 0; j < std::min(slen, nbits); j++) + if(slice(w[j]) != s[j]) + break; + + // was the fc burst detected? + if(j == slen) { + + // update stats + d_found_fc_count++; + + d_mu += d_omega / 4.0l; // advance quarter-bit + d_bitno = 0; // burst sync'ed now + d_tn = 0; // fc always in timeslot 0 + next_timeslot(); + d_state = state_s; + + return i + c; + } + + // restore clock to start of attempt + restore_clock(); + + // skip 1 bit and start again + nbits = 1; + i += mm_demod(in + i, nitems - i, w, nbits); + } + + return i; +} + + +void gssm_sink::stats() { + + printf("search fc:\t%d\n", d_search_fc_count); + printf("found fc:\t%d\n", d_found_fc_count); + printf("valid s:\t%d\n", d_valid_s); + printf("invalid s:\t%d\n", d_invalid_s); +} + + +int gssm_sink::process_qd(const gr_complex *in, int nitems) { + + float *w; + int wl, ret; + + w = (float *)d_buf_qd->write_pointer(); + wl = d_buf_qd->space_available(); + ret = quad_demod(in, nitems, w, wl); + d_buf_qd->update_write_pointer(wl); + + return ret; +} + + +int gssm_sink::work(int nitems, gr_vector_const_void_star &input_items, + gr_vector_void_star &) { + + const gr_complex *in = (gr_complex *)input_items[0]; + const float *r; + int rl, ret, i, imax, n; + + ret = process_qd(in, nitems); + + r = (const float *)d_qd_reader->read_pointer(); + rl = d_qd_reader->items_available(); + + imax = rl - + (int)(ceil((BURST_LENGTH + 1) * d_samples_per_symbol + d_mu) + + d_interp->ntaps()); + + for(i = 0; i < imax;) { + switch(d_state) { + case state_fc: + n = search_state_fc(r + i, rl - i); + break; + case state_s: + n = search_state_s(r + i, rl - i); + break; + case state_data: + n = search_state_data(r + i, rl - i); + break; + default: + fprintf(stderr, "error: bad state\n"); + reset_state(); + return 0; + } + i += n; + } + d_qd_reader->update_read_pointer(i); + + return ret; +} diff --git a/gssm/src/lib/gssm_sink.h b/gssm/src/lib/gssm_sink.h new file mode 100644 index 0000000..3e8a57f --- /dev/null +++ b/gssm/src/lib/gssm_sink.h @@ -0,0 +1,125 @@ +// $Id: gssm_sink.h,v 1.2 2007-07-07 16:31:42 jl Exp $ + +#pragma once + +#include +#include +#include +#include "gssm_state.h" + +class gssm_sink; +typedef boost::shared_ptr gssm_sink_sptr; +gssm_sink_sptr gssm_make_sink(double); + +class gssm_sink : public gr_sync_block { + +public: + ~gssm_sink(void); + + int work(int nitems, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + +private: + // sample speeds + double d_sps; // samples per second + double d_samples_per_symbol; + + // M&M clock recovery + gri_mmse_fir_interpolator *d_interp; + double d_mu; + double d_gain_mu; + double d_omega; + double d_gain_omega; + double d_omega_relative_limit; + double d_max_omega; + double d_min_omega; + float d_last_sample; + + double d_mu_bak; + double d_omega_bak; + double d_last_sample_bak; + + int d_bitno; + + // buffers + gr_buffer_sptr d_buf_qd; + gr_buffer_reader_sptr d_qd_reader; + gr_buffer_sptr d_buf_mm; + gr_buffer_reader_sptr d_mm_reader; + + // quad demod + gr_complex d_qd_last; + double d_qd_gain; + + // GSM BTS timing + int d_tn; // time slot + int d_fn; // frame number + int d_fnm51; // frame number mod 51 + int d_fnm102; // frame number mod 102 + int d_bsic; // current bsic + + // program state + gssm_state_t d_state; + + // buffer to hold physical data + unsigned char * d_phy_buf; + int * d_phy_ind; + + // Wireshark interface + int d_tunfd; // TUN fd + unsigned char d_ether_addr[ETH_ALEN]; + + /*******************************************************************/ + + friend gssm_sink_sptr gssm_make_sink(double); + gssm_sink(double); + + int search_state_fc(const float *, int); + int search_state_s(const float *, int); + int search_state_data(const float *, int); + + void search_sch(const unsigned char *); + int handle_sch(const unsigned char *, int *, int *); + + void next_timeslot(void); + + int check_logical_channel(int, int, int, int); + void check_logical_channels(void); + + int mm_demod(const float *, int, float *, int &); + int quad_demod(const gr_complex *, int, float *, int &); + int process_input(const gr_complex *, int); + int process_qd(const gr_complex *, int); + + void save_clock(); + void restore_clock(); + void reset_clock(); + void flush_buffers(); + void reset_state(); + + + /*******************************************************************/ + // Debug + + int check_num_invalid_s(); + +public: + int d_search_fc_count, + d_found_fc_count, + d_valid_s, + d_invalid_s, + d_invalid_s_1, + d_valid_bcch, + d_invalid_bcch, + d_valid_ia, + d_invalid_ia, + d_valid_sdcch4, + d_invalid_sdcch4, + d_valid_sacchc4, + d_invalid_sacchc4, + d_valid_sdcch8, + d_invalid_sdcch8, + d_valid_sacchc8, + d_invalid_sacchc8; + void stats(); +}; diff --git a/gssm/src/lib/gssm_state.h b/gssm/src/lib/gssm_state.h new file mode 100644 index 0000000..44400a2 --- /dev/null +++ b/gssm/src/lib/gssm_state.h @@ -0,0 +1,9 @@ +// $Id: gssm_state.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#pragma once + +typedef enum { + state_fc, + state_s, + state_data +} gssm_state_t; diff --git a/gssm/src/lib/rr_decode.cc b/gssm/src/lib/rr_decode.cc new file mode 100644 index 0000000..312c883 --- /dev/null +++ b/gssm/src/lib/rr_decode.cc @@ -0,0 +1,236 @@ +// $Id: rr_decode.cc,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#include +#include +#include + +static char *pd_string(unsigned char pd) { + + switch(pd) { + case 0: + return "group call control"; + case 1: + return "broadcast call control"; + case 2: + return "reserved (PDSS1 in earlier phases)"; + case 3: + return "call control; call related SS messages"; + case 4: + return "GPRS Transparent Transport Protocol (GTTP)"; + case 5: + return "mobility management messages"; + case 6: + return "radio resources management messages"; + case 8: + return "GPRS mobility management messages"; + case 9: + return "SMS messages"; + case 10: + return "GPRS session management messages"; + case 11: + return "non-call related SS messages"; + case 12: + return "location services"; + case 14: + return "reserved for extension of the PD"; + case 15: + return "reserved for tests procedures"; + default: + return "unknown PD"; + } +} + + +static char *message_type_rrm_string(unsigned char mt) { + + switch(mt) { + case 0x3c: + return "channel establishment message: RR " + "initialization request"; + case 0x3b: + return "channel establishment message: aditional " + "assignment"; + case 0x3f: + return "channel establishment message: immediate " + "assignment"; + case 0x39: + return "channel establishment message: immediate " + "assignment extended"; + case 0x3a: + return "channel establishment message: immediate " + "assignment reject"; + + case 0x35: + return "ciphering message: ciphering mode command"; + case 0x32: + return "ciphering message: ciphering mode complete"; + + case 0x30: + return "configuration change message: configuration " + "change command"; + case 0x31: + return "configuration change message: configuration " + "change acknowledgement"; + case 0x33: + return "configuration change message: configuration " + "change reject"; + + case 0x2e: + return "handover message: assignment command"; + case 0x29: + return "handover message: assignment complete"; + case 0x2f: + return "handover message: assignment failure"; + case 0x2b: + return "handover message: handover command"; + case 0x2c: + return "handover message: handover complete"; + case 0x28: + return "handover message: handover failure"; + case 0x2d: + return "handover message: physical information"; + + case 0x08: + return "RR-cell change order"; + + case 0x23: + return "PDCH assignment command"; + + case 0x0d: + return "channel release message: channel release"; + case 0x0a: + return "channel release message: partial release"; + case 0x0f: + return "channel release message: partial release " + "complete"; + + case 0x21: + return "paging and notification message: paging " + "request type 1"; + case 0x22: + return "paging and notification message: paging " + "request type 2"; + case 0x24: + return "paging and notification message: paging " + "request type 3"; + case 0x27: + return "paging and notification message: paging " + "response"; + case 0x20: + return "paging and notification message: " + "notification / NCH"; + case 0x25: + return "paging and notification message: " + "notification / FACCH"; + case 0x26: + return "paging and notification message: " + "notification response"; + + case 0x0b: + return "reserved"; + + case 0x18: + return "system information message: type 8"; + case 0x19: + return "system information message: type 1"; + case 0x1a: + return "system information message: type 2"; + case 0x1b: + return "system information message: type 3"; + case 0x1c: + return "system information message: type 4"; + case 0x1d: + return "system information message: type 5"; + case 0x1e: + return "system information message: type 6"; + case 0x1f: + return "system information message: type 7"; + case 0x02: + return "system information message: type 2bis"; + case 0x03: + return "system information message: type 2ter"; + case 0x05: + return "system information message: type 5bis"; + case 0x06: + return "system information message: type 5ter"; + case 0x04: + return "system information message: type 9"; + case 0x00: + return "system information message: type 13"; + case 0x3d: + return "system information message: type 16"; + case 0x3e: + return "system information message: type 17"; + + case 0x10: + return "miscellaneous message: channel mode modify"; + case 0x12: + return "miscellaneous message: RR status"; + case 0x17: + return "miscellaneous message: channel mode modify " + "acknowledge"; + case 0x14: + return "miscellaneous message: frequency redefinition"; + case 0x15: + return "miscellaneous message: measurement report"; + case 0x16: + return "miscellaneous message: classmark change"; + case 0x13: + return "miscellaneous message: classmark enquiry"; + case 0x36: + return "miscellaneous message: extended measurement " + "report"; + case 0x37: + return "miscellaneous message: extended measurement " + "order"; + case 0x34: + return "miscellaneous message: GPRS suspension request"; + + case 0x09: + return "VGCS uplink control message: uplink grant"; + case 0x0e: + return "VGCS uplink control message: uplink release"; + case 0x0c: + return "VGCS uplink control message: uplink free"; + case 0x2a: + return "VGCS uplink control message: uplink busy"; + case 0x11: + return "VGCS uplink control message: talker indication"; + + case 0x38: + return "application message: application information"; + + default: + return "unknown radio resource management message " + "type"; + } +} + + +void display_l3(unsigned char *buf, unsigned int buflen) { + + printf("(%d) PD: %s: (%2.2x) %s\n", buflen, pd_string(buf[0] & 0xf), + buf[1], message_type_rrm_string(buf[1])); +} + + +void display_ns_l3(unsigned char *data, unsigned int datalen) { + + int len; + + // bit 1 == 1, bit 2 == 0 + if((data[0] & 3) != 1) { + fprintf(stderr, "error: display_ns_l3: pseudo-length reserved " + "bits bad (%2.2x)\n", data[0] & 3); + return; + } + len = data[0] >> 2; + if(datalen < len) { + fprintf(stderr, "error: display_ns_l3: bad data length " + "(%d < %d)\n", datalen, len); + return; + } + + printf("L3 length: %d\n", len); + display_l3(data + 1, datalen - 1); +} diff --git a/gssm/src/lib/rr_decode.h b/gssm/src/lib/rr_decode.h new file mode 100644 index 0000000..42d6266 --- /dev/null +++ b/gssm/src/lib/rr_decode.h @@ -0,0 +1,4 @@ +// $Id: rr_decode.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +void display_l3(unsigned char *, unsigned int); +void display_ns_l3(unsigned char *, unsigned int); diff --git a/gssm/src/lib/rrm.h b/gssm/src/lib/rrm.h new file mode 100644 index 0000000..52be6a5 --- /dev/null +++ b/gssm/src/lib/rrm.h @@ -0,0 +1,22 @@ +// $Id: rrm.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#pragma once + +typedef struct { + unsigned char b0:1, + b1:1, + len:6; +} l2_pseudo_length_s; + +typedef union { + unsigned char v; + l2_pseudo_length_s b; +} l2_pseudo_length_t; + + +typedef struct { + unsigned char pd:4, + si:4; + unsigned char mt; + unsigned char ie[0]; +} l3_h_t; diff --git a/gssm/src/lib/sch.cc b/gssm/src/lib/sch.cc new file mode 100644 index 0000000..c336dc1 --- /dev/null +++ b/gssm/src/lib/sch.cc @@ -0,0 +1,320 @@ +// $Id: sch.cc,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +#include +#include +#include +#include +#include "burst_types.h" + +/* + * Synchronization channel. + * + * Timeslot Repeat length Frame Number (mod repeat length) + * 0 51 1, 11, 21, 31, 41 + */ + +/* + * Parity (FIRE) for the GSM SCH. + * + * g(x) = x^10 + x^8 + x^6 + x^5 + x^4 + x^2 + 1 + */ +#define DATA_BLOCK_SIZE 25 +#define PARITY_SIZE 10 +#define TAIL_BITS_SIZE 4 +#define PARITY_OUTPUT_SIZE (DATA_BLOCK_SIZE + PARITY_SIZE + TAIL_BITS_SIZE) + +static const unsigned char parity_polynomial[PARITY_SIZE + 1] = { + 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1 +}; + +static const unsigned char parity_remainder[PARITY_SIZE] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + + +static void parity_encode(unsigned char *d, unsigned char *p) { + + unsigned int i; + unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q; + + memcpy(buf, d, DATA_BLOCK_SIZE); + memset(buf + DATA_BLOCK_SIZE, 0, PARITY_SIZE); + + for(q = buf; q < buf + DATA_BLOCK_SIZE; q++) + if(*q) + for(i = 0; i < PARITY_SIZE + 1; i++) + q[i] ^= parity_polynomial[i]; + for(i = 0; i < PARITY_SIZE; i++) + p[i] = !buf[DATA_BLOCK_SIZE + i]; +} + + +static int parity_check(unsigned char *d) { + + unsigned int i; + unsigned char buf[DATA_BLOCK_SIZE + PARITY_SIZE], *q; + + memcpy(buf, d, DATA_BLOCK_SIZE + PARITY_SIZE); + + for(q = buf; q < buf + DATA_BLOCK_SIZE; q++) + if(*q) + for(i = 0; i < PARITY_SIZE + 1; i++) + q[i] ^= parity_polynomial[i]; + return memcmp(buf + DATA_BLOCK_SIZE, parity_remainder, PARITY_SIZE); +} + + +/* + * Convolutional encoding and Viterbi decoding for the GSM SCH. + * (Equivalent to the GSM SACCH.) + * + * G_0 = 1 + x^3 + x^4 + * G_1 = 1 + x + x^3 + x^4 + * + * i.e., + * + * c_{2k} = u_k + u_{k - 3} + u_{k - 4} + * c_{2k + 1} = u_k + u_{k - 1} + u_{k - 3} + u_{k - 4} + */ +#define CONV_INPUT_SIZE PARITY_OUTPUT_SIZE +#define CONV_SIZE (2 * CONV_INPUT_SIZE) +#define K 5 +#define MAX_ERROR (2 * CONV_INPUT_SIZE + 1) + + +/* + * Given the current state and input bit, what are the output bits? + * + * encode[current_state][input_bit] + */ +static const unsigned int encode[1 << (K - 1)][2] = { + {0, 3}, {3, 0}, {3, 0}, {0, 3}, + {0, 3}, {3, 0}, {3, 0}, {0, 3}, + {1, 2}, {2, 1}, {2, 1}, {1, 2}, + {1, 2}, {2, 1}, {2, 1}, {1, 2} +}; + + +/* + * Given the current state and input bit, what is the next state? + * + * next_state[current_state][input_bit] + */ +static const unsigned int next_state[1 << (K - 1)][2] = { + {0, 8}, {0, 8}, {1, 9}, {1, 9}, + {2, 10}, {2, 10}, {3, 11}, {3, 11}, + {4, 12}, {4, 12}, {5, 13}, {5, 13}, + {6, 14}, {6, 14}, {7, 15}, {7, 15} +}; + + +/* + * Given the previous state and the current state, what input bit caused + * the transition? If it is impossible to transition between the two + * states, the value is 2. + * + * prev_next_state[previous_state][current_state] + */ +static const unsigned int prev_next_state[1 << (K - 1)][1 << (K - 1)] = { + { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2}, + { 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2}, + { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2}, + { 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2}, + { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2}, + { 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2}, + { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2}, + { 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2}, + { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2}, + { 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2}, + { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2}, + { 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2}, + { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2}, + { 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2}, + { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1}, + { 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1} +}; + + +static inline unsigned int hamming_distance2(unsigned int w) { + + return (w & 1) + !!(w & 2); +} + + +static void conv_encode(unsigned char *data, unsigned char *output) { + + unsigned int i, state = 0, o; + + // encode data + for(i = 0; i < CONV_INPUT_SIZE; i++) { + o = encode[state][data[i]]; + state = next_state[state][data[i]]; + *output++ = !!(o & 2); + *output++ = o & 1; + } +} + + +static int conv_decode(unsigned char *data, unsigned char *output) { + + int i, t; + unsigned int rdata, state, nstate, b, o, distance, accumulated_error, + min_state, min_error, cur_state; + + unsigned int ae[1 << (K - 1)]; + unsigned int nae[1 << (K - 1)]; // next accumulated error + unsigned int state_history[1 << (K - 1)][CONV_INPUT_SIZE + 1]; + + // initialize accumulated error, assume starting state is 0 + for(i = 0; i < (1 << (K - 1)); i++) + ae[i] = nae[i] = MAX_ERROR; + ae[0] = 0; + + // build trellis + for(t = 0; t < CONV_INPUT_SIZE; t++) { + + // get received data symbol + rdata = (data[2 * t] << 1) | data[2 * t + 1]; + + // for each state + for(state = 0; state < (1 << (K - 1)); state++) { + + // make sure this state is possible + if(ae[state] >= MAX_ERROR) + continue; + + // find all states we lead to + for(b = 0; b < 2; b++) { + + // get next state given input bit b + nstate = next_state[state][b]; + + // find output for this transition + o = encode[state][b]; + + // calculate distance from received data + distance = hamming_distance2(rdata ^ o); + + // choose surviving path + accumulated_error = ae[state] + distance; + if(accumulated_error < nae[nstate]) { + + // save error for surviving state + nae[nstate] = accumulated_error; + + // update state history + state_history[nstate][t + 1] = state; + } + } + } + + // get accumulated error ready for next time slice + for(i = 0; i < (1 << (K - 1)); i++) { + ae[i] = nae[i]; + nae[i] = MAX_ERROR; + } + } + + // the final state is the state with the fewest errors + min_state = (unsigned int)-1; + min_error = MAX_ERROR; + for(i = 0; i < (1 << (K - 1)); i++) { + if(ae[i] < min_error) { + min_state = i; + min_error = ae[i]; + } + } + + // trace the path + cur_state = min_state; + for(t = CONV_INPUT_SIZE; t >= 1; t--) { + min_state = cur_state; + cur_state = state_history[cur_state][t]; // get previous + output[t - 1] = prev_next_state[cur_state][min_state]; + } + + // return the number of errors detected (hard-decision) + return min_error; +} + + +int decode_sch(const unsigned char *buf, int *fn_o, int *bsic_o) { + + int errors, bsic, t1, t2, t3p, t3, fn, tt; + unsigned char data[CONV_SIZE], decoded_data[PARITY_OUTPUT_SIZE]; + + // extract encoded data from synchronization burst + memcpy(data, buf + SB_EDATA_OS_1, SB_EDATA_LEN_1); + memcpy(data + SB_EDATA_LEN_1, buf + SB_EDATA_OS_2, SB_EDATA_LEN_2); + + // Viterbi decode + if(errors = conv_decode(data, decoded_data)) { + // fprintf(stderr, "error: sch: conv_decode (%d)\n", errors); + return errors; + } + + // check parity + if(parity_check(decoded_data)) { + // fprintf(stderr, "error: sch: parity failed\n"); + return 1; + } + + // Synchronization channel information, 44.018 page 171. (V7.2.0) + bsic = + (decoded_data[ 7] << 5) | + (decoded_data[ 6] << 4) | + (decoded_data[ 5] << 3) | + (decoded_data[ 4] << 2) | + (decoded_data[ 3] << 1) | + (decoded_data[ 2] << 0); + t1 = + (decoded_data[ 1] << 10) | + (decoded_data[ 0] << 9) | + (decoded_data[15] << 8) | + (decoded_data[14] << 7) | + (decoded_data[13] << 6) | + (decoded_data[12] << 5) | + (decoded_data[11] << 4) | + (decoded_data[10] << 3) | + (decoded_data[ 9] << 2) | + (decoded_data[ 8] << 1) | + (decoded_data[23] << 0); + t2 = + (decoded_data[22] << 4) | + (decoded_data[21] << 3) | + (decoded_data[20] << 2) | + (decoded_data[19] << 1) | + (decoded_data[18] << 0); + t3p = + (decoded_data[17] << 2) | + (decoded_data[16] << 1) | + (decoded_data[24] << 0); + + t3 = 10 * t3p + 1; + + // modulo arithmetic + tt = t3; + while(tt < t2) + tt += 26; + tt = (tt - t2) % 26; + fn = (51 * 26 * t1) + (51 * tt) + t3; + + /* + * BSIC: Base Station Identification Code + * BCC: Base station Color Code + * NCC: Network Color Code + * + * FN: Frame Number + */ + /* + printf("bsic: %x (bcc: %u; ncc: %u)\tFN: %u\n", bsic, bsic & 7, + (bsic >> 3) & 7, fn); + */ + + if(fn_o) + *fn_o = fn; + if(bsic_o) + *bsic_o = bsic; + + return 0; +} diff --git a/gssm/src/lib/sch.h b/gssm/src/lib/sch.h new file mode 100644 index 0000000..5f8b217 --- /dev/null +++ b/gssm/src/lib/sch.h @@ -0,0 +1,3 @@ +// $Id: sch.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +int decode_sch(const unsigned char *, int *, int *); diff --git a/gssm/src/lib/tun.cc b/gssm/src/lib/tun.cc new file mode 100644 index 0000000..2abda90 --- /dev/null +++ b/gssm/src/lib/tun.cc @@ -0,0 +1,125 @@ +// $Id: tun.cc,v 1.2 2007-07-07 16:31:42 jl Exp $ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int mktun(const char *chan_name, unsigned char *ether_addr) { + + struct ifreq ifr; + // struct ifreq ifw; + char if_name[IFNAMSIZ]; + int fd, one = 1; + // int sd; + + // construct TUN interface + if((fd = open("/dev/net/tun", O_RDWR)) == -1) { + perror("open"); + return -1; + } + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + snprintf(ifr.ifr_name, IFNAMSIZ, "%s", chan_name); + if(ioctl(fd, TUNSETIFF, (void *)&ifr) == -1) { + perror("TUNSETIFF"); + close(fd); + return -1; + } + + // save actual name + memcpy(if_name, ifr.ifr_name, IFNAMSIZ); + + // get ether addr + memset(&ifr, 0, sizeof(ifr)); + memcpy(ifr.ifr_name, if_name, IFNAMSIZ); + if(ioctl(fd, SIOCGIFHWADDR, (void *)&ifr) == -1) { + perror("SIOCGIFHWADDR"); + close(fd); + return -1; + } + memcpy(ether_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + + // set persistent + if(ioctl(fd, TUNSETPERSIST, (void *)&one) == -1) { + perror("TUNSETPERSIST"); + close(fd); + return -1; + } + + // set interface up + /* XXX must be root + if((sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket"); + close(fd); + return -1; + } + + // get current flags + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1); + if(ioctl(sd, SIOCGIFFLAGS, &ifr) == -1) { + perror("SIOCGIFFLAGS"); + close(sd); + close(fd); + return -1; + } + + // set up + memset(&ifw, 0, sizeof(ifw)); + strncpy(ifw.ifr_name, if_name, IFNAMSIZ - 1); + ifw.ifr_flags = ifr.ifr_flags | IFF_UP | IFF_RUNNING; + if(ioctl(sd, SIOCSIFFLAGS, &ifw) == -1) { + perror("SIOCSIFFLAGS"); + close(sd); + close(fd); + return -1; + } + close(sd); + */ + + return fd; +} + + +static inline int min(int a, int b) { + + return (a < b)? a : b; +} + + +static const unsigned int DEFAULT_MTU = 1500; +static const unsigned short ether_type = 0xfed5; // current dtap ethertype + +int write_interface(int fd, unsigned char *data, unsigned int data_len, + unsigned char *ether_addr) { + + unsigned char frame[DEFAULT_MTU]; // XXX buffer overflow? + struct ethhdr eh; + + if(fd < 0) + return data_len; + + memcpy(eh.h_dest, ether_addr, ETH_ALEN); + memcpy(eh.h_source, ether_addr, ETH_ALEN); + eh.h_proto = htons(ether_type); + + memcpy(frame, &eh, sizeof(eh)); + memcpy(frame + sizeof(eh), data, + min(data_len, sizeof(frame) - sizeof(eh))); + + if(write(fd, frame, sizeof(eh) + data_len) == -1) { + perror("write"); + return -1; + } + + return data_len; +} diff --git a/gssm/src/lib/tun.h b/gssm/src/lib/tun.h new file mode 100644 index 0000000..a7868c4 --- /dev/null +++ b/gssm/src/lib/tun.h @@ -0,0 +1,4 @@ +// $Id: tun.h,v 1.1.1.1 2007-06-01 04:26:57 jl Exp $ + +int mktun(const char *, unsigned char *); +int write_interface(int, unsigned char *, unsigned int, unsigned char *); diff --git a/gssm/src/mktun/Makefile.am b/gssm/src/mktun/Makefile.am new file mode 100644 index 0000000..95dc50a --- /dev/null +++ b/gssm/src/mktun/Makefile.am @@ -0,0 +1,7 @@ +# $Id: Makefile.am,v 1.3 2007-06-01 05:35:59 jl Exp $ + +#include $(top_srcdir)/Makefile.common + +bin_PROGRAMS = mktun +mktun_SOURCES = mktun.c + diff --git a/gssm/src/mktun/mktun.c b/gssm/src/mktun/mktun.c new file mode 100644 index 0000000..e22d496 --- /dev/null +++ b/gssm/src/mktun/mktun.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static struct option long_options[] = { + { "delete", no_argument, 0, 'd'}, + { "help", no_argument, 0, 'h'}, + { 0, 0, 0, 0} +}; + + +void usage(char *prog) { + + fprintf(stderr, "note: you must be root (except perhaps to delete " + "the interface)\n"); + fprintf(stderr, "usage: %s [--help | -h] | [--delete | -d] " + "\n", basename(prog)); + exit(-1); +} + + +int main(int argc, char **argv) { + + struct ifreq ifr, ifw; + char if_name[IFNAMSIZ], *chan_name = "gsm"; + int option_index = 0, c, delete_if = 0, persist = 1, fd, sd; + + while((c = getopt_long(argc, argv, "dh?", long_options, &option_index)) + != -1) { + switch(c) { + case 'd': + delete_if = 1; + break; + case 'h': + case '?': + default: + usage(argv[0]); + break; + } + } + + if(optind >= argc) + usage(argv[0]); + + chan_name = argv[optind]; + + if(!delete_if && getuid() && geteuid()) + usage(argv[0]); + + // construct TUN interface + if((fd = open("/dev/net/tun", O_RDWR)) == -1) { + perror("open"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + snprintf(ifr.ifr_name, IFNAMSIZ, "%s", chan_name); + if(ioctl(fd, TUNSETIFF, (void *)&ifr) == -1) { + perror("TUNSETIFF"); + close(fd); + return -1; + } + + // save actual name + memcpy(if_name, ifr.ifr_name, IFNAMSIZ); + + if(delete_if) + persist = 0; + + if(ioctl(fd, TUNSETPERSIST, (void *)persist) == -1) { + perror("TUNSETPERSIST"); + close(fd); + return -1; + } + + if(delete_if) { + close(fd); + return 0; + } + + // set interface up + if((sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket"); + close(fd); + return -1; + } + + // get current flags + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1); + if(ioctl(sd, SIOCGIFFLAGS, &ifr) == -1) { + perror("SIOCGIFFLAGS"); + close(sd); + close(fd); + return -1; + } + + // set up + memset(&ifw, 0, sizeof(ifw)); + strncpy(ifw.ifr_name, if_name, IFNAMSIZ - 1); + ifw.ifr_flags = ifr.ifr_flags | IFF_UP | IFF_RUNNING; + if(ioctl(sd, SIOCSIFFLAGS, &ifw) == -1) { + perror("SIOCSIFFLAGS"); + close(sd); + close(fd); + return -1; + } + + close(sd); + close(fd); + + return 0; +} diff --git a/gssm/src/python/file_gssm.py b/gssm/src/python/file_gssm.py new file mode 100755 index 0000000..47013f3 --- /dev/null +++ b/gssm/src/python/file_gssm.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# $Id: file_gssm.py,v 1.3 2007-07-07 16:31:44 jl Exp $ + +from gnuradio import gr, usrp, db_dbs_rx, blks +from gnuradio.blksimpl import gmsk +import gssm +import sys + +#sps = 1000e3 + +usrp_rate = 64e6 +decim_rate = 112 +sps = usrp_rate / decim_rate + +gsm_rate = 1625000.0 / 6.0 + +#xcf = 150e3 +#xtw = 50e3 +#xm = -31127.933289 + +file_name = "signal.data" + + +class gssm_graph(gr.flow_graph): + def __init__(self, fname): + gr.flow_graph.__init__(self) + + src = gr.file_source(gr.sizeof_gr_complex, fname) + gs = gssm.sink() + self.connect(src, gs) + +def main(): + fname = file_name + if len(sys.argv) == 2: + fname = sys.argv[1] + try: + gg = gssm_graph(fname) + gg.run() + + except KeyboardInterrupt: + pass + +if __name__ == '__main__': + main() diff --git a/gssm/src/python/file_stats.py b/gssm/src/python/file_stats.py new file mode 100755 index 0000000..cf8a109 --- /dev/null +++ b/gssm/src/python/file_stats.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +# $Id: file_stats.py,v 1.1 2007-07-07 16:26:33 jl Exp $ + +from gnuradio import gr, usrp, db_dbs_rx, blks +from gnuradio.blksimpl import gmsk +import gssm +import sys + +#sps = 1000e3 + +usrp_rate = 64e6 +decim_rate = 112 +sps = usrp_rate / decim_rate + +gsm_rate = 1625000.0 / 6.0 + +#xcf = 150e3 +#xtw = 50e3 +#xm = -31127.933289 + +file_name = "signal.data" + + +class gssm_graph(gr.flow_graph): + def __init__(self, fname): + gr.flow_graph.__init__(self) + + src = gr.file_source(gr.sizeof_gr_complex, fname) + self.gs = gs = gssm.sink(sps) + self.connect(src, gs) + +def main(): + fname = file_name + if len(sys.argv) == 2: + fname = sys.argv[1] + try: + gg = gssm_graph(fname) + gg.run() + gg.gs.stats() + + except KeyboardInterrupt: + pass + +if __name__ == '__main__': + main() diff --git a/gssm/src/python/gssm_stats.py b/gssm/src/python/gssm_stats.py new file mode 100755 index 0000000..43677d9 --- /dev/null +++ b/gssm/src/python/gssm_stats.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python + +# $Id: gssm_stats.py,v 1.2 2007-07-07 16:31:44 jl Exp $ + +from gnuradio import gr, usrp, db_dbs_rx, blks +from gnuradio.blksimpl import gmsk +import usrp_dbid +import gssm +import sys +import time +import thread + +# constant +gsm_rate = 1625000.0 / 6.0 + +# script constant +decim = 112 +gain = 32 + +# bts channel +c0 = 874e6 + +# experimental constant +default_usrp_offset = 4e3 + +# filter constants +xcf = 150e3 +xtw = 50e3 + +def display_stats(gs): + while 1: + print "%d:\t%d:%d" % \ + (gs.d_found_fc_count, gs.d_valid_s, gs.d_invalid_s) + time.sleep(1) + + +class gssm_flow_graph(gr.flow_graph): + def __init__(self, usrp_offset): + gr.flow_graph.__init__(self) + + print "decim = %d, gain = %d, offset = %.2f" % \ + (decim, gain, usrp_offset) + print "filter center %.2f, filter width %.2f" % \ + (xcf, xtw) + + u = usrp.source_c(decim_rate = decim) + s = usrp.pick_subdev(u, (usrp_dbid.DBS_RX,)) + u.set_mux(usrp.determine_rx_mux_value(u, s)) + subdev = usrp.selected_subdev(u, s) + + if subdev.dbid() != usrp_dbid.DBS_RX: + raise Exception('dbs daughterboard not detected!') + + subdev.set_gain(gain) + + sps = u.adc_freq() / u.decim_rate() + if sps < 2 * gsm_rate: + raise Exception('sample rate too low') + + u.tune(0, subdev, c0 + usrp_offset) + + xt = gr.firdes.low_pass(1.0, sps, xcf, xtw, + gr.firdes.WIN_HAMMING) + xf = gr.fir_filter_ccf(1, xt) + + self.gs = gs = gssm.sink() + + self.connect(u, xf, gs) + +def main(): + if len(sys.argv) == 2: + uo = float(sys.argv[1]) + else: + uo = default_usrp_offset + g = gssm_flow_graph(uo) + # thread.start_new_thread(display_stats, (g.gs,)) + # g.run() + g.start() + time.sleep(10.0) + g.stop() + g.gs.stats() + +if __name__ == '__main__': + main() + diff --git a/gssm/src/python/gssm_usrp.py b/gssm/src/python/gssm_usrp.py new file mode 100755 index 0000000..6fe84c5 --- /dev/null +++ b/gssm/src/python/gssm_usrp.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# $Id: gssm_usrp.py,v 1.2 2007-07-07 16:31:44 jl Exp $ + +from gnuradio import gr, usrp, db_dbs_rx, blks +from gnuradio.blksimpl import gmsk +from usrpm import usrp_dbid +import gssm +import sys + +# constant +gsm_rate = 1625000.0 / 6.0 + +# script constant +decim = 112 +gain = 70 + +# bts channel +c0 = 875.4e6 + +# experimental constant +default_usrp_offset = 12e3 + +class gssm_flow_graph(gr.flow_graph): + def __init__(self, usrp_offset): + gr.flow_graph.__init__(self) + + u = usrp.source_c(decim_rate = decim) + s = usrp.pick_subdev(u, (usrp_dbid.DBS_RX,)) + u.set_mux(usrp.determine_rx_mux_value(u, s)) + subdev = usrp.selected_subdev(u, s) + + if subdev.dbid() != usrp_dbid.DBS_RX: + raise Exception('dbs daughterboard not detected!') + + subdev.set_gain(gain) + + sps = u.adc_freq() / u.decim_rate() + if sps < 2 * gsm_rate: + raise Exception('sample rate too low') + + u.tune(0, subdev, c0 + usrp_offset) + + xcf = 150e3 + xtw = 50e3 + xt = gr.firdes.low_pass(1.0, sps, xcf, xtw, + gr.firdes.WIN_HAMMING) + xf = gr.fir_filter_ccf(1, xt) + + g = gssm.sink() + + self.connect(u, xf, g) + +def main(): + if len(sys.argv) == 2: + uo = float(sys.argv[1]) + else: + uo = default_usrp_offset + g = gssm_flow_graph(uo) + g.run() + +if __name__ == '__main__': + main() -- cgit v1.2.3