blob: 6d14bddaffb1e49eaf4e615b26951f47f7124bad [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
Harald Weltebda367c2011-07-28 00:03:49 +020045#define RESET_INTERVAL 0, 3000000 /* 3 seconds */
Dieter Spaar16646022011-07-28 00:01:50 +020046
47extern int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg);
48/* was static in system_information.c */
Harald Weltebda367c2011-07-28 00:03:49 +020049extern int generate_cell_chan_list(uint8_t * chan_list, struct gsm_bts *bts);
Dieter Spaar16646022011-07-28 00:01:50 +020050
51static void abis_nm_queue_send_next(struct gsm_bts *bts);
52static void reset_timer_cb(void *_bts);
53static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref);
Harald Weltebda367c2011-07-28 00:03:49 +020054static int dump_elements(uint8_t * data, int len);
Dieter Spaar16646022011-07-28 00:01:50 +020055
56static void bootstrap_om_bts(struct gsm_bts *bts)
57{
Harald Weltebda367c2011-07-28 00:03:49 +020058 LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
59
Harald Weltec8755af2011-07-28 00:22:17 +020060 if (bts->nokia.do_reset)
Harald Weltebda367c2011-07-28 00:03:49 +020061 abis_nm_reset(bts, 1);
Dieter Spaar16646022011-07-28 00:01:50 +020062}
63
64static void bootstrap_om_trx(struct gsm_bts_trx *trx)
65{
Harald Weltebda367c2011-07-28 00:03:49 +020066 LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
67 trx->bts->nr, trx->nr);
Dieter Spaar16646022011-07-28 00:01:50 +020068}
69
70static int shutdown_om(struct gsm_bts *bts)
71{
Harald Weltebda367c2011-07-28 00:03:49 +020072 /* TODO !? */
73 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +020074}
75
76#define SAPI_OML 62
77#define SAPI_RSL 0
78
Harald Weltecde57942011-07-28 00:13:46 +020079/*
Dieter Spaar16646022011-07-28 00:01:50 +020080
81 Tell LAPD to start start the SAP (send SABM requests) for all signalling
Harald Weltecde57942011-07-28 00:13:46 +020082 timeslots in this line
83
84 Attention: this has to be adapted for mISDN
Dieter Spaar16646022011-07-28 00:01:50 +020085*/
Harald Weltebda367c2011-07-28 00:03:49 +020086
Dieter Spaar16646022011-07-28 00:01:50 +020087static void start_sabm_in_line(struct e1inp_line *line, int start, int sapi)
88{
Harald Weltebda367c2011-07-28 00:03:49 +020089 struct e1inp_sign_link *link;
90 int i;
Dieter Spaar16646022011-07-28 00:01:50 +020091
Harald Weltebda367c2011-07-28 00:03:49 +020092 for (i = 0; i < ARRAY_SIZE(line->ts); i++) {
93 struct e1inp_ts *ts = &line->ts[i];
Dieter Spaar16646022011-07-28 00:01:50 +020094
Harald Weltebda367c2011-07-28 00:03:49 +020095 if (ts->type != E1INP_TS_TYPE_SIGN)
96 continue;
Dieter Spaar16646022011-07-28 00:01:50 +020097
Harald Weltebda367c2011-07-28 00:03:49 +020098 llist_for_each_entry(link, &ts->sign.sign_links, list) {
99 if (sapi != -1 && link->sapi != sapi)
100 continue;
101
102#if 0 /* debugging */
103 printf("sap start/stop (%d): %d tei=%d sapi=%d\n",
104 start, i + 1, link->tei, link->sapi);
Dieter Spaar16646022011-07-28 00:01:50 +0200105#endif
Harald Weltebda367c2011-07-28 00:03:49 +0200106
107 if (start)
108 lapd_sap_start(ts->driver.dahdi.lapd, link->tei,
109 link->sapi);
110 else
111 lapd_sap_stop(ts->driver.dahdi.lapd, link->tei,
112 link->sapi);
113 }
114 }
Dieter Spaar16646022011-07-28 00:01:50 +0200115}
116
117/* Callback function to be called every time we receive a signal from INPUT */
118static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200119 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200120{
Harald Weltebda367c2011-07-28 00:03:49 +0200121 struct gsm_bts *bts;
Dieter Spaar16646022011-07-28 00:01:50 +0200122
Harald Weltebda367c2011-07-28 00:03:49 +0200123 if (subsys != SS_GLOBAL)
124 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200125
Harald Weltebda367c2011-07-28 00:03:49 +0200126 switch (signal) {
127 case S_GLOBAL_BTS_CLOSE_OM:
128 bts = signal_data;
129 if (bts->type == GSM_BTS_TYPE_NOKIA_SITE)
130 shutdown_om(signal_data);
131 break;
132 }
Dieter Spaar16646022011-07-28 00:01:50 +0200133
Harald Weltebda367c2011-07-28 00:03:49 +0200134 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200135}
136
137/* Callback function to be called every time we receive a signal from INPUT */
138static int inp_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200139 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200140{
Harald Weltebda367c2011-07-28 00:03:49 +0200141 struct input_signal_data *isd = signal_data;
Dieter Spaar16646022011-07-28 00:01:50 +0200142
Harald Weltebda367c2011-07-28 00:03:49 +0200143 if (subsys != SS_INPUT)
144 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200145
Harald Weltebda367c2011-07-28 00:03:49 +0200146 switch (signal) {
147 case S_INP_LINE_INIT:
148 start_sabm_in_line(isd->line, 1, SAPI_OML); /* start only OML */
149 break;
150 case S_INP_TEI_DN:
151 break;
152 case S_INP_TEI_UP:
153 switch (isd->link_type) {
154 case E1INP_SIGN_OML:
155 if (isd->trx->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
156 break;
Dieter Spaar16646022011-07-28 00:01:50 +0200157
Harald Weltebda367c2011-07-28 00:03:49 +0200158 if (isd->tei == isd->trx->bts->oml_tei)
159 bootstrap_om_bts(isd->trx->bts);
160 else
161 bootstrap_om_trx(isd->trx);
162 break;
163 }
164 break;
165 }
166
167 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200168}
169
170static void nm_statechg_evt(unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200171 struct nm_statechg_signal_data *nsd)
Dieter Spaar16646022011-07-28 00:01:50 +0200172{
Harald Weltebda367c2011-07-28 00:03:49 +0200173 if (nsd->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
174 return;
Dieter Spaar16646022011-07-28 00:01:50 +0200175}
176
177static int nm_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200178 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200179{
Harald Weltebda367c2011-07-28 00:03:49 +0200180 if (subsys != SS_NM)
181 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200182
Harald Weltebda367c2011-07-28 00:03:49 +0200183 switch (signal) {
184 case S_NM_STATECHG_OPER:
185 case S_NM_STATECHG_ADM:
186 nm_statechg_evt(signal, signal_data);
187 break;
188 default:
189 break;
190 }
Dieter Spaar16646022011-07-28 00:01:50 +0200191
Harald Weltebda367c2011-07-28 00:03:49 +0200192 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200193}
194
195/* TODO: put in a separate file ? */
196
Harald Welte44d26112011-07-28 00:43:13 +0200197static const struct value_string nokia_msgt_name[] = {
198 { 0x80, "NOKIA_BTS_CONF_DATA" },
199 { 0x81, "NOKIA_BTS_ACK" },
200 { 0x82, "NOKIA_BTS_OMU_STARTED" },
201 { 0x83, "NOKIA_BTS_START_DOWNLOAD_REQ" },
202 { 0x84, "NOKIA_BTS_MF_REQ" },
203 { 0x85, "NOKIA_BTS_AF_REQ" },
204 { 0x86, "NOKIA_BTS_RESET_REQ" },
205 { 0x87, "NOKIA_reserved" },
206 { 0x88, "NOKIA_BTS_CONF_REQ" },
207 { 0x89, "NOKIA_BTS_TEST_REQ" },
208 { 0x8A, "NOKIA_BTS_TEST_REPORT" },
209 { 0x8B, "NOKIA_reserved" },
210 { 0x8C, "NOKIA_reserved" },
211 { 0x8D, "NOKIA_reserved" },
212 { 0x8E, "NOKIA_BTS_CONF_COMPL" },
213 { 0x8F, "NOKIA_reserved" },
214 { 0x90, "NOKIA_BTS_STM_TEST_REQ" },
215 { 0x91, "NOKIA_BTS_STM_TEST_REPORT" },
216 { 0x92, "NOKIA_BTS_TRANSMISSION_COMMAND" },
217 { 0x93, "NOKIA_BTS_TRANSMISSION_ANSWER" },
218 { 0x94, "NOKIA_BTS_HW_DB_UPLOAD_REQ" },
219 { 0x95, "NOKIA_BTS_START_HW_DB_DOWNLOAD_REQ" },
220 { 0x96, "NOKIA_BTS_HW_DB_SAVE_REQ" },
221 { 0x97, "NOKIA_BTS_FLASH_ERASURE_REQ" },
222 { 0x98, "NOKIA_BTS_HW_DB_DOWNLOAD_REQ" },
223 { 0x99, "NOKIA_BTS_PWR_SUPPLY_CONTROL" },
224 { 0x9A, "NOKIA_BTS_ATTRIBUTE_REQ" },
225 { 0x9B, "NOKIA_BTS_ATTRIBUTE_REPORT" },
226 { 0x9C, "NOKIA_BTS_HW_REQ" },
227 { 0x9D, "NOKIA_BTS_HW_REPORT" },
228 { 0x9E, "NOKIA_BTS_RTE_TEST_REQ" },
229 { 0x9F, "NOKIA_BTS_RTE_TEST_REPORT" },
230 { 0xA0, "NOKIA_BTS_HW_DB_VERIFICATION_REQ" },
231 { 0xA1, "NOKIA_BTS_CLOCK_REQ" },
232 { 0xA2, "NOKIA_AC_CIRCUIT_REQ_NACK" },
233 { 0xA3, "NOKIA_AC_INTERRUPTED" },
234 { 0xA4, "NOKIA_BTS_NEW_TRE_INFO" },
235 { 0xA5, "NOKIA_AC_BSC_CIRCUITS_ALLOCATED" },
236 { 0xA6, "NOKIA_BTS_TRE_POLL_LIST" },
237 { 0xA7, "NOKIA_AC_CIRCUIT_REQ" },
238 { 0xA8, "NOKIA_BTS_BLOCK_CTRL_REQ" },
239 { 0xA9, "NOKIA_BTS_GSM_TIME_REQ" },
240 { 0xAA, "NOKIA_BTS_GSM_TIME" },
241 { 0xAB, "NOKIA_BTS_OUTPUT_CONTROL" },
242 { 0xAC, "NOKIA_BTS_STATE_CHANGED" },
243 { 0xAD, "NOKIA_BTS_SW_SAVE_REQ" },
244 { 0xAE, "NOKIA_BTS_ALARM" },
245 { 0xAF, "NOKIA_BTS_CHA_ADM_STATE" },
246 { 0xB0, "NOKIA_AC_POOL_SIZE_REPORT" },
247 { 0xB1, "NOKIA_AC_POOL_SIZE_INQUIRY" },
248 { 0xB2, "NOKIA_BTS_COMMISS_TEST_COMPLETED" },
249 { 0xB3, "NOKIA_BTS_COMMISS_TEST_REQ" },
250 { 0xB4, "NOKIA_BTS_TRANSP_BTS_TO_BSC" },
251 { 0xB5, "NOKIA_BTS_TRANSP_BSC_TO_BTS" },
252 { 0xB6, "NOKIA_BTS_LCS_COMMAND" },
253 { 0xB7, "NOKIA_BTS_LCS_ANSWER" },
254 { 0xB8, "NOKIA_BTS_LMU_FN_OFFSET_COMMAND" },
255 { 0xB9, "NOKIA_BTS_LMU_FN_OFFSET_ANSWER" },
256 { 0, NULL }
257};
258
259static const char *get_msg_type_name_string(uint8_t msg_type)
Dieter Spaar16646022011-07-28 00:01:50 +0200260{
Harald Welte44d26112011-07-28 00:43:13 +0200261 return get_value_string(nokia_msgt_name, msg_type);
Dieter Spaar16646022011-07-28 00:01:50 +0200262}
263
Harald Welte44d26112011-07-28 00:43:13 +0200264static const struct value_string nokia_element_name[] = {
265 { 0x01, "Ny1" },
266 { 0x02, "T3105_F" },
267 { 0x03, "Interference band limits" },
268 { 0x04, "Interference report timer in secs" },
269 { 0x05, "Channel configuration per TS" },
270 { 0x06, "BSIC" },
271 { 0x07, "RACH report timer in secs" },
272 { 0x08, "Hardware database status" },
273 { 0x09, "BTS RX level" },
274 { 0x0A, "ARFN" },
275 { 0x0B, "STM antenna attenuation" },
276 { 0x0C, "Cell allocation bitmap" },
277 { 0x0D, "Radio definition per TS" },
278 { 0x0E, "Frame number" },
279 { 0x0F, "Antenna diversity" },
280 { 0x10, "T3105_D" },
281 { 0x11, "File format" },
282 { 0x12, "Last File" },
283 { 0x13, "BTS type" },
284 { 0x14, "Erasure mode" },
285 { 0x15, "Hopping mode" },
286 { 0x16, "Floating TRX" },
287 { 0x17, "Power supplies" },
288 { 0x18, "Reset type" },
289 { 0x19, "Averaging period" },
290 { 0x1A, "RBER2" },
291 { 0x1B, "LAC" },
292 { 0x1C, "CI" },
293 { 0x1D, "Failure parameters" },
294 { 0x1E, "(RF max power reduction)" },
295 { 0x1F, "Measured RX_SENS" },
296 { 0x20, "Extended cell radius" },
297 { 0x21, "reserved" },
298 { 0x22, "Success-Failure" },
299 { 0x23, "Ack-Nack" },
300 { 0x24, "OMU test results" },
301 { 0x25, "File identity" },
302 { 0x26, "Generation and version code" },
303 { 0x27, "SW description" },
304 { 0x28, "BCCH LEV" },
305 { 0x29, "Test type" },
306 { 0x2A, "Subscriber number" },
307 { 0x2B, "reserved" },
308 { 0x2C, "HSN" },
309 { 0x2D, "reserved" },
310 { 0x2E, "MS RXLEV" },
311 { 0x2F, "MS TXLEV" },
312 { 0x30, "RXQUAL" },
313 { 0x31, "RX SENS" },
314 { 0x32, "Alarm block" },
315 { 0x33, "Neighbouring BCCH levels" },
316 { 0x34, "STM report type" },
317 { 0x35, "MA" },
318 { 0x36, "MAIO" },
319 { 0x37, "H_FLAG" },
320 { 0x38, "TCH_ARFN" },
321 { 0x39, "Clock output" },
322 { 0x3A, "Transmitted power" },
323 { 0x3B, "Clock sync" },
324 { 0x3C, "TMS protocol discriminator" },
325 { 0x3D, "TMS protocol data" },
326 { 0x3E, "FER" },
327 { 0x3F, "SWR result" },
328 { 0x40, "Object identity" },
329 { 0x41, "STM RX Antenna Test" },
330 { 0x42, "reserved" },
331 { 0x43, "reserved" },
332 { 0x44, "Object current state" },
333 { 0x45, "reserved" },
334 { 0x46, "FU channel configuration" },
335 { 0x47, "reserved" },
336 { 0x48, "ARFN of a CU" },
337 { 0x49, "FU radio definition" },
338 { 0x4A, "reserved" },
339 { 0x4B, "Severity" },
340 { 0x4C, "Diversity selection" },
341 { 0x4D, "RX antenna test" },
342 { 0x4E, "RX antenna supervision period" },
343 { 0x4F, "RX antenna state" },
344 { 0x50, "Sector configuration" },
345 { 0x51, "Additional info" },
346 { 0x52, "SWR parameters" },
347 { 0x53, "HW inquiry mode" },
348 { 0x54, "reserved" },
349 { 0x55, "Availability status" },
350 { 0x56, "reserved" },
351 { 0x57, "EAC inputs" },
352 { 0x58, "EAC outputs" },
353 { 0x59, "reserved" },
354 { 0x5A, "Position" },
355 { 0x5B, "HW unit identity" },
356 { 0x5C, "RF test signal attenuation" },
357 { 0x5D, "Operational state" },
358 { 0x5E, "Logical object identity" },
359 { 0x5F, "reserved" },
360 { 0x60, "BS_TXPWR_OM" },
361 { 0x61, "Loop_Duration" },
362 { 0x62, "LNA_Path_Selection" },
363 { 0x63, "Serial number" },
364 { 0x64, "HW version" },
365 { 0x65, "Obj. identity and obj. state" },
366 { 0x66, "reserved" },
367 { 0x67, "EAC input definition" },
368 { 0x68, "EAC id and text" },
369 { 0x69, "HW unit status" },
370 { 0x6A, "SW release version" },
371 { 0x6B, "FW version" },
372 { 0x6C, "Bit_Error_Ratio" },
373 { 0x6D, "RXLEV_with_Attenuation" },
374 { 0x6E, "RXLEV_without_Attenuation" },
375 { 0x6F, "reserved" },
376 { 0x70, "CU_Results" },
377 { 0x71, "reserved" },
378 { 0x72, "LNA_Path_Results" },
379 { 0x73, "RTE Results" },
380 { 0x74, "Real Time" },
381 { 0x75, "RX diversity selection" },
382 { 0x76, "EAC input config" },
383 { 0x77, "Feature support" },
384 { 0x78, "File version" },
385 { 0x79, "Outputs" },
386 { 0x7A, "FU parameters" },
387 { 0x7B, "Diagnostic info" },
388 { 0x7C, "FU BSIC" },
389 { 0x7D, "TRX Configuration" },
390 { 0x7E, "Download status" },
391 { 0x7F, "RX difference limit" },
392 { 0x80, "TRX HW capability" },
393 { 0x81, "Common HW config" },
394 { 0x82, "Autoconfiguration pool size" },
395 { 0x83, "TRE diagnostic info" },
396 { 0x84, "TRE object identity" },
397 { 0x85, "New TRE Info" },
398 { 0x86, "Acknowledgement period" },
399 { 0x87, "Synchronization mode" },
400 { 0x88, "reserved" },
401 { 0x89, "Block Control Data" },
402 { 0x8A, "SW load mode" },
403 { 0x8B, "Recommended recovery action" },
404 { 0x8C, "BSC BCF id" },
405 { 0x8D, "Q1 baud rate" },
406 { 0x8E, "Allocation status" },
407 { 0x8F, "Functional entity number" },
408 { 0x90, "Transmission delay" },
409 { 0x91, "Loop Duration ms" },
410 { 0x92, "Logical channel" },
411 { 0x93, "Q1 address" },
412 { 0x94, "Alarm detail" },
413 { 0x95, "Cabinet type" },
414 { 0x96, "HW unit existence" },
415 { 0x97, "RF power parameters" },
416 { 0x98, "Message scenario" },
417 { 0x99, "HW unit max amount" },
418 { 0x9A, "Master TRX" },
419 { 0x9B, "Transparent data" },
420 { 0x9C, "BSC topology info" },
421 { 0x9D, "Air i/f modulation" },
422 { 0x9E, "LCS Q1 command data" },
423 { 0x9F, "Frame number offset" },
424 { 0xA0, "Abis TSL" },
425 { 0xA1, "Dynamic pool info" },
426 { 0xA2, "LCS LLP data" },
427 { 0xA3, "LCS Q1 answer data" },
428 { 0xA4, "DFCA FU Radio Definition" },
429 { 0xA5, "Antenna hopping" },
430 { 0xA6, "Field record sequence number" },
431 { 0xA7, "Timeslot offslot" },
432 { 0xA8, "EPCR capability" },
433 { 0xA9, "Connectsite optional element" },
434 { 0xAA, "TSC" },
435 { 0xAB, "Special TX Power Setting" },
436 { 0xAC, "Optional sync settings" },
437 { 0xFA, "Abis If parameters" },
438 { 0, NULL }
439};
440
441static const char *get_element_name_string(uint16_t element)
Dieter Spaar16646022011-07-28 00:01:50 +0200442{
Harald Welte44d26112011-07-28 00:43:13 +0200443 return get_value_string(nokia_element_name, element);
Dieter Spaar16646022011-07-28 00:01:50 +0200444}
445
Harald Welte3c3003f2011-07-28 00:28:20 +0200446static const struct value_string nokia_bts_types[] = {
447 { 0x0a, "MetroSite GSM 900" },
448 { 0x0b, "MetroSite GSM 1800" },
449 { 0x0c, "MetroSite GSM 1900 (PCS)" },
450 { 0x0d, "MetroSite GSM 900 & 1800" },
451 { 0x0e, "InSite GSM 900" },
452 { 0x0f, "InSite GSM 1800" },
453 { 0x10, "InSite GSM 1900" },
454 { 0x11, "UltraSite GSM 900" },
455 { 0x12, "UltraSite GSM 1800" },
456 { 0x13, "UltraSite GSM/US-TDMA 1900" },
457 { 0x14, "UltraSite GSM 900 & 1800" },
458 { 0x16, "UltraSite GSM/US-TDMA 850" },
459 { 0x18, "MetroSite GSM/US-TDMA 850" },
460 { 0x19, "UltraSite GSM 800/1900" },
461 { 0, NULL }
462};
463
464static const char *get_bts_type_string(uint8_t type)
Dieter Spaar16646022011-07-28 00:01:50 +0200465{
Harald Welte3c3003f2011-07-28 00:28:20 +0200466 return get_value_string(nokia_bts_types, type);
Dieter Spaar16646022011-07-28 00:01:50 +0200467}
468
Harald Welte3c3003f2011-07-28 00:28:20 +0200469static const struct value_string nokia_severity[] = {
470 { 0, "indeterminate" },
471 { 1, "critical" },
472 { 2, "major" },
473 { 3, "minor" },
474 { 4, "warning" },
475 { 0, NULL }
476};
477
478static const char *get_severity_string(uint8_t severity)
Dieter Spaar16646022011-07-28 00:01:50 +0200479{
Harald Welte3c3003f2011-07-28 00:28:20 +0200480 return get_value_string(nokia_severity, severity);
Dieter Spaar16646022011-07-28 00:01:50 +0200481}
482
483/* TODO: put in a separate file ? */
484
485/* some message IDs */
486
487#define NOKIA_MSG_CONF_DATA 128
488#define NOKIA_MSG_ACK 129
489#define NOKIA_MSG_OMU_STARTED 130
490#define NOKIA_MSG_START_DOWNLOAD_REQ 131
491#define NOKIA_MSG_MF_REQ 132
492#define NOKIA_MSG_RESET_REQ 134
493#define NOKIA_MSG_CONF_REQ 136
494#define NOKIA_MSG_CONF_COMPLETE 142
495#define NOKIA_MSG_BLOCK_CTRL_REQ 168
496#define NOKIA_MSG_STATE_CHANGED 172
497#define NOKIA_MSG_ALARM 174
498
499/* some element IDs */
500
501#define NOKIA_EI_BTS_TYPE 0x13
502#define NOKIA_EI_ACK 0x23
503#define NOKIA_EI_ADD_INFO 0x51
504#define NOKIA_EI_SEVERITY 0x4B
505#define NOKIA_EI_ALARM_DETAIL 0x94
506
507#define OM_ALLOC_SIZE 1024
508#define OM_HEADROOM_SIZE 128
509
Harald Weltebda367c2011-07-28 00:03:49 +0200510static uint8_t fu_config_template[] = {
511 0x7F, 0x7A, 0x39,
512 /* ID = 0x7A (FU parameters) ## constructed ## */
513 /* length = 57 */
514 /* [3] */
Dieter Spaar16646022011-07-28 00:01:50 +0200515
Harald Weltebda367c2011-07-28 00:03:49 +0200516 0x5F, 0x40, 0x04,
517 /* ID = 0x40 (Object identity) */
518 /* length = 4 */
519 /* [6] */
520 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200521
Harald Weltebda367c2011-07-28 00:03:49 +0200522 0x41, 0x02,
523 /* ID = 0x01 (Ny1) */
524 /* length = 2 */
525 /* [12] */
526 0x00, 0x05,
Dieter Spaar16646022011-07-28 00:01:50 +0200527
Harald Weltebda367c2011-07-28 00:03:49 +0200528 0x42, 0x02,
529 /* ID = 0x02 (T3105_F) */
530 /* length = 2 */
531 /* [16] */
532 0x00, 0x28,
Dieter Spaar16646022011-07-28 00:01:50 +0200533
Harald Weltebda367c2011-07-28 00:03:49 +0200534 0x50, 0x02,
535 /* ID = 0x10 (T3105_D) */
536 /* length = 2 */
537 /* [20] */
538 0x00, 0x28,
Dieter Spaar16646022011-07-28 00:01:50 +0200539
Harald Weltebda367c2011-07-28 00:03:49 +0200540 0x43, 0x05,
541 /* ID = 0x03 (Interference band limits) */
542 /* length = 5 */
543 /* [24] */
544 0x0F, 0x1B, 0x27, 0x33, 0x3F,
Dieter Spaar16646022011-07-28 00:01:50 +0200545
Harald Weltebda367c2011-07-28 00:03:49 +0200546 0x44, 0x02,
547 /* ID = 0x04 (Interference report timer in secs) */
548 /* length = 2 */
549 /* [31] */
550 0x00, 0x10,
Dieter Spaar16646022011-07-28 00:01:50 +0200551
Harald Weltebda367c2011-07-28 00:03:49 +0200552 0x47, 0x01,
553 /* ID = 0x07 (RACH report timer in secs) */
554 /* length = 1 */
555 /* [35] */
556 0x1E,
Dieter Spaar16646022011-07-28 00:01:50 +0200557
Harald Weltebda367c2011-07-28 00:03:49 +0200558 0x4C, 0x10,
559 /* ID = 0x0C (Cell allocation bitmap) ####### */
560 /* length = 16 */
561 /* [38] */
562 0x8F, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200564
Harald Weltebda367c2011-07-28 00:03:49 +0200565 0x59, 0x01,
566 /* ID = 0x19 (Averaging period) */
567 /* length = 1 */
568 /* [56] */
569 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +0200570
Harald Weltebda367c2011-07-28 00:03:49 +0200571 0x5E, 0x01,
572 /* ID = 0x1E ((RF max power reduction)) */
573 /* length = 1 */
574 /* [59] */
575 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200576
Harald Weltebda367c2011-07-28 00:03:49 +0200577 0x7F, 0x46, 0x11,
578 /* ID = 0x46 (FU channel configuration) ## constructed ## */
579 /* length = 17 */
580 /* [63] */
Dieter Spaar16646022011-07-28 00:01:50 +0200581
Harald Weltebda367c2011-07-28 00:03:49 +0200582 0x5F, 0x40, 0x04,
583 /* ID = 0x40 (Object identity) */
584 /* length = 4 */
585 /* [66] */
586 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200587
Harald Weltebda367c2011-07-28 00:03:49 +0200588 0x45, 0x08,
589 /* ID = 0x05 (Channel configuration per TS) */
590 /* length = 8 */
591 /* [72] */
592 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
Dieter Spaar16646022011-07-28 00:01:50 +0200593
Harald Weltebda367c2011-07-28 00:03:49 +0200594 0x7F, 0x65, 0x0B,
595 /* ID = 0x65 (Obj. identity and obj. state) ## constructed ## */
596 /* length = 11 */
597 /* [83] */
Dieter Spaar16646022011-07-28 00:01:50 +0200598
Harald Weltebda367c2011-07-28 00:03:49 +0200599 0x5F, 0x40, 0x04,
600 /* ID = 0x40 (Object identity) */
601 /* length = 4 */
602 /* [86] */
603 0x00, 0x04, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200604
Harald Weltebda367c2011-07-28 00:03:49 +0200605 0x5F, 0x44, 0x01,
606 /* ID = 0x44 (Object current state) */
607 /* length = 1 */
608 /* [93] */
609 0x03,
Dieter Spaar16646022011-07-28 00:01:50 +0200610
Harald Weltebda367c2011-07-28 00:03:49 +0200611 0x7F, 0x7C, 0x0A,
612 /* ID = 0x7C (FU BSIC) ## constructed ## */
613 /* length = 10 */
614 /* [97] */
Dieter Spaar16646022011-07-28 00:01:50 +0200615
Harald Weltebda367c2011-07-28 00:03:49 +0200616 0x5F, 0x40, 0x04,
617 /* ID = 0x40 (Object identity) */
618 /* length = 4 */
619 /* [100] */
620 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200621
Harald Weltebda367c2011-07-28 00:03:49 +0200622 0x46, 0x01,
623 /* ID = 0x06 (BSIC) */
624 /* length = 1 */
625 /* [106] */
626 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200627
Harald Weltebda367c2011-07-28 00:03:49 +0200628 0x7F, 0x48, 0x0B,
629 /* ID = 0x48 (ARFN of a CU) ## constructed ## */
630 /* length = 11 */
631 /* [110] */
Dieter Spaar16646022011-07-28 00:01:50 +0200632
Harald Weltebda367c2011-07-28 00:03:49 +0200633 0x5F, 0x40, 0x04,
634 /* ID = 0x40 (Object identity) */
635 /* length = 4 */
636 /* [113] */
637 0x00, 0x08, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200638
Harald Weltebda367c2011-07-28 00:03:49 +0200639 0x4A, 0x02,
640 /* ID = 0x0A (ARFN) ####### */
641 /* length = 2 */
642 /* [119] */
643 0x03, 0x62,
Dieter Spaar16646022011-07-28 00:01:50 +0200644
Harald Weltebda367c2011-07-28 00:03:49 +0200645 0x7F, 0x49, 0x59,
646 /* ID = 0x49 (FU radio definition) ## constructed ## */
647 /* length = 89 */
648 /* [124] */
Dieter Spaar16646022011-07-28 00:01:50 +0200649
Harald Weltebda367c2011-07-28 00:03:49 +0200650 0x5F, 0x40, 0x04,
651 /* ID = 0x40 (Object identity) */
652 /* length = 4 */
653 /* [127] */
654 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200655
Harald Weltebda367c2011-07-28 00:03:49 +0200656 0x4D, 0x50,
657 /* ID = 0x0D (Radio definition per TS) ####### */
658 /* length = 80 */
659 /* [133] */
660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MA */
661 0x03, 0x62, /* HSN, MAIO or ARFCN if no hopping */
662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663 0x03, 0x62,
664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
665 0x03, 0x62,
666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667 0x03, 0x62,
668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669 0x03, 0x62,
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671 0x03, 0x62,
672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673 0x03, 0x62,
674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675 0x03, 0x62,
Dieter Spaar16646022011-07-28 00:01:50 +0200676};
677
678/* TODO: put in a separate file ? */
679
680/*
Harald Weltecde57942011-07-28 00:13:46 +0200681 build the configuration for each TRX
Dieter Spaar16646022011-07-28 00:01:50 +0200682*/
683
Harald Weltebda367c2011-07-28 00:03:49 +0200684static int make_fu_config(struct gsm_bts_trx *trx, uint8_t id,
685 uint8_t * fu_config, int *hopping)
Dieter Spaar16646022011-07-28 00:01:50 +0200686{
Harald Weltebda367c2011-07-28 00:03:49 +0200687 int i;
Dieter Spaar16646022011-07-28 00:01:50 +0200688
Harald Weltebda367c2011-07-28 00:03:49 +0200689 *hopping = 0;
690
691 memcpy(fu_config, fu_config_template, sizeof(fu_config_template));
692
693 /* set ID */
694
695 fu_config[6 + 2] = id;
696 fu_config[66 + 2] = id;
697 fu_config[86 + 2] = id;
698 fu_config[100 + 2] = id;
699 fu_config[113 + 2] = id;
700 fu_config[127 + 2] = id;
701
702 /* set ARFCN */
703
704 uint16_t arfcn = trx->arfcn;
705
706 fu_config[119] = arfcn >> 8;
707 fu_config[119 + 1] = arfcn & 0xFF;
708
709 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
710 struct gsm_bts_trx_ts *ts = &trx->ts[i];
711
712 if (ts->hopping.enabled) {
713 /* reverse order */
714 int j;
715 for (j = 0; j < ts->hopping.ma_len; j++)
716 fu_config[133 + (i * 10) + (7 - j)] =
717 ts->hopping.ma_data[j];
718 fu_config[133 + 8 + (i * 10)] = ts->hopping.hsn;
719 fu_config[133 + 8 + 1 + (i * 10)] = ts->hopping.maio;
720 *hopping = 1;
721 } else {
722 fu_config[133 + 8 + (i * 10)] = arfcn >> 8;
723 fu_config[133 + 8 + 1 + (i * 10)] = arfcn & 0xFF;
724 }
725 }
726
727 /* set BSIC */
728
Harald Weltecde57942011-07-28 00:13:46 +0200729 /*
Harald Weltebda367c2011-07-28 00:03:49 +0200730 Attention: all TRX except the first one seem to get the TSC
731 from the CHANNEL ACTIVATION command (in CHANNEL IDENTIFICATION,
Harald Weltecde57942011-07-28 00:13:46 +0200732 GSM 04.08 CHANNEL DESCRIPTION).
733 There was a bug in rsl_chan_activate_lchan() setting this parameter.
Harald Weltebda367c2011-07-28 00:03:49 +0200734 */
735
736 uint8_t bsic = trx->bts->bsic;
737
738 fu_config[106] = bsic;
739
740 /* set CA */
741
742 if (generate_cell_chan_list(&fu_config[38], trx->bts) != 0) {
743 fprintf(stderr, "generate_cell_chan_list failed\n");
744 return 0;
745 }
746
747 /* set channel configuration */
748
749 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
750 struct gsm_bts_trx_ts *ts = &trx->ts[i];
751 uint8_t chan_config;
752
753 /*
754 0 = FCCH + SCH + BCCH + CCCH
755 1 = FCCH + SCH + BCCH + CCCH + SDCCH/4 + SACCH/4
756 2 = BCCH + CCCH (This combination is not used in any BTS)
757 3 = FCCH + SCH + BCCH + CCCH + SDCCH/4 with SDCCH2 used as CBCH
758 4 = SDCCH/8 + SACCH/8
759 5 = SDCCH/8 with SDCCH2 used as CBCH
760 6 = TCH/F + FACCH/F + SACCH/F
761 7 = E-RACH (Talk family)
762 9 = Dual rate (capability for TCH/F and TCH/H)
763 10 = reserved for BTS internal use
Harald Weltecde57942011-07-28 00:13:46 +0200764 11 = PBCCH + PCCCH + PDTCH + PACCH + PTCCH (can be used in GPRS release 2).
765 0xFF = spare TS
Harald Weltebda367c2011-07-28 00:03:49 +0200766 */
767
768 if (ts->pchan == GSM_PCHAN_NONE)
769 chan_config = 0xFF;
770 else if (ts->pchan == GSM_PCHAN_CCCH)
771 chan_config = 0;
772 else if (ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
773 chan_config = 1;
774 else if (ts->pchan == GSM_PCHAN_TCH_F)
775 chan_config = 6; /* 9 should work too */
776 else if (ts->pchan == GSM_PCHAN_TCH_H)
777 chan_config = 9;
778 else if (ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C)
779 chan_config = 4;
780 else if (ts->pchan == GSM_PCHAN_PDCH)
781 chan_config = 11;
782 else {
783 fprintf(stderr,
784 "unsupported channel config %d for timeslot %d\n",
785 ts->pchan, i);
786 return 0;
787 }
788
789 fu_config[72 + i] = chan_config;
790 }
791 return sizeof(fu_config_template);
Dieter Spaar16646022011-07-28 00:01:50 +0200792}
793
794/* TODO: put in a separate file ? */
795
Harald Weltebda367c2011-07-28 00:03:49 +0200796static uint8_t bts_config_1[] = {
797 0x4E, 0x02,
798 /* ID = 0x0E (Frame number) */
799 /* length = 2 */
800 /* [2] */
801 0xFF, 0xFF,
802
803 0x5F, 0x4E, 0x02,
804 /* ID = 0x4E (RX antenna supervision period) */
805 /* length = 2 */
806 /* [7] */
807 0xFF, 0xFF,
808
809 0x5F, 0x50, 0x02,
810 /* ID = 0x50 (Sector configuration) */
811 /* length = 2 */
812 /* [12] */
813 0x01, 0x01,
814};
815
816static uint8_t bts_config_2[] = {
817 0x55, 0x02,
818 /* ID = 0x15 (Hopping mode) */
819 /* length = 2 */
820 /* [2] */
821 0x01, 0x00,
822
823 0x5F, 0x75, 0x02,
824 /* ID = 0x75 (RX diversity selection) */
825 /* length = 2 */
826 /* [7] */
827 0x01, 0x01,
828};
829
830static uint8_t bts_config_3[] = {
831 0x5F, 0x20, 0x02,
832 /* ID = 0x20 (Extended cell radius) */
833 /* length = 2 */
834 /* [3] */
835 0x01, 0x00,
836};
837
838static uint8_t bts_config_4[] = {
839 0x5F, 0x74, 0x09,
840 /* ID = 0x74 (Real Time) */
841 /* length = 9 */
842 /* [3] year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
843 0x07, 0xDB, 0x06, 0x02, 0x0B, 0x20, 0x0C, 0x00,
844 0x00,
845
846 0x5F, 0x76, 0x03,
847 /* ID = 0x76 (EAC input config) */
848 /* length = 3 */
849 /* [15] */
850 0x01, 0x01, 0x00,
851
852 0x5F, 0x76, 0x03,
853 /* ID = 0x76 (EAC input config) */
854 /* length = 3 */
855 /* [21] */
856 0x02, 0x01, 0x00,
857
858 0x5F, 0x76, 0x03,
859 /* ID = 0x76 (EAC input config) */
860 /* length = 3 */
861 /* [27] */
862 0x03, 0x01, 0x00,
863
864 0x5F, 0x76, 0x03,
865 /* ID = 0x76 (EAC input config) */
866 /* length = 3 */
867 /* [33] */
868 0x04, 0x01, 0x00,
869
870 0x5F, 0x76, 0x03,
871 /* ID = 0x76 (EAC input config) */
872 /* length = 3 */
873 /* [39] */
874 0x05, 0x01, 0x00,
875
876 0x5F, 0x76, 0x03,
877 /* ID = 0x76 (EAC input config) */
878 /* length = 3 */
879 /* [45] */
880 0x06, 0x01, 0x00,
881
882 0x5F, 0x76, 0x03,
883 /* ID = 0x76 (EAC input config) */
884 /* length = 3 */
885 /* [51] */
886 0x07, 0x01, 0x00,
887
888 0x5F, 0x76, 0x03,
889 /* ID = 0x76 (EAC input config) */
890 /* length = 3 */
891 /* [57] */
892 0x08, 0x01, 0x00,
893
894 0x5F, 0x76, 0x03,
895 /* ID = 0x76 (EAC input config) */
896 /* length = 3 */
897 /* [63] */
898 0x09, 0x01, 0x00,
899
900 0x5F, 0x76, 0x03,
901 /* ID = 0x76 (EAC input config) */
902 /* length = 3 */
903 /* [69] */
904 0x0A, 0x01, 0x00,
905};
906
907static uint8_t bts_config_insite[] = {
908 0x4E, 0x02,
909 /* ID = 0x0E (Frame number) */
910 /* length = 2 */
911 /* [2] */
912 0xFF, 0xFF,
913
914 0x5F, 0x4E, 0x02,
915 /* ID = 0x4E (RX antenna supervision period) */
916 /* length = 2 */
917 /* [7] */
918 0xFF, 0xFF,
919
920 0x5F, 0x50, 0x02,
921 /* ID = 0x50 (Sector configuration) */
922 /* length = 2 */
923 /* [12] */
924 0x01, 0x01,
925
926 0x55, 0x02,
927 /* ID = 0x15 (Hopping mode) */
928 /* length = 2 */
929 /* [16] */
930 0x01, 0x00,
931
932 0x5F, 0x20, 0x02,
933 /* ID = 0x20 (Extended cell radius) */
934 /* length = 2 */
935 /* [21] */
936 0x01, 0x00,
937
938 0x5F, 0x74, 0x09,
939 /* ID = 0x74 (Real Time) */
940 /* length = 9 */
941 /* [26] */
942 0x07, 0xDB, 0x07, 0x0A, 0x0F, 0x09, 0x0B, 0x00,
943 0x00,
944};
945
946void set_real_time(uint8_t * real_time)
Dieter Spaar16646022011-07-28 00:01:50 +0200947{
Harald Weltebda367c2011-07-28 00:03:49 +0200948 time_t t;
949 struct tm *tm;
Dieter Spaar16646022011-07-28 00:01:50 +0200950
Harald Weltebda367c2011-07-28 00:03:49 +0200951 t = time(NULL);
952 tm = localtime(&t);
Dieter Spaar16646022011-07-28 00:01:50 +0200953
Harald Weltebda367c2011-07-28 00:03:49 +0200954 /* year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
Dieter Spaar16646022011-07-28 00:01:50 +0200955
Harald Weltebda367c2011-07-28 00:03:49 +0200956 real_time[0] = (1900 + tm->tm_year) >> 8;
957 real_time[1] = (1900 + tm->tm_year) & 0xFF;
958 real_time[2] = tm->tm_mon + 1;
959 real_time[3] = tm->tm_mday;
960 real_time[4] = tm->tm_hour;
961 real_time[5] = tm->tm_min;
962 real_time[6] = tm->tm_sec;
963 real_time[7] = 0;
964 real_time[8] = 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200965}
966
967/* TODO: put in a separate file ? */
968
969/*
Dieter Spaar16646022011-07-28 00:01:50 +0200970 build the configuration data
Dieter Spaar16646022011-07-28 00:01:50 +0200971*/
972
Harald Weltebda367c2011-07-28 00:03:49 +0200973static int make_bts_config(uint8_t bts_type, int n_trx, uint8_t * fu_config,
974 int need_hopping)
Dieter Spaar16646022011-07-28 00:01:50 +0200975{
Harald Weltebda367c2011-07-28 00:03:49 +0200976 /* is it an InSite BTS ? */
977 if (bts_type == 0x0E || bts_type == 0x0F || bts_type == 0x10) { /* TODO */
978 if (n_trx != 1) {
979 fprintf(stderr, "InSite has only one TRX\n");
980 return 0;
981 }
982 if (need_hopping != 0) {
983 fprintf(stderr, "InSite does not support hopping\n");
984 return 0;
985 }
986 memcpy(fu_config, bts_config_insite, sizeof(bts_config_insite));
987 set_real_time(&fu_config[26]);
988 return sizeof(bts_config_insite);
989 }
Dieter Spaar16646022011-07-28 00:01:50 +0200990
Harald Weltebda367c2011-07-28 00:03:49 +0200991 int len = 0;
992 int i;
993
994 memcpy(fu_config + len, bts_config_1, sizeof(bts_config_1));
995
996 /* set sector configuration */
997 fu_config[len + 12 - 1] = 1 + n_trx; /* len */
998 for (i = 0; i < n_trx; i++)
999 fu_config[len + 12 + 1 + i] = ((i + 1) & 0xFF);
1000
1001 len += (sizeof(bts_config_1) + (n_trx - 1));
1002
1003 memcpy(fu_config + len, bts_config_2, sizeof(bts_config_2));
1004 /* set hopping mode (Baseband and RF hopping work for the MetroSite) */
1005 if (need_hopping)
1006 fu_config[len + 2 + 1] = 1; /* 0: no hopping, 1: Baseband hopping, 2: RF hopping */
1007 len += sizeof(bts_config_2);
1008
1009 /* set extended cell radius for each TRX */
1010 for (i = 0; i < n_trx; i++) {
1011 memcpy(fu_config + len, bts_config_3, sizeof(bts_config_3));
1012 fu_config[len + 3] = ((i + 1) & 0xFF);
1013 len += sizeof(bts_config_3);
1014 }
1015
1016 memcpy(fu_config + len, bts_config_4, sizeof(bts_config_4));
1017 set_real_time(&fu_config[len + 3]);
1018 len += sizeof(bts_config_4);
1019
1020 return len;
Dieter Spaar16646022011-07-28 00:01:50 +02001021}
1022
1023/* TODO: put in a separate file ? */
1024
1025static struct msgb *nm_msgb_alloc(void)
1026{
Harald Weltebda367c2011-07-28 00:03:49 +02001027 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML");
Dieter Spaar16646022011-07-28 00:01:50 +02001028}
1029
1030/* TODO: put in a separate file ? */
1031
1032struct abis_om_nokia_hdr {
Harald Weltebda367c2011-07-28 00:03:49 +02001033 uint8_t msg_type;
1034 uint8_t spare;
1035 uint16_t reference;
1036 uint8_t data[0];
Dieter Spaar16646022011-07-28 00:01:50 +02001037} __attribute__ ((packed));
1038
1039#define ABIS_OM_NOKIA_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_nokia_hdr))
1040
Harald Weltebda367c2011-07-28 00:03:49 +02001041static int abis_nm_send(struct gsm_bts *bts, uint8_t msg_type, uint16_t ref,
1042 uint8_t * data, int len_data)
Dieter Spaar16646022011-07-28 00:01:50 +02001043{
Harald Weltebda367c2011-07-28 00:03:49 +02001044 struct abis_om_hdr *oh;
1045 struct abis_om_nokia_hdr *noh;
1046 struct msgb *msg = nm_msgb_alloc();
Dieter Spaar16646022011-07-28 00:01:50 +02001047
Harald Weltebda367c2011-07-28 00:03:49 +02001048 oh = (struct abis_om_hdr *)msgb_put(msg,
1049 ABIS_OM_NOKIA_HDR_SIZE + len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001050
Harald Weltebda367c2011-07-28 00:03:49 +02001051 oh->mdisc = ABIS_OM_MDISC_FOM;
1052 oh->placement = ABIS_OM_PLACEMENT_ONLY;
1053 oh->sequence = 0;
1054 oh->length = sizeof(struct abis_om_nokia_hdr) + len_data;
1055
1056 noh = (struct abis_om_nokia_hdr *)oh->data;
1057
1058 noh->msg_type = msg_type;
1059 noh->spare = 0;
1060 noh->reference = htons(ref);
1061 memcpy(noh->data, data, len_data);
1062
1063 DEBUGPC(DNM, "Sending %s\n", get_msg_type_name_string(msg_type));
1064
1065 return abis_nm_sendmsg(bts, msg);
Dieter Spaar16646022011-07-28 00:01:50 +02001066}
1067
1068/* TODO: put in a separate file ? */
1069
1070static uint8_t download_req[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001071 0x5F, 0x25, 0x0B,
1072 /* ID = 0x25 (File identity) */
1073 /* length = 11 */
1074 /* [3] */
1075 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
1076 0x2A, 0x2A, 0x2A,
Dieter Spaar16646022011-07-28 00:01:50 +02001077
Harald Weltebda367c2011-07-28 00:03:49 +02001078 0x5F, 0x78, 0x03,
1079 /* ID = 0x78 (File version) */
1080 /* length = 3 */
1081 /* [17] */
1082 0x2A, 0x2A, 0x2A,
Dieter Spaar16646022011-07-28 00:01:50 +02001083
Harald Weltebda367c2011-07-28 00:03:49 +02001084 0x5F, 0x81, 0x0A, 0x01,
1085 /* ID = 0x8A (SW load mode) */
1086 /* length = 1 */
1087 /* [24] */
1088 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001089
Harald Weltebda367c2011-07-28 00:03:49 +02001090 0x5F, 0x81, 0x06, 0x01,
1091 /* ID = 0x86 (Acknowledgement period) */
1092 /* length = 1 */
1093 /* [29] */
1094 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001095};
1096
1097static int abis_nm_download_req(struct gsm_bts *bts, uint16_t ref)
1098{
Harald Weltebda367c2011-07-28 00:03:49 +02001099 uint8_t *data = download_req;
1100 int len_data = sizeof(download_req);
1101
1102 return abis_nm_send(bts, NOKIA_MSG_START_DOWNLOAD_REQ, ref, data,
1103 len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001104}
1105
1106/* TODO: put in a separate file ? */
1107
1108static uint8_t ack[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001109 0x5F, 0x23, 0x01,
1110 /* ID = 0x23 (Ack-Nack) */
1111 /* length = 1 */
1112 /* [3] */
1113 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001114};
1115
1116static int abis_nm_ack(struct gsm_bts *bts, uint16_t ref)
1117{
Harald Weltebda367c2011-07-28 00:03:49 +02001118 uint8_t *data = ack;
1119 int len_data = sizeof(ack);
1120
1121 return abis_nm_send(bts, NOKIA_MSG_ACK, ref, data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001122}
1123
1124/* TODO: put in a separate file ? */
1125
1126static uint8_t reset[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001127 0x5F, 0x40, 0x04,
1128 /* ID = 0x40 (Object identity) */
1129 /* length = 4 */
1130 /* [3] */
1131 0x00, 0x01, 0xFF, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +02001132};
1133
1134static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref)
1135{
Harald Weltebda367c2011-07-28 00:03:49 +02001136 uint8_t *data = reset;
1137 int len_data = sizeof(reset);
1138
1139 return abis_nm_send(bts, NOKIA_MSG_RESET_REQ, ref, data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001140}
1141
1142/* TODO: put in a separate file ? */
1143
Harald Weltebda367c2011-07-28 00:03:49 +02001144static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type,
1145 uint16_t ref, uint8_t * data, int len)
Dieter Spaar16646022011-07-28 00:01:50 +02001146{
Harald Weltebda367c2011-07-28 00:03:49 +02001147 int len_remain, len_to_send, max_send;
1148 int seq = 0;
1149 int ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001150
Harald Weltebda367c2011-07-28 00:03:49 +02001151 len_remain = len;
1152
1153 while (len_remain) {
1154 struct abis_om_hdr *oh;
1155 struct abis_om_nokia_hdr *noh;
1156 struct msgb *msg = nm_msgb_alloc();
1157
1158 if (seq == 0)
1159 max_send = 256 - sizeof(struct abis_om_nokia_hdr);
1160 else
1161 max_send = 256;
1162
1163 if (len_remain > max_send) {
1164 len_to_send = max_send;
1165
1166 if (seq == 0) {
1167 /* first segment */
1168 oh = (struct abis_om_hdr *)msgb_put(msg,
1169 ABIS_OM_NOKIA_HDR_SIZE
1170 +
1171 len_to_send);
1172
1173 oh->mdisc = ABIS_OM_MDISC_FOM;
1174 oh->placement = ABIS_OM_PLACEMENT_FIRST; /* first segment of multi-segment message */
1175 oh->sequence = seq;
1176 oh->length = 0; /* 256 bytes */
1177
1178 noh = (struct abis_om_nokia_hdr *)oh->data;
1179
1180 noh->msg_type = msg_type;
1181 noh->spare = 0;
1182 noh->reference = htons(ref);
1183 memcpy(noh->data, data, len_to_send);
1184 } else {
1185 /* segment in between */
1186 oh = (struct abis_om_hdr *)msgb_put(msg,
1187 sizeof
1188 (struct
1189 abis_om_hdr)
1190 +
1191 len_to_send);
1192
1193 oh->mdisc = ABIS_OM_MDISC_FOM;
1194 oh->placement = ABIS_OM_PLACEMENT_MIDDLE; /* segment of multi-segment message */
1195 oh->sequence = seq;
1196 oh->length = 0; /* 256 bytes */
1197
1198 memcpy(oh->data, data, len_to_send);
1199 }
1200 } else {
1201
1202 len_to_send = len_remain;
1203
1204 /* check if message fits in a single segment */
1205
1206 if (seq == 0)
1207 return abis_nm_send(bts, msg_type, ref, data,
1208 len_to_send);
1209
1210 /* last segment */
1211
1212 oh = (struct abis_om_hdr *)msgb_put(msg,
1213 sizeof(struct
1214 abis_om_hdr)
1215 + len_to_send);
1216
1217 oh->mdisc = ABIS_OM_MDISC_FOM;
1218 oh->placement = ABIS_OM_PLACEMENT_LAST; /* last segment of multi-segment message */
1219 oh->sequence = seq;
1220 oh->length = len_to_send;
1221
1222 memcpy(oh->data, data, len_to_send);
1223 }
1224
1225 DEBUGPC(DNM, "Sending multi-segment %d\n", seq);
1226
1227 ret = abis_nm_sendmsg(bts, msg);
1228 if (ret < 0)
1229 return ret;
1230
1231 abis_nm_queue_send_next(bts);
1232
1233 /* next segment */
1234 len_remain -= len_to_send;
1235 data += len_to_send;
1236 seq++;
1237 }
1238 return ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001239}
1240
1241/* TODO: put in a separate file ? */
1242
1243static int abis_nm_send_config(struct gsm_bts *bts, uint8_t bts_type)
1244{
Harald Weltebda367c2011-07-28 00:03:49 +02001245 struct gsm_bts_trx *trx;
1246 uint8_t config[2048]; /* TODO: might be too small if lots of TRX are used */
1247 int len = 0;
1248 int idx = 0;
1249 int ret;
1250 int hopping = 0;
1251 int need_hopping = 0;
1252
1253 memset(config, 0, sizeof(config));
1254
1255 llist_for_each_entry(trx, &bts->trx_list, list) {
1256#if 0 /* debugging */
1257 printf("TRX\n");
1258 printf(" arfcn: %d\n", trx->arfcn);
1259 printf(" bsic: %d\n", trx->bts->bsic);
1260 uint8_t ca[20];
1261 memset(ca, 0xFF, sizeof(ca));
1262 ret = generate_cell_chan_list(ca, trx->bts);
1263 printf(" ca (%d): %s\n", ret, osmo_hexdump(ca, sizeof(ca)));
1264 int i;
1265 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
1266 struct gsm_bts_trx_ts *ts = &trx->ts[i];
1267
1268 printf(" pchan %d: %d\n", i, ts->pchan);
1269 }
Dieter Spaar16646022011-07-28 00:01:50 +02001270#endif
Harald Weltebda367c2011-07-28 00:03:49 +02001271 ret = make_fu_config(trx, idx + 1, config + len, &hopping);
1272 need_hopping |= hopping;
1273 len += ret;
1274
1275 idx++;
1276 }
1277
1278 ret = make_bts_config(bts_type, idx, config + len, need_hopping);
1279 len += ret;
1280
1281#if 0 /* debugging */
1282 dump_elements(config, len);
1283#endif
1284
1285 return abis_nm_send_multi_segments(bts, NOKIA_MSG_CONF_DATA, 1, config,
1286 len);
Dieter Spaar16646022011-07-28 00:01:50 +02001287}
1288
1289#define GET_NEXT_BYTE if(idx >= len) return 0; \
Harald Weltebda367c2011-07-28 00:03:49 +02001290 ub = data[idx++];
Dieter Spaar16646022011-07-28 00:01:50 +02001291
Harald Weltebda367c2011-07-28 00:03:49 +02001292static int find_element(uint8_t * data, int len, uint16_t id, uint8_t * value,
1293 int max_value)
1294{
1295 uint8_t ub;
1296 int idx = 0;
1297 int found = 0;
1298 int constructed;
1299 uint16_t id_value;
1300
1301 for (;;) {
1302
1303 GET_NEXT_BYTE;
1304
1305 /* encoding bit, construced means that other elements are contained */
1306 constructed = ((ub & 0x20) ? 1 : 0);
1307
1308 if ((ub & 0x1F) == 0x1F) {
1309 /* fixed pattern, ID follows */
1310 GET_NEXT_BYTE; /* ID */
1311 id_value = ub & 0x7F;
1312 if (ub & 0x80) {
1313 /* extension bit */
1314 GET_NEXT_BYTE; /* ID low part */
1315 id_value = (id_value << 7) | (ub & 0x7F);
1316 }
1317 if (id_value == id)
1318 found = 1;
1319 } else {
1320 id_value = (ub & 0x3F);
1321 if (id_value == id)
1322 found = 1;
1323 }
1324
1325 GET_NEXT_BYTE; /* length */
1326
1327 if (found) {
1328 /* get data */
1329 uint8_t n = ub;
1330 uint8_t i;
1331 for (i = 0; i < n; i++) {
1332 GET_NEXT_BYTE;
1333 if (max_value <= 0)
1334 return -1; /* buffer too small */
1335 *value = ub;
1336 value++;
1337 max_value--;
1338 }
1339 return n; /* length */
1340 } else {
1341 /* skip data */
1342 uint8_t n = ub;
1343 uint8_t i;
1344 for (i = 0; i < n; i++) {
1345 GET_NEXT_BYTE;
1346 }
1347 }
1348 }
1349 return 0; /* not found */
Dieter Spaar16646022011-07-28 00:01:50 +02001350}
1351
Harald Weltebda367c2011-07-28 00:03:49 +02001352static int dump_elements(uint8_t * data, int len)
1353{
1354 uint8_t ub;
1355 int idx = 0;
1356 int constructed;
1357 uint16_t id_value;
1358 static char indent[100] = ""; /* TODO: move static to BTS context */
Dieter Spaar16646022011-07-28 00:01:50 +02001359
Harald Weltebda367c2011-07-28 00:03:49 +02001360 for (;;) {
1361
1362 GET_NEXT_BYTE;
1363
1364 /* encoding bit, construced means that other elements are contained */
1365 constructed = ((ub & 0x20) ? 1 : 0);
1366
1367 if ((ub & 0x1F) == 0x1F) {
1368 /* fixed pattern, ID follows */
1369 GET_NEXT_BYTE; /* ID */
1370 id_value = ub & 0x7F;
1371 if (ub & 0x80) {
1372 /* extension bit */
1373 GET_NEXT_BYTE; /* ID low part */
1374 id_value = (id_value << 7) | (ub & 0x7F);
1375 }
1376
1377 } else {
1378 id_value = (ub & 0x3F);
1379 }
1380
1381 GET_NEXT_BYTE; /* length */
1382
1383 printf("%s--ID = 0x%02X (%s) %s\n", indent, id_value,
1384 get_element_name_string(id_value),
1385 constructed ? "** constructed **" : "");
1386 printf("%s length = %d\n", indent, ub);
1387 printf("%s %s\n", indent, osmo_hexdump(data + idx, ub));
1388
1389 if (constructed) {
1390 int indent_len = strlen(indent);
1391 strcat(indent, " ");
1392
1393 dump_elements(data + idx, ub);
1394
1395 indent[indent_len] = 0;
1396 }
1397 /* skip data */
1398 uint8_t n = ub;
1399 uint8_t i;
1400 for (i = 0; i < n; i++) {
1401 GET_NEXT_BYTE;
1402 }
1403 }
1404 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001405}
1406
1407/* TODO: put in a separate file ? */
1408
1409/* taken from abis_nm.c */
1410
1411static void abis_nm_queue_send_next(struct gsm_bts *bts)
1412{
Harald Weltebda367c2011-07-28 00:03:49 +02001413 int wait = 0;
1414 struct msgb *msg;
1415 /* the queue is empty */
1416 while (!llist_empty(&bts->abis_queue)) {
1417 msg = msgb_dequeue(&bts->abis_queue);
1418 wait = OBSC_NM_W_ACK_CB(msg);
1419 _abis_nm_sendmsg(msg, 0);
Dieter Spaar16646022011-07-28 00:01:50 +02001420
Harald Weltebda367c2011-07-28 00:03:49 +02001421 if (wait)
1422 break;
1423 }
Dieter Spaar16646022011-07-28 00:01:50 +02001424
Harald Weltebda367c2011-07-28 00:03:49 +02001425 bts->abis_nm_pend = wait;
Dieter Spaar16646022011-07-28 00:01:50 +02001426}
1427
1428/* TODO: put in a separate file ? */
1429
1430/* timer for restarting OML after BTS reset */
1431
1432static void reset_timer_cb(void *_bts)
1433{
Harald Weltebda367c2011-07-28 00:03:49 +02001434 struct gsm_bts *bts = _bts;
1435 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1436 struct e1inp_line *line;
1437
Harald Weltec8755af2011-07-28 00:22:17 +02001438 bts->nokia.wait_reset = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001439
1440 /* OML link */
1441 line = e1inp_line_get(e1_link->e1_nr);
1442 if (!line) {
1443 LOGP(DINP, LOGL_ERROR, "BTS %u OML link referring to "
1444 "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
1445 return;
1446 }
1447
1448 start_sabm_in_line(line, 0, -1); /* stop all first */
1449 start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */
Dieter Spaar16646022011-07-28 00:01:50 +02001450}
1451
1452/* TODO: put in a separate file ? */
1453
1454/*
1455 This is how the configuration is done:
Dieter Spaar16646022011-07-28 00:01:50 +02001456 - start OML link
Dieter Spaar16646022011-07-28 00:01:50 +02001457 - reset BTS
Dieter Spaar16646022011-07-28 00:01:50 +02001458 - receive ACK, wait some time and restart OML link
Dieter Spaar16646022011-07-28 00:01:50 +02001459 - receive OMU STARTED message, send START DOWNLOAD REQ
Dieter Spaar16646022011-07-28 00:01:50 +02001460 - receive CNF REQ message, send CONF DATA
Dieter Spaar16646022011-07-28 00:01:50 +02001461 - receive ACK, start RSL link(s)
Dieter Spaar16646022011-07-28 00:01:50 +02001462 ACK some other messages received from the BTS.
Harald Weltecde57942011-07-28 00:13:46 +02001463
Dieter Spaar16646022011-07-28 00:01:50 +02001464 Probably its also possible to configure the BTS without a reset, this
1465 has not been tested yet.
1466*/
1467
1468static int abis_nm_rcvmsg_fom(struct msgb *mb)
1469{
Harald Weltebda367c2011-07-28 00:03:49 +02001470 struct gsm_bts *bts = mb->trx->bts;
1471 struct abis_om_hdr *oh = msgb_l2(mb);
1472 struct abis_om_nokia_hdr *noh = msgb_l3(mb);
1473 uint8_t mt = noh->msg_type;
1474 int ret = 0;
1475 uint16_t ref = ntohs(noh->reference);
Harald Weltebda367c2011-07-28 00:03:49 +02001476 uint8_t info[256];
1477 uint8_t ack = 0xFF;
1478 uint8_t severity = 0xFF;
1479 int str_len;
1480 int len_data;
Dieter Spaar16646022011-07-28 00:01:50 +02001481
Harald Weltec8755af2011-07-28 00:22:17 +02001482 if (bts->nokia.wait_reset) {
Harald Weltebda367c2011-07-28 00:03:49 +02001483 LOGP(DNM, LOGL_INFO,
1484 "Ignore message while waiting for reset\n");
1485 return ret;
1486 }
Dieter Spaar16646022011-07-28 00:01:50 +02001487
Harald Weltebda367c2011-07-28 00:03:49 +02001488 if (oh->length < sizeof(struct abis_om_nokia_hdr)) {
1489 LOGP(DNM, LOGL_ERROR, "Message too short\n");
1490 return -EINVAL;
1491 }
1492
1493 len_data = oh->length - sizeof(struct abis_om_nokia_hdr);
1494 LOGP(DNM, LOGL_INFO, "(0x%02X) %s\n", mt, get_msg_type_name_string(mt));
1495#if 0 /* debugging */
1496 dump_elements(noh->data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001497#endif
Dieter Spaar16646022011-07-28 00:01:50 +02001498
Harald Weltebda367c2011-07-28 00:03:49 +02001499 switch (mt) {
1500 case NOKIA_MSG_OMU_STARTED:
Harald Welte9d2f3772011-07-28 00:19:06 +02001501 if (find_element(noh->data, len_data,
1502 NOKIA_EI_BTS_TYPE, &bts->nokia.bts_type,
1503 sizeof(uint8_t)) == sizeof(uint8_t))
1504 LOGP(DNM, LOGL_INFO, "BTS type = %d (%s)\n",
1505 bts->nokia.bts_type,
1506 get_bts_type_string(bts->nokia.bts_type));
Harald Weltebda367c2011-07-28 00:03:49 +02001507 else
1508 LOGP(DNM, LOGL_ERROR, "BTS type not found\n");
1509 /* send START_DOWNLOAD_REQ */
1510 abis_nm_download_req(bts, ref);
1511 break;
1512 case NOKIA_MSG_MF_REQ:
1513 break;
1514 case NOKIA_MSG_CONF_REQ:
1515 /* send ACK */
1516 abis_nm_ack(bts, ref);
1517 abis_nm_queue_send_next(bts);
1518 /* send CONF_DATA */
Harald Welte9d2f3772011-07-28 00:19:06 +02001519 abis_nm_send_config(bts, bts->nokia.bts_type);
1520 bts->nokia.configured = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001521 break;
1522 case NOKIA_MSG_ACK:
1523 if (find_element
1524 (noh->data, len_data, NOKIA_EI_ACK, &ack,
1525 sizeof(uint8_t)) == sizeof(uint8_t)) {
1526 LOGP(DNM, LOGL_INFO, "ACK = %d\n", ack);
1527 if (ack != 1) {
1528 LOGP(DNM, LOGL_ERROR, "No ACK received (%d)\n",
1529 ack);
1530 /* TODO: properly handle failures (NACK) */
1531 }
1532 } else
1533 LOGP(DNM, LOGL_ERROR, "ACK not found\n");
Dieter Spaar16646022011-07-28 00:01:50 +02001534
Harald Weltebda367c2011-07-28 00:03:49 +02001535 /* TODO: the assumption for the following is that no NACK was received */
1536
1537 /* ACK for reset message ? */
Harald Weltec8755af2011-07-28 00:22:17 +02001538 if (bts->nokia.do_reset != 0) {
1539 bts->nokia.do_reset = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001540
1541 /*
1542 TODO: For the InSite processing the received data is
1543 blocked in the driver during reset.
1544 Otherwise the LAPD module might assert because the InSite
1545 sends garbage on the E1 line during reset.
1546 This is done by looking at "wait_reset" in the driver
1547 (function handle_ts1_read()) and ignoring the received data.
1548 It seems to be necessary for the MetroSite too.
1549 */
Harald Weltec8755af2011-07-28 00:22:17 +02001550 bts->nokia.wait_reset = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001551
Harald Weltec8755af2011-07-28 00:22:17 +02001552 bts->nokia.reset_timer.cb = &reset_timer_cb;
1553 bts->nokia.reset_timer.data = bts;
1554 osmo_timer_schedule(&bts->nokia.reset_timer, RESET_INTERVAL);
Harald Weltebda367c2011-07-28 00:03:49 +02001555
1556 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1557 struct e1inp_line *line;
1558 /* OML link */
1559 line = e1inp_line_get(e1_link->e1_nr);
1560 if (!line) {
1561 LOGP(DINP, LOGL_ERROR,
1562 "BTS %u OML link referring to "
1563 "non-existing E1 line %u\n", bts->nr,
1564 e1_link->e1_nr);
1565 return -ENOMEM;
1566 }
1567
1568 start_sabm_in_line(line, 0, -1); /* stop all first */
1569 }
1570
1571 /* ACK for CONF DATA message ? */
Harald Welte9d2f3772011-07-28 00:19:06 +02001572 if (bts->nokia.configured != 0) {
Harald Weltebda367c2011-07-28 00:03:49 +02001573 /* start TRX (RSL link) */
1574
1575 struct gsm_e1_subslot *e1_link = &mb->trx->rsl_e1_link;
1576 struct e1inp_line *line;
1577
Harald Welte9d2f3772011-07-28 00:19:06 +02001578 bts->nokia.configured = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001579
1580 /* RSL Link */
1581 line = e1inp_line_get(e1_link->e1_nr);
1582 if (!line) {
1583 LOGP(DINP, LOGL_ERROR,
1584 "TRX (%u/%u) RSL link referring "
1585 "to non-existing E1 line %u\n",
1586 mb->trx->bts->nr, mb->trx->nr,
1587 e1_link->e1_nr);
1588 return -ENOMEM;
1589 }
1590 /* start TRX */
1591 start_sabm_in_line(line, 1, SAPI_RSL); /* start only RSL */
1592 }
1593 break;
1594 case NOKIA_MSG_STATE_CHANGED:
1595 /* send ACK */
1596 abis_nm_ack(bts, ref);
1597 break;
1598 case NOKIA_MSG_CONF_COMPLETE:
1599 /* send ACK */
1600 abis_nm_ack(bts, ref);
1601 break;
1602 case NOKIA_MSG_BLOCK_CTRL_REQ: /* seems to be send when something goes wrong !? */
1603 /* send ACK (do we have to send an ACK ?) */
1604 abis_nm_ack(bts, ref);
1605 break;
1606 case NOKIA_MSG_ALARM:
1607 find_element(noh->data, len_data, NOKIA_EI_SEVERITY, &severity,
1608 sizeof(severity));
1609 /* TODO: there might be alarms with both elements set */
1610 str_len =
1611 find_element(noh->data, len_data, NOKIA_EI_ADD_INFO, info,
1612 sizeof(info));
1613 if (str_len > 0) {
1614 info[str_len] = 0;
1615 LOGP(DNM, LOGL_INFO, "ALARM Severity %s (%d) : %s\n",
1616 get_severity_string(severity), severity, info);
1617 } else { /* nothing found, try details */
1618 str_len =
1619 find_element(noh->data, len_data,
1620 NOKIA_EI_ALARM_DETAIL, info,
1621 sizeof(info));
1622 if (str_len > 0) {
1623 uint16_t code;
1624 info[str_len] = 0;
1625 code = (info[0] << 8) + info[1];
1626 LOGP(DNM, LOGL_INFO,
1627 "ALARM Severity %s (%d), code 0x%X : %s\n",
1628 get_severity_string(severity), severity,
1629 code, info + 2);
1630 }
1631 }
1632 /* send ACK */
1633 abis_nm_ack(bts, ref);
1634 break;
1635 }
1636
1637 abis_nm_queue_send_next(bts);
1638
1639 return ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001640}
1641
1642/* TODO: put in a separate file ? */
1643
1644int abis_nokia_rcvmsg(struct msgb *msg)
1645{
Harald Weltebda367c2011-07-28 00:03:49 +02001646 struct abis_om_hdr *oh = msgb_l2(msg);
1647 int rc = 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001648
Harald Weltebda367c2011-07-28 00:03:49 +02001649 /* Various consistency checks */
1650 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
1651 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
1652 oh->placement);
1653 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1654 return -EINVAL;
1655 }
1656 if (oh->sequence != 0) {
1657 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
1658 oh->sequence);
1659 return -EINVAL;
1660 }
1661 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Dieter Spaar16646022011-07-28 00:01:50 +02001662
Harald Weltebda367c2011-07-28 00:03:49 +02001663 switch (oh->mdisc) {
1664 case ABIS_OM_MDISC_FOM:
1665 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_FOM\n");
1666 rc = abis_nm_rcvmsg_fom(msg);
1667 break;
1668 case ABIS_OM_MDISC_MANUF:
1669 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_MANUF\n");
1670 break;
1671 case ABIS_OM_MDISC_MMI:
1672 case ABIS_OM_MDISC_TRAU:
1673 LOGP(DNM, LOGL_ERROR,
1674 "unimplemented ABIS OML message discriminator 0x%x\n",
1675 oh->mdisc);
1676 break;
1677 default:
1678 LOGP(DNM, LOGL_ERROR,
1679 "unknown ABIS OML message discriminator 0x%x\n",
1680 oh->mdisc);
1681 return -EINVAL;
1682 }
Dieter Spaar16646022011-07-28 00:01:50 +02001683
Harald Weltebda367c2011-07-28 00:03:49 +02001684 msgb_free(msg);
1685 return rc;
Dieter Spaar16646022011-07-28 00:01:50 +02001686}
1687
1688static int bts_model_nokia_site_start(struct gsm_network *net);
1689
1690static struct gsm_bts_model model_nokia_site = {
Harald Weltebda367c2011-07-28 00:03:49 +02001691 .type = GSM_BTS_TYPE_NOKIA_SITE,
1692 .name = "nokia_site",
1693 .start = bts_model_nokia_site_start,
1694 .oml_rcvmsg = &abis_nokia_rcvmsg
Dieter Spaar16646022011-07-28 00:01:50 +02001695};
1696
1697static struct gsm_network *my_net;
1698
1699static int bts_model_nokia_site_start(struct gsm_network *net)
1700{
Harald Weltebda367c2011-07-28 00:03:49 +02001701 model_nokia_site.features.data = &model_nokia_site._features_data[0];
1702 model_nokia_site.features.data_len =
1703 sizeof(model_nokia_site._features_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001704
Harald Weltebda367c2011-07-28 00:03:49 +02001705 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HOPPING);
1706 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HSCSD);
Dieter Spaar16646022011-07-28 00:01:50 +02001707
Harald Weltebda367c2011-07-28 00:03:49 +02001708 osmo_signal_register_handler(SS_INPUT, inp_sig_cb, NULL);
1709 osmo_signal_register_handler(SS_GLOBAL, gbl_sig_cb, NULL);
1710 osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
Dieter Spaar16646022011-07-28 00:01:50 +02001711
Harald Weltebda367c2011-07-28 00:03:49 +02001712 my_net = net;
1713
1714 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001715}
1716
1717int bts_model_nokia_site_init(void)
1718{
Harald Weltebda367c2011-07-28 00:03:49 +02001719 return gsm_bts_model_register(&model_nokia_site);
Dieter Spaar16646022011-07-28 00:01:50 +02001720}