blob: 7b3088986222f0119cbb7e9fb81bb85109052300 [file] [log] [blame]
Harald Welte61e42ad2009-01-18 19:10:46 +00001/* Siemens BS-11 microBTS configuration tool */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * This software is based on ideas (but not code) of BS11Config
7 * (C) 2009 by Dieter Spaar <spaar@mirider.augusta.de>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <unistd.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <errno.h>
29#include <string.h>
30#include <getopt.h>
31#include <fcntl.h>
Harald Weltef186c462009-01-29 08:45:19 +000032#include <termios.h>
Harald Welte14f09342009-01-29 19:28:38 +000033#include <signal.h>
Harald Welte61e42ad2009-01-18 19:10:46 +000034
35#include <sys/types.h>
36#include <sys/stat.h>
37
38#include <openbsc/gsm_data.h>
39#include <openbsc/abis_nm.h>
40#include <openbsc/msgb.h>
41#include <openbsc/tlv.h>
42#include <openbsc/debug.h>
Harald Welte14f09342009-01-29 19:28:38 +000043#include <openbsc/select.h>
Harald Welte61e42ad2009-01-18 19:10:46 +000044
Harald Welte3b8ba212009-01-29 12:27:58 +000045/* state of our bs11_config application */
46enum bs11cfg_state {
47 STATE_NONE,
48 STATE_LOGON_WAIT,
49 STATE_LOGON_ACK,
50 STATE_SWLOAD,
51};
52static enum bs11cfg_state bs11cfg_state = STATE_NONE;
53
Harald Welte61e42ad2009-01-18 19:10:46 +000054static const u_int8_t obj_li_attr[] = {
55 0xa0, 0x09, 0x00,
56 0xab, 0x00,
57 0xac, 0x00,
58};
59static const u_int8_t obj_bbsig0_attr[] = {
60 0x3d, 0x02, 0x00, 0x00,
61 0x3f, 0x01, 0x00,
62};
63static const u_int8_t obj_pa0_attr[] = {
64 NM_ATT_BS11_TXPWR, 0x01, BS11_TRX_POWER_30mW,
65};
66static const char *trx1_password = "1111111111";
67#define TEI_OML 25
68
Harald Welte3b8ba212009-01-29 12:27:58 +000069static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
70
Harald Welte14f09342009-01-29 19:28:38 +000071struct serial_handle {
72 struct bsc_fd fd;
73 struct llist_head tx_queue;
74
75 struct msgb *rx_msg;
76 unsigned int rxmsg_bytes_missing;
77};
78
79/* FIXME: this needs to go */
80static struct serial_handle _ser_handle, *ser_handle = &_ser_handle;
81
82static int handle_serial_msg(struct msgb *rx_msg);
83
Harald Welte61e42ad2009-01-18 19:10:46 +000084/* create all objects for an initial configuration */
85static int create_objects(struct gsm_bts *bts, int trx1)
86{
Harald Weltecfe6dce2009-01-19 16:06:43 +000087 //abis_nm_bs11_factory_logon(bts, 1);
Harald Welte61e42ad2009-01-18 19:10:46 +000088 abis_nm_bs11_create_object(bts, BS11_OBJ_LI, 0, sizeof(obj_li_attr),
89 obj_li_attr);
90 abis_nm_bs11_create_object(bts, BS11_OBJ_GPSU, 0, 0, NULL);
91 abis_nm_bs11_create_object(bts, BS11_OBJ_ALCO, 0, 0, NULL);
92 abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 0,
93 sizeof(obj_bbsig0_attr), obj_bbsig0_attr);
94 abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 0,
95 sizeof(obj_pa0_attr), obj_pa0_attr);
96 if (trx1) {
97 u_int8_t bbsig1_attr[sizeof(obj_bbsig0_attr)+12];
98 u_int8_t *cur = bbsig1_attr;
99
100 abis_nm_bs11_set_trx1_pw(bts, trx1_password);
101
102 cur = tlv_put(cur, NM_ATT_BS11_PASSWORD, 10,
103 (u_int8_t *)trx1_password);
104 memcpy(cur, obj_bbsig0_attr, sizeof(obj_bbsig0_attr));
105 abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 1,
106 sizeof(bbsig1_attr), bbsig1_attr);
107
108 abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 1,
109 sizeof(obj_pa0_attr), obj_pa0_attr);
110 }
111
112 abis_nm_bs11_create_envaBTSE(bts, 0);
113 abis_nm_bs11_create_envaBTSE(bts, 1);
114 abis_nm_bs11_create_envaBTSE(bts, 2);
115 abis_nm_bs11_create_envaBTSE(bts, 3);
116
117 abis_nm_bs11_conn_oml(bts, 0, 1, 0xff);
118 abis_nm_bs11_set_oml_tei(bts, TEI_OML);
119
120 abis_nm_bs11_set_trx_power(&bts->trx[0], BS11_TRX_POWER_30mW);
121
122 if (trx1)
123 abis_nm_bs11_set_trx_power(&bts->trx[1], BS11_TRX_POWER_30mW);
124
Harald Weltecfe6dce2009-01-19 16:06:43 +0000125 //abis_nm_bs11_factory_logon(bts, 0);
Harald Welte61e42ad2009-01-18 19:10:46 +0000126
127 return 0;
128}
129
130static char *serial_port = "/dev/ttyUSB0";
131static char *fname_safety = "BTSBMC76.SWI";
132static char *fname_software = "HS011106.SWL";
Harald Welte3b8ba212009-01-29 12:27:58 +0000133static int delay_ms = 100;
Harald Welte61e42ad2009-01-18 19:10:46 +0000134static int serial_fd = -1;
135static int have_trx1 = 0;
136static struct gsm_bts *g_bts;
137
138/* adaption layer from GSM 08.59 + 12.21 to RS232 */
139
140#define LAPD_HDR_LEN 10
141
142/* callback from abis_nm */
143int _abis_nm_sendmsg(struct msgb *msg)
144{
Harald Welte14f09342009-01-29 19:28:38 +0000145 struct serial_handle *sh = ser_handle;
Harald Welte61e42ad2009-01-18 19:10:46 +0000146 u_int8_t *lapd;
Harald Welte14f09342009-01-29 19:28:38 +0000147 unsigned int len;
Harald Welte61e42ad2009-01-18 19:10:46 +0000148
149 msg->l2h = msg->data;
150
151 /* prepend LAPD header */
152 lapd = msgb_push(msg, LAPD_HDR_LEN);
153
Harald Welte14f09342009-01-29 19:28:38 +0000154 len = msg->len - 2;
155
156 lapd[0] = (len >> 8) & 0xff;
157 lapd[1] = len & 0xff; /* length of bytes startign at lapd[2] */
Harald Welte61e42ad2009-01-18 19:10:46 +0000158 lapd[2] = 0x00;
159 lapd[3] = 0x07;
160 lapd[4] = 0x01;
161 lapd[5] = 0x3e;
162 lapd[6] = 0x00;
163 lapd[7] = 0x00;
164 lapd[8] = msg->len - 10; /* length of bytes starting at lapd[10] */
165 lapd[9] = lapd[8] ^ 0x38;
166
Harald Welte14f09342009-01-29 19:28:38 +0000167 msgb_enqueue(&sh->tx_queue, msg);
168 sh->fd.when |= BSC_FD_WRITE;
169
170 return 0;
171}
172
173static int handle_ser_write(struct bsc_fd *bfd)
174{
175 struct serial_handle *sh = bfd->data;
176 struct msgb *msg;
177 int written;
178
179 msg = msgb_dequeue(&sh->tx_queue);
180 if (!msg) {
181 bfd->when &= ~BSC_FD_WRITE;
182 return 0;
183 }
184
Harald Welte61e42ad2009-01-18 19:10:46 +0000185 fprintf(stdout, "TX: ");
186 hexdump(msg->data, msg->len);
187
188 /* send over serial line */
189 written = write(serial_fd, msg->data, msg->len);
190 if (written < msg->len) {
191 perror("short write:");
192 msgb_free(msg);
193 return -1;
194 }
195
196 msgb_free(msg);
Harald Welte3b8ba212009-01-29 12:27:58 +0000197 usleep(delay_ms*1000);
Harald Welte61e42ad2009-01-18 19:10:46 +0000198
199 return 0;
200}
201
202#define SERIAL_ALLOC_SIZE 300
203
Harald Welte14f09342009-01-29 19:28:38 +0000204static int handle_ser_read(struct bsc_fd *bfd)
Harald Welte61e42ad2009-01-18 19:10:46 +0000205{
Harald Welte14f09342009-01-29 19:28:38 +0000206 struct serial_handle *sh = bfd->data;
207 struct msgb *msg;
208 int rc = 0;
Harald Welte61e42ad2009-01-18 19:10:46 +0000209
Harald Welte14f09342009-01-29 19:28:38 +0000210 if (!sh->rx_msg) {
211 sh->rx_msg = msgb_alloc(SERIAL_ALLOC_SIZE);
212 sh->rx_msg->l2h = NULL;
213 }
214 msg = sh->rx_msg;
Harald Welte3b8ba212009-01-29 12:27:58 +0000215
Harald Welte61e42ad2009-01-18 19:10:46 +0000216 /* first read two byes to obtain length */
Harald Welte14f09342009-01-29 19:28:38 +0000217 if (msg->len < 2) {
218 rc = read(sh->fd.fd, msg->tail, 2 - msg->len);
Harald Welte61e42ad2009-01-18 19:10:46 +0000219 if (rc < 0) {
Harald Welte14f09342009-01-29 19:28:38 +0000220 perror("ERROR reading from serial port");
Harald Welte61e42ad2009-01-18 19:10:46 +0000221 msgb_free(msg);
Harald Welte14f09342009-01-29 19:28:38 +0000222 return rc;
Harald Welte61e42ad2009-01-18 19:10:46 +0000223 }
224 msgb_put(msg, rc);
Harald Welte61e42ad2009-01-18 19:10:46 +0000225
Harald Welte14f09342009-01-29 19:28:38 +0000226 if (msg->len >= 2) {
227 /* parse LAPD payload length */
228 if (msg->data[0] != 0)
229 fprintf(stderr, "Suspicious header byte 0: 0x%02x\n",
230 msg->data[0]);
Harald Welte61e42ad2009-01-18 19:10:46 +0000231
Harald Welte14f09342009-01-29 19:28:38 +0000232 sh->rxmsg_bytes_missing = msg->data[0] << 8;
233 sh->rxmsg_bytes_missing += msg->data[1];
234
235 if (sh->rxmsg_bytes_missing < LAPD_HDR_LEN -2)
236 fprintf(stderr, "Invalid length in hdr: %u\n",
237 sh->rxmsg_bytes_missing);
238 }
239 } else {
240 /* try to read as many of the missing bytes as are available */
241 rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing);
Harald Welte61e42ad2009-01-18 19:10:46 +0000242 if (rc < 0) {
Harald Welte14f09342009-01-29 19:28:38 +0000243 perror("ERROR reading from serial port");
Harald Welte61e42ad2009-01-18 19:10:46 +0000244 msgb_free(msg);
Harald Welte14f09342009-01-29 19:28:38 +0000245 return rc;
Harald Welte61e42ad2009-01-18 19:10:46 +0000246 }
247 msgb_put(msg, rc);
Harald Welte14f09342009-01-29 19:28:38 +0000248 sh->rxmsg_bytes_missing -= rc;
249
250 if (sh->rxmsg_bytes_missing == 0) {
251 /* we have one complete message now */
252 sh->rx_msg = NULL;
253
254 if (msg->len > LAPD_HDR_LEN)
255 msg->l2h = msg->data + LAPD_HDR_LEN;
256
257 fprintf(stdout, "RX: ");
258 hexdump(msg->data, msg->len);
259 rc = handle_serial_msg(msg);
260 }
Harald Welte61e42ad2009-01-18 19:10:46 +0000261 }
262
Harald Welte14f09342009-01-29 19:28:38 +0000263 return rc;
264}
Harald Welte61e42ad2009-01-18 19:10:46 +0000265
Harald Welte14f09342009-01-29 19:28:38 +0000266static int serial_fd_cb(struct bsc_fd *bfd, unsigned int what)
267{
268 int rc = 0;
Harald Welte61e42ad2009-01-18 19:10:46 +0000269
Harald Welte14f09342009-01-29 19:28:38 +0000270 if (what & BSC_FD_READ)
271 rc = handle_ser_read(bfd);
272
273 if (rc < 0)
274 return rc;
275
276 if (what & BSC_FD_WRITE)
277 rc = handle_ser_write(bfd);
278
279 return rc;
Harald Welte61e42ad2009-01-18 19:10:46 +0000280}
281
282static int file_is_readable(const char *fname)
283{
284 int rc;
285 struct stat st;
286
287 rc = stat(fname, &st);
288 if (rc < 0)
289 return 0;
290
291 if (S_ISREG(st.st_mode) && (st.st_mode & S_IRUSR))
292 return 1;
293
294 return 0;
295}
296
297
298static int handle_state_resp(u_int8_t state)
299{
Harald Welte3b8ba212009-01-29 12:27:58 +0000300 int rc = 0;
301
Harald Welte61e42ad2009-01-18 19:10:46 +0000302 printf("STATE: ");
Harald Welte3b8ba212009-01-29 12:27:58 +0000303
Harald Welte61e42ad2009-01-18 19:10:46 +0000304 switch (state) {
305 case BS11_STATE_WARM_UP:
306 printf("Warm Up...\n");
307 sleep(5);
308 break;
309 case BS11_STATE_LOAD_SMU_SAFETY:
310 printf("Load SMU Safety...\n");
311 sleep(5);
312 break;
313 case BS11_STATE_SOFTWARE_RQD:
314 printf("Software required...\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000315 bs11cfg_state = STATE_SWLOAD;
Harald Welte61e42ad2009-01-18 19:10:46 +0000316 /* send safety load */
317 if (file_is_readable(fname_safety))
Harald Welte3b8ba212009-01-29 12:27:58 +0000318 rc = abis_nm_software_load(g_bts, fname_safety, 8);
Harald Welte61e42ad2009-01-18 19:10:46 +0000319 else
Harald Welte071f34d2009-01-29 09:24:38 +0000320 fprintf(stderr, "No valid Safety Load file \"%s\"\n",
321 fname_safety);
Harald Welte61e42ad2009-01-18 19:10:46 +0000322 break;
323 case BS11_STATE_WAIT_MIN_CFG:
324 case BS11_STATE_WAIT_MIN_CFG_2:
325 printf("Wait minimal config...\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000326 bs11cfg_state = STATE_SWLOAD;
327 rc = create_objects(g_bts, have_trx1);
Harald Welte61e42ad2009-01-18 19:10:46 +0000328 break;
329 case BS11_STATE_MAINTENANCE:
330 printf("Maintenance...\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000331 bs11cfg_state = STATE_SWLOAD;
Harald Welte61e42ad2009-01-18 19:10:46 +0000332 /* send software (FIXME: over A-bis?) */
333 if (file_is_readable(fname_software))
Harald Welte3b8ba212009-01-29 12:27:58 +0000334 rc = abis_nm_software_load(g_bts, fname_software, 8);
Harald Welte61e42ad2009-01-18 19:10:46 +0000335 else
Harald Welte071f34d2009-01-29 09:24:38 +0000336 fprintf(stderr, "No valid Software file \"%s\"\n",
337 fname_software);
Harald Welte61e42ad2009-01-18 19:10:46 +0000338 break;
339 case BS11_STATE_NORMAL:
340 printf("Normal...\n");
341 return 1;
342 default:
343 printf("Unknown state 0x%02u\n", state);
344 sleep(5);
345 break;
346 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000347 return rc;
Harald Welte61e42ad2009-01-18 19:10:46 +0000348}
349
Harald Welte14f09342009-01-29 19:28:38 +0000350static int handle_serial_msg(struct msgb *rx_msg)
351{
352 struct abis_om_hdr *oh;
353 struct abis_om_fom_hdr *foh;
354 int rc = -1;
355
356 if (rx_msg->len < LAPD_HDR_LEN
357 + sizeof(struct abis_om_fom_hdr)
358 + sizeof(struct abis_om_hdr)) {
359 if (!memcmp(rx_msg->data + 2, too_fast,
360 sizeof(too_fast))) {
361 fprintf(stderr, "BS11 tells us we're too "
362 "fast, try --delay bigger than %u\n",
363 delay_ms);
364 return -E2BIG;
365 } else
366 fprintf(stderr, "unknown BS11 message\n");
367 }
368
369 oh = (struct abis_om_hdr *) msgb_l2(rx_msg);
370 foh = (struct abis_om_fom_hdr *) oh->data;
371 switch (foh->msg_type) {
372 case NM_MT_BS11_FACTORY_LOGON_ACK:
373 printf("FACTORY LOGON: ACK\n");
374 if (bs11cfg_state == STATE_NONE)
375 bs11cfg_state = STATE_LOGON_ACK;
376 rc = 0;
377 break;
378 case NM_MT_BS11_GET_STATE_ACK:
379 rc = handle_state_resp(foh->data[2]);
380 break;
381 default:
382 rc = abis_nm_rcvmsg(rx_msg);
383 }
384 if (rc < 0) {
385 perror("ERROR in main loop");
386 //break;
387 }
388 if (rc == 1)
389 return rc;
390
391 switch (bs11cfg_state) {
392 case STATE_NONE:
393 abis_nm_bs11_factory_logon(g_bts, 1);
394 break;
395 case STATE_LOGON_ACK:
396 abis_nm_bs11_get_state(g_bts);
397 break;
398 default:
399 break;
400 }
401
402 return rc;
403}
404
Harald Welte61e42ad2009-01-18 19:10:46 +0000405static void print_banner(void)
406{
407 printf("bs11_config (C) 2009 by Harald Welte and Dieter Spaar\n");
408 printf("THIS SOFTWARE IS FREE SOFTWARE WIH NO WARRANTY\n\n");
409}
410
411static void print_help(void)
412{
413 printf("Supported arguments:\n");
414 printf("\t--help\t\t\t-h\tPrint this help text\n");
415 printf("\t--port /dev/ttyXXX\t-p\tSpecify serial port\n");
416 printf("\t--with-trx1\t\t-t\tAssume the BS-11 has 2 TRX\n");
417 printf("\t--software file\t\t-s\tSpecify Software file\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000418 printf("\t--safety file\t\t-S\tSpecify Safety Load file\n");
Harald Welte61e42ad2009-01-18 19:10:46 +0000419}
420
421static void handle_options(int argc, char **argv)
422{
423 print_banner();
424
425 while (1) {
426 int option_index = 0, c;
427 static struct option long_options[] = {
428 { "help", 0, 0, 'h' },
429 { "port", 1, 0, 'p' },
430 { "with-trx1", 0, 0, 't' },
431 { "software", 1, 0, 's' },
432 { "safety", 1, 0, 'S' },
Harald Welte3b8ba212009-01-29 12:27:58 +0000433 { "delay", 1, 0, 'd' },
Harald Welte61e42ad2009-01-18 19:10:46 +0000434 };
435
436 c = getopt_long(argc, argv, "hp:s:S:t",
437 long_options, &option_index);
438
439 if (c == -1)
440 break;
441
442 switch (c) {
443 case 'h':
444 print_help();
445 exit(0);
446 case 'p':
447 serial_port = optarg;
448 break;
449 case 't':
450 have_trx1 = 1;
451 break;
452 case 's':
453 fname_software = optarg;
454 break;
455 case 'S':
456 fname_safety = optarg;
457 break;
Harald Welte3b8ba212009-01-29 12:27:58 +0000458 case 'd':
459 delay_ms = atoi(optarg);
460 break;
Harald Welte61e42ad2009-01-18 19:10:46 +0000461 default:
462 break;
463 }
464 }
465}
466
Harald Welte14f09342009-01-29 19:28:38 +0000467static void signal_handler(int signal)
468{
469 fprintf(stdout, "signal %u received\n", signal);
470
471 switch (signal) {
472 case SIGABRT:
473 abis_nm_bs11_factory_logon(g_bts, 0);
474 break;
475 }
476}
477
Harald Welte61e42ad2009-01-18 19:10:46 +0000478int main(int argc, char **argv)
479{
480 struct gsm_network *gsmnet;
Harald Weltef186c462009-01-29 08:45:19 +0000481 struct termios tio;
482 int rc;
Harald Welte61e42ad2009-01-18 19:10:46 +0000483
484 handle_options(argc, argv);
485
486 serial_fd = open(serial_port, O_RDWR);
487 if (serial_fd < 0) {
488 perror("cannot open serial port:");
489 exit(1);
490 }
491
Harald Weltef186c462009-01-29 08:45:19 +0000492 /* set baudrate */
493 rc = tcgetattr(serial_fd, &tio);
494 if (rc < 0) {
495 perror("tcgetattr()");
496 exit(1);
497 }
498 cfsetispeed(&tio, B19200);
499 cfsetospeed(&tio, B19200);
Harald Welte071f34d2009-01-29 09:24:38 +0000500 tio.c_cflag |= (CREAD | CLOCAL | CS8);
501 tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
502 tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
503 tio.c_iflag |= (INPCK | ISTRIP);
504 tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR);
Harald Weltef186c462009-01-29 08:45:19 +0000505 rc = tcsetattr(serial_fd, TCSADRAIN, &tio);
506 if (rc < 0) {
507 perror("tcsetattr()");
508 exit(1);
509 }
Harald Welte61e42ad2009-01-18 19:10:46 +0000510
511 gsmnet = gsm_network_init(1, 1, 1);
512 if (!gsmnet) {
513 fprintf(stderr, "Unable to allocate gsm network\n");
514 exit(1);
515 }
516 g_bts = &gsmnet->bts[0];
517
Harald Welte14f09342009-01-29 19:28:38 +0000518 INIT_LLIST_HEAD(&ser_handle->tx_queue);
519 ser_handle->fd.fd = serial_fd;
520 ser_handle->fd.when = BSC_FD_READ;
521 ser_handle->fd.cb = serial_fd_cb;
522 ser_handle->fd.data = ser_handle;
523 rc = bsc_register_fd(&ser_handle->fd);
524 if (rc < 0) {
525 fprintf(stderr, "could not register FD: %s\n",
526 strerror(rc));
527 exit(1);
528 }
529
530 signal(SIGABRT, &signal_handler);
531
Harald Welte61e42ad2009-01-18 19:10:46 +0000532 abis_nm_bs11_factory_logon(g_bts, 1);
533
534 while (1) {
Harald Welte14f09342009-01-29 19:28:38 +0000535 bsc_select_main();
Harald Welte61e42ad2009-01-18 19:10:46 +0000536 }
537
538 abis_nm_bs11_factory_logon(g_bts, 0);
539
540 close(serial_fd);
541 exit(0);
542}