layer23: first version of a 'scan all BCCHs' application
bcch_scan first iterates over all GSM900/EGSM900/GSM1800 channels and performs a power measurement. Based on this, it tries to look for BCCH data on those ARFCNs. Currently, they are simply written to the pcap file and not analyzed/processed in layer23 yet.
This commit is contained in:
parent
13a0a05887
commit
58cede7c8a
|
@ -4,7 +4,7 @@ AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
|
|||
|
||||
noinst_LIBRARIES = liblayer23.a
|
||||
liblayer23_a_SOURCES = l1ctl.c gsmtap_util.c lapdm.c rslms.c \
|
||||
layer3.c logging.c
|
||||
layer3.c logging.c bcch_scan.c
|
||||
|
||||
bin_PROGRAMS = bcch_scan layer23 echo_test
|
||||
|
||||
|
|
|
@ -44,8 +44,7 @@ static int signal_cb(unsigned int subsys, unsigned int signal,
|
|||
switch (signal) {
|
||||
case S_L1CTL_RESET:
|
||||
ms = signal_data;
|
||||
return l1ctl_tx_pm_req_range(ms, 0, 124);
|
||||
break;
|
||||
return fps_start(ms);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -53,5 +52,6 @@ static int signal_cb(unsigned int subsys, unsigned int signal,
|
|||
int l23_app_init(struct osmocom_ms *ms)
|
||||
{
|
||||
/* don't do layer3_init() as we don't want an actualy L3 */
|
||||
fps_init(ms);
|
||||
return register_signal_handler(SS_L1CTL, &signal_cb, NULL);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,297 @@
|
|||
/* BCCH Scanning code for OsmocomBB */
|
||||
|
||||
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <l1a_l23_interface.h>
|
||||
|
||||
#include <osmocore/logging.h>
|
||||
#include <osmocore/talloc.h>
|
||||
#include <osmocore/signal.h>
|
||||
#include <osmocore/timer.h>
|
||||
#include <osmocore/msgb.h>
|
||||
#include <osmocore/tlv.h>
|
||||
#include <osmocore/gsm_utils.h>
|
||||
#include <osmocore/protocol/gsm_04_08.h>
|
||||
#include <osmocore/protocol/gsm_08_58.h>
|
||||
#include <osmocore/rsl.h>
|
||||
|
||||
#include <osmocom/l1ctl.h>
|
||||
#include <osmocom/osmocom_data.h>
|
||||
#include <osmocom/lapdm.h>
|
||||
#include <osmocom/logging.h>
|
||||
#include <osmocom/gsmtap_util.h>
|
||||
|
||||
/* somewhere in 05.08 */
|
||||
#define MAX_CELLS_IN_BA 32
|
||||
|
||||
/* Information about a single cell / BCCH */
|
||||
struct cell_info {
|
||||
struct llist_head list;
|
||||
|
||||
uint16_t band_arfcn;
|
||||
uint8_t bsic;
|
||||
uint8_t rxlev;
|
||||
|
||||
struct {
|
||||
uint16_t mcc; /* Mobile Country Code */
|
||||
uint16_t mnc; /* Mobile Network Code */
|
||||
uint16_t lac; /* Location Area Code */
|
||||
uint16_t rac; /* Routing Area Code */
|
||||
uint16_t cid; /* Cell ID */
|
||||
} id;
|
||||
uint16_t ba_arfcn[MAX_CELLS_IN_BA];
|
||||
uint8_t ba_arfcn_num;
|
||||
|
||||
struct {
|
||||
int32_t fn_delta; /* delta to current L1 fn */
|
||||
int16_t qbit_delta;
|
||||
int16_t afc_delta;
|
||||
} l1_sync;
|
||||
};
|
||||
|
||||
#define AFS_F_PM_DONE 0x01
|
||||
#define AFS_F_TESTED 0x02
|
||||
#define AFS_F_BCCH 0x04
|
||||
struct arfcn_state {
|
||||
uint8_t rxlev;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
enum bscan_state {
|
||||
BSCAN_S_NONE,
|
||||
BSCAN_S_WAIT_DATA,
|
||||
BSCAN_S_DONE,
|
||||
};
|
||||
|
||||
enum fps_state {
|
||||
FPS_S_NONE,
|
||||
FPS_S_PM_GSM900,
|
||||
FPS_S_PM_EGSM900,
|
||||
FPS_S_PM_GSM1800,
|
||||
FPS_S_BINFO,
|
||||
};
|
||||
|
||||
struct full_power_scan {
|
||||
/* Full Power Scan */
|
||||
enum fps_state fps_state;
|
||||
struct arfcn_state arfcn_state[1024];
|
||||
|
||||
struct osmocom_ms *ms;
|
||||
|
||||
/* BCCH info part */
|
||||
enum bscan_state state;
|
||||
struct llist_head cell_list;
|
||||
struct cell_info *cur_cell;
|
||||
uint16_t cur_arfcn;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
static struct full_power_scan fps;
|
||||
|
||||
static int get_next_arfcn(struct full_power_scan *fps)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t best_rxlev = 0;
|
||||
int best_arfcn = -1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fps->arfcn_state); i++) {
|
||||
struct arfcn_state *af = &fps->arfcn_state[i];
|
||||
/* skip ARFCN's where we don't have a PM */
|
||||
if (!(af->flags & AFS_F_PM_DONE))
|
||||
continue;
|
||||
/* skip ARFCN's that we already tested */
|
||||
if (af->flags & AFS_F_TESTED)
|
||||
continue;
|
||||
/* if current arfcn_state is better than best so far,
|
||||
* select it */
|
||||
if (af->rxlev > best_rxlev) {
|
||||
best_rxlev = af->rxlev;
|
||||
best_arfcn = i;
|
||||
}
|
||||
}
|
||||
printf("arfcn=%u rxlev=%u\n", best_arfcn, best_rxlev);
|
||||
return best_arfcn;
|
||||
}
|
||||
|
||||
static struct cell_info *cell_info_alloc(void)
|
||||
{
|
||||
struct cell_info *ci = talloc_zero(NULL, struct cell_info);
|
||||
return ci;
|
||||
}
|
||||
|
||||
static void cell_info_free(struct cell_info *ci)
|
||||
{
|
||||
talloc_free(ci);
|
||||
}
|
||||
|
||||
/* start to scan for one ARFCN */
|
||||
static int _cinfo_start_arfcn(unsigned int band_arfcn)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* ask L1 to try to tune to new ARFCN */
|
||||
/* FIXME: decode band */
|
||||
fps.ms->arfcn = band_arfcn;
|
||||
rc = l1ctl_tx_ccch_req(fps.ms);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* allocate new cell info structure */
|
||||
fps.cur_cell = cell_info_alloc();
|
||||
fps.cur_arfcn = fps.ms->arfcn;
|
||||
fps.cur_cell->band_arfcn = fps.ms->arfcn;
|
||||
/* FIXME: start timer in case we never get a sync */
|
||||
fps.state = BSCAN_S_WAIT_DATA;
|
||||
bsc_schedule_timer(&fps.timer, 2, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cinfo_timer_cb(void *data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (fps.state) {
|
||||
case BSCAN_S_WAIT_DATA:
|
||||
/* we've been waiting for BCCH info */
|
||||
fps.arfcn_state[fps.cur_arfcn].flags |= AFS_F_TESTED;
|
||||
/* if there is a BCCH, we need to add the collected BCCH
|
||||
* information to our list */
|
||||
if (fps.arfcn_state[fps.cur_arfcn].flags & AFS_F_BCCH)
|
||||
llist_add(&fps.cur_cell->list, &fps.cell_list);
|
||||
else
|
||||
cell_info_free(fps.cur_cell);
|
||||
rc = get_next_arfcn(&fps);
|
||||
if (rc < 0) {
|
||||
fps.state = BSCAN_S_DONE;
|
||||
return;
|
||||
}
|
||||
/* start syncing to the next ARFCN */
|
||||
_cinfo_start_arfcn(rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update cell_info for current cell with received BCCH info */
|
||||
static int rx_bcch_info(const uint8_t *data)
|
||||
{
|
||||
struct cell_info *ci = fps.cur_cell;
|
||||
struct gsm48_system_information_type_header *si_hdr;
|
||||
si_hdr = (struct gsm48_system_information_type_header *) data;;
|
||||
|
||||
/* we definitely have a BCCH on this channel */
|
||||
fps.arfcn_state[ci->band_arfcn].flags |= AFS_F_BCCH;
|
||||
|
||||
switch (si_hdr->system_information) {
|
||||
case GSM48_MT_RR_SYSINFO_1:
|
||||
/* FIXME: CA, RACH control */
|
||||
break;
|
||||
case GSM48_MT_RR_SYSINFO_2:
|
||||
/* FIXME: BA, NCC, RACH control */
|
||||
break;
|
||||
case GSM48_MT_RR_SYSINFO_3:
|
||||
/* FIXME: cell_id, LAI */
|
||||
break;
|
||||
case GSM48_MT_RR_SYSINFO_4:
|
||||
/* FIXME: LAI */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update L1/SCH information (AFC/QBIT/FN offset, BSIC) */
|
||||
static int rx_sch_info()
|
||||
{
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
static int bscan_sig_cb(unsigned int subsys, unsigned int signal,
|
||||
void *handler_data, void *signal_data)
|
||||
{
|
||||
struct osmocom_ms *ms;
|
||||
struct osmobb_meas_res *mr;
|
||||
uint16_t arfcn;
|
||||
int rc;
|
||||
|
||||
if (subsys != SS_L1CTL)
|
||||
return 0;
|
||||
|
||||
switch (signal) {
|
||||
case S_L1CTL_PM_RES:
|
||||
mr = signal_data;
|
||||
/* check if PM result is for same MS */
|
||||
if (fps.ms != mr->ms)
|
||||
return 0;
|
||||
arfcn = mr->band_arfcn & 0x3ff;
|
||||
/* update RxLev and notice that PM was done */
|
||||
fps.arfcn_state[arfcn].rxlev = mr->rx_lev;
|
||||
fps.arfcn_state[arfcn].flags |= AFS_F_PM_DONE;
|
||||
break;
|
||||
case S_L1CTL_PM_DONE:
|
||||
ms = signal_data;
|
||||
switch (fps.fps_state) {
|
||||
case FPS_S_PM_GSM900:
|
||||
fps.fps_state = FPS_S_PM_EGSM900;
|
||||
return l1ctl_tx_pm_req_range(ms, 955, 1023);
|
||||
case FPS_S_PM_EGSM900:
|
||||
fps.fps_state = FPS_S_PM_GSM1800;
|
||||
return l1ctl_tx_pm_req_range(ms, 512, 885);
|
||||
case FPS_S_PM_GSM1800:
|
||||
/* power measurement has finished, we can start
|
||||
* to actually iterate over the ARFCN's and try
|
||||
* to sync to BCCHs */
|
||||
fps.fps_state = FPS_S_BINFO;
|
||||
rc = get_next_arfcn(&fps);
|
||||
if (rc < 0) {
|
||||
fps.state = BSCAN_S_DONE;
|
||||
return;
|
||||
}
|
||||
_cinfo_start_arfcn(rc);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* start the full power scan */
|
||||
int fps_start(struct osmocom_ms *ms)
|
||||
{
|
||||
memset(&fps, 0, sizeof(fps));
|
||||
fps.ms = ms;
|
||||
|
||||
fps.timer.cb = cinfo_timer_cb;
|
||||
fps.timer.data = &fps;
|
||||
|
||||
/* Start by scanning the good old GSM900 band */
|
||||
fps.fps_state = FPS_S_PM_GSM900;
|
||||
return l1ctl_tx_pm_req_range(ms, 0, 124);
|
||||
}
|
||||
|
||||
int fps_init(void)
|
||||
{
|
||||
return register_signal_handler(SS_L1CTL, &bscan_sig_cb, NULL);
|
||||
}
|
Loading…
Reference in New Issue