blob: d30881bba346f5025006c02ea829a34e60baf1ac [file] [log] [blame]
Dieter Spaar16646022011-07-28 00:01:50 +02001/* Nokia XXXsite family specific code */
2
3/* (C) 2011 by Dieter Spaar <spaar@mirider.augusta.de>
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 Affero General Public License as published by
9 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22/*
23 TODO: Attention: There are some static variables used for states during
24 configuration. Those variables have to be moved to a BTS specific context,
25 otherwise there will most certainly be problems if more than one Nokia BTS
26 is used.
27*/
28
29#include <time.h>
30
31#include <osmocom/gsm/tlv.h>
32
33#include <openbsc/debug.h>
34#include <openbsc/gsm_data.h>
35#include <openbsc/abis_nm.h>
36#include <openbsc/e1_input.h>
37#include <openbsc/signal.h>
38
39#include <osmocom/core/timer.h>
40
41#include "../libabis/input/lapd.h"
42
43/* TODO: put in a separate file ? */
44
45/* TODO: move statics to BTS context */
46static int do_reset = 1;
47/*static*/ int wait_reset = 0;
48struct osmo_timer_list reset_timer; /* timer to re-start after reset */
49
50#define RESET_INTERVAL 0, 3000000 /* 3 seconds */
51
52extern int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg);
53/* was static in system_information.c */
54extern int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts);
55
56static void abis_nm_queue_send_next(struct gsm_bts *bts);
57static void reset_timer_cb(void *_bts);
58static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref);
59static int dump_elements(uint8_t *data, int len);
60
61static void bootstrap_om_bts(struct gsm_bts *bts)
62{
63 LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
64
65 if(do_reset)
66 abis_nm_reset(bts, 1);
67}
68
69static void bootstrap_om_trx(struct gsm_bts_trx *trx)
70{
71 LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
72 trx->bts->nr, trx->nr);
73}
74
75static int shutdown_om(struct gsm_bts *bts)
76{
77 /* TODO !? */
78 return 0;
79}
80
81#define SAPI_OML 62
82#define SAPI_RSL 0
83
84/*
85
86 Tell LAPD to start start the SAP (send SABM requests) for all signalling
87 timeslots in this line
88
89 Attention: this has to be adapted for MISDN
90*/
91
92static void start_sabm_in_line(struct e1inp_line *line, int start, int sapi)
93{
94 struct e1inp_sign_link *link;
95 int i;
96
97 for (i = 0; i < ARRAY_SIZE(line->ts); i++) {
98 struct e1inp_ts *ts = &line->ts[i];
99
100 if (ts->type != E1INP_TS_TYPE_SIGN)
101 continue;
102
103 llist_for_each_entry(link, &ts->sign.sign_links, list) {
104 if(sapi != -1 && link->sapi != sapi)
105 continue;
106
107#if 0 /* debugging */
108 printf("sap start/stop (%d): %d tei=%d sapi=%d\n", start, i + 1, link->tei, link->sapi);
109#endif
110
111 if (start)
112 lapd_sap_start(ts->driver.dahdi.lapd, link->tei, link->sapi);
113 else
114 lapd_sap_stop(ts->driver.dahdi.lapd, link->tei, link->sapi);
115 }
116 }
117}
118
119/* Callback function to be called every time we receive a signal from INPUT */
120static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
121 void *handler_data, void *signal_data)
122{
123 struct gsm_bts *bts;
124
125 if (subsys != SS_GLOBAL)
126 return 0;
127
128 switch (signal) {
129 case S_GLOBAL_BTS_CLOSE_OM:
130 bts = signal_data;
131 if (bts->type == GSM_BTS_TYPE_NOKIA_SITE)
132 shutdown_om(signal_data);
133 break;
134 }
135
136 return 0;
137}
138
139/* Callback function to be called every time we receive a signal from INPUT */
140static int inp_sig_cb(unsigned int subsys, unsigned int signal,
141 void *handler_data, void *signal_data)
142{
143 struct input_signal_data *isd = signal_data;
144
145 if (subsys != SS_INPUT)
146 return 0;
147
148 switch (signal) {
149 case S_INP_LINE_INIT:
150 start_sabm_in_line(isd->line, 1, SAPI_OML); /* start only OML */
151 break;
152 case S_INP_TEI_DN:
153 break;
154 case S_INP_TEI_UP:
155 switch (isd->link_type) {
156 case E1INP_SIGN_OML:
157 if (isd->trx->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
158 break;
159
160 if (isd->tei == isd->trx->bts->oml_tei)
161 bootstrap_om_bts(isd->trx->bts);
162 else
163 bootstrap_om_trx(isd->trx);
164 break;
165 }
166 break;
167 }
168
169 return 0;
170}
171
172static void nm_statechg_evt(unsigned int signal,
173 struct nm_statechg_signal_data *nsd)
174{
175 if (nsd->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
176 return;
177}
178
179static int nm_sig_cb(unsigned int subsys, unsigned int signal,
180 void *handler_data, void *signal_data)
181{
182 if (subsys != SS_NM)
183 return 0;
184
185 switch (signal) {
186 case S_NM_STATECHG_OPER:
187 case S_NM_STATECHG_ADM:
188 nm_statechg_evt(signal, signal_data);
189 break;
190 default:
191 break;
192 }
193
194 return 0;
195}
196
197/* TODO: put in a separate file ? */
198
199static char *get_msg_type_name_string(uint8_t msg_type)
200{
201 switch(msg_type) {
202 case 0x80:
203 return "NOKIA_BTS_CONF_DATA";
204 case 0x81:
205 return "NOKIA_BTS_ACK";
206 case 0x82:
207 return "NOKIA_BTS_OMU_STARTED";
208 case 0x83:
209 return "NOKIA_BTS_START_DOWNLOAD_REQ";
210 case 0x84:
211 return "NOKIA_BTS_MF_REQ";
212 case 0x85:
213 return "NOKIA_BTS_AF_REQ";
214 case 0x86:
215 return "NOKIA_BTS_RESET_REQ";
216 case 0x87:
217 return "NOKIA_reserved";
218 case 0x88:
219 return "NOKIA_BTS_CONF_REQ";
220 case 0x89:
221 return "NOKIA_BTS_TEST_REQ";
222 case 0x8A:
223 return "NOKIA_BTS_TEST_REPORT";
224 case 0x8B:
225 return "NOKIA_reserved";
226 case 0x8C:
227 return "NOKIA_reserved";
228 case 0x8D:
229 return "NOKIA_reserved";
230 case 0x8E:
231 return "NOKIA_BTS_CONF_COMPL";
232 case 0x8F:
233 return "NOKIA_reserved";
234 case 0x90:
235 return "NOKIA_BTS_STM_TEST_REQ";
236 case 0x91:
237 return "NOKIA_BTS_STM_TEST_REPORT";
238 case 0x92:
239 return "NOKIA_BTS_TRANSMISSION_COMMAND";
240 case 0x93:
241 return "NOKIA_BTS_TRANSMISSION_ANSWER";
242 case 0x94:
243 return "NOKIA_BTS_HW_DB_UPLOAD_REQ";
244 case 0x95:
245 return "NOKIA_BTS_START_HW_DB_DOWNLOAD_REQ";
246 case 0x96:
247 return "NOKIA_BTS_HW_DB_SAVE_REQ";
248 case 0x97:
249 return "NOKIA_BTS_FLASH_ERASURE_REQ";
250 case 0x98:
251 return "NOKIA_BTS_HW_DB_DOWNLOAD_REQ";
252 case 0x99:
253 return "NOKIA_BTS_PWR_SUPPLY_CONTROL";
254 case 0x9A:
255 return "NOKIA_BTS_ATTRIBUTE_REQ";
256 case 0x9B:
257 return "NOKIA_BTS_ATTRIBUTE_REPORT";
258 case 0x9C:
259 return "NOKIA_BTS_HW_REQ";
260 case 0x9D:
261 return "NOKIA_BTS_HW_REPORT";
262 case 0x9E:
263 return "NOKIA_BTS_RTE_TEST_REQ";
264 case 0x9F:
265 return "NOKIA_BTS_RTE_TEST_REPORT";
266 case 0xA0:
267 return "NOKIA_BTS_HW_DB_VERIFICATION_REQ";
268 case 0xA1:
269 return "NOKIA_BTS_CLOCK_REQ";
270 case 0xA2:
271 return "NOKIA_AC_CIRCUIT_REQ_NACK";
272 case 0xA3:
273 return "NOKIA_AC_INTERRUPTED";
274 case 0xA4:
275 return "NOKIA_BTS_NEW_TRE_INFO";
276 case 0xA5:
277 return "NOKIA_AC_BSC_CIRCUITS_ALLOCATED";
278 case 0xA6:
279 return "NOKIA_BTS_TRE_POLL_LIST";
280 case 0xA7:
281 return "NOKIA_AC_CIRCUIT_REQ";
282 case 0xA8:
283 return "NOKIA_BTS_BLOCK_CTRL_REQ";
284 case 0xA9:
285 return "NOKIA_BTS_GSM_TIME_REQ";
286 case 0xAA:
287 return "NOKIA_BTS_GSM_TIME";
288 case 0xAB:
289 return "NOKIA_BTS_OUTPUT_CONTROL";
290 case 0xAC:
291 return "NOKIA_BTS_STATE_CHANGED";
292 case 0xAD:
293 return "NOKIA_BTS_SW_SAVE_REQ";
294 case 0xAE:
295 return "NOKIA_BTS_ALARM";
296 case 0xAF:
297 return "NOKIA_BTS_CHA_ADM_STATE";
298 case 0xB0:
299 return "NOKIA_AC_POOL_SIZE_REPORT";
300 case 0xB1:
301 return "NOKIA_AC_POOL_SIZE_INQUIRY";
302 case 0xB2:
303 return "NOKIA_BTS_COMMISS_TEST_COMPLETED";
304 case 0xB3:
305 return "NOKIA_BTS_COMMISS_TEST_REQ";
306 case 0xB4:
307 return "NOKIA_BTS_TRANSP_BTS_TO_BSC";
308 case 0xB5:
309 return "NOKIA_BTS_TRANSP_BSC_TO_BTS";
310 case 0xB6:
311 return "NOKIA_BTS_LCS_COMMAND";
312 case 0xB7:
313 return "NOKIA_BTS_LCS_ANSWER";
314 case 0xB8:
315 return "NOKIA_BTS_LMU_FN_OFFSET_COMMAND";
316 case 0xB9:
317 return "NOKIA_BTS_LMU_FN_OFFSET_ANSWER";
318 default:
319 return "unknown";
320 }
321}
322
323static char *get_element_name_string(uint16_t element)
324{
325 switch(element) {
326 case 0x01:
327 return "Ny1";
328 case 0x02:
329 return "T3105_F";
330 case 0x03:
331 return "Interference band limits";
332 case 0x04:
333 return "Interference report timer in secs";
334 case 0x05:
335 return "Channel configuration per TS";
336 case 0x06:
337 return "BSIC";
338 case 0x07:
339 return "RACH report timer in secs";
340 case 0x08:
341 return "Hardware database status";
342 case 0x09:
343 return "BTS RX level";
344 case 0x0A:
345 return "ARFN";
346 case 0x0B:
347 return "STM antenna attenuation";
348 case 0x0C:
349 return "Cell allocation bitmap";
350 case 0x0D:
351 return "Radio definition per TS";
352 case 0x0E:
353 return "Frame number";
354 case 0x0F:
355 return "Antenna diversity";
356 case 0x10:
357 return "T3105_D";
358 case 0x11:
359 return "File format";
360 case 0x12:
361 return "Last File";
362 case 0x13:
363 return "BTS type";
364 case 0x14:
365 return "Erasure mode";
366 case 0x15:
367 return "Hopping mode";
368 case 0x16:
369 return "Floating TRX";
370 case 0x17:
371 return "Power supplies";
372 case 0x18:
373 return "Reset type";
374 case 0x19:
375 return "Averaging period";
376 case 0x1A:
377 return "RBER2";
378 case 0x1B:
379 return "LAC";
380 case 0x1C:
381 return "CI";
382 case 0x1D:
383 return "Failure parameters";
384 case 0x1E:
385 return "(RF max power reduction)";
386 case 0x1F:
387 return "Measured RX_SENS";
388 case 0x20:
389 return "Extended cell radius";
390 case 0x21:
391 return "reserved";
392 case 0x22:
393 return "Success-Failure";
394 case 0x23:
395 return "Ack-Nack";
396 case 0x24:
397 return "OMU test results";
398 case 0x25:
399 return "File identity";
400 case 0x26:
401 return "Generation and version code";
402 case 0x27:
403 return "SW description";
404 case 0x28:
405 return "BCCH LEV";
406 case 0x29:
407 return "Test type";
408 case 0x2A:
409 return "Subscriber number";
410 case 0x2B:
411 return "reserved";
412 case 0x2C:
413 return "HSN";
414 case 0x2D:
415 return "reserved";
416 case 0x2E:
417 return "MS RXLEV";
418 case 0x2F:
419 return "MS TXLEV";
420 case 0x30:
421 return "RXQUAL";
422 case 0x31:
423 return "RX SENS";
424 case 0x32:
425 return "Alarm block";
426 case 0x33:
427 return "Neighbouring BCCH levels";
428 case 0x34:
429 return "STM report type";
430 case 0x35:
431 return "MA";
432 case 0x36:
433 return "MAIO";
434 case 0x37:
435 return "H_FLAG";
436 case 0x38:
437 return "TCH_ARFN";
438 case 0x39:
439 return "Clock output";
440 case 0x3A:
441 return "Transmitted power";
442 case 0x3B:
443 return "Clock sync";
444 case 0x3C:
445 return "TMS protocol discriminator";
446 case 0x3D:
447 return "TMS protocol data";
448 case 0x3E:
449 return "FER";
450 case 0x3F:
451 return "SWR result";
452 case 0x40:
453 return "Object identity";
454 case 0x41:
455 return "STM RX Antenna Test";
456 case 0x42:
457 return "reserved";
458 case 0x43:
459 return "reserved";
460 case 0x44:
461 return "Object current state";
462 case 0x45:
463 return "reserved";
464 case 0x46:
465 return "FU channel configuration";
466 case 0x47:
467 return "reserved";
468 case 0x48:
469 return "ARFN of a CU";
470 case 0x49:
471 return "FU radio definition";
472 case 0x4A:
473 return "reserved";
474 case 0x4B:
475 return "Severity";
476 case 0x4C:
477 return "Diversity selection";
478 case 0x4D:
479 return "RX antenna test";
480 case 0x4E:
481 return "RX antenna supervision period";
482 case 0x4F:
483 return "RX antenna state";
484 case 0x50:
485 return "Sector configuration";
486 case 0x51:
487 return "Additional info";
488 case 0x52:
489 return "SWR parameters";
490 case 0x53:
491 return "HW inquiry mode";
492 case 0x54:
493 return "reserved";
494 case 0x55:
495 return "Availability status";
496 case 0x56:
497 return "reserved";
498 case 0x57:
499 return "EAC inputs";
500 case 0x58:
501 return "EAC outputs";
502 case 0x59:
503 return "reserved";
504 case 0x5A:
505 return "Position";
506 case 0x5B:
507 return "HW unit identity";
508 case 0x5C:
509 return "RF test signal attenuation";
510 case 0x5D:
511 return "Operational state";
512 case 0x5E:
513 return "Logical object identity";
514 case 0x5F:
515 return "reserved";
516 case 0x60:
517 return "BS_TXPWR_OM";
518 case 0x61:
519 return "Loop_Duration";
520 case 0x62:
521 return "LNA_Path_Selection";
522 case 0x63:
523 return "Serial number";
524 case 0x64:
525 return "HW version";
526 case 0x65:
527 return "Obj. identity and obj. state";
528 case 0x66:
529 return "reserved";
530 case 0x67:
531 return "EAC input definition";
532 case 0x68:
533 return "EAC id and text";
534 case 0x69:
535 return "HW unit status";
536 case 0x6A:
537 return "SW release version";
538 case 0x6B:
539 return "FW version";
540 case 0x6C:
541 return "Bit_Error_Ratio";
542 case 0x6D:
543 return "RXLEV_with_Attenuation";
544 case 0x6E:
545 return "RXLEV_without_Attenuation";
546 case 0x6F:
547 return "reserved";
548 case 0x70:
549 return "CU_Results";
550 case 0x71:
551 return "reserved";
552 case 0x72:
553 return "LNA_Path_Results";
554 case 0x73:
555 return "RTE Results";
556 case 0x74:
557 return "Real Time";
558 case 0x75:
559 return "RX diversity selection";
560 case 0x76:
561 return "EAC input config";
562 case 0x77:
563 return "Feature support";
564 case 0x78:
565 return "File version";
566 case 0x79:
567 return "Outputs";
568 case 0x7A:
569 return "FU parameters";
570 case 0x7B:
571 return "Diagnostic info";
572 case 0x7C:
573 return "FU BSIC";
574 case 0x7D:
575 return "TRX Configuration";
576 case 0x7E:
577 return "Download status";
578 case 0x7F:
579 return "RX difference limit";
580 case 0x80:
581 return "TRX HW capability";
582 case 0x81:
583 return "Common HW config";
584 case 0x82:
585 return "Autoconfiguration pool size";
586 case 0x83:
587 return "TRE diagnostic info";
588 case 0x84:
589 return "TRE object identity";
590 case 0x85:
591 return "New TRE Info";
592 case 0x86:
593 return "Acknowledgement period";
594 case 0x87:
595 return "Synchronization mode";
596 case 0x88:
597 return "reserved";
598 case 0x89:
599 return "Block Control Data";
600 case 0x8A:
601 return "SW load mode";
602 case 0x8B:
603 return "Recommended recovery action";
604 case 0x8C:
605 return "BSC BCF id";
606 case 0x8D:
607 return "Q1 baud rate";
608 case 0x8E:
609 return "Allocation status";
610 case 0x8F:
611 return "Functional entity number";
612 case 0x90:
613 return "Transmission delay";
614 case 0x91:
615 return "Loop Duration ms";
616 case 0x92:
617 return "Logical channel";
618 case 0x93:
619 return "Q1 address";
620 case 0x94:
621 return "Alarm detail";
622 case 0x95:
623 return "Cabinet type";
624 case 0x96:
625 return "HW unit existence";
626 case 0x97:
627 return "RF power parameters";
628 case 0x98:
629 return "Message scenario";
630 case 0x99:
631 return "HW unit max amount";
632 case 0x9A:
633 return "Master TRX";
634 case 0x9B:
635 return "Transparent data";
636 case 0x9C:
637 return "BSC topology info";
638 case 0x9D:
639 return "Air i/f modulation";
640 case 0x9E:
641 return "LCS Q1 command data";
642 case 0x9F:
643 return "Frame number offset";
644 case 0xA0:
645 return "Abis TSL";
646 case 0xA1:
647 return "Dynamic pool info";
648 case 0xA2:
649 return "LCS LLP data";
650 case 0xA3:
651 return "LCS Q1 answer data";
652 case 0xA4:
653 return "DFCA FU Radio Definition";
654 case 0xA5:
655 return "Antenna hopping";
656 case 0xA6:
657 return "Field record sequence number";
658 case 0xA7:
659 return "Timeslot offslot";
660 case 0xA8:
661 return "EPCR capability";
662 case 0xA9:
663 return "Connectsite optional element";
664 case 0xAA:
665 return "TSC";
666 case 0xAB:
667 return "Special TX Power Setting";
668 case 0xAC:
669 return "Optional sync settings";
670 case 0xFA:
671 return "Abis If parameters";
672 default:
673 return "unknown";
674 }
675}
676
677static char *get_bts_type_string(uint8_t type)
678{
679 switch(type) {
680 case 0x0A:
681 return "MetroSite GSM 900";
682 case 0x0B:
683 return "MetroSite GSM 1800";
684 case 0x0C:
685 return "MetroSite GSM 1900 (PCS)";
686 case 0x0D:
687 return "MetroSite GSM 900 & 1800";
688 case 0x0E:
689 return "InSite GSM 900";
690 case 0x0F:
691 return "InSite GSM 1800";
692 case 0x10:
693 return "InSite GSM 1900";
694 case 0x11:
695 return "UltraSite GSM 900";
696 case 0x12:
697 return "UltraSite GSM 1800";
698 case 0x13:
699 return "UltraSite GSM/US-TDMA 1900";
700 case 0x14:
701 return "UltraSite GSM 900 & 1800";
702 case 0x16:
703 return "UltraSite GSM/US-TDMA 850";
704 case 0x18:
705 return "MetroSite GSM/US-TDMA 850";
706 case 0x19:
707 return "UltraSite GSM 800/1900";
708 default:
709 return "unknown";
710 }
711}
712
713static char *get_severity_string(uint8_t severity)
714{
715 switch(severity) {
716 case 0:
717 return "indeterminate";
718 case 1:
719 return "critical";
720 case 2:
721 return "major";
722 case 3:
723 return "minor";
724 case 4:
725 return "warning";
726 default:
727 return "unknown";
728 }
729}
730
731/* TODO: put in a separate file ? */
732
733/* some message IDs */
734
735#define NOKIA_MSG_CONF_DATA 128
736#define NOKIA_MSG_ACK 129
737#define NOKIA_MSG_OMU_STARTED 130
738#define NOKIA_MSG_START_DOWNLOAD_REQ 131
739#define NOKIA_MSG_MF_REQ 132
740#define NOKIA_MSG_RESET_REQ 134
741#define NOKIA_MSG_CONF_REQ 136
742#define NOKIA_MSG_CONF_COMPLETE 142
743#define NOKIA_MSG_BLOCK_CTRL_REQ 168
744#define NOKIA_MSG_STATE_CHANGED 172
745#define NOKIA_MSG_ALARM 174
746
747/* some element IDs */
748
749#define NOKIA_EI_BTS_TYPE 0x13
750#define NOKIA_EI_ACK 0x23
751#define NOKIA_EI_ADD_INFO 0x51
752#define NOKIA_EI_SEVERITY 0x4B
753#define NOKIA_EI_ALARM_DETAIL 0x94
754
755#define OM_ALLOC_SIZE 1024
756#define OM_HEADROOM_SIZE 128
757
758static uint8_t fu_config_template[] =
759{
760 0x7F, 0x7A, 0x39,
761 /* ID = 0x7A (FU parameters) ## constructed ## */
762 /* length = 57 */
763 /* [3] */
764
765 0x5F, 0x40, 0x04,
766 /* ID = 0x40 (Object identity) */
767 /* length = 4 */
768 /* [6] */
769 0x00, 0x07, 0x01, 0xFF,
770
771 0x41, 0x02,
772 /* ID = 0x01 (Ny1) */
773 /* length = 2 */
774 /* [12] */
775 0x00, 0x05,
776
777 0x42, 0x02,
778 /* ID = 0x02 (T3105_F) */
779 /* length = 2 */
780 /* [16] */
781 0x00, 0x28,
782
783 0x50, 0x02,
784 /* ID = 0x10 (T3105_D) */
785 /* length = 2 */
786 /* [20] */
787 0x00, 0x28,
788
789 0x43, 0x05,
790 /* ID = 0x03 (Interference band limits) */
791 /* length = 5 */
792 /* [24] */
793 0x0F, 0x1B, 0x27, 0x33, 0x3F,
794
795 0x44, 0x02,
796 /* ID = 0x04 (Interference report timer in secs) */
797 /* length = 2 */
798 /* [31] */
799 0x00, 0x10,
800
801 0x47, 0x01,
802 /* ID = 0x07 (RACH report timer in secs) */
803 /* length = 1 */
804 /* [35] */
805 0x1E,
806
807 0x4C, 0x10,
808 /* ID = 0x0C (Cell allocation bitmap) ####### */
809 /* length = 16 */
810 /* [38] */
811 0x8F, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813
814 0x59, 0x01,
815 /* ID = 0x19 (Averaging period) */
816 /* length = 1 */
817 /* [56] */
818 0x01,
819
820 0x5E, 0x01,
821 /* ID = 0x1E ((RF max power reduction)) */
822 /* length = 1 */
823 /* [59] */
824 0x00,
825
826
827 0x7F, 0x46, 0x11,
828 /* ID = 0x46 (FU channel configuration) ## constructed ## */
829 /* length = 17 */
830 /* [63] */
831
832 0x5F, 0x40, 0x04,
833 /* ID = 0x40 (Object identity) */
834 /* length = 4 */
835 /* [66] */
836 0x00, 0x07, 0x01, 0xFF,
837
838 0x45, 0x08,
839 /* ID = 0x05 (Channel configuration per TS) */
840 /* length = 8 */
841 /* [72] */
842 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
843
844
845 0x7F, 0x65, 0x0B,
846 /* ID = 0x65 (Obj. identity and obj. state) ## constructed ## */
847 /* length = 11 */
848 /* [83] */
849
850 0x5F, 0x40, 0x04,
851 /* ID = 0x40 (Object identity) */
852 /* length = 4 */
853 /* [86] */
854 0x00, 0x04, 0x01, 0xFF,
855
856 0x5F, 0x44, 0x01,
857 /* ID = 0x44 (Object current state) */
858 /* length = 1 */
859 /* [93] */
860 0x03,
861
862
863 0x7F, 0x7C, 0x0A,
864 /* ID = 0x7C (FU BSIC) ## constructed ## */
865 /* length = 10 */
866 /* [97] */
867
868 0x5F, 0x40, 0x04,
869 /* ID = 0x40 (Object identity) */
870 /* length = 4 */
871 /* [100] */
872 0x00, 0x07, 0x01, 0xFF,
873
874 0x46, 0x01,
875 /* ID = 0x06 (BSIC) */
876 /* length = 1 */
877 /* [106] */
878 0x00,
879
880
881 0x7F, 0x48, 0x0B,
882 /* ID = 0x48 (ARFN of a CU) ## constructed ## */
883 /* length = 11 */
884 /* [110] */
885
886 0x5F, 0x40, 0x04,
887 /* ID = 0x40 (Object identity) */
888 /* length = 4 */
889 /* [113] */
890 0x00, 0x08, 0x01, 0xFF,
891
892 0x4A, 0x02,
893 /* ID = 0x0A (ARFN) ####### */
894 /* length = 2 */
895 /* [119] */
896 0x03, 0x62,
897
898
899 0x7F, 0x49, 0x59,
900 /* ID = 0x49 (FU radio definition) ## constructed ## */
901 /* length = 89 */
902 /* [124] */
903
904 0x5F, 0x40, 0x04,
905 /* ID = 0x40 (Object identity) */
906 /* length = 4 */
907 /* [127] */
908 0x00, 0x07, 0x01, 0xFF,
909
910 0x4D, 0x50,
911 /* ID = 0x0D (Radio definition per TS) ####### */
912 /* length = 80 */
913 /* [133] */
914 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MA */
915 0x03, 0x62, /* HSN, MAIO or ARFCN if no hopping */
916 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
917 0x03, 0x62,
918 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
919 0x03, 0x62,
920 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
921 0x03, 0x62,
922 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
923 0x03, 0x62,
924 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
925 0x03, 0x62,
926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
927 0x03, 0x62,
928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
929 0x03, 0x62,
930};
931
932/* TODO: put in a separate file ? */
933
934/*
935 build the configuration for each TRX
936*/
937
938static int make_fu_config(struct gsm_bts_trx *trx, uint8_t id, uint8_t *fu_config, int *hopping)
939{
940 int i;
941
942 *hopping = 0;
943
944 memcpy(fu_config, fu_config_template, sizeof(fu_config_template));
945
946 /* set ID */
947
948 fu_config[ 6 + 2] = id;
949 fu_config[ 66 + 2] = id;
950 fu_config[ 86 + 2] = id;
951 fu_config[100 + 2] = id;
952 fu_config[113 + 2] = id;
953 fu_config[127 + 2] = id;
954
955 /* set ARFCN */
956
957 uint16_t arfcn = trx->arfcn;
958
959 fu_config[119] = arfcn >> 8;
960 fu_config[119 + 1] = arfcn & 0xFF;
961
962 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
963 struct gsm_bts_trx_ts *ts = &trx->ts[i];
964
965 if (ts->hopping.enabled) {
966 /* reverse order */
967 int j;
968 for(j = 0; j < ts->hopping.ma_len; j++)
969 fu_config[133 + (i * 10) + (7 - j)] = ts->hopping.ma_data[j];
970 fu_config[133 + 8 + (i * 10)] = ts->hopping.hsn;
971 fu_config[133 + 8 + 1 + (i * 10)] = ts->hopping.maio;
972 *hopping = 1;
973 } else {
974 fu_config[133 + 8 + (i * 10)] = arfcn >> 8;
975 fu_config[133 + 8 + 1 + (i * 10)] = arfcn & 0xFF;
976 }
977 }
978
979 /* set BSIC */
980
981 /*
982 Attention: all TRX except the first one seem to get the TSC
983 from the CHANNEL ACTIVATION command (in CHANNEL IDENTIFICATION,
984 GSM 04.08 CHANNEL DESCRIPTION).
985 There was a bug in rsl_chan_activate_lchan() setting this parameter.
986 */
987
988 uint8_t bsic = trx->bts->bsic;
989
990 fu_config[106] = bsic;
991
992 /* set CA */
993
994 if(generate_cell_chan_list(&fu_config[38], trx->bts) != 0) {
995 fprintf(stderr, "generate_cell_chan_list failed\n");
996 return 0;
997 }
998
999 /* set channel configuration */
1000
1001 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
1002 struct gsm_bts_trx_ts *ts = &trx->ts[i];
1003 uint8_t chan_config;
1004
1005 /*
1006 0 = FCCH + SCH + BCCH + CCCH
1007 1 = FCCH + SCH + BCCH + CCCH + SDCCH/4 + SACCH/4
1008 2 = BCCH + CCCH (This combination is not used in any BTS)
1009 3 = FCCH + SCH + BCCH + CCCH + SDCCH/4 with SDCCH2 used as CBCH
1010 4 = SDCCH/8 + SACCH/8
1011 5 = SDCCH/8 with SDCCH2 used as CBCH
1012 6 = TCH/F + FACCH/F + SACCH/F
1013 7 = E-RACH (Talk family)
1014 9 = Dual rate (capability for TCH/F and TCH/H)
1015 10 = reserved for BTS internal use
1016 11 = PBCCH + PCCCH + PDTCH + PACCH + PTCCH (This channel configuration type can be used in GPRS release 2).
1017 0xFF = spare TS
1018 */
1019
1020 if(ts->pchan == GSM_PCHAN_NONE)
1021 chan_config = 0xFF;
1022 else if(ts->pchan == GSM_PCHAN_CCCH)
1023 chan_config = 0;
1024 else if(ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
1025 chan_config = 1;
1026 else if(ts->pchan == GSM_PCHAN_TCH_F)
1027 chan_config = 6; /* 9 should work too */
1028 else if(ts->pchan == GSM_PCHAN_TCH_H)
1029 chan_config = 9;
1030 else if(ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C)
1031 chan_config = 4;
1032 else if(ts->pchan == GSM_PCHAN_PDCH)
1033 chan_config = 11;
1034 else {
1035 fprintf(stderr, "unsupported channel config %d for timeslot %d\n", ts->pchan, i);
1036 return 0;
1037 }
1038
1039 fu_config[72 + i] = chan_config;
1040 }
1041 return sizeof(fu_config_template);
1042}
1043
1044/* TODO: put in a separate file ? */
1045
1046static uint8_t bts_config_1[] =
1047{
1048 0x4E, 0x02,
1049 /* ID = 0x0E (Frame number) */
1050 /* length = 2 */
1051 /* [2] */
1052 0xFF, 0xFF,
1053
1054 0x5F, 0x4E, 0x02,
1055 /* ID = 0x4E (RX antenna supervision period) */
1056 /* length = 2 */
1057 /* [7] */
1058 0xFF, 0xFF,
1059
1060 0x5F, 0x50, 0x02,
1061 /* ID = 0x50 (Sector configuration) */
1062 /* length = 2 */
1063 /* [12] */
1064 0x01, 0x01,
1065};
1066
1067static uint8_t bts_config_2[] =
1068{
1069 0x55, 0x02,
1070 /* ID = 0x15 (Hopping mode) */
1071 /* length = 2 */
1072 /* [2] */
1073 0x01, 0x00,
1074
1075 0x5F, 0x75, 0x02,
1076 /* ID = 0x75 (RX diversity selection) */
1077 /* length = 2 */
1078 /* [7] */
1079 0x01, 0x01,
1080};
1081
1082static uint8_t bts_config_3[] =
1083{
1084 0x5F, 0x20, 0x02,
1085 /* ID = 0x20 (Extended cell radius) */
1086 /* length = 2 */
1087 /* [3] */
1088 0x01, 0x00,
1089};
1090
1091static uint8_t bts_config_4[] =
1092{
1093 0x5F, 0x74, 0x09,
1094 /* ID = 0x74 (Real Time) */
1095 /* length = 9 */
1096 /* [3] year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
1097 0x07, 0xDB, 0x06, 0x02, 0x0B, 0x20, 0x0C, 0x00,
1098 0x00,
1099
1100 0x5F, 0x76, 0x03,
1101 /* ID = 0x76 (EAC input config) */
1102 /* length = 3 */
1103 /* [15] */
1104 0x01, 0x01, 0x00,
1105
1106 0x5F, 0x76, 0x03,
1107 /* ID = 0x76 (EAC input config) */
1108 /* length = 3 */
1109 /* [21] */
1110 0x02, 0x01, 0x00,
1111
1112 0x5F, 0x76, 0x03,
1113 /* ID = 0x76 (EAC input config) */
1114 /* length = 3 */
1115 /* [27] */
1116 0x03, 0x01, 0x00,
1117
1118 0x5F, 0x76, 0x03,
1119 /* ID = 0x76 (EAC input config) */
1120 /* length = 3 */
1121 /* [33] */
1122 0x04, 0x01, 0x00,
1123
1124 0x5F, 0x76, 0x03,
1125 /* ID = 0x76 (EAC input config) */
1126 /* length = 3 */
1127 /* [39] */
1128 0x05, 0x01, 0x00,
1129
1130 0x5F, 0x76, 0x03,
1131 /* ID = 0x76 (EAC input config) */
1132 /* length = 3 */
1133 /* [45] */
1134 0x06, 0x01, 0x00,
1135
1136 0x5F, 0x76, 0x03,
1137 /* ID = 0x76 (EAC input config) */
1138 /* length = 3 */
1139 /* [51] */
1140 0x07, 0x01, 0x00,
1141
1142 0x5F, 0x76, 0x03,
1143 /* ID = 0x76 (EAC input config) */
1144 /* length = 3 */
1145 /* [57] */
1146 0x08, 0x01, 0x00,
1147
1148 0x5F, 0x76, 0x03,
1149 /* ID = 0x76 (EAC input config) */
1150 /* length = 3 */
1151 /* [63] */
1152 0x09, 0x01, 0x00,
1153
1154 0x5F, 0x76, 0x03,
1155 /* ID = 0x76 (EAC input config) */
1156 /* length = 3 */
1157 /* [69] */
1158 0x0A, 0x01, 0x00,
1159};
1160
1161static uint8_t bts_config_insite[] =
1162{
1163 0x4E, 0x02,
1164 /* ID = 0x0E (Frame number) */
1165 /* length = 2 */
1166 /* [2] */
1167 0xFF, 0xFF,
1168
1169 0x5F, 0x4E, 0x02,
1170 /* ID = 0x4E (RX antenna supervision period) */
1171 /* length = 2 */
1172 /* [7] */
1173 0xFF, 0xFF,
1174
1175 0x5F, 0x50, 0x02,
1176 /* ID = 0x50 (Sector configuration) */
1177 /* length = 2 */
1178 /* [12] */
1179 0x01, 0x01,
1180
1181 0x55, 0x02,
1182 /* ID = 0x15 (Hopping mode) */
1183 /* length = 2 */
1184 /* [16] */
1185 0x01, 0x00,
1186
1187 0x5F, 0x20, 0x02,
1188 /* ID = 0x20 (Extended cell radius) */
1189 /* length = 2 */
1190 /* [21] */
1191 0x01, 0x00,
1192
1193 0x5F, 0x74, 0x09,
1194 /* ID = 0x74 (Real Time) */
1195 /* length = 9 */
1196 /* [26] */
1197 0x07, 0xDB, 0x07, 0x0A, 0x0F, 0x09, 0x0B, 0x00,
1198 0x00,
1199};
1200
1201void set_real_time(uint8_t *real_time)
1202{
1203 time_t t;
1204 struct tm *tm;
1205
1206 t = time(NULL);
1207 tm = localtime(&t);
1208
1209 /* year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
1210
1211 real_time[0] = (1900 + tm->tm_year) >> 8;
1212 real_time[1] = (1900 + tm->tm_year) & 0xFF;
1213 real_time[2] = tm->tm_mon + 1;
1214 real_time[3] = tm->tm_mday;
1215 real_time[4] = tm->tm_hour;
1216 real_time[5] = tm->tm_min;
1217 real_time[6] = tm->tm_sec;
1218 real_time[7] = 0;
1219 real_time[8] = 0;
1220}
1221
1222/* TODO: put in a separate file ? */
1223
1224/*
1225
1226 build the configuration data
1227
1228*/
1229
1230static int make_bts_config(uint8_t bts_type, int n_trx, uint8_t *fu_config, int need_hopping)
1231{
1232 /* is it an InSite BTS ? */
1233 if(bts_type == 0x0E || bts_type == 0x0F || bts_type == 0x10) { /* TODO */
1234 if(n_trx != 1) {
1235 fprintf(stderr, "InSite has only one TRX\n");
1236 return 0;
1237 }
1238 if(need_hopping != 0) {
1239 fprintf(stderr, "InSite does not support hopping\n");
1240 return 0;
1241 }
1242 memcpy(fu_config, bts_config_insite, sizeof(bts_config_insite));
1243 set_real_time(&fu_config[26]);
1244 return sizeof(bts_config_insite);
1245 }
1246
1247 int len = 0;
1248 int i;
1249
1250 memcpy(fu_config + len, bts_config_1, sizeof(bts_config_1));
1251
1252 /* set sector configuration */
1253 fu_config[len + 12 - 1] = 1 + n_trx; /* len */
1254 for(i = 0; i < n_trx; i++)
1255 fu_config[len + 12 + 1 + i] = ((i + 1) & 0xFF);
1256
1257 len += (sizeof(bts_config_1) + (n_trx - 1));
1258
1259 memcpy(fu_config + len, bts_config_2, sizeof(bts_config_2));
1260 /* set hopping mode (Baseband and RF hopping work for the MetroSite) */
1261 if(need_hopping)
1262 fu_config[len + 2 + 1] = 1; /* 0: no hopping, 1: Baseband hopping, 2: RF hopping */
1263 len += sizeof(bts_config_2);
1264
1265 /* set extended cell radius for each TRX */
1266 for(i = 0; i < n_trx; i++) {
1267 memcpy(fu_config + len, bts_config_3, sizeof(bts_config_3));
1268 fu_config[len + 3] = ((i + 1) & 0xFF);
1269 len += sizeof(bts_config_3);
1270 }
1271
1272 memcpy(fu_config + len, bts_config_4, sizeof(bts_config_4));
1273 set_real_time(&fu_config[len + 3]);
1274 len += sizeof(bts_config_4);
1275
1276 return len;
1277}
1278
1279/* TODO: put in a separate file ? */
1280
1281static struct msgb *nm_msgb_alloc(void)
1282{
1283 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
1284 "OML");
1285}
1286
1287/* TODO: put in a separate file ? */
1288
1289struct abis_om_nokia_hdr {
1290 uint8_t msg_type;
1291 uint8_t spare;
1292 uint16_t reference;
1293 uint8_t data[0];
1294} __attribute__ ((packed));
1295
1296#define ABIS_OM_NOKIA_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_nokia_hdr))
1297
1298static int abis_nm_send(struct gsm_bts *bts, uint8_t msg_type, uint16_t ref, uint8_t *data, int len_data)
1299{
1300 struct abis_om_hdr *oh;
1301 struct abis_om_nokia_hdr *noh;
1302 struct msgb *msg = nm_msgb_alloc();
1303
1304 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_NOKIA_HDR_SIZE + len_data);
1305
1306 oh->mdisc = ABIS_OM_MDISC_FOM;
1307 oh->placement = ABIS_OM_PLACEMENT_ONLY;
1308 oh->sequence = 0;
1309 oh->length = sizeof(struct abis_om_nokia_hdr) + len_data;
1310
1311 noh = (struct abis_om_nokia_hdr *)oh->data;
1312
1313 noh->msg_type = msg_type;
1314 noh->spare = 0;
1315 noh->reference = htons(ref);
1316 memcpy(noh->data, data, len_data);
1317
1318 DEBUGPC(DNM, "Sending %s\n", get_msg_type_name_string(msg_type));
1319
1320 return abis_nm_sendmsg(bts, msg);
1321}
1322
1323/* TODO: put in a separate file ? */
1324
1325static uint8_t download_req[] = {
1326 0x5F, 0x25, 0x0B,
1327 /* ID = 0x25 (File identity) */
1328 /* length = 11 */
1329 /* [3] */
1330 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
1331 0x2A, 0x2A, 0x2A,
1332
1333 0x5F, 0x78, 0x03,
1334 /* ID = 0x78 (File version) */
1335 /* length = 3 */
1336 /* [17] */
1337 0x2A, 0x2A, 0x2A,
1338
1339 0x5F, 0x81, 0x0A, 0x01,
1340 /* ID = 0x8A (SW load mode) */
1341 /* length = 1 */
1342 /* [24] */
1343 0x01,
1344
1345 0x5F, 0x81, 0x06, 0x01,
1346 /* ID = 0x86 (Acknowledgement period) */
1347 /* length = 1 */
1348 /* [29] */
1349 0x01,
1350};
1351
1352static int abis_nm_download_req(struct gsm_bts *bts, uint16_t ref)
1353{
1354 uint8_t *data = download_req;
1355 int len_data = sizeof(download_req);
1356
1357 return abis_nm_send(bts, NOKIA_MSG_START_DOWNLOAD_REQ, ref, data, len_data);
1358}
1359
1360/* TODO: put in a separate file ? */
1361
1362static uint8_t ack[] = {
1363 0x5F, 0x23, 0x01,
1364 /* ID = 0x23 (Ack-Nack) */
1365 /* length = 1 */
1366 /* [3] */
1367 0x01,
1368};
1369
1370static int abis_nm_ack(struct gsm_bts *bts, uint16_t ref)
1371{
1372 uint8_t *data = ack;
1373 int len_data = sizeof(ack);
1374
1375 return abis_nm_send(bts, NOKIA_MSG_ACK, ref, data, len_data);
1376}
1377
1378/* TODO: put in a separate file ? */
1379
1380static uint8_t reset[] = {
1381 0x5F, 0x40, 0x04,
1382 /* ID = 0x40 (Object identity) */
1383 /* length = 4 */
1384 /* [3] */
1385 0x00, 0x01, 0xFF, 0xFF,
1386};
1387
1388static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref)
1389{
1390 uint8_t *data = reset;
1391 int len_data = sizeof(reset);
1392
1393 return abis_nm_send(bts, NOKIA_MSG_RESET_REQ, ref, data, len_data);
1394}
1395
1396/* TODO: put in a separate file ? */
1397
1398static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type, uint16_t ref, uint8_t *data, int len)
1399{
1400 int len_remain, len_to_send, max_send;
1401 int seq = 0;
1402 int ret;
1403
1404 len_remain = len;
1405
1406 while(len_remain) {
1407 struct abis_om_hdr *oh;
1408 struct abis_om_nokia_hdr *noh;
1409 struct msgb *msg = nm_msgb_alloc();
1410
1411 if(seq == 0)
1412 max_send = 256 - sizeof(struct abis_om_nokia_hdr);
1413 else
1414 max_send = 256;
1415
1416 if(len_remain > max_send) {
1417 len_to_send = max_send;
1418
1419 if(seq == 0) {
1420 /* first segment */
1421 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_NOKIA_HDR_SIZE + len_to_send);
1422
1423 oh->mdisc = ABIS_OM_MDISC_FOM;
1424 oh->placement = ABIS_OM_PLACEMENT_FIRST; /* first segment of multi-segment message */
1425 oh->sequence = seq;
1426 oh->length = 0; /* 256 bytes */
1427
1428 noh = (struct abis_om_nokia_hdr *)oh->data;
1429
1430 noh->msg_type = msg_type;
1431 noh->spare = 0;
1432 noh->reference = htons(ref);
1433 memcpy(noh->data, data, len_to_send);
1434 } else {
1435 /* segment in between */
1436 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(struct abis_om_hdr) + len_to_send);
1437
1438 oh->mdisc = ABIS_OM_MDISC_FOM;
1439 oh->placement = ABIS_OM_PLACEMENT_MIDDLE; /* segment of multi-segment message */
1440 oh->sequence = seq;
1441 oh->length = 0; /* 256 bytes */
1442
1443 memcpy(oh->data, data, len_to_send);
1444 }
1445 }
1446 else {
1447
1448 len_to_send = len_remain;
1449
1450 /* check if message fits in a single segment */
1451
1452 if(seq == 0)
1453 return abis_nm_send(bts, msg_type, ref, data, len_to_send);
1454
1455 /* last segment */
1456
1457 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(struct abis_om_hdr) + len_to_send);
1458
1459 oh->mdisc = ABIS_OM_MDISC_FOM;
1460 oh->placement = ABIS_OM_PLACEMENT_LAST; /* last segment of multi-segment message */
1461 oh->sequence = seq;
1462 oh->length = len_to_send;
1463
1464 memcpy(oh->data, data, len_to_send);
1465 }
1466
1467 DEBUGPC(DNM, "Sending multi-segment %d\n", seq);
1468
1469 ret = abis_nm_sendmsg(bts, msg);
1470 if(ret < 0)
1471 return ret;
1472
1473 abis_nm_queue_send_next(bts);
1474
1475 /* next segment */
1476 len_remain -= len_to_send;
1477 data += len_to_send;
1478 seq++;
1479 }
1480 return ret;
1481}
1482
1483/* TODO: put in a separate file ? */
1484
1485static int abis_nm_send_config(struct gsm_bts *bts, uint8_t bts_type)
1486{
1487 struct gsm_bts_trx *trx;
1488 uint8_t config[2048]; /* TODO: might be too small if lots of TRX are used */
1489 int len = 0;
1490 int idx = 0;
1491 int ret;
1492 int hopping = 0;
1493 int need_hopping = 0;
1494
1495 memset(config, 0, sizeof(config));
1496
1497 llist_for_each_entry(trx, &bts->trx_list, list)
1498 {
1499#if 0 /* debugging */
1500 printf("TRX\n");
1501 printf(" arfcn: %d\n", trx->arfcn);
1502 printf(" bsic: %d\n", trx->bts->bsic);
1503 uint8_t ca[20];
1504 memset(ca, 0xFF, sizeof(ca));
1505 ret = generate_cell_chan_list(ca, trx->bts);
1506 printf(" ca (%d): %s\n", ret, osmo_hexdump(ca, sizeof(ca)));
1507 int i;
1508 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
1509 struct gsm_bts_trx_ts *ts = &trx->ts[i];
1510
1511 printf(" pchan %d: %d\n", i, ts->pchan);
1512 }
1513#endif
1514 ret = make_fu_config(trx, idx + 1, config + len, &hopping);
1515 need_hopping |= hopping;
1516 len += ret;
1517
1518 idx++;
1519 }
1520
1521 ret = make_bts_config(bts_type, idx, config + len, need_hopping);
1522 len += ret;
1523
1524#if 0 /* debugging */
1525 dump_elements(config, len);
1526#endif
1527
1528 return abis_nm_send_multi_segments(bts, NOKIA_MSG_CONF_DATA, 1, config, len);
1529}
1530
1531#define GET_NEXT_BYTE if(idx >= len) return 0; \
1532 ub = data[idx++];
1533
1534static int find_element(uint8_t *data, int len, uint16_t id, uint8_t *value, int max_value)
1535{
1536 uint8_t ub;
1537 int idx = 0;
1538 int found = 0;
1539 int constructed;
1540 uint16_t id_value;
1541
1542 for(;;) {
1543
1544 GET_NEXT_BYTE;
1545
1546 /* encoding bit, construced means that other elements are contained */
1547 constructed = ((ub & 0x20) ? 1 : 0);
1548
1549 if((ub & 0x1F) == 0x1F) {
1550 /* fixed pattern, ID follows */
1551 GET_NEXT_BYTE; /* ID */
1552 id_value = ub & 0x7F;
1553 if(ub & 0x80) {
1554 /* extension bit */
1555 GET_NEXT_BYTE; /* ID low part */
1556 id_value = (id_value << 7) | (ub & 0x7F);
1557 }
1558 if(id_value == id)
1559 found = 1;
1560 }
1561 else {
1562 id_value = (ub & 0x3F);
1563 if(id_value == id)
1564 found = 1;
1565 }
1566
1567 GET_NEXT_BYTE; /* length */
1568
1569 if(found) {
1570 /* get data */
1571 uint8_t n = ub;
1572 uint8_t i;
1573 for(i = 0; i < n; i++) {
1574 GET_NEXT_BYTE;
1575 if(max_value <= 0)
1576 return -1; /* buffer too small */
1577 *value = ub;
1578 value++;
1579 max_value--;
1580 }
1581 return n; /* length */
1582 }
1583 else {
1584 /* skip data */
1585 uint8_t n = ub;
1586 uint8_t i;
1587 for(i = 0; i < n; i++) {
1588 GET_NEXT_BYTE;
1589 }
1590 }
1591 }
1592 return 0; /* not found */
1593}
1594
1595static int dump_elements(uint8_t *data, int len)
1596{
1597 uint8_t ub;
1598 int idx = 0;
1599 int constructed;
1600 uint16_t id_value;
1601 static char indent[100] = ""; /* TODO: move static to BTS context */
1602
1603 for(;;) {
1604
1605 GET_NEXT_BYTE;
1606
1607 /* encoding bit, construced means that other elements are contained */
1608 constructed = ((ub & 0x20) ? 1 : 0);
1609
1610 if((ub & 0x1F) == 0x1F) {
1611 /* fixed pattern, ID follows */
1612 GET_NEXT_BYTE; /* ID */
1613 id_value = ub & 0x7F;
1614 if(ub & 0x80) {
1615 /* extension bit */
1616 GET_NEXT_BYTE; /* ID low part */
1617 id_value = (id_value << 7) | (ub & 0x7F);
1618 }
1619
1620 }
1621 else {
1622 id_value = (ub & 0x3F);
1623 }
1624
1625 GET_NEXT_BYTE; /* length */
1626
1627 printf("%s--ID = 0x%02X (%s) %s\n", indent, id_value, get_element_name_string(id_value), constructed ? "** constructed **" : "");
1628 printf("%s length = %d\n", indent, ub);
1629 printf("%s %s\n", indent, osmo_hexdump(data + idx, ub));
1630
1631 if(constructed) {
1632 int indent_len = strlen(indent);
1633 strcat(indent, " ");
1634
1635 dump_elements(data + idx, ub);
1636
1637 indent[indent_len] = 0;
1638 }
1639 /* skip data */
1640 uint8_t n = ub;
1641 uint8_t i;
1642 for(i = 0; i < n; i++) {
1643 GET_NEXT_BYTE;
1644 }
1645 }
1646 return 0;
1647}
1648
1649/* TODO: put in a separate file ? */
1650
1651/* taken from abis_nm.c */
1652
1653static void abis_nm_queue_send_next(struct gsm_bts *bts)
1654{
1655 int wait = 0;
1656 struct msgb *msg;
1657 /* the queue is empty */
1658 while (!llist_empty(&bts->abis_queue)) {
1659 msg = msgb_dequeue(&bts->abis_queue);
1660 wait = OBSC_NM_W_ACK_CB(msg);
1661 _abis_nm_sendmsg(msg, 0);
1662
1663 if (wait)
1664 break;
1665 }
1666
1667 bts->abis_nm_pend = wait;
1668}
1669
1670/* TODO: put in a separate file ? */
1671
1672/* timer for restarting OML after BTS reset */
1673
1674static void reset_timer_cb(void *_bts)
1675{
1676 struct gsm_bts *bts = _bts;
1677 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1678 struct e1inp_line *line;
1679
1680 wait_reset = 0;
1681
1682 /* OML link */
1683 line = e1inp_line_get(e1_link->e1_nr);
1684 if (!line) {
1685 LOGP(DINP, LOGL_ERROR, "BTS %u OML link referring to "
1686 "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
1687 return;
1688 }
1689
1690 start_sabm_in_line(line, 0, -1); /* stop all first */
1691 start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */
1692}
1693
1694/* TODO: put in a separate file ? */
1695
1696/*
1697 This is how the configuration is done:
1698
1699 - start OML link
1700
1701 - reset BTS
1702
1703 - receive ACK, wait some time and restart OML link
1704
1705 - receive OMU STARTED message, send START DOWNLOAD REQ
1706
1707 - receive CNF REQ message, send CONF DATA
1708
1709 - receive ACK, start RSL link(s)
1710
1711 ACK some other messages received from the BTS.
1712
1713 Probably its also possible to configure the BTS without a reset, this
1714 has not been tested yet.
1715*/
1716
1717static int abis_nm_rcvmsg_fom(struct msgb *mb)
1718{
1719 struct gsm_bts *bts = mb->trx->bts;
1720 struct abis_om_hdr *oh = msgb_l2(mb);
1721 struct abis_om_nokia_hdr *noh = msgb_l3(mb);
1722 uint8_t mt = noh->msg_type;
1723 int ret = 0;
1724 uint16_t ref = ntohs(noh->reference);
1725 /* TODO: move statics to BTS context */
1726 static int conf = 0;
1727 static uint8_t bts_type = 0xFF;
1728 uint8_t info[256];
1729 uint8_t ack = 0xFF;
1730 uint8_t severity = 0xFF;
1731 int str_len;
1732 int len_data;
1733
1734 if(wait_reset) {
1735 LOGP(DNM, LOGL_INFO, "Ignore message while waiting for reset\n");
1736 return ret;
1737 }
1738
1739 if(oh->length < sizeof(struct abis_om_nokia_hdr)) {
1740 LOGP(DNM, LOGL_ERROR, "Message too short\n");
1741 return -EINVAL;
1742 }
1743
1744 len_data = oh->length - sizeof(struct abis_om_nokia_hdr);
1745 LOGP(DNM, LOGL_INFO, "(0x%02X) %s\n", mt, get_msg_type_name_string(mt));
1746#if 0 /* debugging */
1747 dump_elements(noh->data, len_data);
1748#endif
1749
1750 switch (mt) {
1751 case NOKIA_MSG_OMU_STARTED:
1752 if(find_element(noh->data, len_data, NOKIA_EI_BTS_TYPE, &bts_type, sizeof(uint8_t)) == sizeof(uint8_t))
1753 LOGP(DNM, LOGL_INFO, "BTS type = %d (%s)\n", bts_type, get_bts_type_string(bts_type));
1754 else
1755 LOGP(DNM, LOGL_ERROR, "BTS type not found\n");
1756 /* send START_DOWNLOAD_REQ */
1757 abis_nm_download_req(bts, ref);
1758 break;
1759 case NOKIA_MSG_MF_REQ:
1760 break;
1761 case NOKIA_MSG_CONF_REQ:
1762 /* send ACK */
1763 abis_nm_ack(bts, ref);
1764 abis_nm_queue_send_next(bts);
1765 /* send CONF_DATA */
1766 abis_nm_send_config(bts, bts_type);
1767 conf = 1;
1768 break;
1769 case NOKIA_MSG_ACK:
1770 if(find_element(noh->data, len_data, NOKIA_EI_ACK, &ack, sizeof(uint8_t)) == sizeof(uint8_t)) {
1771 LOGP(DNM, LOGL_INFO, "ACK = %d\n", ack);
1772 if(ack != 1) {
1773 LOGP(DNM, LOGL_ERROR, "No ACK received (%d)\n", ack);
1774 /* TODO: properly handle failures (NACK) */
1775 }
1776 }
1777 else
1778 LOGP(DNM, LOGL_ERROR, "ACK not found\n");
1779
1780 /* TODO: the assumption for the following is that no NACK was received */
1781
1782 /* ACK for reset message ? */
1783 if(do_reset != 0) {
1784 do_reset = 0;
1785
1786 /*
1787 TODO: For the InSite processing the received data is
1788 blocked in the driver during reset.
1789 Otherwise the LAPD module might assert because the InSite
1790 sends garbage on the E1 line during reset.
1791 This is done by looking at "wait_reset" in the driver
1792 (function handle_ts1_read()) and ignoring the received data.
1793 It seems to be necessary for the MetroSite too.
1794 */
1795 wait_reset = 1;
1796
1797 reset_timer.cb = &reset_timer_cb;
1798 reset_timer.data = bts;
1799 osmo_timer_schedule(&reset_timer, RESET_INTERVAL);
1800
1801 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1802 struct e1inp_line *line;
1803 /* OML link */
1804 line = e1inp_line_get(e1_link->e1_nr);
1805 if (!line) {
1806 LOGP(DINP, LOGL_ERROR, "BTS %u OML link referring to "
1807 "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
1808 return -ENOMEM;
1809 }
1810
1811 start_sabm_in_line(line, 0, -1); /* stop all first */
1812 }
1813
1814 /* ACK for CONF DATA message ? */
1815 if(conf != 0) {
1816 /* start TRX (RSL link) */
1817
1818 struct gsm_e1_subslot *e1_link = &mb->trx->rsl_e1_link;
1819 struct e1inp_line *line;
1820
1821 conf = 0;
1822
1823 /* RSL Link */
1824 line = e1inp_line_get(e1_link->e1_nr);
1825 if (!line) {
1826 LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link referring "
1827 "to non-existing E1 line %u\n", mb->trx->bts->nr,
1828 mb->trx->nr, e1_link->e1_nr);
1829 return -ENOMEM;
1830 }
1831 /* start TRX */
1832 start_sabm_in_line(line, 1, SAPI_RSL); /* start only RSL */
1833 }
1834 break;
1835 case NOKIA_MSG_STATE_CHANGED:
1836 /* send ACK */
1837 abis_nm_ack(bts, ref);
1838 break;
1839 case NOKIA_MSG_CONF_COMPLETE:
1840 /* send ACK */
1841 abis_nm_ack(bts, ref);
1842 break;
1843 case NOKIA_MSG_BLOCK_CTRL_REQ: /* seems to be send when something goes wrong !? */
1844 /* send ACK (do we have to send an ACK ?) */
1845 abis_nm_ack(bts, ref);
1846 break;
1847 case NOKIA_MSG_ALARM:
1848 find_element(noh->data, len_data, NOKIA_EI_SEVERITY, &severity, sizeof(severity));
1849 /* TODO: there might be alarms with both elements set */
1850 str_len = find_element(noh->data, len_data, NOKIA_EI_ADD_INFO, info, sizeof(info));
1851 if(str_len > 0) {
1852 info[str_len] = 0;
1853 LOGP(DNM, LOGL_INFO, "ALARM Severity %s (%d) : %s\n", get_severity_string(severity), severity, info);
1854 } else { /* nothing found, try details */
1855 str_len = find_element(noh->data, len_data, NOKIA_EI_ALARM_DETAIL, info, sizeof(info));
1856 if(str_len > 0) {
1857 uint16_t code;
1858 info[str_len] = 0;
1859 code = (info[0] << 8) + info[1];
1860 LOGP(DNM, LOGL_INFO, "ALARM Severity %s (%d), code 0x%X : %s\n", get_severity_string(severity), severity, code, info + 2);
1861 }
1862 }
1863 /* send ACK */
1864 abis_nm_ack(bts, ref);
1865 break;
1866 }
1867
1868 abis_nm_queue_send_next(bts);
1869
1870 return ret;
1871}
1872
1873/* TODO: put in a separate file ? */
1874
1875int abis_nokia_rcvmsg(struct msgb *msg)
1876{
1877 struct abis_om_hdr *oh = msgb_l2(msg);
1878 int rc = 0;
1879
1880 /* Various consistency checks */
1881 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
1882 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
1883 oh->placement);
1884 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1885 return -EINVAL;
1886 }
1887 if (oh->sequence != 0) {
1888 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
1889 oh->sequence);
1890 return -EINVAL;
1891 }
1892 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1893
1894 switch (oh->mdisc) {
1895 case ABIS_OM_MDISC_FOM:
1896 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_FOM\n");
1897 rc = abis_nm_rcvmsg_fom(msg);
1898 break;
1899 case ABIS_OM_MDISC_MANUF:
1900 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_MANUF\n");
1901 break;
1902 case ABIS_OM_MDISC_MMI:
1903 case ABIS_OM_MDISC_TRAU:
1904 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
1905 oh->mdisc);
1906 break;
1907 default:
1908 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
1909 oh->mdisc);
1910 return -EINVAL;
1911 }
1912
1913 msgb_free(msg);
1914 return rc;
1915}
1916
1917static int bts_model_nokia_site_start(struct gsm_network *net);
1918
1919static struct gsm_bts_model model_nokia_site = {
1920 .type = GSM_BTS_TYPE_NOKIA_SITE,
1921 .name = "nokia_site",
1922 .start = bts_model_nokia_site_start,
1923 .oml_rcvmsg = &abis_nokia_rcvmsg
1924};
1925
1926static struct gsm_network *my_net;
1927
1928static int bts_model_nokia_site_start(struct gsm_network *net)
1929{
1930 model_nokia_site.features.data = &model_nokia_site._features_data[0];
1931 model_nokia_site.features.data_len = sizeof(model_nokia_site._features_data);
1932
1933 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HOPPING);
1934 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HSCSD);
1935
1936 osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
1937 osmo_signal_register_handler(SS_GLOBAL, gbl_sig_cb, NULL);
1938 osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
1939
1940 my_net = net;
1941
1942 return 0;
1943}
1944
1945int bts_model_nokia_site_init(void)
1946{
1947 return gsm_bts_model_register(&model_nokia_site);
1948}
1949