blob: f64f44ec162b9ba4f30b8b54527119aa1898609e [file] [log] [blame]
Harald Welte549faad2010-03-05 19:36:20 +01001/* ip.access nanoBTS network listen mode */
2
3/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <unistd.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <errno.h>
28#include <stdint.h>
29
30#include <osmocore/talloc.h>
31#include <osmocore/timer.h>
32
33#include <openbsc/gsm_data.h>
34#include <openbsc/abis_nm.h>
35#include <openbsc/signal.h>
36#include <openbsc/debug.h>
37
38enum ipac_test_state {
39 IPAC_TEST_S_IDLE,
40 IPAC_TEST_S_RQD,
41 IPAC_TEST_S_EXEC,
42 IPAC_TEST_S_PARTIAL,
43};
44
45int ipac_nwl_test_start(struct gsm_bts_trx *trx, uint8_t testnr)
46{
47 const uint8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
48
49 if (trx->ipaccess.test_state != IPAC_TEST_S_IDLE) {
50 fprintf(stderr, "Cannot start test in state %u\n", trx->ipaccess.test_state);
51 return -EINVAL;
52 }
53
54 abis_nm_perform_test(trx->bts, 2, 0, trx->nr, 0xff, testnr, 1,
55 phys_config, sizeof(phys_config));
56
57 /* FIXME: start safety timer until when test is supposed to complete */
58
59 return 0;
60}
61
62struct ipacc_ferr_elem {
63 int16_t freq_err;
64 uint8_t freq_qual;
65 uint8_t arfcn;
66} __attribute__((packed));
67
68struct ipacc_cusage_elem {
69 uint16_t arfcn:10,
70 rxlev:6;
71} __attribute__ ((packed));
72
73static int test_rep(void *_msg)
74{
75 struct msgb *msg = _msg;
76 struct abis_om_fom_hdr *foh = msgb_l3(msg);
77 uint16_t test_rep_len, ferr_list_len;
78 struct ipacc_ferr_elem *ife;
79 struct ipac_bcch_info binfo;
80 int i, rc;
81
82 DEBUGP(DNM, "TEST REPORT: ");
83
84 if (foh->data[0] != NM_ATT_TEST_NO ||
85 foh->data[2] != NM_ATT_TEST_REPORT)
86 return -EINVAL;
87
88 DEBUGPC(DNM, "test_no=0x%02x ", foh->data[1]);
89 /* data[2] == NM_ATT_TEST_REPORT */
90 /* data[3..4]: test_rep_len */
91 test_rep_len = ntohs(*(uint16_t *) &foh->data[3]);
92 /* data[5]: ip.access test result */
93 DEBUGPC(DNM, "tst_res=%s\n", ipacc_testres_name(foh->data[5]));
94
95 /* data[6]: ip.access nested IE. 3 == freq_err_list */
96 switch (foh->data[6]) {
97 case NM_IPAC_EIE_FREQ_ERR_LIST:
98 /* data[7..8]: length of ferr_list */
99 ferr_list_len = ntohs(*(uint16_t *) &foh->data[7]);
100
101 /* data[9...]: frequency error list elements */
102 for (i = 0; i < ferr_list_len; i+= sizeof(*ife)) {
103 ife = (struct ipacc_ferr_elem *) (foh->data + 9 + i);
104 DEBUGP(DNM, "==> ARFCN %4u, Frequency Error %6hd\n",
105 ife->arfcn, ntohs(ife->freq_err));
106 }
107 break;
108 case NM_IPAC_EIE_CHAN_USE_LIST:
109 /* data[7..8]: length of ferr_list */
110 ferr_list_len = ntohs(*(uint16_t *) &foh->data[7]);
111
112 /* data[9...]: channel usage list elements */
113 for (i = 0; i < ferr_list_len; i+= 2) {
114 uint16_t *cu_ptr = (uint16_t *)(foh->data + 9 + i);
115 uint16_t cu = ntohs(*cu_ptr);
116 DEBUGP(DNM, "==> ARFCN %4u, RxLev %2u\n",
117 cu & 0x3ff, cu >> 10);
118 }
119 break;
120 case NM_IPAC_EIE_BCCH_INFO_TYPE:
121 break;
122 case NM_IPAC_EIE_BCCH_INFO:
123 rc = ipac_parse_bcch_info(&binfo, foh->data+6);
124 if (rc < 0) {
125 DEBUGP(DNM, "BCCH Info parsing failed\n");
126 break;
127 }
128 DEBUGP(DNM, "==> ARFCN %u, RxLev %2u, RxQual %2u: %3d-%d, LAC %d CI %d\n",
129 binfo.arfcn, binfo.rx_lev, binfo.rx_qual,
130 binfo.cgi.mcc, binfo.cgi.mnc,
131 binfo.cgi.lac, binfo.cgi.ci);
132 break;
133 default:
134 break;
135 }
136
137 switch (foh->data[5]) {
138 case NM_IPACC_TESTRES_SUCCESS:
139 case NM_IPACC_TESTRES_STOPPED:
140 case NM_IPACC_TESTRES_TIMEOUT:
141 case NM_IPACC_TESTRES_NO_CHANS:
142 msg->trx->ipaccess.test_state = IPAC_TEST_S_IDLE;
143 /* Send signal to notify higher layers of test completion */
144 dispatch_signal(SS_IPAC_NWL, S_IPAC_NWL_COMPLETE, msg->trx);
145 break;
146 case NM_IPACC_TESTRES_PARTIAL:
147 msg->trx->ipaccess.test_state = IPAC_TEST_S_PARTIAL;
148 break;
149 }
150
151 return 0;
152}
153
154static int nwl_sig_cb(unsigned int subsys, unsigned int signal,
155 void *handler_data, void *signal_data)
156{
157 struct ipacc_ack_signal_data *ipacc_data;
158
159 switch (signal) {
160 case S_NM_TEST_REP:
161 return test_rep(signal_data);
162 default:
163 break;
164 }
165
166 return 0;
167}
168
169void ipac_nwl_init(void)
170{
171 register_signal_handler(SS_NM, nwl_sig_cb, NULL);
172}