blob: a7fb9c43bfa7b23cd9073b5b6c83ae3e4589743d [file] [log] [blame]
Harald Welte25de9912009-04-30 15:53:07 +00001/* ip.access nanoBTS configuration tool */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#include <unistd.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <getopt.h>
27#include <sys/types.h>
28
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32
33
34#include <openbsc/select.h>
35#include <openbsc/timer.h>
36#include <openbsc/ipaccess.h>
37#include <openbsc/gsm_data.h>
38#include <openbsc/e1_input.h>
39#include <openbsc/abis_nm.h>
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +020040#include <openbsc/signal.h>
Harald Weltec7310382009-08-08 00:02:36 +020041#include <openbsc/debug.h>
Harald Welte25de9912009-04-30 15:53:07 +000042
43static struct gsm_network *gsmnet;
44
Harald Weltec7310382009-08-08 00:02:36 +020045static int net_listen;
Harald Welte25de9912009-04-30 15:53:07 +000046static int restart;
47static char *prim_oml_ip;
48static char *unit_id;
Harald Welte684b1a82009-07-03 11:26:45 +020049static u_int16_t nv_flags;
50static u_int16_t nv_mask;
Harald Welte25de9912009-04-30 15:53:07 +000051
52/*
53static u_int8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00, 0x00 };
54static u_int8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
55*/
56
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +020057/*
58 * Callback function for NACK on the OML NM
59 *
60 * Currently we send the config requests but don't check the
61 * result. The nanoBTS will send us a NACK when we did something the
62 * BTS didn't like.
63 */
64static int ipacc_msg_nack(int mt)
65{
66 fprintf(stderr, "Failure to set attribute. This seems fatal\n");
67 exit(-1);
68 return 0;
69}
70
Harald Weltec7310382009-08-08 00:02:36 +020071struct ipacc_ferr_elem {
72 int16_t freq_err;
73 u_int8_t freq_qual;
74 u_int8_t arfcn;
75} __attribute__((packed));
76
77static int test_rep(void *_msg)
78{
79 struct msgb *msg = _msg;
80 struct abis_om_fom_hdr *foh = msgb_l3(msg);
81 u_int16_t test_rep_len, ferr_list_len;
82 struct ipacc_ferr_elem *ife;
83 int i;
84
85 DEBUGP(DNM, "TEST REPORT: ");
86
87 if (foh->data[0] != NM_ATT_TEST_NO ||
88 foh->data[2] != NM_ATT_TEST_REPORT)
89 return -EINVAL;
90
91 DEBUGPC(DNM, "test_no=0x%02x ", foh->data[1]);
92 /* data[2] == NM_ATT_TEST_REPORT */
93 /* data[3..4]: test_rep_len */
94 test_rep_len = ntohs(*(u_int16_t *) &foh->data[3]);
95 /* data[5]: ip.access test result */
96 DEBUGPC(DNM, "test_res=%u\n", foh->data[5]);
97
98 /* data[6]: ip.access nested IE. 3 == freq_err_list */
99 switch (foh->data[6]) {
100 case 3:
101 /* data[7..8]: length of ferr_list */
102 ferr_list_len = ntohs(*(u_int16_t *) &foh->data[7]);
103
104 /* data[9...]: frequency error list elements */
105 for (i = 0; i < ferr_list_len; i+= sizeof(*ife)) {
106 ife = (struct ipacc_ferr_elem *) (foh->data + 9 + i);
107 DEBUGP(DNM, "==> ARFCN %4u, Frequency Error %6hd\n",
108 ife->arfcn, ntohs(ife->freq_err));
109 }
110 break;
111 default:
112 break;
113 }
114
115 return 0;
116}
117
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +0200118static int nm_sig_cb(unsigned int subsys, unsigned int signal,
119 void *handler_data, void *signal_data)
120{
121 switch (signal) {
122 case S_NM_IPACC_NACK:
123 return ipacc_msg_nack((int)signal_data);
Harald Weltec7310382009-08-08 00:02:36 +0200124 case S_NM_TEST_REP:
125 return test_rep(signal_data);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +0200126 default:
127 break;
128 }
129
130 return 0;
131}
132
Harald Welte25de9912009-04-30 15:53:07 +0000133static void bootstrap_om(struct gsm_bts *bts)
134{
135 int len;
136 static u_int8_t buf[1024];
Harald Welte684b1a82009-07-03 11:26:45 +0200137 u_int8_t *cur = buf;
Harald Welte25de9912009-04-30 15:53:07 +0000138
139 printf("OML link established\n");
140
141 if (unit_id) {
142 len = strlen(unit_id);
143 if (len > sizeof(buf)-10)
144 return;
145 buf[0] = NM_ATT_IPACC_UNIT_ID;
146 buf[1] = (len+1) >> 8;
147 buf[2] = (len+1) & 0xff;
148 memcpy(buf+3, unit_id, len);
149 buf[3+len] = 0;
150 printf("setting Unit ID to '%s'\n", unit_id);
151 abis_nm_ipaccess_set_nvattr(bts, buf, 3+len+1);
152 }
153 if (prim_oml_ip) {
154 struct in_addr ia;
Harald Welte25de9912009-04-30 15:53:07 +0000155
156 if (!inet_aton(prim_oml_ip, &ia)) {
157 fprintf(stderr, "invalid IP address: %s\n",
158 prim_oml_ip);
159 return;
160 }
161
162 /* 0x88 + IP + port */
163 len = 1 + sizeof(ia) + 2;
164
Harald Welte0efe9b72009-07-12 09:33:54 +0200165 *cur++ = NM_ATT_IPACC_PRIM_OML_CFG_LIST;
Harald Welte25de9912009-04-30 15:53:07 +0000166 *cur++ = (len) >> 8;
167 *cur++ = (len) & 0xff;
168 *cur++ = 0x88;
169 memcpy(cur, &ia, sizeof(ia));
170 cur += sizeof(ia);
171 *cur++ = 0;
172 *cur++ = 0;
Harald Welte4802b882009-04-30 16:23:45 +0000173 printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia));
Harald Welte25de9912009-04-30 15:53:07 +0000174 abis_nm_ipaccess_set_nvattr(bts, buf, 3+len);
175 }
Harald Welte684b1a82009-07-03 11:26:45 +0200176 if (nv_mask) {
177 len = 4;
178
179 *cur++ = NM_ATT_IPACC_NV_FLAGS;
180 *cur++ = (len) >> 8;
181 *cur++ = (len) & 0xff;
182 *cur++ = nv_flags & 0xff;
183 *cur++ = nv_mask & 0xff;
184 *cur++ = nv_flags >> 8;
185 *cur++ = nv_mask >> 8;
186 printf("setting NV Flags/Mask to 0x%04x/0x%04x\n",
187 nv_flags, nv_mask);
188 abis_nm_ipaccess_set_nvattr(bts, buf, 3+len);
189 }
Harald Welte25de9912009-04-30 15:53:07 +0000190
191 if (restart) {
192 printf("restarting BTS\n");
193 abis_nm_ipaccess_restart(bts);
194 }
Harald Weltec7310382009-08-08 00:02:36 +0200195
196 if (net_listen) {
197 }
Harald Welte25de9912009-04-30 15:53:07 +0000198}
199
200void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
201{
202 switch (event) {
203 case EVT_E1_TEI_UP:
204 switch (type) {
205 case E1INP_SIGN_OML:
206 bootstrap_om(trx->bts);
207 break;
208 case E1INP_SIGN_RSL:
209 /* FIXME */
210 break;
211 default:
212 break;
213 }
214 break;
215 case EVT_E1_TEI_DN:
216 fprintf(stderr, "Lost some E1 TEI link\n");
217 /* FIXME: deal with TEI or L1 link loss */
218 break;
219 default:
220 break;
221 }
222}
223
224int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
225 struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
226{
Harald Weltec7310382009-08-08 00:02:36 +0200227 if (evt == EVT_STATECHG_OPER &&
228 obj_class == NM_OC_RADIO_CARRIER &&
229 new_state->availability == 3 &&
230 net_listen) {
231 struct gsm_bts_trx *trx = obj;
232 u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
233 abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff,
234 NM_IPACC_TESTNO_FREQ_SYNC, 1,
235 phys_config, sizeof(phys_config));
236 }
Harald Welte25de9912009-04-30 15:53:07 +0000237 return 0;
238}
239
Holger Hans Peter Freyther42b40072009-07-04 11:53:10 +0200240static void print_usage(void)
241{
242 printf("Usage: ipaccess-config\n");
243}
244
245static void print_help(void)
246{
247 printf(" -u --unit-id UNIT_ID\n");
248 printf(" -o --oml-ip ip\n");
249 printf(" -r --restart\n");
Harald Weltec7310382009-08-08 00:02:36 +0200250 printf(" -n flags/mask\tSet NVRAM attributes.\n");
251 printf(" -l --listen\tPerform Frequency Error test\n");
Holger Hans Peter Freyther42b40072009-07-04 11:53:10 +0200252 printf(" -h --help this text\n");
253}
254
Harald Welte25de9912009-04-30 15:53:07 +0000255int main(int argc, char **argv)
256{
257 struct gsm_bts *bts;
258 struct sockaddr_in sin;
259 int rc, option_index = 0;
260
261 printf("ipaccess-config (C) 2009 by Harald Welte\n");
262 printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
263
264 while (1) {
265 int c;
Harald Welte684b1a82009-07-03 11:26:45 +0200266 unsigned long ul;
267 char *slash;
Harald Welte25de9912009-04-30 15:53:07 +0000268 static struct option long_options[] = {
269 { "unit-id", 1, 0, 'u' },
270 { "oml-ip", 1, 0, 'o' },
271 { "restart", 0, 0, 'r' },
Holger Hans Peter Freyther42b40072009-07-04 11:53:10 +0200272 { "help", 0, 0, 'h' },
Harald Weltec7310382009-08-08 00:02:36 +0200273 { "listen", 0, 0, 'l' },
Harald Welte25de9912009-04-30 15:53:07 +0000274 };
275
Harald Weltec7310382009-08-08 00:02:36 +0200276 c = getopt_long(argc, argv, "u:o:rn:lh", long_options,
Harald Welte25de9912009-04-30 15:53:07 +0000277 &option_index);
278
279 if (c == -1)
280 break;
281
282 switch (c) {
283 case 'u':
284 unit_id = optarg;
285 break;
286 case 'o':
287 prim_oml_ip = optarg;
288 break;
289 case 'r':
290 restart = 1;
291 break;
Harald Welte684b1a82009-07-03 11:26:45 +0200292 case 'n':
293 slash = strchr(optarg, '/');
294 if (!slash)
295 exit(2);
296 ul = strtoul(optarg, NULL, 16);
297 nv_flags = ul & 0xffff;
298 ul = strtoul(slash+1, NULL, 16);
299 nv_mask = ul & 0xffff;
300 break;
Harald Weltec7310382009-08-08 00:02:36 +0200301 case 'l':
302 net_listen = 1;
303 break;
Holger Hans Peter Freyther42b40072009-07-04 11:53:10 +0200304 case 'h':
305 print_usage();
306 print_help();
307 exit(0);
Harald Welte25de9912009-04-30 15:53:07 +0000308 }
309 };
310
311 if (optind >= argc) {
Holger Hans Peter Freyther42b40072009-07-04 11:53:10 +0200312 fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n");
Harald Welte25de9912009-04-30 15:53:07 +0000313 exit(2);
314 }
315
Harald Weltee441d9c2009-06-21 16:17:15 +0200316 gsmnet = gsm_network_init(1, 1, NULL);
Harald Welte25de9912009-04-30 15:53:07 +0000317 if (!gsmnet)
318 exit(1);
319
Harald Weltee441d9c2009-06-21 16:17:15 +0200320 bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_NANOBTS_900, HARDCODED_TSC,
321 HARDCODED_BSIC);
Harald Welte25de9912009-04-30 15:53:07 +0000322
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +0200323 register_signal_handler(SS_NM, nm_sig_cb, NULL);
Harald Welte25de9912009-04-30 15:53:07 +0000324 printf("Trying to connect to ip.access BTS ...\n");
325
326 memset(&sin, 0, sizeof(sin));
327 sin.sin_family = AF_INET;
328 inet_aton(argv[optind], &sin.sin_addr);
329 rc = ia_config_connect(bts, &sin);
330 if (rc < 0) {
331 perror("Error connecting to the BTS");
332 exit(1);
333 }
334
335 while (1) {
Harald Welte04d3c922009-05-23 06:07:04 +0000336 rc = bsc_select_main(0);
Harald Welte25de9912009-04-30 15:53:07 +0000337 if (rc < 0)
338 exit(3);
339 }
340
341 exit(0);
342}
343