blob: 3ca76c017e4c1589c54c3d4c6593bf829d95e826 [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>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020036#include <osmocom/abis/e1_input.h>
Dieter Spaar16646022011-07-28 00:01:50 +020037#include <openbsc/signal.h>
38
39#include <osmocom/core/timer.h>
40
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020041#include <osmocom/abis/lapd.h>
Dieter Spaar16646022011-07-28 00:01:50 +020042
43/* TODO: put in a separate file ? */
44
Dieter Spaar16646022011-07-28 00:01:50 +020045extern int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg);
46/* was static in system_information.c */
Harald Weltebda367c2011-07-28 00:03:49 +020047extern int generate_cell_chan_list(uint8_t * chan_list, struct gsm_bts *bts);
Dieter Spaar16646022011-07-28 00:01:50 +020048
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020049static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts);
Dieter Spaar16646022011-07-28 00:01:50 +020050static void reset_timer_cb(void *_bts);
51static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref);
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +020052static int dump_elements(uint8_t * data, int len) __attribute__((unused));
Dieter Spaar16646022011-07-28 00:01:50 +020053
54static void bootstrap_om_bts(struct gsm_bts *bts)
55{
Harald Weltebda367c2011-07-28 00:03:49 +020056 LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
57
Sylvain Munautc9519462011-10-17 14:04:55 +020058 if (!bts->nokia.skip_reset) {
59 if (!bts->nokia.did_reset)
60 abis_nm_reset(bts, 1);
61 } else
62 bts->nokia.did_reset = 1;
Dieter Spaar16646022011-07-28 00:01:50 +020063}
64
65static void bootstrap_om_trx(struct gsm_bts_trx *trx)
66{
Harald Weltebda367c2011-07-28 00:03:49 +020067 LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
68 trx->bts->nr, trx->nr);
Dieter Spaar16646022011-07-28 00:01:50 +020069}
70
71static int shutdown_om(struct gsm_bts *bts)
72{
Harald Weltebda367c2011-07-28 00:03:49 +020073 /* TODO !? */
74 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +020075}
76
77#define SAPI_OML 62
78#define SAPI_RSL 0
79
Harald Weltecde57942011-07-28 00:13:46 +020080/*
Dieter Spaar16646022011-07-28 00:01:50 +020081
82 Tell LAPD to start start the SAP (send SABM requests) for all signalling
Harald Weltecde57942011-07-28 00:13:46 +020083 timeslots in this line
84
85 Attention: this has to be adapted for mISDN
Dieter Spaar16646022011-07-28 00:01:50 +020086*/
Harald Weltebda367c2011-07-28 00:03:49 +020087
Andreas Eversbergc57e6ed2011-09-26 11:44:22 +020088static void start_sabm_in_line(struct e1inp_line *line, int start, int sapi)
Dieter Spaar16646022011-07-28 00:01:50 +020089{
Harald Weltebda367c2011-07-28 00:03:49 +020090 struct e1inp_sign_link *link;
91 int i;
Dieter Spaar16646022011-07-28 00:01:50 +020092
Harald Weltebda367c2011-07-28 00:03:49 +020093 for (i = 0; i < ARRAY_SIZE(line->ts); i++) {
94 struct e1inp_ts *ts = &line->ts[i];
Dieter Spaar16646022011-07-28 00:01:50 +020095
Harald Weltebda367c2011-07-28 00:03:49 +020096 if (ts->type != E1INP_TS_TYPE_SIGN)
97 continue;
Dieter Spaar16646022011-07-28 00:01:50 +020098
Harald Weltebda367c2011-07-28 00:03:49 +020099 llist_for_each_entry(link, &ts->sign.sign_links, list) {
100 if (sapi != -1 && link->sapi != sapi)
101 continue;
102
103#if 0 /* debugging */
104 printf("sap start/stop (%d): %d tei=%d sapi=%d\n",
105 start, i + 1, link->tei, link->sapi);
Dieter Spaar16646022011-07-28 00:01:50 +0200106#endif
Harald Weltebda367c2011-07-28 00:03:49 +0200107
Andreas.Eversbergbb5c5942011-11-02 22:22:24 +0100108 if (start) {
109 ts->lapd->profile.t200_sec = 1;
110 ts->lapd->profile.t200_usec = 0;
Harald Welteb4d913d2011-08-26 19:14:55 +0200111 lapd_sap_start(ts->lapd, link->tei,
Harald Weltebda367c2011-07-28 00:03:49 +0200112 link->sapi);
Andreas.Eversbergbb5c5942011-11-02 22:22:24 +0100113 } else
Harald Welteb4d913d2011-08-26 19:14:55 +0200114 lapd_sap_stop(ts->lapd, link->tei,
Harald Weltebda367c2011-07-28 00:03:49 +0200115 link->sapi);
116 }
117 }
Dieter Spaar16646022011-07-28 00:01:50 +0200118}
119
120/* Callback function to be called every time we receive a signal from INPUT */
121static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200122 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200123{
Harald Weltebda367c2011-07-28 00:03:49 +0200124 struct gsm_bts *bts;
Dieter Spaar16646022011-07-28 00:01:50 +0200125
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200126 if (subsys != SS_L_GLOBAL)
Harald Weltebda367c2011-07-28 00:03:49 +0200127 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200128
Harald Weltebda367c2011-07-28 00:03:49 +0200129 switch (signal) {
130 case S_GLOBAL_BTS_CLOSE_OM:
131 bts = signal_data;
132 if (bts->type == GSM_BTS_TYPE_NOKIA_SITE)
133 shutdown_om(signal_data);
134 break;
135 }
Dieter Spaar16646022011-07-28 00:01:50 +0200136
Harald Weltebda367c2011-07-28 00:03:49 +0200137 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200138}
139
140/* Callback function to be called every time we receive a signal from INPUT */
141static int inp_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200142 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200143{
Harald Weltebda367c2011-07-28 00:03:49 +0200144 struct input_signal_data *isd = signal_data;
Dieter Spaar16646022011-07-28 00:01:50 +0200145
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200146 if (subsys != SS_L_INPUT)
Harald Weltebda367c2011-07-28 00:03:49 +0200147 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200148
Harald Weltebda367c2011-07-28 00:03:49 +0200149 switch (signal) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200150 case S_L_INP_LINE_INIT:
Harald Weltebda367c2011-07-28 00:03:49 +0200151 start_sabm_in_line(isd->line, 1, SAPI_OML); /* start only OML */
152 break;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200153 case S_L_INP_TEI_DN:
Harald Weltebda367c2011-07-28 00:03:49 +0200154 break;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200155 case S_L_INP_TEI_UP:
Harald Weltebda367c2011-07-28 00:03:49 +0200156 switch (isd->link_type) {
157 case E1INP_SIGN_OML:
158 if (isd->trx->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
159 break;
Dieter Spaar16646022011-07-28 00:01:50 +0200160
Harald Weltebda367c2011-07-28 00:03:49 +0200161 if (isd->tei == isd->trx->bts->oml_tei)
162 bootstrap_om_bts(isd->trx->bts);
163 else
164 bootstrap_om_trx(isd->trx);
165 break;
166 }
167 break;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200168 case S_L_INP_TEI_UNKNOWN:
Pablo Neira Ayuso2962c202011-08-10 00:48:10 +0200169 /* We are receiving LAPD frames with one TEI that we do not
170 * seem to know, likely that we (the BSC) stopped working
171 * and lost our local states. However, the BTS is already
172 * configured, we try to take over the RSL links. */
173 start_sabm_in_line(isd->line, 1, SAPI_RSL);
174 break;
Harald Weltebda367c2011-07-28 00:03:49 +0200175 }
176
177 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200178}
179
180static void nm_statechg_evt(unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200181 struct nm_statechg_signal_data *nsd)
Dieter Spaar16646022011-07-28 00:01:50 +0200182{
Harald Weltebda367c2011-07-28 00:03:49 +0200183 if (nsd->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
184 return;
Dieter Spaar16646022011-07-28 00:01:50 +0200185}
186
187static int nm_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200188 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200189{
Harald Weltebda367c2011-07-28 00:03:49 +0200190 if (subsys != SS_NM)
191 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200192
Harald Weltebda367c2011-07-28 00:03:49 +0200193 switch (signal) {
194 case S_NM_STATECHG_OPER:
195 case S_NM_STATECHG_ADM:
196 nm_statechg_evt(signal, signal_data);
197 break;
198 default:
199 break;
200 }
Dieter Spaar16646022011-07-28 00:01:50 +0200201
Harald Weltebda367c2011-07-28 00:03:49 +0200202 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200203}
204
205/* TODO: put in a separate file ? */
206
Harald Welte44d26112011-07-28 00:43:13 +0200207static const struct value_string nokia_msgt_name[] = {
208 { 0x80, "NOKIA_BTS_CONF_DATA" },
209 { 0x81, "NOKIA_BTS_ACK" },
210 { 0x82, "NOKIA_BTS_OMU_STARTED" },
211 { 0x83, "NOKIA_BTS_START_DOWNLOAD_REQ" },
212 { 0x84, "NOKIA_BTS_MF_REQ" },
213 { 0x85, "NOKIA_BTS_AF_REQ" },
214 { 0x86, "NOKIA_BTS_RESET_REQ" },
215 { 0x87, "NOKIA_reserved" },
216 { 0x88, "NOKIA_BTS_CONF_REQ" },
217 { 0x89, "NOKIA_BTS_TEST_REQ" },
218 { 0x8A, "NOKIA_BTS_TEST_REPORT" },
219 { 0x8B, "NOKIA_reserved" },
220 { 0x8C, "NOKIA_reserved" },
221 { 0x8D, "NOKIA_reserved" },
222 { 0x8E, "NOKIA_BTS_CONF_COMPL" },
223 { 0x8F, "NOKIA_reserved" },
224 { 0x90, "NOKIA_BTS_STM_TEST_REQ" },
225 { 0x91, "NOKIA_BTS_STM_TEST_REPORT" },
226 { 0x92, "NOKIA_BTS_TRANSMISSION_COMMAND" },
227 { 0x93, "NOKIA_BTS_TRANSMISSION_ANSWER" },
228 { 0x94, "NOKIA_BTS_HW_DB_UPLOAD_REQ" },
229 { 0x95, "NOKIA_BTS_START_HW_DB_DOWNLOAD_REQ" },
230 { 0x96, "NOKIA_BTS_HW_DB_SAVE_REQ" },
231 { 0x97, "NOKIA_BTS_FLASH_ERASURE_REQ" },
232 { 0x98, "NOKIA_BTS_HW_DB_DOWNLOAD_REQ" },
233 { 0x99, "NOKIA_BTS_PWR_SUPPLY_CONTROL" },
234 { 0x9A, "NOKIA_BTS_ATTRIBUTE_REQ" },
235 { 0x9B, "NOKIA_BTS_ATTRIBUTE_REPORT" },
236 { 0x9C, "NOKIA_BTS_HW_REQ" },
237 { 0x9D, "NOKIA_BTS_HW_REPORT" },
238 { 0x9E, "NOKIA_BTS_RTE_TEST_REQ" },
239 { 0x9F, "NOKIA_BTS_RTE_TEST_REPORT" },
240 { 0xA0, "NOKIA_BTS_HW_DB_VERIFICATION_REQ" },
241 { 0xA1, "NOKIA_BTS_CLOCK_REQ" },
242 { 0xA2, "NOKIA_AC_CIRCUIT_REQ_NACK" },
243 { 0xA3, "NOKIA_AC_INTERRUPTED" },
244 { 0xA4, "NOKIA_BTS_NEW_TRE_INFO" },
245 { 0xA5, "NOKIA_AC_BSC_CIRCUITS_ALLOCATED" },
246 { 0xA6, "NOKIA_BTS_TRE_POLL_LIST" },
247 { 0xA7, "NOKIA_AC_CIRCUIT_REQ" },
248 { 0xA8, "NOKIA_BTS_BLOCK_CTRL_REQ" },
249 { 0xA9, "NOKIA_BTS_GSM_TIME_REQ" },
250 { 0xAA, "NOKIA_BTS_GSM_TIME" },
251 { 0xAB, "NOKIA_BTS_OUTPUT_CONTROL" },
252 { 0xAC, "NOKIA_BTS_STATE_CHANGED" },
253 { 0xAD, "NOKIA_BTS_SW_SAVE_REQ" },
254 { 0xAE, "NOKIA_BTS_ALARM" },
255 { 0xAF, "NOKIA_BTS_CHA_ADM_STATE" },
256 { 0xB0, "NOKIA_AC_POOL_SIZE_REPORT" },
257 { 0xB1, "NOKIA_AC_POOL_SIZE_INQUIRY" },
258 { 0xB2, "NOKIA_BTS_COMMISS_TEST_COMPLETED" },
259 { 0xB3, "NOKIA_BTS_COMMISS_TEST_REQ" },
260 { 0xB4, "NOKIA_BTS_TRANSP_BTS_TO_BSC" },
261 { 0xB5, "NOKIA_BTS_TRANSP_BSC_TO_BTS" },
262 { 0xB6, "NOKIA_BTS_LCS_COMMAND" },
263 { 0xB7, "NOKIA_BTS_LCS_ANSWER" },
264 { 0xB8, "NOKIA_BTS_LMU_FN_OFFSET_COMMAND" },
265 { 0xB9, "NOKIA_BTS_LMU_FN_OFFSET_ANSWER" },
266 { 0, NULL }
267};
268
269static const char *get_msg_type_name_string(uint8_t msg_type)
Dieter Spaar16646022011-07-28 00:01:50 +0200270{
Harald Welte44d26112011-07-28 00:43:13 +0200271 return get_value_string(nokia_msgt_name, msg_type);
Dieter Spaar16646022011-07-28 00:01:50 +0200272}
273
Harald Welte44d26112011-07-28 00:43:13 +0200274static const struct value_string nokia_element_name[] = {
275 { 0x01, "Ny1" },
276 { 0x02, "T3105_F" },
277 { 0x03, "Interference band limits" },
278 { 0x04, "Interference report timer in secs" },
279 { 0x05, "Channel configuration per TS" },
280 { 0x06, "BSIC" },
281 { 0x07, "RACH report timer in secs" },
282 { 0x08, "Hardware database status" },
283 { 0x09, "BTS RX level" },
284 { 0x0A, "ARFN" },
285 { 0x0B, "STM antenna attenuation" },
286 { 0x0C, "Cell allocation bitmap" },
287 { 0x0D, "Radio definition per TS" },
288 { 0x0E, "Frame number" },
289 { 0x0F, "Antenna diversity" },
290 { 0x10, "T3105_D" },
291 { 0x11, "File format" },
292 { 0x12, "Last File" },
293 { 0x13, "BTS type" },
294 { 0x14, "Erasure mode" },
295 { 0x15, "Hopping mode" },
296 { 0x16, "Floating TRX" },
297 { 0x17, "Power supplies" },
298 { 0x18, "Reset type" },
299 { 0x19, "Averaging period" },
300 { 0x1A, "RBER2" },
301 { 0x1B, "LAC" },
302 { 0x1C, "CI" },
303 { 0x1D, "Failure parameters" },
304 { 0x1E, "(RF max power reduction)" },
305 { 0x1F, "Measured RX_SENS" },
306 { 0x20, "Extended cell radius" },
307 { 0x21, "reserved" },
308 { 0x22, "Success-Failure" },
309 { 0x23, "Ack-Nack" },
310 { 0x24, "OMU test results" },
311 { 0x25, "File identity" },
312 { 0x26, "Generation and version code" },
313 { 0x27, "SW description" },
314 { 0x28, "BCCH LEV" },
315 { 0x29, "Test type" },
316 { 0x2A, "Subscriber number" },
317 { 0x2B, "reserved" },
318 { 0x2C, "HSN" },
319 { 0x2D, "reserved" },
320 { 0x2E, "MS RXLEV" },
321 { 0x2F, "MS TXLEV" },
322 { 0x30, "RXQUAL" },
323 { 0x31, "RX SENS" },
324 { 0x32, "Alarm block" },
325 { 0x33, "Neighbouring BCCH levels" },
326 { 0x34, "STM report type" },
327 { 0x35, "MA" },
328 { 0x36, "MAIO" },
329 { 0x37, "H_FLAG" },
330 { 0x38, "TCH_ARFN" },
331 { 0x39, "Clock output" },
332 { 0x3A, "Transmitted power" },
333 { 0x3B, "Clock sync" },
334 { 0x3C, "TMS protocol discriminator" },
335 { 0x3D, "TMS protocol data" },
336 { 0x3E, "FER" },
337 { 0x3F, "SWR result" },
338 { 0x40, "Object identity" },
339 { 0x41, "STM RX Antenna Test" },
340 { 0x42, "reserved" },
341 { 0x43, "reserved" },
342 { 0x44, "Object current state" },
343 { 0x45, "reserved" },
344 { 0x46, "FU channel configuration" },
345 { 0x47, "reserved" },
346 { 0x48, "ARFN of a CU" },
347 { 0x49, "FU radio definition" },
348 { 0x4A, "reserved" },
349 { 0x4B, "Severity" },
350 { 0x4C, "Diversity selection" },
351 { 0x4D, "RX antenna test" },
352 { 0x4E, "RX antenna supervision period" },
353 { 0x4F, "RX antenna state" },
354 { 0x50, "Sector configuration" },
355 { 0x51, "Additional info" },
356 { 0x52, "SWR parameters" },
357 { 0x53, "HW inquiry mode" },
358 { 0x54, "reserved" },
359 { 0x55, "Availability status" },
360 { 0x56, "reserved" },
361 { 0x57, "EAC inputs" },
362 { 0x58, "EAC outputs" },
363 { 0x59, "reserved" },
364 { 0x5A, "Position" },
365 { 0x5B, "HW unit identity" },
366 { 0x5C, "RF test signal attenuation" },
367 { 0x5D, "Operational state" },
368 { 0x5E, "Logical object identity" },
369 { 0x5F, "reserved" },
370 { 0x60, "BS_TXPWR_OM" },
371 { 0x61, "Loop_Duration" },
372 { 0x62, "LNA_Path_Selection" },
373 { 0x63, "Serial number" },
374 { 0x64, "HW version" },
375 { 0x65, "Obj. identity and obj. state" },
376 { 0x66, "reserved" },
377 { 0x67, "EAC input definition" },
378 { 0x68, "EAC id and text" },
379 { 0x69, "HW unit status" },
380 { 0x6A, "SW release version" },
381 { 0x6B, "FW version" },
382 { 0x6C, "Bit_Error_Ratio" },
383 { 0x6D, "RXLEV_with_Attenuation" },
384 { 0x6E, "RXLEV_without_Attenuation" },
385 { 0x6F, "reserved" },
386 { 0x70, "CU_Results" },
387 { 0x71, "reserved" },
388 { 0x72, "LNA_Path_Results" },
389 { 0x73, "RTE Results" },
390 { 0x74, "Real Time" },
391 { 0x75, "RX diversity selection" },
392 { 0x76, "EAC input config" },
393 { 0x77, "Feature support" },
394 { 0x78, "File version" },
395 { 0x79, "Outputs" },
396 { 0x7A, "FU parameters" },
397 { 0x7B, "Diagnostic info" },
398 { 0x7C, "FU BSIC" },
399 { 0x7D, "TRX Configuration" },
400 { 0x7E, "Download status" },
401 { 0x7F, "RX difference limit" },
402 { 0x80, "TRX HW capability" },
403 { 0x81, "Common HW config" },
404 { 0x82, "Autoconfiguration pool size" },
405 { 0x83, "TRE diagnostic info" },
406 { 0x84, "TRE object identity" },
407 { 0x85, "New TRE Info" },
408 { 0x86, "Acknowledgement period" },
409 { 0x87, "Synchronization mode" },
410 { 0x88, "reserved" },
411 { 0x89, "Block Control Data" },
412 { 0x8A, "SW load mode" },
413 { 0x8B, "Recommended recovery action" },
414 { 0x8C, "BSC BCF id" },
415 { 0x8D, "Q1 baud rate" },
416 { 0x8E, "Allocation status" },
417 { 0x8F, "Functional entity number" },
418 { 0x90, "Transmission delay" },
419 { 0x91, "Loop Duration ms" },
420 { 0x92, "Logical channel" },
421 { 0x93, "Q1 address" },
422 { 0x94, "Alarm detail" },
423 { 0x95, "Cabinet type" },
424 { 0x96, "HW unit existence" },
425 { 0x97, "RF power parameters" },
426 { 0x98, "Message scenario" },
427 { 0x99, "HW unit max amount" },
428 { 0x9A, "Master TRX" },
429 { 0x9B, "Transparent data" },
430 { 0x9C, "BSC topology info" },
431 { 0x9D, "Air i/f modulation" },
432 { 0x9E, "LCS Q1 command data" },
433 { 0x9F, "Frame number offset" },
434 { 0xA0, "Abis TSL" },
435 { 0xA1, "Dynamic pool info" },
436 { 0xA2, "LCS LLP data" },
437 { 0xA3, "LCS Q1 answer data" },
438 { 0xA4, "DFCA FU Radio Definition" },
439 { 0xA5, "Antenna hopping" },
440 { 0xA6, "Field record sequence number" },
441 { 0xA7, "Timeslot offslot" },
442 { 0xA8, "EPCR capability" },
443 { 0xA9, "Connectsite optional element" },
444 { 0xAA, "TSC" },
445 { 0xAB, "Special TX Power Setting" },
446 { 0xAC, "Optional sync settings" },
447 { 0xFA, "Abis If parameters" },
448 { 0, NULL }
449};
450
451static const char *get_element_name_string(uint16_t element)
Dieter Spaar16646022011-07-28 00:01:50 +0200452{
Harald Welte44d26112011-07-28 00:43:13 +0200453 return get_value_string(nokia_element_name, element);
Dieter Spaar16646022011-07-28 00:01:50 +0200454}
455
Harald Welte3c3003f2011-07-28 00:28:20 +0200456static const struct value_string nokia_bts_types[] = {
457 { 0x0a, "MetroSite GSM 900" },
458 { 0x0b, "MetroSite GSM 1800" },
459 { 0x0c, "MetroSite GSM 1900 (PCS)" },
460 { 0x0d, "MetroSite GSM 900 & 1800" },
461 { 0x0e, "InSite GSM 900" },
462 { 0x0f, "InSite GSM 1800" },
463 { 0x10, "InSite GSM 1900" },
464 { 0x11, "UltraSite GSM 900" },
465 { 0x12, "UltraSite GSM 1800" },
466 { 0x13, "UltraSite GSM/US-TDMA 1900" },
467 { 0x14, "UltraSite GSM 900 & 1800" },
468 { 0x16, "UltraSite GSM/US-TDMA 850" },
469 { 0x18, "MetroSite GSM/US-TDMA 850" },
470 { 0x19, "UltraSite GSM 800/1900" },
471 { 0, NULL }
472};
473
474static const char *get_bts_type_string(uint8_t type)
Dieter Spaar16646022011-07-28 00:01:50 +0200475{
Harald Welte3c3003f2011-07-28 00:28:20 +0200476 return get_value_string(nokia_bts_types, type);
Dieter Spaar16646022011-07-28 00:01:50 +0200477}
478
Harald Welte3c3003f2011-07-28 00:28:20 +0200479static const struct value_string nokia_severity[] = {
480 { 0, "indeterminate" },
481 { 1, "critical" },
482 { 2, "major" },
483 { 3, "minor" },
484 { 4, "warning" },
485 { 0, NULL }
486};
487
488static const char *get_severity_string(uint8_t severity)
Dieter Spaar16646022011-07-28 00:01:50 +0200489{
Harald Welte3c3003f2011-07-28 00:28:20 +0200490 return get_value_string(nokia_severity, severity);
Dieter Spaar16646022011-07-28 00:01:50 +0200491}
492
493/* TODO: put in a separate file ? */
494
495/* some message IDs */
496
497#define NOKIA_MSG_CONF_DATA 128
498#define NOKIA_MSG_ACK 129
499#define NOKIA_MSG_OMU_STARTED 130
500#define NOKIA_MSG_START_DOWNLOAD_REQ 131
501#define NOKIA_MSG_MF_REQ 132
502#define NOKIA_MSG_RESET_REQ 134
503#define NOKIA_MSG_CONF_REQ 136
504#define NOKIA_MSG_CONF_COMPLETE 142
505#define NOKIA_MSG_BLOCK_CTRL_REQ 168
506#define NOKIA_MSG_STATE_CHANGED 172
507#define NOKIA_MSG_ALARM 174
508
509/* some element IDs */
510
511#define NOKIA_EI_BTS_TYPE 0x13
512#define NOKIA_EI_ACK 0x23
513#define NOKIA_EI_ADD_INFO 0x51
514#define NOKIA_EI_SEVERITY 0x4B
515#define NOKIA_EI_ALARM_DETAIL 0x94
516
517#define OM_ALLOC_SIZE 1024
518#define OM_HEADROOM_SIZE 128
519
Harald Weltebda367c2011-07-28 00:03:49 +0200520static uint8_t fu_config_template[] = {
521 0x7F, 0x7A, 0x39,
522 /* ID = 0x7A (FU parameters) ## constructed ## */
523 /* length = 57 */
524 /* [3] */
Dieter Spaar16646022011-07-28 00:01:50 +0200525
Harald Weltebda367c2011-07-28 00:03:49 +0200526 0x5F, 0x40, 0x04,
527 /* ID = 0x40 (Object identity) */
528 /* length = 4 */
529 /* [6] */
530 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200531
Harald Weltebda367c2011-07-28 00:03:49 +0200532 0x41, 0x02,
533 /* ID = 0x01 (Ny1) */
534 /* length = 2 */
535 /* [12] */
536 0x00, 0x05,
Dieter Spaar16646022011-07-28 00:01:50 +0200537
Harald Weltebda367c2011-07-28 00:03:49 +0200538 0x42, 0x02,
539 /* ID = 0x02 (T3105_F) */
540 /* length = 2 */
541 /* [16] */
Harald Welte67161f22012-06-03 13:01:47 +0200542 0x00, 0x28, /* FIXME: use net->T3105 */
Dieter Spaar16646022011-07-28 00:01:50 +0200543
Harald Weltebda367c2011-07-28 00:03:49 +0200544 0x50, 0x02,
545 /* ID = 0x10 (T3105_D) */
546 /* length = 2 */
547 /* [20] */
Harald Welte67161f22012-06-03 13:01:47 +0200548 0x00, 0x28, /* FIXME: use net->T3105 */
Dieter Spaar16646022011-07-28 00:01:50 +0200549
Harald Weltebda367c2011-07-28 00:03:49 +0200550 0x43, 0x05,
551 /* ID = 0x03 (Interference band limits) */
552 /* length = 5 */
553 /* [24] */
554 0x0F, 0x1B, 0x27, 0x33, 0x3F,
Dieter Spaar16646022011-07-28 00:01:50 +0200555
Harald Weltebda367c2011-07-28 00:03:49 +0200556 0x44, 0x02,
557 /* ID = 0x04 (Interference report timer in secs) */
558 /* length = 2 */
559 /* [31] */
560 0x00, 0x10,
Dieter Spaar16646022011-07-28 00:01:50 +0200561
Harald Weltebda367c2011-07-28 00:03:49 +0200562 0x47, 0x01,
563 /* ID = 0x07 (RACH report timer in secs) */
564 /* length = 1 */
565 /* [35] */
566 0x1E,
Dieter Spaar16646022011-07-28 00:01:50 +0200567
Harald Weltebda367c2011-07-28 00:03:49 +0200568 0x4C, 0x10,
569 /* ID = 0x0C (Cell allocation bitmap) ####### */
570 /* length = 16 */
571 /* [38] */
572 0x8F, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200574
Harald Weltebda367c2011-07-28 00:03:49 +0200575 0x59, 0x01,
576 /* ID = 0x19 (Averaging period) */
577 /* length = 1 */
578 /* [56] */
579 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +0200580
Harald Weltebda367c2011-07-28 00:03:49 +0200581 0x5E, 0x01,
582 /* ID = 0x1E ((RF max power reduction)) */
583 /* length = 1 */
584 /* [59] */
585 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200586
Harald Weltebda367c2011-07-28 00:03:49 +0200587 0x7F, 0x46, 0x11,
588 /* ID = 0x46 (FU channel configuration) ## constructed ## */
589 /* length = 17 */
590 /* [63] */
Dieter Spaar16646022011-07-28 00:01:50 +0200591
Harald Weltebda367c2011-07-28 00:03:49 +0200592 0x5F, 0x40, 0x04,
593 /* ID = 0x40 (Object identity) */
594 /* length = 4 */
595 /* [66] */
596 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200597
Harald Weltebda367c2011-07-28 00:03:49 +0200598 0x45, 0x08,
599 /* ID = 0x05 (Channel configuration per TS) */
600 /* length = 8 */
601 /* [72] */
602 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
Dieter Spaar16646022011-07-28 00:01:50 +0200603
Harald Weltebda367c2011-07-28 00:03:49 +0200604 0x7F, 0x65, 0x0B,
605 /* ID = 0x65 (Obj. identity and obj. state) ## constructed ## */
606 /* length = 11 */
607 /* [83] */
Dieter Spaar16646022011-07-28 00:01:50 +0200608
Harald Weltebda367c2011-07-28 00:03:49 +0200609 0x5F, 0x40, 0x04,
610 /* ID = 0x40 (Object identity) */
611 /* length = 4 */
612 /* [86] */
613 0x00, 0x04, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200614
Harald Weltebda367c2011-07-28 00:03:49 +0200615 0x5F, 0x44, 0x01,
616 /* ID = 0x44 (Object current state) */
617 /* length = 1 */
618 /* [93] */
619 0x03,
Dieter Spaar16646022011-07-28 00:01:50 +0200620
Harald Weltebda367c2011-07-28 00:03:49 +0200621 0x7F, 0x7C, 0x0A,
622 /* ID = 0x7C (FU BSIC) ## constructed ## */
623 /* length = 10 */
624 /* [97] */
Dieter Spaar16646022011-07-28 00:01:50 +0200625
Harald Weltebda367c2011-07-28 00:03:49 +0200626 0x5F, 0x40, 0x04,
627 /* ID = 0x40 (Object identity) */
628 /* length = 4 */
629 /* [100] */
630 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200631
Harald Weltebda367c2011-07-28 00:03:49 +0200632 0x46, 0x01,
633 /* ID = 0x06 (BSIC) */
634 /* length = 1 */
635 /* [106] */
636 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200637
Harald Weltebda367c2011-07-28 00:03:49 +0200638 0x7F, 0x48, 0x0B,
639 /* ID = 0x48 (ARFN of a CU) ## constructed ## */
640 /* length = 11 */
641 /* [110] */
Dieter Spaar16646022011-07-28 00:01:50 +0200642
Harald Weltebda367c2011-07-28 00:03:49 +0200643 0x5F, 0x40, 0x04,
644 /* ID = 0x40 (Object identity) */
645 /* length = 4 */
646 /* [113] */
647 0x00, 0x08, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200648
Harald Weltebda367c2011-07-28 00:03:49 +0200649 0x4A, 0x02,
650 /* ID = 0x0A (ARFN) ####### */
651 /* length = 2 */
652 /* [119] */
653 0x03, 0x62,
Dieter Spaar16646022011-07-28 00:01:50 +0200654
Harald Weltebda367c2011-07-28 00:03:49 +0200655 0x7F, 0x49, 0x59,
656 /* ID = 0x49 (FU radio definition) ## constructed ## */
657 /* length = 89 */
658 /* [124] */
Dieter Spaar16646022011-07-28 00:01:50 +0200659
Harald Weltebda367c2011-07-28 00:03:49 +0200660 0x5F, 0x40, 0x04,
661 /* ID = 0x40 (Object identity) */
662 /* length = 4 */
663 /* [127] */
664 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200665
Harald Weltebda367c2011-07-28 00:03:49 +0200666 0x4D, 0x50,
667 /* ID = 0x0D (Radio definition per TS) ####### */
668 /* length = 80 */
669 /* [133] */
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MA */
671 0x03, 0x62, /* HSN, MAIO or ARFCN if no hopping */
672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673 0x03, 0x62,
674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675 0x03, 0x62,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 0x03, 0x62,
678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0x03, 0x62,
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x03, 0x62,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x03, 0x62,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x03, 0x62,
Dieter Spaar16646022011-07-28 00:01:50 +0200686};
687
688/* TODO: put in a separate file ? */
689
690/*
Harald Weltecde57942011-07-28 00:13:46 +0200691 build the configuration for each TRX
Dieter Spaar16646022011-07-28 00:01:50 +0200692*/
693
Harald Weltebda367c2011-07-28 00:03:49 +0200694static int make_fu_config(struct gsm_bts_trx *trx, uint8_t id,
695 uint8_t * fu_config, int *hopping)
Dieter Spaar16646022011-07-28 00:01:50 +0200696{
Harald Weltebda367c2011-07-28 00:03:49 +0200697 int i;
Dieter Spaar16646022011-07-28 00:01:50 +0200698
Harald Weltebda367c2011-07-28 00:03:49 +0200699 *hopping = 0;
700
701 memcpy(fu_config, fu_config_template, sizeof(fu_config_template));
702
703 /* set ID */
704
705 fu_config[6 + 2] = id;
706 fu_config[66 + 2] = id;
707 fu_config[86 + 2] = id;
708 fu_config[100 + 2] = id;
709 fu_config[113 + 2] = id;
710 fu_config[127 + 2] = id;
711
712 /* set ARFCN */
713
714 uint16_t arfcn = trx->arfcn;
715
716 fu_config[119] = arfcn >> 8;
717 fu_config[119 + 1] = arfcn & 0xFF;
718
719 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
720 struct gsm_bts_trx_ts *ts = &trx->ts[i];
721
722 if (ts->hopping.enabled) {
723 /* reverse order */
724 int j;
725 for (j = 0; j < ts->hopping.ma_len; j++)
726 fu_config[133 + (i * 10) + (7 - j)] =
727 ts->hopping.ma_data[j];
728 fu_config[133 + 8 + (i * 10)] = ts->hopping.hsn;
729 fu_config[133 + 8 + 1 + (i * 10)] = ts->hopping.maio;
730 *hopping = 1;
731 } else {
732 fu_config[133 + 8 + (i * 10)] = arfcn >> 8;
733 fu_config[133 + 8 + 1 + (i * 10)] = arfcn & 0xFF;
734 }
735 }
736
737 /* set BSIC */
738
Harald Weltecde57942011-07-28 00:13:46 +0200739 /*
Harald Weltebda367c2011-07-28 00:03:49 +0200740 Attention: all TRX except the first one seem to get the TSC
741 from the CHANNEL ACTIVATION command (in CHANNEL IDENTIFICATION,
Harald Weltecde57942011-07-28 00:13:46 +0200742 GSM 04.08 CHANNEL DESCRIPTION).
743 There was a bug in rsl_chan_activate_lchan() setting this parameter.
Harald Weltebda367c2011-07-28 00:03:49 +0200744 */
745
746 uint8_t bsic = trx->bts->bsic;
747
748 fu_config[106] = bsic;
749
750 /* set CA */
751
752 if (generate_cell_chan_list(&fu_config[38], trx->bts) != 0) {
753 fprintf(stderr, "generate_cell_chan_list failed\n");
754 return 0;
755 }
756
757 /* set channel configuration */
758
759 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
760 struct gsm_bts_trx_ts *ts = &trx->ts[i];
761 uint8_t chan_config;
762
763 /*
764 0 = FCCH + SCH + BCCH + CCCH
765 1 = FCCH + SCH + BCCH + CCCH + SDCCH/4 + SACCH/4
766 2 = BCCH + CCCH (This combination is not used in any BTS)
767 3 = FCCH + SCH + BCCH + CCCH + SDCCH/4 with SDCCH2 used as CBCH
768 4 = SDCCH/8 + SACCH/8
769 5 = SDCCH/8 with SDCCH2 used as CBCH
770 6 = TCH/F + FACCH/F + SACCH/F
771 7 = E-RACH (Talk family)
772 9 = Dual rate (capability for TCH/F and TCH/H)
773 10 = reserved for BTS internal use
Harald Weltecde57942011-07-28 00:13:46 +0200774 11 = PBCCH + PCCCH + PDTCH + PACCH + PTCCH (can be used in GPRS release 2).
775 0xFF = spare TS
Harald Weltebda367c2011-07-28 00:03:49 +0200776 */
777
778 if (ts->pchan == GSM_PCHAN_NONE)
779 chan_config = 0xFF;
780 else if (ts->pchan == GSM_PCHAN_CCCH)
781 chan_config = 0;
782 else if (ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
783 chan_config = 1;
784 else if (ts->pchan == GSM_PCHAN_TCH_F)
785 chan_config = 6; /* 9 should work too */
786 else if (ts->pchan == GSM_PCHAN_TCH_H)
787 chan_config = 9;
788 else if (ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C)
789 chan_config = 4;
790 else if (ts->pchan == GSM_PCHAN_PDCH)
791 chan_config = 11;
792 else {
793 fprintf(stderr,
794 "unsupported channel config %d for timeslot %d\n",
795 ts->pchan, i);
796 return 0;
797 }
798
799 fu_config[72 + i] = chan_config;
800 }
801 return sizeof(fu_config_template);
Dieter Spaar16646022011-07-28 00:01:50 +0200802}
803
804/* TODO: put in a separate file ? */
805
Harald Weltebda367c2011-07-28 00:03:49 +0200806static uint8_t bts_config_1[] = {
807 0x4E, 0x02,
808 /* ID = 0x0E (Frame number) */
809 /* length = 2 */
810 /* [2] */
811 0xFF, 0xFF,
812
813 0x5F, 0x4E, 0x02,
814 /* ID = 0x4E (RX antenna supervision period) */
815 /* length = 2 */
816 /* [7] */
817 0xFF, 0xFF,
818
819 0x5F, 0x50, 0x02,
820 /* ID = 0x50 (Sector configuration) */
821 /* length = 2 */
822 /* [12] */
823 0x01, 0x01,
824};
825
826static uint8_t bts_config_2[] = {
827 0x55, 0x02,
828 /* ID = 0x15 (Hopping mode) */
829 /* length = 2 */
830 /* [2] */
831 0x01, 0x00,
832
833 0x5F, 0x75, 0x02,
834 /* ID = 0x75 (RX diversity selection) */
835 /* length = 2 */
836 /* [7] */
837 0x01, 0x01,
838};
839
840static uint8_t bts_config_3[] = {
841 0x5F, 0x20, 0x02,
842 /* ID = 0x20 (Extended cell radius) */
843 /* length = 2 */
844 /* [3] */
845 0x01, 0x00,
846};
847
848static uint8_t bts_config_4[] = {
849 0x5F, 0x74, 0x09,
850 /* ID = 0x74 (Real Time) */
851 /* length = 9 */
852 /* [3] year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
853 0x07, 0xDB, 0x06, 0x02, 0x0B, 0x20, 0x0C, 0x00,
854 0x00,
855
856 0x5F, 0x76, 0x03,
857 /* ID = 0x76 (EAC input config) */
858 /* length = 3 */
859 /* [15] */
860 0x01, 0x01, 0x00,
861
862 0x5F, 0x76, 0x03,
863 /* ID = 0x76 (EAC input config) */
864 /* length = 3 */
865 /* [21] */
866 0x02, 0x01, 0x00,
867
868 0x5F, 0x76, 0x03,
869 /* ID = 0x76 (EAC input config) */
870 /* length = 3 */
871 /* [27] */
872 0x03, 0x01, 0x00,
873
874 0x5F, 0x76, 0x03,
875 /* ID = 0x76 (EAC input config) */
876 /* length = 3 */
877 /* [33] */
878 0x04, 0x01, 0x00,
879
880 0x5F, 0x76, 0x03,
881 /* ID = 0x76 (EAC input config) */
882 /* length = 3 */
883 /* [39] */
884 0x05, 0x01, 0x00,
885
886 0x5F, 0x76, 0x03,
887 /* ID = 0x76 (EAC input config) */
888 /* length = 3 */
889 /* [45] */
890 0x06, 0x01, 0x00,
891
892 0x5F, 0x76, 0x03,
893 /* ID = 0x76 (EAC input config) */
894 /* length = 3 */
895 /* [51] */
896 0x07, 0x01, 0x00,
897
898 0x5F, 0x76, 0x03,
899 /* ID = 0x76 (EAC input config) */
900 /* length = 3 */
901 /* [57] */
902 0x08, 0x01, 0x00,
903
904 0x5F, 0x76, 0x03,
905 /* ID = 0x76 (EAC input config) */
906 /* length = 3 */
907 /* [63] */
908 0x09, 0x01, 0x00,
909
910 0x5F, 0x76, 0x03,
911 /* ID = 0x76 (EAC input config) */
912 /* length = 3 */
913 /* [69] */
914 0x0A, 0x01, 0x00,
915};
916
917static uint8_t bts_config_insite[] = {
918 0x4E, 0x02,
919 /* ID = 0x0E (Frame number) */
920 /* length = 2 */
921 /* [2] */
922 0xFF, 0xFF,
923
924 0x5F, 0x4E, 0x02,
925 /* ID = 0x4E (RX antenna supervision period) */
926 /* length = 2 */
927 /* [7] */
928 0xFF, 0xFF,
929
930 0x5F, 0x50, 0x02,
931 /* ID = 0x50 (Sector configuration) */
932 /* length = 2 */
933 /* [12] */
934 0x01, 0x01,
935
936 0x55, 0x02,
937 /* ID = 0x15 (Hopping mode) */
938 /* length = 2 */
939 /* [16] */
940 0x01, 0x00,
941
942 0x5F, 0x20, 0x02,
943 /* ID = 0x20 (Extended cell radius) */
944 /* length = 2 */
945 /* [21] */
946 0x01, 0x00,
947
948 0x5F, 0x74, 0x09,
949 /* ID = 0x74 (Real Time) */
950 /* length = 9 */
951 /* [26] */
952 0x07, 0xDB, 0x07, 0x0A, 0x0F, 0x09, 0x0B, 0x00,
953 0x00,
954};
955
956void set_real_time(uint8_t * real_time)
Dieter Spaar16646022011-07-28 00:01:50 +0200957{
Harald Weltebda367c2011-07-28 00:03:49 +0200958 time_t t;
959 struct tm *tm;
Dieter Spaar16646022011-07-28 00:01:50 +0200960
Harald Weltebda367c2011-07-28 00:03:49 +0200961 t = time(NULL);
962 tm = localtime(&t);
Dieter Spaar16646022011-07-28 00:01:50 +0200963
Harald Weltebda367c2011-07-28 00:03:49 +0200964 /* year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
Dieter Spaar16646022011-07-28 00:01:50 +0200965
Harald Weltebda367c2011-07-28 00:03:49 +0200966 real_time[0] = (1900 + tm->tm_year) >> 8;
967 real_time[1] = (1900 + tm->tm_year) & 0xFF;
968 real_time[2] = tm->tm_mon + 1;
969 real_time[3] = tm->tm_mday;
970 real_time[4] = tm->tm_hour;
971 real_time[5] = tm->tm_min;
972 real_time[6] = tm->tm_sec;
973 real_time[7] = 0;
974 real_time[8] = 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200975}
976
977/* TODO: put in a separate file ? */
978
979/*
Dieter Spaar16646022011-07-28 00:01:50 +0200980 build the configuration data
Dieter Spaar16646022011-07-28 00:01:50 +0200981*/
982
Harald Weltebda367c2011-07-28 00:03:49 +0200983static int make_bts_config(uint8_t bts_type, int n_trx, uint8_t * fu_config,
984 int need_hopping)
Dieter Spaar16646022011-07-28 00:01:50 +0200985{
Harald Weltebda367c2011-07-28 00:03:49 +0200986 /* is it an InSite BTS ? */
987 if (bts_type == 0x0E || bts_type == 0x0F || bts_type == 0x10) { /* TODO */
988 if (n_trx != 1) {
989 fprintf(stderr, "InSite has only one TRX\n");
990 return 0;
991 }
992 if (need_hopping != 0) {
993 fprintf(stderr, "InSite does not support hopping\n");
994 return 0;
995 }
996 memcpy(fu_config, bts_config_insite, sizeof(bts_config_insite));
997 set_real_time(&fu_config[26]);
998 return sizeof(bts_config_insite);
999 }
Dieter Spaar16646022011-07-28 00:01:50 +02001000
Harald Weltebda367c2011-07-28 00:03:49 +02001001 int len = 0;
1002 int i;
1003
1004 memcpy(fu_config + len, bts_config_1, sizeof(bts_config_1));
1005
1006 /* set sector configuration */
1007 fu_config[len + 12 - 1] = 1 + n_trx; /* len */
1008 for (i = 0; i < n_trx; i++)
1009 fu_config[len + 12 + 1 + i] = ((i + 1) & 0xFF);
1010
1011 len += (sizeof(bts_config_1) + (n_trx - 1));
1012
1013 memcpy(fu_config + len, bts_config_2, sizeof(bts_config_2));
1014 /* set hopping mode (Baseband and RF hopping work for the MetroSite) */
1015 if (need_hopping)
1016 fu_config[len + 2 + 1] = 1; /* 0: no hopping, 1: Baseband hopping, 2: RF hopping */
1017 len += sizeof(bts_config_2);
1018
1019 /* set extended cell radius for each TRX */
1020 for (i = 0; i < n_trx; i++) {
1021 memcpy(fu_config + len, bts_config_3, sizeof(bts_config_3));
1022 fu_config[len + 3] = ((i + 1) & 0xFF);
1023 len += sizeof(bts_config_3);
1024 }
1025
1026 memcpy(fu_config + len, bts_config_4, sizeof(bts_config_4));
1027 set_real_time(&fu_config[len + 3]);
1028 len += sizeof(bts_config_4);
1029
1030 return len;
Dieter Spaar16646022011-07-28 00:01:50 +02001031}
1032
1033/* TODO: put in a separate file ? */
1034
1035static struct msgb *nm_msgb_alloc(void)
1036{
Harald Weltebda367c2011-07-28 00:03:49 +02001037 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML");
Dieter Spaar16646022011-07-28 00:01:50 +02001038}
1039
1040/* TODO: put in a separate file ? */
1041
1042struct abis_om_nokia_hdr {
Harald Weltebda367c2011-07-28 00:03:49 +02001043 uint8_t msg_type;
1044 uint8_t spare;
1045 uint16_t reference;
1046 uint8_t data[0];
Dieter Spaar16646022011-07-28 00:01:50 +02001047} __attribute__ ((packed));
1048
1049#define ABIS_OM_NOKIA_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_nokia_hdr))
1050
Harald Weltebda367c2011-07-28 00:03:49 +02001051static int abis_nm_send(struct gsm_bts *bts, uint8_t msg_type, uint16_t ref,
1052 uint8_t * data, int len_data)
Dieter Spaar16646022011-07-28 00:01:50 +02001053{
Harald Weltebda367c2011-07-28 00:03:49 +02001054 struct abis_om_hdr *oh;
1055 struct abis_om_nokia_hdr *noh;
1056 struct msgb *msg = nm_msgb_alloc();
Dieter Spaar16646022011-07-28 00:01:50 +02001057
Harald Weltebda367c2011-07-28 00:03:49 +02001058 oh = (struct abis_om_hdr *)msgb_put(msg,
1059 ABIS_OM_NOKIA_HDR_SIZE + len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001060
Harald Weltebda367c2011-07-28 00:03:49 +02001061 oh->mdisc = ABIS_OM_MDISC_FOM;
1062 oh->placement = ABIS_OM_PLACEMENT_ONLY;
1063 oh->sequence = 0;
1064 oh->length = sizeof(struct abis_om_nokia_hdr) + len_data;
1065
1066 noh = (struct abis_om_nokia_hdr *)oh->data;
1067
1068 noh->msg_type = msg_type;
1069 noh->spare = 0;
1070 noh->reference = htons(ref);
1071 memcpy(noh->data, data, len_data);
1072
1073 DEBUGPC(DNM, "Sending %s\n", get_msg_type_name_string(msg_type));
1074
1075 return abis_nm_sendmsg(bts, msg);
Dieter Spaar16646022011-07-28 00:01:50 +02001076}
1077
1078/* TODO: put in a separate file ? */
1079
1080static uint8_t download_req[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001081 0x5F, 0x25, 0x0B,
1082 /* ID = 0x25 (File identity) */
1083 /* length = 11 */
1084 /* [3] */
1085 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
1086 0x2A, 0x2A, 0x2A,
Dieter Spaar16646022011-07-28 00:01:50 +02001087
Harald Weltebda367c2011-07-28 00:03:49 +02001088 0x5F, 0x78, 0x03,
1089 /* ID = 0x78 (File version) */
1090 /* length = 3 */
1091 /* [17] */
1092 0x2A, 0x2A, 0x2A,
Dieter Spaar16646022011-07-28 00:01:50 +02001093
Harald Weltebda367c2011-07-28 00:03:49 +02001094 0x5F, 0x81, 0x0A, 0x01,
1095 /* ID = 0x8A (SW load mode) */
1096 /* length = 1 */
1097 /* [24] */
1098 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001099
Harald Weltebda367c2011-07-28 00:03:49 +02001100 0x5F, 0x81, 0x06, 0x01,
1101 /* ID = 0x86 (Acknowledgement period) */
1102 /* length = 1 */
1103 /* [29] */
1104 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001105};
1106
1107static int abis_nm_download_req(struct gsm_bts *bts, uint16_t ref)
1108{
Harald Weltebda367c2011-07-28 00:03:49 +02001109 uint8_t *data = download_req;
1110 int len_data = sizeof(download_req);
1111
1112 return abis_nm_send(bts, NOKIA_MSG_START_DOWNLOAD_REQ, ref, data,
1113 len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001114}
1115
1116/* TODO: put in a separate file ? */
1117
1118static uint8_t ack[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001119 0x5F, 0x23, 0x01,
1120 /* ID = 0x23 (Ack-Nack) */
1121 /* length = 1 */
1122 /* [3] */
1123 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001124};
1125
1126static int abis_nm_ack(struct gsm_bts *bts, uint16_t ref)
1127{
Harald Weltebda367c2011-07-28 00:03:49 +02001128 uint8_t *data = ack;
1129 int len_data = sizeof(ack);
1130
1131 return abis_nm_send(bts, NOKIA_MSG_ACK, ref, data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001132}
1133
1134/* TODO: put in a separate file ? */
1135
1136static uint8_t reset[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001137 0x5F, 0x40, 0x04,
1138 /* ID = 0x40 (Object identity) */
1139 /* length = 4 */
1140 /* [3] */
1141 0x00, 0x01, 0xFF, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +02001142};
1143
1144static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref)
1145{
Harald Weltebda367c2011-07-28 00:03:49 +02001146 uint8_t *data = reset;
1147 int len_data = sizeof(reset);
Sipos Csaba56e17662015-02-07 13:27:36 +01001148 LOGP(DLINP, LOGL_INFO, "Nokia BTS reset timer: %d\n", bts->nokia.bts_reset_timer_cnf);
Harald Weltebda367c2011-07-28 00:03:49 +02001149 return abis_nm_send(bts, NOKIA_MSG_RESET_REQ, ref, data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001150}
1151
1152/* TODO: put in a separate file ? */
1153
Harald Weltebda367c2011-07-28 00:03:49 +02001154static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type,
1155 uint16_t ref, uint8_t * data, int len)
Dieter Spaar16646022011-07-28 00:01:50 +02001156{
Harald Weltebda367c2011-07-28 00:03:49 +02001157 int len_remain, len_to_send, max_send;
1158 int seq = 0;
1159 int ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001160
Harald Weltebda367c2011-07-28 00:03:49 +02001161 len_remain = len;
1162
1163 while (len_remain) {
1164 struct abis_om_hdr *oh;
1165 struct abis_om_nokia_hdr *noh;
1166 struct msgb *msg = nm_msgb_alloc();
1167
1168 if (seq == 0)
1169 max_send = 256 - sizeof(struct abis_om_nokia_hdr);
1170 else
1171 max_send = 256;
1172
1173 if (len_remain > max_send) {
1174 len_to_send = max_send;
1175
1176 if (seq == 0) {
1177 /* first segment */
1178 oh = (struct abis_om_hdr *)msgb_put(msg,
1179 ABIS_OM_NOKIA_HDR_SIZE
1180 +
1181 len_to_send);
1182
1183 oh->mdisc = ABIS_OM_MDISC_FOM;
1184 oh->placement = ABIS_OM_PLACEMENT_FIRST; /* first segment of multi-segment message */
1185 oh->sequence = seq;
1186 oh->length = 0; /* 256 bytes */
1187
1188 noh = (struct abis_om_nokia_hdr *)oh->data;
1189
1190 noh->msg_type = msg_type;
1191 noh->spare = 0;
1192 noh->reference = htons(ref);
1193 memcpy(noh->data, data, len_to_send);
1194 } else {
1195 /* segment in between */
1196 oh = (struct abis_om_hdr *)msgb_put(msg,
1197 sizeof
1198 (struct
1199 abis_om_hdr)
1200 +
1201 len_to_send);
1202
1203 oh->mdisc = ABIS_OM_MDISC_FOM;
1204 oh->placement = ABIS_OM_PLACEMENT_MIDDLE; /* segment of multi-segment message */
1205 oh->sequence = seq;
1206 oh->length = 0; /* 256 bytes */
1207
1208 memcpy(oh->data, data, len_to_send);
1209 }
1210 } else {
1211
1212 len_to_send = len_remain;
1213
1214 /* check if message fits in a single segment */
1215
1216 if (seq == 0)
1217 return abis_nm_send(bts, msg_type, ref, data,
1218 len_to_send);
1219
1220 /* last segment */
1221
1222 oh = (struct abis_om_hdr *)msgb_put(msg,
1223 sizeof(struct
1224 abis_om_hdr)
1225 + len_to_send);
1226
1227 oh->mdisc = ABIS_OM_MDISC_FOM;
1228 oh->placement = ABIS_OM_PLACEMENT_LAST; /* last segment of multi-segment message */
1229 oh->sequence = seq;
1230 oh->length = len_to_send;
1231
1232 memcpy(oh->data, data, len_to_send);
1233 }
1234
1235 DEBUGPC(DNM, "Sending multi-segment %d\n", seq);
1236
1237 ret = abis_nm_sendmsg(bts, msg);
1238 if (ret < 0)
1239 return ret;
1240
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001241 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001242
1243 /* next segment */
1244 len_remain -= len_to_send;
1245 data += len_to_send;
1246 seq++;
1247 }
1248 return ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001249}
1250
1251/* TODO: put in a separate file ? */
1252
1253static int abis_nm_send_config(struct gsm_bts *bts, uint8_t bts_type)
1254{
Harald Weltebda367c2011-07-28 00:03:49 +02001255 struct gsm_bts_trx *trx;
1256 uint8_t config[2048]; /* TODO: might be too small if lots of TRX are used */
1257 int len = 0;
1258 int idx = 0;
1259 int ret;
1260 int hopping = 0;
1261 int need_hopping = 0;
1262
1263 memset(config, 0, sizeof(config));
1264
1265 llist_for_each_entry(trx, &bts->trx_list, list) {
1266#if 0 /* debugging */
1267 printf("TRX\n");
1268 printf(" arfcn: %d\n", trx->arfcn);
1269 printf(" bsic: %d\n", trx->bts->bsic);
1270 uint8_t ca[20];
1271 memset(ca, 0xFF, sizeof(ca));
1272 ret = generate_cell_chan_list(ca, trx->bts);
1273 printf(" ca (%d): %s\n", ret, osmo_hexdump(ca, sizeof(ca)));
1274 int i;
1275 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
1276 struct gsm_bts_trx_ts *ts = &trx->ts[i];
1277
1278 printf(" pchan %d: %d\n", i, ts->pchan);
1279 }
Dieter Spaar16646022011-07-28 00:01:50 +02001280#endif
Harald Weltebda367c2011-07-28 00:03:49 +02001281 ret = make_fu_config(trx, idx + 1, config + len, &hopping);
1282 need_hopping |= hopping;
1283 len += ret;
1284
1285 idx++;
1286 }
1287
1288 ret = make_bts_config(bts_type, idx, config + len, need_hopping);
1289 len += ret;
1290
1291#if 0 /* debugging */
1292 dump_elements(config, len);
1293#endif
1294
1295 return abis_nm_send_multi_segments(bts, NOKIA_MSG_CONF_DATA, 1, config,
1296 len);
Dieter Spaar16646022011-07-28 00:01:50 +02001297}
1298
1299#define GET_NEXT_BYTE if(idx >= len) return 0; \
Harald Weltebda367c2011-07-28 00:03:49 +02001300 ub = data[idx++];
Dieter Spaar16646022011-07-28 00:01:50 +02001301
Harald Weltebda367c2011-07-28 00:03:49 +02001302static int find_element(uint8_t * data, int len, uint16_t id, uint8_t * value,
1303 int max_value)
1304{
1305 uint8_t ub;
1306 int idx = 0;
1307 int found = 0;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02001308 int constructed __attribute__((unused));
Harald Weltebda367c2011-07-28 00:03:49 +02001309 uint16_t id_value;
1310
1311 for (;;) {
1312
1313 GET_NEXT_BYTE;
1314
1315 /* encoding bit, construced means that other elements are contained */
1316 constructed = ((ub & 0x20) ? 1 : 0);
1317
1318 if ((ub & 0x1F) == 0x1F) {
1319 /* fixed pattern, ID follows */
1320 GET_NEXT_BYTE; /* ID */
1321 id_value = ub & 0x7F;
1322 if (ub & 0x80) {
1323 /* extension bit */
1324 GET_NEXT_BYTE; /* ID low part */
1325 id_value = (id_value << 7) | (ub & 0x7F);
1326 }
1327 if (id_value == id)
1328 found = 1;
1329 } else {
1330 id_value = (ub & 0x3F);
1331 if (id_value == id)
1332 found = 1;
1333 }
1334
1335 GET_NEXT_BYTE; /* length */
1336
1337 if (found) {
1338 /* get data */
1339 uint8_t n = ub;
1340 uint8_t i;
1341 for (i = 0; i < n; i++) {
1342 GET_NEXT_BYTE;
1343 if (max_value <= 0)
1344 return -1; /* buffer too small */
1345 *value = ub;
1346 value++;
1347 max_value--;
1348 }
1349 return n; /* length */
1350 } else {
1351 /* skip data */
1352 uint8_t n = ub;
1353 uint8_t i;
1354 for (i = 0; i < n; i++) {
1355 GET_NEXT_BYTE;
1356 }
1357 }
1358 }
1359 return 0; /* not found */
Dieter Spaar16646022011-07-28 00:01:50 +02001360}
1361
Harald Weltebda367c2011-07-28 00:03:49 +02001362static int dump_elements(uint8_t * data, int len)
1363{
1364 uint8_t ub;
1365 int idx = 0;
1366 int constructed;
1367 uint16_t id_value;
1368 static char indent[100] = ""; /* TODO: move static to BTS context */
Dieter Spaar16646022011-07-28 00:01:50 +02001369
Harald Weltebda367c2011-07-28 00:03:49 +02001370 for (;;) {
1371
1372 GET_NEXT_BYTE;
1373
1374 /* encoding bit, construced means that other elements are contained */
1375 constructed = ((ub & 0x20) ? 1 : 0);
1376
1377 if ((ub & 0x1F) == 0x1F) {
1378 /* fixed pattern, ID follows */
1379 GET_NEXT_BYTE; /* ID */
1380 id_value = ub & 0x7F;
1381 if (ub & 0x80) {
1382 /* extension bit */
1383 GET_NEXT_BYTE; /* ID low part */
1384 id_value = (id_value << 7) | (ub & 0x7F);
1385 }
1386
1387 } else {
1388 id_value = (ub & 0x3F);
1389 }
1390
1391 GET_NEXT_BYTE; /* length */
1392
1393 printf("%s--ID = 0x%02X (%s) %s\n", indent, id_value,
1394 get_element_name_string(id_value),
1395 constructed ? "** constructed **" : "");
1396 printf("%s length = %d\n", indent, ub);
1397 printf("%s %s\n", indent, osmo_hexdump(data + idx, ub));
1398
1399 if (constructed) {
1400 int indent_len = strlen(indent);
1401 strcat(indent, " ");
1402
1403 dump_elements(data + idx, ub);
1404
1405 indent[indent_len] = 0;
1406 }
1407 /* skip data */
1408 uint8_t n = ub;
1409 uint8_t i;
1410 for (i = 0; i < n; i++) {
1411 GET_NEXT_BYTE;
1412 }
1413 }
1414 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001415}
1416
1417/* TODO: put in a separate file ? */
1418
1419/* taken from abis_nm.c */
1420
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001421static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts)
Dieter Spaar16646022011-07-28 00:01:50 +02001422{
Harald Weltebda367c2011-07-28 00:03:49 +02001423 int wait = 0;
1424 struct msgb *msg;
1425 /* the queue is empty */
1426 while (!llist_empty(&bts->abis_queue)) {
1427 msg = msgb_dequeue(&bts->abis_queue);
1428 wait = OBSC_NM_W_ACK_CB(msg);
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001429 abis_sendmsg(msg);
Dieter Spaar16646022011-07-28 00:01:50 +02001430
Harald Weltebda367c2011-07-28 00:03:49 +02001431 if (wait)
1432 break;
1433 }
Dieter Spaar16646022011-07-28 00:01:50 +02001434
Harald Weltebda367c2011-07-28 00:03:49 +02001435 bts->abis_nm_pend = wait;
Dieter Spaar16646022011-07-28 00:01:50 +02001436}
1437
1438/* TODO: put in a separate file ? */
1439
1440/* timer for restarting OML after BTS reset */
1441
1442static void reset_timer_cb(void *_bts)
1443{
Harald Weltebda367c2011-07-28 00:03:49 +02001444 struct gsm_bts *bts = _bts;
1445 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1446 struct e1inp_line *line;
1447
Harald Weltec8755af2011-07-28 00:22:17 +02001448 bts->nokia.wait_reset = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001449
1450 /* OML link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001451 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001452 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001453 LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to "
Harald Weltebda367c2011-07-28 00:03:49 +02001454 "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
1455 return;
1456 }
1457
1458 start_sabm_in_line(line, 0, -1); /* stop all first */
1459 start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */
Dieter Spaar16646022011-07-28 00:01:50 +02001460}
1461
1462/* TODO: put in a separate file ? */
1463
1464/*
1465 This is how the configuration is done:
Dieter Spaar16646022011-07-28 00:01:50 +02001466 - start OML link
Dieter Spaar16646022011-07-28 00:01:50 +02001467 - reset BTS
Dieter Spaar16646022011-07-28 00:01:50 +02001468 - receive ACK, wait some time and restart OML link
Dieter Spaar16646022011-07-28 00:01:50 +02001469 - receive OMU STARTED message, send START DOWNLOAD REQ
Dieter Spaar16646022011-07-28 00:01:50 +02001470 - receive CNF REQ message, send CONF DATA
Dieter Spaar16646022011-07-28 00:01:50 +02001471 - receive ACK, start RSL link(s)
Dieter Spaar16646022011-07-28 00:01:50 +02001472 ACK some other messages received from the BTS.
Harald Weltecde57942011-07-28 00:13:46 +02001473
Dieter Spaar16646022011-07-28 00:01:50 +02001474 Probably its also possible to configure the BTS without a reset, this
1475 has not been tested yet.
1476*/
1477
1478static int abis_nm_rcvmsg_fom(struct msgb *mb)
1479{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001480 struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)mb->dst;
1481 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltebda367c2011-07-28 00:03:49 +02001482 struct abis_om_hdr *oh = msgb_l2(mb);
1483 struct abis_om_nokia_hdr *noh = msgb_l3(mb);
1484 uint8_t mt = noh->msg_type;
1485 int ret = 0;
1486 uint16_t ref = ntohs(noh->reference);
Harald Weltebda367c2011-07-28 00:03:49 +02001487 uint8_t info[256];
1488 uint8_t ack = 0xFF;
1489 uint8_t severity = 0xFF;
1490 int str_len;
1491 int len_data;
Dieter Spaar16646022011-07-28 00:01:50 +02001492
Harald Weltec8755af2011-07-28 00:22:17 +02001493 if (bts->nokia.wait_reset) {
Harald Weltebda367c2011-07-28 00:03:49 +02001494 LOGP(DNM, LOGL_INFO,
1495 "Ignore message while waiting for reset\n");
1496 return ret;
1497 }
Dieter Spaar16646022011-07-28 00:01:50 +02001498
Harald Weltebda367c2011-07-28 00:03:49 +02001499 if (oh->length < sizeof(struct abis_om_nokia_hdr)) {
1500 LOGP(DNM, LOGL_ERROR, "Message too short\n");
1501 return -EINVAL;
1502 }
1503
1504 len_data = oh->length - sizeof(struct abis_om_nokia_hdr);
1505 LOGP(DNM, LOGL_INFO, "(0x%02X) %s\n", mt, get_msg_type_name_string(mt));
1506#if 0 /* debugging */
1507 dump_elements(noh->data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001508#endif
Dieter Spaar16646022011-07-28 00:01:50 +02001509
Harald Weltebda367c2011-07-28 00:03:49 +02001510 switch (mt) {
1511 case NOKIA_MSG_OMU_STARTED:
Harald Welte9d2f3772011-07-28 00:19:06 +02001512 if (find_element(noh->data, len_data,
1513 NOKIA_EI_BTS_TYPE, &bts->nokia.bts_type,
1514 sizeof(uint8_t)) == sizeof(uint8_t))
1515 LOGP(DNM, LOGL_INFO, "BTS type = %d (%s)\n",
1516 bts->nokia.bts_type,
1517 get_bts_type_string(bts->nokia.bts_type));
Harald Weltebda367c2011-07-28 00:03:49 +02001518 else
1519 LOGP(DNM, LOGL_ERROR, "BTS type not found\n");
1520 /* send START_DOWNLOAD_REQ */
1521 abis_nm_download_req(bts, ref);
1522 break;
1523 case NOKIA_MSG_MF_REQ:
1524 break;
1525 case NOKIA_MSG_CONF_REQ:
1526 /* send ACK */
1527 abis_nm_ack(bts, ref);
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001528 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001529 /* send CONF_DATA */
Harald Welte9d2f3772011-07-28 00:19:06 +02001530 abis_nm_send_config(bts, bts->nokia.bts_type);
1531 bts->nokia.configured = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001532 break;
1533 case NOKIA_MSG_ACK:
1534 if (find_element
1535 (noh->data, len_data, NOKIA_EI_ACK, &ack,
1536 sizeof(uint8_t)) == sizeof(uint8_t)) {
1537 LOGP(DNM, LOGL_INFO, "ACK = %d\n", ack);
1538 if (ack != 1) {
1539 LOGP(DNM, LOGL_ERROR, "No ACK received (%d)\n",
1540 ack);
1541 /* TODO: properly handle failures (NACK) */
1542 }
1543 } else
1544 LOGP(DNM, LOGL_ERROR, "ACK not found\n");
Dieter Spaar16646022011-07-28 00:01:50 +02001545
Harald Weltebda367c2011-07-28 00:03:49 +02001546 /* TODO: the assumption for the following is that no NACK was received */
1547
1548 /* ACK for reset message ? */
Sylvain Munautc9519462011-10-17 14:04:55 +02001549 if (!bts->nokia.did_reset) {
1550 bts->nokia.did_reset = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001551
1552 /*
1553 TODO: For the InSite processing the received data is
1554 blocked in the driver during reset.
1555 Otherwise the LAPD module might assert because the InSite
1556 sends garbage on the E1 line during reset.
1557 This is done by looking at "wait_reset" in the driver
1558 (function handle_ts1_read()) and ignoring the received data.
1559 It seems to be necessary for the MetroSite too.
1560 */
Harald Weltec8755af2011-07-28 00:22:17 +02001561 bts->nokia.wait_reset = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001562
Pablo Neira Ayuso51215762017-05-08 20:57:52 +02001563 osmo_timer_setup(&bts->nokia.reset_timer,
1564 reset_timer_cb, bts);
Sipos Csaba56e17662015-02-07 13:27:36 +01001565 osmo_timer_schedule(&bts->nokia.reset_timer, bts->nokia.bts_reset_timer_cnf, 0);
Harald Weltebda367c2011-07-28 00:03:49 +02001566
1567 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1568 struct e1inp_line *line;
1569 /* OML link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001570 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001571 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001572 LOGP(DLINP, LOGL_ERROR,
Harald Weltebda367c2011-07-28 00:03:49 +02001573 "BTS %u OML link referring to "
1574 "non-existing E1 line %u\n", bts->nr,
1575 e1_link->e1_nr);
1576 return -ENOMEM;
1577 }
1578
1579 start_sabm_in_line(line, 0, -1); /* stop all first */
1580 }
1581
1582 /* ACK for CONF DATA message ? */
Harald Welte9d2f3772011-07-28 00:19:06 +02001583 if (bts->nokia.configured != 0) {
Harald Weltebda367c2011-07-28 00:03:49 +02001584 /* start TRX (RSL link) */
1585
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001586 struct gsm_e1_subslot *e1_link =
1587 &sign_link->trx->rsl_e1_link;
Harald Weltebda367c2011-07-28 00:03:49 +02001588 struct e1inp_line *line;
1589
Harald Welte9d2f3772011-07-28 00:19:06 +02001590 bts->nokia.configured = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001591
1592 /* RSL Link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001593 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001594 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001595 LOGP(DLINP, LOGL_ERROR,
Harald Weltebda367c2011-07-28 00:03:49 +02001596 "TRX (%u/%u) RSL link referring "
1597 "to non-existing E1 line %u\n",
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001598 sign_link->trx->bts->nr, sign_link->trx->nr,
Harald Weltebda367c2011-07-28 00:03:49 +02001599 e1_link->e1_nr);
1600 return -ENOMEM;
1601 }
1602 /* start TRX */
1603 start_sabm_in_line(line, 1, SAPI_RSL); /* start only RSL */
1604 }
1605 break;
1606 case NOKIA_MSG_STATE_CHANGED:
1607 /* send ACK */
1608 abis_nm_ack(bts, ref);
1609 break;
1610 case NOKIA_MSG_CONF_COMPLETE:
1611 /* send ACK */
1612 abis_nm_ack(bts, ref);
1613 break;
1614 case NOKIA_MSG_BLOCK_CTRL_REQ: /* seems to be send when something goes wrong !? */
1615 /* send ACK (do we have to send an ACK ?) */
1616 abis_nm_ack(bts, ref);
1617 break;
1618 case NOKIA_MSG_ALARM:
1619 find_element(noh->data, len_data, NOKIA_EI_SEVERITY, &severity,
1620 sizeof(severity));
1621 /* TODO: there might be alarms with both elements set */
1622 str_len =
1623 find_element(noh->data, len_data, NOKIA_EI_ADD_INFO, info,
1624 sizeof(info));
1625 if (str_len > 0) {
1626 info[str_len] = 0;
1627 LOGP(DNM, LOGL_INFO, "ALARM Severity %s (%d) : %s\n",
1628 get_severity_string(severity), severity, info);
1629 } else { /* nothing found, try details */
1630 str_len =
1631 find_element(noh->data, len_data,
1632 NOKIA_EI_ALARM_DETAIL, info,
1633 sizeof(info));
1634 if (str_len > 0) {
1635 uint16_t code;
1636 info[str_len] = 0;
1637 code = (info[0] << 8) + info[1];
1638 LOGP(DNM, LOGL_INFO,
1639 "ALARM Severity %s (%d), code 0x%X : %s\n",
1640 get_severity_string(severity), severity,
1641 code, info + 2);
1642 }
1643 }
1644 /* send ACK */
1645 abis_nm_ack(bts, ref);
1646 break;
1647 }
1648
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001649 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001650
1651 return ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001652}
1653
1654/* TODO: put in a separate file ? */
1655
1656int abis_nokia_rcvmsg(struct msgb *msg)
1657{
Harald Weltebda367c2011-07-28 00:03:49 +02001658 struct abis_om_hdr *oh = msgb_l2(msg);
1659 int rc = 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001660
Harald Weltebda367c2011-07-28 00:03:49 +02001661 /* Various consistency checks */
1662 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
1663 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
1664 oh->placement);
1665 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1666 return -EINVAL;
1667 }
1668 if (oh->sequence != 0) {
1669 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
1670 oh->sequence);
1671 return -EINVAL;
1672 }
1673 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Dieter Spaar16646022011-07-28 00:01:50 +02001674
Harald Weltebda367c2011-07-28 00:03:49 +02001675 switch (oh->mdisc) {
1676 case ABIS_OM_MDISC_FOM:
1677 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_FOM\n");
1678 rc = abis_nm_rcvmsg_fom(msg);
1679 break;
1680 case ABIS_OM_MDISC_MANUF:
1681 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_MANUF\n");
1682 break;
1683 case ABIS_OM_MDISC_MMI:
1684 case ABIS_OM_MDISC_TRAU:
1685 LOGP(DNM, LOGL_ERROR,
1686 "unimplemented ABIS OML message discriminator 0x%x\n",
1687 oh->mdisc);
1688 break;
1689 default:
1690 LOGP(DNM, LOGL_ERROR,
1691 "unknown ABIS OML message discriminator 0x%x\n",
1692 oh->mdisc);
1693 return -EINVAL;
1694 }
Dieter Spaar16646022011-07-28 00:01:50 +02001695
Harald Weltebda367c2011-07-28 00:03:49 +02001696 msgb_free(msg);
1697 return rc;
Dieter Spaar16646022011-07-28 00:01:50 +02001698}
1699
1700static int bts_model_nokia_site_start(struct gsm_network *net);
1701
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001702static void bts_model_nokia_site_e1line_bind_ops(struct e1inp_line *line)
1703{
1704 e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
1705}
1706
Dieter Spaar16646022011-07-28 00:01:50 +02001707static struct gsm_bts_model model_nokia_site = {
Harald Weltebda367c2011-07-28 00:03:49 +02001708 .type = GSM_BTS_TYPE_NOKIA_SITE,
1709 .name = "nokia_site",
1710 .start = bts_model_nokia_site_start,
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001711 .oml_rcvmsg = &abis_nokia_rcvmsg,
1712 .e1line_bind_ops = &bts_model_nokia_site_e1line_bind_ops,
Dieter Spaar16646022011-07-28 00:01:50 +02001713};
1714
1715static struct gsm_network *my_net;
1716
1717static int bts_model_nokia_site_start(struct gsm_network *net)
1718{
Harald Weltebda367c2011-07-28 00:03:49 +02001719 model_nokia_site.features.data = &model_nokia_site._features_data[0];
1720 model_nokia_site.features.data_len =
1721 sizeof(model_nokia_site._features_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001722
Harald Weltebda367c2011-07-28 00:03:49 +02001723 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HOPPING);
1724 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HSCSD);
Harald Welte903aaea2014-01-19 17:10:50 +01001725 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_MULTI_TSC);
Dieter Spaar16646022011-07-28 00:01:50 +02001726
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001727 osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
1728 osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL);
Harald Weltebda367c2011-07-28 00:03:49 +02001729 osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
Dieter Spaar16646022011-07-28 00:01:50 +02001730
Harald Weltebda367c2011-07-28 00:03:49 +02001731 my_net = net;
1732
1733 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001734}
1735
1736int bts_model_nokia_site_init(void)
1737{
Harald Weltebda367c2011-07-28 00:03:49 +02001738 return gsm_bts_model_register(&model_nokia_site);
Dieter Spaar16646022011-07-28 00:01:50 +02001739}