blob: 4b5c50f98fc1dbab270db5808bbf17c95a828885 [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
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
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020051static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts);
Dieter Spaar16646022011-07-28 00:01:50 +020052static 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
Pablo Neira Ayuso2962c202011-08-10 00:48:10 +020087void start_sabm_in_line(struct e1inp_line *line, int start, int sapi)
Dieter Spaar16646022011-07-28 00:01:50 +020088{
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)
Harald Welteb4d913d2011-08-26 19:14:55 +0200108 lapd_sap_start(ts->lapd, link->tei,
Harald Weltebda367c2011-07-28 00:03:49 +0200109 link->sapi);
110 else
Harald Welteb4d913d2011-08-26 19:14:55 +0200111 lapd_sap_stop(ts->lapd, link->tei,
Harald Weltebda367c2011-07-28 00:03:49 +0200112 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
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200123 if (subsys != SS_L_GLOBAL)
Harald Weltebda367c2011-07-28 00:03:49 +0200124 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
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200143 if (subsys != SS_L_INPUT)
Harald Weltebda367c2011-07-28 00:03:49 +0200144 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200145
Harald Weltebda367c2011-07-28 00:03:49 +0200146 switch (signal) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200147 case S_L_INP_LINE_INIT:
Harald Weltebda367c2011-07-28 00:03:49 +0200148 start_sabm_in_line(isd->line, 1, SAPI_OML); /* start only OML */
149 break;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200150 case S_L_INP_TEI_DN:
Harald Weltebda367c2011-07-28 00:03:49 +0200151 break;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200152 case S_L_INP_TEI_UP:
Harald Weltebda367c2011-07-28 00:03:49 +0200153 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;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200165 case S_L_INP_TEI_UNKNOWN:
Pablo Neira Ayuso2962c202011-08-10 00:48:10 +0200166 /* We are receiving LAPD frames with one TEI that we do not
167 * seem to know, likely that we (the BSC) stopped working
168 * and lost our local states. However, the BTS is already
169 * configured, we try to take over the RSL links. */
170 start_sabm_in_line(isd->line, 1, SAPI_RSL);
171 break;
Harald Weltebda367c2011-07-28 00:03:49 +0200172 }
173
174 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200175}
176
177static void nm_statechg_evt(unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200178 struct nm_statechg_signal_data *nsd)
Dieter Spaar16646022011-07-28 00:01:50 +0200179{
Harald Weltebda367c2011-07-28 00:03:49 +0200180 if (nsd->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
181 return;
Dieter Spaar16646022011-07-28 00:01:50 +0200182}
183
184static int nm_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200185 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200186{
Harald Weltebda367c2011-07-28 00:03:49 +0200187 if (subsys != SS_NM)
188 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200189
Harald Weltebda367c2011-07-28 00:03:49 +0200190 switch (signal) {
191 case S_NM_STATECHG_OPER:
192 case S_NM_STATECHG_ADM:
193 nm_statechg_evt(signal, signal_data);
194 break;
195 default:
196 break;
197 }
Dieter Spaar16646022011-07-28 00:01:50 +0200198
Harald Weltebda367c2011-07-28 00:03:49 +0200199 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200200}
201
202/* TODO: put in a separate file ? */
203
Harald Welte44d26112011-07-28 00:43:13 +0200204static const struct value_string nokia_msgt_name[] = {
205 { 0x80, "NOKIA_BTS_CONF_DATA" },
206 { 0x81, "NOKIA_BTS_ACK" },
207 { 0x82, "NOKIA_BTS_OMU_STARTED" },
208 { 0x83, "NOKIA_BTS_START_DOWNLOAD_REQ" },
209 { 0x84, "NOKIA_BTS_MF_REQ" },
210 { 0x85, "NOKIA_BTS_AF_REQ" },
211 { 0x86, "NOKIA_BTS_RESET_REQ" },
212 { 0x87, "NOKIA_reserved" },
213 { 0x88, "NOKIA_BTS_CONF_REQ" },
214 { 0x89, "NOKIA_BTS_TEST_REQ" },
215 { 0x8A, "NOKIA_BTS_TEST_REPORT" },
216 { 0x8B, "NOKIA_reserved" },
217 { 0x8C, "NOKIA_reserved" },
218 { 0x8D, "NOKIA_reserved" },
219 { 0x8E, "NOKIA_BTS_CONF_COMPL" },
220 { 0x8F, "NOKIA_reserved" },
221 { 0x90, "NOKIA_BTS_STM_TEST_REQ" },
222 { 0x91, "NOKIA_BTS_STM_TEST_REPORT" },
223 { 0x92, "NOKIA_BTS_TRANSMISSION_COMMAND" },
224 { 0x93, "NOKIA_BTS_TRANSMISSION_ANSWER" },
225 { 0x94, "NOKIA_BTS_HW_DB_UPLOAD_REQ" },
226 { 0x95, "NOKIA_BTS_START_HW_DB_DOWNLOAD_REQ" },
227 { 0x96, "NOKIA_BTS_HW_DB_SAVE_REQ" },
228 { 0x97, "NOKIA_BTS_FLASH_ERASURE_REQ" },
229 { 0x98, "NOKIA_BTS_HW_DB_DOWNLOAD_REQ" },
230 { 0x99, "NOKIA_BTS_PWR_SUPPLY_CONTROL" },
231 { 0x9A, "NOKIA_BTS_ATTRIBUTE_REQ" },
232 { 0x9B, "NOKIA_BTS_ATTRIBUTE_REPORT" },
233 { 0x9C, "NOKIA_BTS_HW_REQ" },
234 { 0x9D, "NOKIA_BTS_HW_REPORT" },
235 { 0x9E, "NOKIA_BTS_RTE_TEST_REQ" },
236 { 0x9F, "NOKIA_BTS_RTE_TEST_REPORT" },
237 { 0xA0, "NOKIA_BTS_HW_DB_VERIFICATION_REQ" },
238 { 0xA1, "NOKIA_BTS_CLOCK_REQ" },
239 { 0xA2, "NOKIA_AC_CIRCUIT_REQ_NACK" },
240 { 0xA3, "NOKIA_AC_INTERRUPTED" },
241 { 0xA4, "NOKIA_BTS_NEW_TRE_INFO" },
242 { 0xA5, "NOKIA_AC_BSC_CIRCUITS_ALLOCATED" },
243 { 0xA6, "NOKIA_BTS_TRE_POLL_LIST" },
244 { 0xA7, "NOKIA_AC_CIRCUIT_REQ" },
245 { 0xA8, "NOKIA_BTS_BLOCK_CTRL_REQ" },
246 { 0xA9, "NOKIA_BTS_GSM_TIME_REQ" },
247 { 0xAA, "NOKIA_BTS_GSM_TIME" },
248 { 0xAB, "NOKIA_BTS_OUTPUT_CONTROL" },
249 { 0xAC, "NOKIA_BTS_STATE_CHANGED" },
250 { 0xAD, "NOKIA_BTS_SW_SAVE_REQ" },
251 { 0xAE, "NOKIA_BTS_ALARM" },
252 { 0xAF, "NOKIA_BTS_CHA_ADM_STATE" },
253 { 0xB0, "NOKIA_AC_POOL_SIZE_REPORT" },
254 { 0xB1, "NOKIA_AC_POOL_SIZE_INQUIRY" },
255 { 0xB2, "NOKIA_BTS_COMMISS_TEST_COMPLETED" },
256 { 0xB3, "NOKIA_BTS_COMMISS_TEST_REQ" },
257 { 0xB4, "NOKIA_BTS_TRANSP_BTS_TO_BSC" },
258 { 0xB5, "NOKIA_BTS_TRANSP_BSC_TO_BTS" },
259 { 0xB6, "NOKIA_BTS_LCS_COMMAND" },
260 { 0xB7, "NOKIA_BTS_LCS_ANSWER" },
261 { 0xB8, "NOKIA_BTS_LMU_FN_OFFSET_COMMAND" },
262 { 0xB9, "NOKIA_BTS_LMU_FN_OFFSET_ANSWER" },
263 { 0, NULL }
264};
265
266static const char *get_msg_type_name_string(uint8_t msg_type)
Dieter Spaar16646022011-07-28 00:01:50 +0200267{
Harald Welte44d26112011-07-28 00:43:13 +0200268 return get_value_string(nokia_msgt_name, msg_type);
Dieter Spaar16646022011-07-28 00:01:50 +0200269}
270
Harald Welte44d26112011-07-28 00:43:13 +0200271static const struct value_string nokia_element_name[] = {
272 { 0x01, "Ny1" },
273 { 0x02, "T3105_F" },
274 { 0x03, "Interference band limits" },
275 { 0x04, "Interference report timer in secs" },
276 { 0x05, "Channel configuration per TS" },
277 { 0x06, "BSIC" },
278 { 0x07, "RACH report timer in secs" },
279 { 0x08, "Hardware database status" },
280 { 0x09, "BTS RX level" },
281 { 0x0A, "ARFN" },
282 { 0x0B, "STM antenna attenuation" },
283 { 0x0C, "Cell allocation bitmap" },
284 { 0x0D, "Radio definition per TS" },
285 { 0x0E, "Frame number" },
286 { 0x0F, "Antenna diversity" },
287 { 0x10, "T3105_D" },
288 { 0x11, "File format" },
289 { 0x12, "Last File" },
290 { 0x13, "BTS type" },
291 { 0x14, "Erasure mode" },
292 { 0x15, "Hopping mode" },
293 { 0x16, "Floating TRX" },
294 { 0x17, "Power supplies" },
295 { 0x18, "Reset type" },
296 { 0x19, "Averaging period" },
297 { 0x1A, "RBER2" },
298 { 0x1B, "LAC" },
299 { 0x1C, "CI" },
300 { 0x1D, "Failure parameters" },
301 { 0x1E, "(RF max power reduction)" },
302 { 0x1F, "Measured RX_SENS" },
303 { 0x20, "Extended cell radius" },
304 { 0x21, "reserved" },
305 { 0x22, "Success-Failure" },
306 { 0x23, "Ack-Nack" },
307 { 0x24, "OMU test results" },
308 { 0x25, "File identity" },
309 { 0x26, "Generation and version code" },
310 { 0x27, "SW description" },
311 { 0x28, "BCCH LEV" },
312 { 0x29, "Test type" },
313 { 0x2A, "Subscriber number" },
314 { 0x2B, "reserved" },
315 { 0x2C, "HSN" },
316 { 0x2D, "reserved" },
317 { 0x2E, "MS RXLEV" },
318 { 0x2F, "MS TXLEV" },
319 { 0x30, "RXQUAL" },
320 { 0x31, "RX SENS" },
321 { 0x32, "Alarm block" },
322 { 0x33, "Neighbouring BCCH levels" },
323 { 0x34, "STM report type" },
324 { 0x35, "MA" },
325 { 0x36, "MAIO" },
326 { 0x37, "H_FLAG" },
327 { 0x38, "TCH_ARFN" },
328 { 0x39, "Clock output" },
329 { 0x3A, "Transmitted power" },
330 { 0x3B, "Clock sync" },
331 { 0x3C, "TMS protocol discriminator" },
332 { 0x3D, "TMS protocol data" },
333 { 0x3E, "FER" },
334 { 0x3F, "SWR result" },
335 { 0x40, "Object identity" },
336 { 0x41, "STM RX Antenna Test" },
337 { 0x42, "reserved" },
338 { 0x43, "reserved" },
339 { 0x44, "Object current state" },
340 { 0x45, "reserved" },
341 { 0x46, "FU channel configuration" },
342 { 0x47, "reserved" },
343 { 0x48, "ARFN of a CU" },
344 { 0x49, "FU radio definition" },
345 { 0x4A, "reserved" },
346 { 0x4B, "Severity" },
347 { 0x4C, "Diversity selection" },
348 { 0x4D, "RX antenna test" },
349 { 0x4E, "RX antenna supervision period" },
350 { 0x4F, "RX antenna state" },
351 { 0x50, "Sector configuration" },
352 { 0x51, "Additional info" },
353 { 0x52, "SWR parameters" },
354 { 0x53, "HW inquiry mode" },
355 { 0x54, "reserved" },
356 { 0x55, "Availability status" },
357 { 0x56, "reserved" },
358 { 0x57, "EAC inputs" },
359 { 0x58, "EAC outputs" },
360 { 0x59, "reserved" },
361 { 0x5A, "Position" },
362 { 0x5B, "HW unit identity" },
363 { 0x5C, "RF test signal attenuation" },
364 { 0x5D, "Operational state" },
365 { 0x5E, "Logical object identity" },
366 { 0x5F, "reserved" },
367 { 0x60, "BS_TXPWR_OM" },
368 { 0x61, "Loop_Duration" },
369 { 0x62, "LNA_Path_Selection" },
370 { 0x63, "Serial number" },
371 { 0x64, "HW version" },
372 { 0x65, "Obj. identity and obj. state" },
373 { 0x66, "reserved" },
374 { 0x67, "EAC input definition" },
375 { 0x68, "EAC id and text" },
376 { 0x69, "HW unit status" },
377 { 0x6A, "SW release version" },
378 { 0x6B, "FW version" },
379 { 0x6C, "Bit_Error_Ratio" },
380 { 0x6D, "RXLEV_with_Attenuation" },
381 { 0x6E, "RXLEV_without_Attenuation" },
382 { 0x6F, "reserved" },
383 { 0x70, "CU_Results" },
384 { 0x71, "reserved" },
385 { 0x72, "LNA_Path_Results" },
386 { 0x73, "RTE Results" },
387 { 0x74, "Real Time" },
388 { 0x75, "RX diversity selection" },
389 { 0x76, "EAC input config" },
390 { 0x77, "Feature support" },
391 { 0x78, "File version" },
392 { 0x79, "Outputs" },
393 { 0x7A, "FU parameters" },
394 { 0x7B, "Diagnostic info" },
395 { 0x7C, "FU BSIC" },
396 { 0x7D, "TRX Configuration" },
397 { 0x7E, "Download status" },
398 { 0x7F, "RX difference limit" },
399 { 0x80, "TRX HW capability" },
400 { 0x81, "Common HW config" },
401 { 0x82, "Autoconfiguration pool size" },
402 { 0x83, "TRE diagnostic info" },
403 { 0x84, "TRE object identity" },
404 { 0x85, "New TRE Info" },
405 { 0x86, "Acknowledgement period" },
406 { 0x87, "Synchronization mode" },
407 { 0x88, "reserved" },
408 { 0x89, "Block Control Data" },
409 { 0x8A, "SW load mode" },
410 { 0x8B, "Recommended recovery action" },
411 { 0x8C, "BSC BCF id" },
412 { 0x8D, "Q1 baud rate" },
413 { 0x8E, "Allocation status" },
414 { 0x8F, "Functional entity number" },
415 { 0x90, "Transmission delay" },
416 { 0x91, "Loop Duration ms" },
417 { 0x92, "Logical channel" },
418 { 0x93, "Q1 address" },
419 { 0x94, "Alarm detail" },
420 { 0x95, "Cabinet type" },
421 { 0x96, "HW unit existence" },
422 { 0x97, "RF power parameters" },
423 { 0x98, "Message scenario" },
424 { 0x99, "HW unit max amount" },
425 { 0x9A, "Master TRX" },
426 { 0x9B, "Transparent data" },
427 { 0x9C, "BSC topology info" },
428 { 0x9D, "Air i/f modulation" },
429 { 0x9E, "LCS Q1 command data" },
430 { 0x9F, "Frame number offset" },
431 { 0xA0, "Abis TSL" },
432 { 0xA1, "Dynamic pool info" },
433 { 0xA2, "LCS LLP data" },
434 { 0xA3, "LCS Q1 answer data" },
435 { 0xA4, "DFCA FU Radio Definition" },
436 { 0xA5, "Antenna hopping" },
437 { 0xA6, "Field record sequence number" },
438 { 0xA7, "Timeslot offslot" },
439 { 0xA8, "EPCR capability" },
440 { 0xA9, "Connectsite optional element" },
441 { 0xAA, "TSC" },
442 { 0xAB, "Special TX Power Setting" },
443 { 0xAC, "Optional sync settings" },
444 { 0xFA, "Abis If parameters" },
445 { 0, NULL }
446};
447
448static const char *get_element_name_string(uint16_t element)
Dieter Spaar16646022011-07-28 00:01:50 +0200449{
Harald Welte44d26112011-07-28 00:43:13 +0200450 return get_value_string(nokia_element_name, element);
Dieter Spaar16646022011-07-28 00:01:50 +0200451}
452
Harald Welte3c3003f2011-07-28 00:28:20 +0200453static const struct value_string nokia_bts_types[] = {
454 { 0x0a, "MetroSite GSM 900" },
455 { 0x0b, "MetroSite GSM 1800" },
456 { 0x0c, "MetroSite GSM 1900 (PCS)" },
457 { 0x0d, "MetroSite GSM 900 & 1800" },
458 { 0x0e, "InSite GSM 900" },
459 { 0x0f, "InSite GSM 1800" },
460 { 0x10, "InSite GSM 1900" },
461 { 0x11, "UltraSite GSM 900" },
462 { 0x12, "UltraSite GSM 1800" },
463 { 0x13, "UltraSite GSM/US-TDMA 1900" },
464 { 0x14, "UltraSite GSM 900 & 1800" },
465 { 0x16, "UltraSite GSM/US-TDMA 850" },
466 { 0x18, "MetroSite GSM/US-TDMA 850" },
467 { 0x19, "UltraSite GSM 800/1900" },
468 { 0, NULL }
469};
470
471static const char *get_bts_type_string(uint8_t type)
Dieter Spaar16646022011-07-28 00:01:50 +0200472{
Harald Welte3c3003f2011-07-28 00:28:20 +0200473 return get_value_string(nokia_bts_types, type);
Dieter Spaar16646022011-07-28 00:01:50 +0200474}
475
Harald Welte3c3003f2011-07-28 00:28:20 +0200476static const struct value_string nokia_severity[] = {
477 { 0, "indeterminate" },
478 { 1, "critical" },
479 { 2, "major" },
480 { 3, "minor" },
481 { 4, "warning" },
482 { 0, NULL }
483};
484
485static const char *get_severity_string(uint8_t severity)
Dieter Spaar16646022011-07-28 00:01:50 +0200486{
Harald Welte3c3003f2011-07-28 00:28:20 +0200487 return get_value_string(nokia_severity, severity);
Dieter Spaar16646022011-07-28 00:01:50 +0200488}
489
490/* TODO: put in a separate file ? */
491
492/* some message IDs */
493
494#define NOKIA_MSG_CONF_DATA 128
495#define NOKIA_MSG_ACK 129
496#define NOKIA_MSG_OMU_STARTED 130
497#define NOKIA_MSG_START_DOWNLOAD_REQ 131
498#define NOKIA_MSG_MF_REQ 132
499#define NOKIA_MSG_RESET_REQ 134
500#define NOKIA_MSG_CONF_REQ 136
501#define NOKIA_MSG_CONF_COMPLETE 142
502#define NOKIA_MSG_BLOCK_CTRL_REQ 168
503#define NOKIA_MSG_STATE_CHANGED 172
504#define NOKIA_MSG_ALARM 174
505
506/* some element IDs */
507
508#define NOKIA_EI_BTS_TYPE 0x13
509#define NOKIA_EI_ACK 0x23
510#define NOKIA_EI_ADD_INFO 0x51
511#define NOKIA_EI_SEVERITY 0x4B
512#define NOKIA_EI_ALARM_DETAIL 0x94
513
514#define OM_ALLOC_SIZE 1024
515#define OM_HEADROOM_SIZE 128
516
Harald Weltebda367c2011-07-28 00:03:49 +0200517static uint8_t fu_config_template[] = {
518 0x7F, 0x7A, 0x39,
519 /* ID = 0x7A (FU parameters) ## constructed ## */
520 /* length = 57 */
521 /* [3] */
Dieter Spaar16646022011-07-28 00:01:50 +0200522
Harald Weltebda367c2011-07-28 00:03:49 +0200523 0x5F, 0x40, 0x04,
524 /* ID = 0x40 (Object identity) */
525 /* length = 4 */
526 /* [6] */
527 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200528
Harald Weltebda367c2011-07-28 00:03:49 +0200529 0x41, 0x02,
530 /* ID = 0x01 (Ny1) */
531 /* length = 2 */
532 /* [12] */
533 0x00, 0x05,
Dieter Spaar16646022011-07-28 00:01:50 +0200534
Harald Weltebda367c2011-07-28 00:03:49 +0200535 0x42, 0x02,
536 /* ID = 0x02 (T3105_F) */
537 /* length = 2 */
538 /* [16] */
539 0x00, 0x28,
Dieter Spaar16646022011-07-28 00:01:50 +0200540
Harald Weltebda367c2011-07-28 00:03:49 +0200541 0x50, 0x02,
542 /* ID = 0x10 (T3105_D) */
543 /* length = 2 */
544 /* [20] */
545 0x00, 0x28,
Dieter Spaar16646022011-07-28 00:01:50 +0200546
Harald Weltebda367c2011-07-28 00:03:49 +0200547 0x43, 0x05,
548 /* ID = 0x03 (Interference band limits) */
549 /* length = 5 */
550 /* [24] */
551 0x0F, 0x1B, 0x27, 0x33, 0x3F,
Dieter Spaar16646022011-07-28 00:01:50 +0200552
Harald Weltebda367c2011-07-28 00:03:49 +0200553 0x44, 0x02,
554 /* ID = 0x04 (Interference report timer in secs) */
555 /* length = 2 */
556 /* [31] */
557 0x00, 0x10,
Dieter Spaar16646022011-07-28 00:01:50 +0200558
Harald Weltebda367c2011-07-28 00:03:49 +0200559 0x47, 0x01,
560 /* ID = 0x07 (RACH report timer in secs) */
561 /* length = 1 */
562 /* [35] */
563 0x1E,
Dieter Spaar16646022011-07-28 00:01:50 +0200564
Harald Weltebda367c2011-07-28 00:03:49 +0200565 0x4C, 0x10,
566 /* ID = 0x0C (Cell allocation bitmap) ####### */
567 /* length = 16 */
568 /* [38] */
569 0x8F, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200571
Harald Weltebda367c2011-07-28 00:03:49 +0200572 0x59, 0x01,
573 /* ID = 0x19 (Averaging period) */
574 /* length = 1 */
575 /* [56] */
576 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +0200577
Harald Weltebda367c2011-07-28 00:03:49 +0200578 0x5E, 0x01,
579 /* ID = 0x1E ((RF max power reduction)) */
580 /* length = 1 */
581 /* [59] */
582 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200583
Harald Weltebda367c2011-07-28 00:03:49 +0200584 0x7F, 0x46, 0x11,
585 /* ID = 0x46 (FU channel configuration) ## constructed ## */
586 /* length = 17 */
587 /* [63] */
Dieter Spaar16646022011-07-28 00:01:50 +0200588
Harald Weltebda367c2011-07-28 00:03:49 +0200589 0x5F, 0x40, 0x04,
590 /* ID = 0x40 (Object identity) */
591 /* length = 4 */
592 /* [66] */
593 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200594
Harald Weltebda367c2011-07-28 00:03:49 +0200595 0x45, 0x08,
596 /* ID = 0x05 (Channel configuration per TS) */
597 /* length = 8 */
598 /* [72] */
599 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
Dieter Spaar16646022011-07-28 00:01:50 +0200600
Harald Weltebda367c2011-07-28 00:03:49 +0200601 0x7F, 0x65, 0x0B,
602 /* ID = 0x65 (Obj. identity and obj. state) ## constructed ## */
603 /* length = 11 */
604 /* [83] */
Dieter Spaar16646022011-07-28 00:01:50 +0200605
Harald Weltebda367c2011-07-28 00:03:49 +0200606 0x5F, 0x40, 0x04,
607 /* ID = 0x40 (Object identity) */
608 /* length = 4 */
609 /* [86] */
610 0x00, 0x04, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200611
Harald Weltebda367c2011-07-28 00:03:49 +0200612 0x5F, 0x44, 0x01,
613 /* ID = 0x44 (Object current state) */
614 /* length = 1 */
615 /* [93] */
616 0x03,
Dieter Spaar16646022011-07-28 00:01:50 +0200617
Harald Weltebda367c2011-07-28 00:03:49 +0200618 0x7F, 0x7C, 0x0A,
619 /* ID = 0x7C (FU BSIC) ## constructed ## */
620 /* length = 10 */
621 /* [97] */
Dieter Spaar16646022011-07-28 00:01:50 +0200622
Harald Weltebda367c2011-07-28 00:03:49 +0200623 0x5F, 0x40, 0x04,
624 /* ID = 0x40 (Object identity) */
625 /* length = 4 */
626 /* [100] */
627 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200628
Harald Weltebda367c2011-07-28 00:03:49 +0200629 0x46, 0x01,
630 /* ID = 0x06 (BSIC) */
631 /* length = 1 */
632 /* [106] */
633 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200634
Harald Weltebda367c2011-07-28 00:03:49 +0200635 0x7F, 0x48, 0x0B,
636 /* ID = 0x48 (ARFN of a CU) ## constructed ## */
637 /* length = 11 */
638 /* [110] */
Dieter Spaar16646022011-07-28 00:01:50 +0200639
Harald Weltebda367c2011-07-28 00:03:49 +0200640 0x5F, 0x40, 0x04,
641 /* ID = 0x40 (Object identity) */
642 /* length = 4 */
643 /* [113] */
644 0x00, 0x08, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200645
Harald Weltebda367c2011-07-28 00:03:49 +0200646 0x4A, 0x02,
647 /* ID = 0x0A (ARFN) ####### */
648 /* length = 2 */
649 /* [119] */
650 0x03, 0x62,
Dieter Spaar16646022011-07-28 00:01:50 +0200651
Harald Weltebda367c2011-07-28 00:03:49 +0200652 0x7F, 0x49, 0x59,
653 /* ID = 0x49 (FU radio definition) ## constructed ## */
654 /* length = 89 */
655 /* [124] */
Dieter Spaar16646022011-07-28 00:01:50 +0200656
Harald Weltebda367c2011-07-28 00:03:49 +0200657 0x5F, 0x40, 0x04,
658 /* ID = 0x40 (Object identity) */
659 /* length = 4 */
660 /* [127] */
661 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200662
Harald Weltebda367c2011-07-28 00:03:49 +0200663 0x4D, 0x50,
664 /* ID = 0x0D (Radio definition per TS) ####### */
665 /* length = 80 */
666 /* [133] */
667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MA */
668 0x03, 0x62, /* HSN, MAIO or ARFCN if no hopping */
669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x03, 0x62,
671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672 0x03, 0x62,
673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
674 0x03, 0x62,
675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0x03, 0x62,
677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678 0x03, 0x62,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x03, 0x62,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x03, 0x62,
Dieter Spaar16646022011-07-28 00:01:50 +0200683};
684
685/* TODO: put in a separate file ? */
686
687/*
Harald Weltecde57942011-07-28 00:13:46 +0200688 build the configuration for each TRX
Dieter Spaar16646022011-07-28 00:01:50 +0200689*/
690
Harald Weltebda367c2011-07-28 00:03:49 +0200691static int make_fu_config(struct gsm_bts_trx *trx, uint8_t id,
692 uint8_t * fu_config, int *hopping)
Dieter Spaar16646022011-07-28 00:01:50 +0200693{
Harald Weltebda367c2011-07-28 00:03:49 +0200694 int i;
Dieter Spaar16646022011-07-28 00:01:50 +0200695
Harald Weltebda367c2011-07-28 00:03:49 +0200696 *hopping = 0;
697
698 memcpy(fu_config, fu_config_template, sizeof(fu_config_template));
699
700 /* set ID */
701
702 fu_config[6 + 2] = id;
703 fu_config[66 + 2] = id;
704 fu_config[86 + 2] = id;
705 fu_config[100 + 2] = id;
706 fu_config[113 + 2] = id;
707 fu_config[127 + 2] = id;
708
709 /* set ARFCN */
710
711 uint16_t arfcn = trx->arfcn;
712
713 fu_config[119] = arfcn >> 8;
714 fu_config[119 + 1] = arfcn & 0xFF;
715
716 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
717 struct gsm_bts_trx_ts *ts = &trx->ts[i];
718
719 if (ts->hopping.enabled) {
720 /* reverse order */
721 int j;
722 for (j = 0; j < ts->hopping.ma_len; j++)
723 fu_config[133 + (i * 10) + (7 - j)] =
724 ts->hopping.ma_data[j];
725 fu_config[133 + 8 + (i * 10)] = ts->hopping.hsn;
726 fu_config[133 + 8 + 1 + (i * 10)] = ts->hopping.maio;
727 *hopping = 1;
728 } else {
729 fu_config[133 + 8 + (i * 10)] = arfcn >> 8;
730 fu_config[133 + 8 + 1 + (i * 10)] = arfcn & 0xFF;
731 }
732 }
733
734 /* set BSIC */
735
Harald Weltecde57942011-07-28 00:13:46 +0200736 /*
Harald Weltebda367c2011-07-28 00:03:49 +0200737 Attention: all TRX except the first one seem to get the TSC
738 from the CHANNEL ACTIVATION command (in CHANNEL IDENTIFICATION,
Harald Weltecde57942011-07-28 00:13:46 +0200739 GSM 04.08 CHANNEL DESCRIPTION).
740 There was a bug in rsl_chan_activate_lchan() setting this parameter.
Harald Weltebda367c2011-07-28 00:03:49 +0200741 */
742
743 uint8_t bsic = trx->bts->bsic;
744
745 fu_config[106] = bsic;
746
747 /* set CA */
748
749 if (generate_cell_chan_list(&fu_config[38], trx->bts) != 0) {
750 fprintf(stderr, "generate_cell_chan_list failed\n");
751 return 0;
752 }
753
754 /* set channel configuration */
755
756 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
757 struct gsm_bts_trx_ts *ts = &trx->ts[i];
758 uint8_t chan_config;
759
760 /*
761 0 = FCCH + SCH + BCCH + CCCH
762 1 = FCCH + SCH + BCCH + CCCH + SDCCH/4 + SACCH/4
763 2 = BCCH + CCCH (This combination is not used in any BTS)
764 3 = FCCH + SCH + BCCH + CCCH + SDCCH/4 with SDCCH2 used as CBCH
765 4 = SDCCH/8 + SACCH/8
766 5 = SDCCH/8 with SDCCH2 used as CBCH
767 6 = TCH/F + FACCH/F + SACCH/F
768 7 = E-RACH (Talk family)
769 9 = Dual rate (capability for TCH/F and TCH/H)
770 10 = reserved for BTS internal use
Harald Weltecde57942011-07-28 00:13:46 +0200771 11 = PBCCH + PCCCH + PDTCH + PACCH + PTCCH (can be used in GPRS release 2).
772 0xFF = spare TS
Harald Weltebda367c2011-07-28 00:03:49 +0200773 */
774
775 if (ts->pchan == GSM_PCHAN_NONE)
776 chan_config = 0xFF;
777 else if (ts->pchan == GSM_PCHAN_CCCH)
778 chan_config = 0;
779 else if (ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
780 chan_config = 1;
781 else if (ts->pchan == GSM_PCHAN_TCH_F)
782 chan_config = 6; /* 9 should work too */
783 else if (ts->pchan == GSM_PCHAN_TCH_H)
784 chan_config = 9;
785 else if (ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C)
786 chan_config = 4;
787 else if (ts->pchan == GSM_PCHAN_PDCH)
788 chan_config = 11;
789 else {
790 fprintf(stderr,
791 "unsupported channel config %d for timeslot %d\n",
792 ts->pchan, i);
793 return 0;
794 }
795
796 fu_config[72 + i] = chan_config;
797 }
798 return sizeof(fu_config_template);
Dieter Spaar16646022011-07-28 00:01:50 +0200799}
800
801/* TODO: put in a separate file ? */
802
Harald Weltebda367c2011-07-28 00:03:49 +0200803static uint8_t bts_config_1[] = {
804 0x4E, 0x02,
805 /* ID = 0x0E (Frame number) */
806 /* length = 2 */
807 /* [2] */
808 0xFF, 0xFF,
809
810 0x5F, 0x4E, 0x02,
811 /* ID = 0x4E (RX antenna supervision period) */
812 /* length = 2 */
813 /* [7] */
814 0xFF, 0xFF,
815
816 0x5F, 0x50, 0x02,
817 /* ID = 0x50 (Sector configuration) */
818 /* length = 2 */
819 /* [12] */
820 0x01, 0x01,
821};
822
823static uint8_t bts_config_2[] = {
824 0x55, 0x02,
825 /* ID = 0x15 (Hopping mode) */
826 /* length = 2 */
827 /* [2] */
828 0x01, 0x00,
829
830 0x5F, 0x75, 0x02,
831 /* ID = 0x75 (RX diversity selection) */
832 /* length = 2 */
833 /* [7] */
834 0x01, 0x01,
835};
836
837static uint8_t bts_config_3[] = {
838 0x5F, 0x20, 0x02,
839 /* ID = 0x20 (Extended cell radius) */
840 /* length = 2 */
841 /* [3] */
842 0x01, 0x00,
843};
844
845static uint8_t bts_config_4[] = {
846 0x5F, 0x74, 0x09,
847 /* ID = 0x74 (Real Time) */
848 /* length = 9 */
849 /* [3] year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
850 0x07, 0xDB, 0x06, 0x02, 0x0B, 0x20, 0x0C, 0x00,
851 0x00,
852
853 0x5F, 0x76, 0x03,
854 /* ID = 0x76 (EAC input config) */
855 /* length = 3 */
856 /* [15] */
857 0x01, 0x01, 0x00,
858
859 0x5F, 0x76, 0x03,
860 /* ID = 0x76 (EAC input config) */
861 /* length = 3 */
862 /* [21] */
863 0x02, 0x01, 0x00,
864
865 0x5F, 0x76, 0x03,
866 /* ID = 0x76 (EAC input config) */
867 /* length = 3 */
868 /* [27] */
869 0x03, 0x01, 0x00,
870
871 0x5F, 0x76, 0x03,
872 /* ID = 0x76 (EAC input config) */
873 /* length = 3 */
874 /* [33] */
875 0x04, 0x01, 0x00,
876
877 0x5F, 0x76, 0x03,
878 /* ID = 0x76 (EAC input config) */
879 /* length = 3 */
880 /* [39] */
881 0x05, 0x01, 0x00,
882
883 0x5F, 0x76, 0x03,
884 /* ID = 0x76 (EAC input config) */
885 /* length = 3 */
886 /* [45] */
887 0x06, 0x01, 0x00,
888
889 0x5F, 0x76, 0x03,
890 /* ID = 0x76 (EAC input config) */
891 /* length = 3 */
892 /* [51] */
893 0x07, 0x01, 0x00,
894
895 0x5F, 0x76, 0x03,
896 /* ID = 0x76 (EAC input config) */
897 /* length = 3 */
898 /* [57] */
899 0x08, 0x01, 0x00,
900
901 0x5F, 0x76, 0x03,
902 /* ID = 0x76 (EAC input config) */
903 /* length = 3 */
904 /* [63] */
905 0x09, 0x01, 0x00,
906
907 0x5F, 0x76, 0x03,
908 /* ID = 0x76 (EAC input config) */
909 /* length = 3 */
910 /* [69] */
911 0x0A, 0x01, 0x00,
912};
913
914static uint8_t bts_config_insite[] = {
915 0x4E, 0x02,
916 /* ID = 0x0E (Frame number) */
917 /* length = 2 */
918 /* [2] */
919 0xFF, 0xFF,
920
921 0x5F, 0x4E, 0x02,
922 /* ID = 0x4E (RX antenna supervision period) */
923 /* length = 2 */
924 /* [7] */
925 0xFF, 0xFF,
926
927 0x5F, 0x50, 0x02,
928 /* ID = 0x50 (Sector configuration) */
929 /* length = 2 */
930 /* [12] */
931 0x01, 0x01,
932
933 0x55, 0x02,
934 /* ID = 0x15 (Hopping mode) */
935 /* length = 2 */
936 /* [16] */
937 0x01, 0x00,
938
939 0x5F, 0x20, 0x02,
940 /* ID = 0x20 (Extended cell radius) */
941 /* length = 2 */
942 /* [21] */
943 0x01, 0x00,
944
945 0x5F, 0x74, 0x09,
946 /* ID = 0x74 (Real Time) */
947 /* length = 9 */
948 /* [26] */
949 0x07, 0xDB, 0x07, 0x0A, 0x0F, 0x09, 0x0B, 0x00,
950 0x00,
951};
952
953void set_real_time(uint8_t * real_time)
Dieter Spaar16646022011-07-28 00:01:50 +0200954{
Harald Weltebda367c2011-07-28 00:03:49 +0200955 time_t t;
956 struct tm *tm;
Dieter Spaar16646022011-07-28 00:01:50 +0200957
Harald Weltebda367c2011-07-28 00:03:49 +0200958 t = time(NULL);
959 tm = localtime(&t);
Dieter Spaar16646022011-07-28 00:01:50 +0200960
Harald Weltebda367c2011-07-28 00:03:49 +0200961 /* year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
Dieter Spaar16646022011-07-28 00:01:50 +0200962
Harald Weltebda367c2011-07-28 00:03:49 +0200963 real_time[0] = (1900 + tm->tm_year) >> 8;
964 real_time[1] = (1900 + tm->tm_year) & 0xFF;
965 real_time[2] = tm->tm_mon + 1;
966 real_time[3] = tm->tm_mday;
967 real_time[4] = tm->tm_hour;
968 real_time[5] = tm->tm_min;
969 real_time[6] = tm->tm_sec;
970 real_time[7] = 0;
971 real_time[8] = 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200972}
973
974/* TODO: put in a separate file ? */
975
976/*
Dieter Spaar16646022011-07-28 00:01:50 +0200977 build the configuration data
Dieter Spaar16646022011-07-28 00:01:50 +0200978*/
979
Harald Weltebda367c2011-07-28 00:03:49 +0200980static int make_bts_config(uint8_t bts_type, int n_trx, uint8_t * fu_config,
981 int need_hopping)
Dieter Spaar16646022011-07-28 00:01:50 +0200982{
Harald Weltebda367c2011-07-28 00:03:49 +0200983 /* is it an InSite BTS ? */
984 if (bts_type == 0x0E || bts_type == 0x0F || bts_type == 0x10) { /* TODO */
985 if (n_trx != 1) {
986 fprintf(stderr, "InSite has only one TRX\n");
987 return 0;
988 }
989 if (need_hopping != 0) {
990 fprintf(stderr, "InSite does not support hopping\n");
991 return 0;
992 }
993 memcpy(fu_config, bts_config_insite, sizeof(bts_config_insite));
994 set_real_time(&fu_config[26]);
995 return sizeof(bts_config_insite);
996 }
Dieter Spaar16646022011-07-28 00:01:50 +0200997
Harald Weltebda367c2011-07-28 00:03:49 +0200998 int len = 0;
999 int i;
1000
1001 memcpy(fu_config + len, bts_config_1, sizeof(bts_config_1));
1002
1003 /* set sector configuration */
1004 fu_config[len + 12 - 1] = 1 + n_trx; /* len */
1005 for (i = 0; i < n_trx; i++)
1006 fu_config[len + 12 + 1 + i] = ((i + 1) & 0xFF);
1007
1008 len += (sizeof(bts_config_1) + (n_trx - 1));
1009
1010 memcpy(fu_config + len, bts_config_2, sizeof(bts_config_2));
1011 /* set hopping mode (Baseband and RF hopping work for the MetroSite) */
1012 if (need_hopping)
1013 fu_config[len + 2 + 1] = 1; /* 0: no hopping, 1: Baseband hopping, 2: RF hopping */
1014 len += sizeof(bts_config_2);
1015
1016 /* set extended cell radius for each TRX */
1017 for (i = 0; i < n_trx; i++) {
1018 memcpy(fu_config + len, bts_config_3, sizeof(bts_config_3));
1019 fu_config[len + 3] = ((i + 1) & 0xFF);
1020 len += sizeof(bts_config_3);
1021 }
1022
1023 memcpy(fu_config + len, bts_config_4, sizeof(bts_config_4));
1024 set_real_time(&fu_config[len + 3]);
1025 len += sizeof(bts_config_4);
1026
1027 return len;
Dieter Spaar16646022011-07-28 00:01:50 +02001028}
1029
1030/* TODO: put in a separate file ? */
1031
1032static struct msgb *nm_msgb_alloc(void)
1033{
Harald Weltebda367c2011-07-28 00:03:49 +02001034 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML");
Dieter Spaar16646022011-07-28 00:01:50 +02001035}
1036
1037/* TODO: put in a separate file ? */
1038
1039struct abis_om_nokia_hdr {
Harald Weltebda367c2011-07-28 00:03:49 +02001040 uint8_t msg_type;
1041 uint8_t spare;
1042 uint16_t reference;
1043 uint8_t data[0];
Dieter Spaar16646022011-07-28 00:01:50 +02001044} __attribute__ ((packed));
1045
1046#define ABIS_OM_NOKIA_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_nokia_hdr))
1047
Harald Weltebda367c2011-07-28 00:03:49 +02001048static int abis_nm_send(struct gsm_bts *bts, uint8_t msg_type, uint16_t ref,
1049 uint8_t * data, int len_data)
Dieter Spaar16646022011-07-28 00:01:50 +02001050{
Harald Weltebda367c2011-07-28 00:03:49 +02001051 struct abis_om_hdr *oh;
1052 struct abis_om_nokia_hdr *noh;
1053 struct msgb *msg = nm_msgb_alloc();
Dieter Spaar16646022011-07-28 00:01:50 +02001054
Harald Weltebda367c2011-07-28 00:03:49 +02001055 oh = (struct abis_om_hdr *)msgb_put(msg,
1056 ABIS_OM_NOKIA_HDR_SIZE + len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001057
Harald Weltebda367c2011-07-28 00:03:49 +02001058 oh->mdisc = ABIS_OM_MDISC_FOM;
1059 oh->placement = ABIS_OM_PLACEMENT_ONLY;
1060 oh->sequence = 0;
1061 oh->length = sizeof(struct abis_om_nokia_hdr) + len_data;
1062
1063 noh = (struct abis_om_nokia_hdr *)oh->data;
1064
1065 noh->msg_type = msg_type;
1066 noh->spare = 0;
1067 noh->reference = htons(ref);
1068 memcpy(noh->data, data, len_data);
1069
1070 DEBUGPC(DNM, "Sending %s\n", get_msg_type_name_string(msg_type));
1071
1072 return abis_nm_sendmsg(bts, msg);
Dieter Spaar16646022011-07-28 00:01:50 +02001073}
1074
1075/* TODO: put in a separate file ? */
1076
1077static uint8_t download_req[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001078 0x5F, 0x25, 0x0B,
1079 /* ID = 0x25 (File identity) */
1080 /* length = 11 */
1081 /* [3] */
1082 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
1083 0x2A, 0x2A, 0x2A,
Dieter Spaar16646022011-07-28 00:01:50 +02001084
Harald Weltebda367c2011-07-28 00:03:49 +02001085 0x5F, 0x78, 0x03,
1086 /* ID = 0x78 (File version) */
1087 /* length = 3 */
1088 /* [17] */
1089 0x2A, 0x2A, 0x2A,
Dieter Spaar16646022011-07-28 00:01:50 +02001090
Harald Weltebda367c2011-07-28 00:03:49 +02001091 0x5F, 0x81, 0x0A, 0x01,
1092 /* ID = 0x8A (SW load mode) */
1093 /* length = 1 */
1094 /* [24] */
1095 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001096
Harald Weltebda367c2011-07-28 00:03:49 +02001097 0x5F, 0x81, 0x06, 0x01,
1098 /* ID = 0x86 (Acknowledgement period) */
1099 /* length = 1 */
1100 /* [29] */
1101 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001102};
1103
1104static int abis_nm_download_req(struct gsm_bts *bts, uint16_t ref)
1105{
Harald Weltebda367c2011-07-28 00:03:49 +02001106 uint8_t *data = download_req;
1107 int len_data = sizeof(download_req);
1108
1109 return abis_nm_send(bts, NOKIA_MSG_START_DOWNLOAD_REQ, ref, data,
1110 len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001111}
1112
1113/* TODO: put in a separate file ? */
1114
1115static uint8_t ack[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001116 0x5F, 0x23, 0x01,
1117 /* ID = 0x23 (Ack-Nack) */
1118 /* length = 1 */
1119 /* [3] */
1120 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001121};
1122
1123static int abis_nm_ack(struct gsm_bts *bts, uint16_t ref)
1124{
Harald Weltebda367c2011-07-28 00:03:49 +02001125 uint8_t *data = ack;
1126 int len_data = sizeof(ack);
1127
1128 return abis_nm_send(bts, NOKIA_MSG_ACK, ref, data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001129}
1130
1131/* TODO: put in a separate file ? */
1132
1133static uint8_t reset[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001134 0x5F, 0x40, 0x04,
1135 /* ID = 0x40 (Object identity) */
1136 /* length = 4 */
1137 /* [3] */
1138 0x00, 0x01, 0xFF, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +02001139};
1140
1141static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref)
1142{
Harald Weltebda367c2011-07-28 00:03:49 +02001143 uint8_t *data = reset;
1144 int len_data = sizeof(reset);
1145
1146 return abis_nm_send(bts, NOKIA_MSG_RESET_REQ, ref, data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001147}
1148
1149/* TODO: put in a separate file ? */
1150
Harald Weltebda367c2011-07-28 00:03:49 +02001151static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type,
1152 uint16_t ref, uint8_t * data, int len)
Dieter Spaar16646022011-07-28 00:01:50 +02001153{
Harald Weltebda367c2011-07-28 00:03:49 +02001154 int len_remain, len_to_send, max_send;
1155 int seq = 0;
1156 int ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001157
Harald Weltebda367c2011-07-28 00:03:49 +02001158 len_remain = len;
1159
1160 while (len_remain) {
1161 struct abis_om_hdr *oh;
1162 struct abis_om_nokia_hdr *noh;
1163 struct msgb *msg = nm_msgb_alloc();
1164
1165 if (seq == 0)
1166 max_send = 256 - sizeof(struct abis_om_nokia_hdr);
1167 else
1168 max_send = 256;
1169
1170 if (len_remain > max_send) {
1171 len_to_send = max_send;
1172
1173 if (seq == 0) {
1174 /* first segment */
1175 oh = (struct abis_om_hdr *)msgb_put(msg,
1176 ABIS_OM_NOKIA_HDR_SIZE
1177 +
1178 len_to_send);
1179
1180 oh->mdisc = ABIS_OM_MDISC_FOM;
1181 oh->placement = ABIS_OM_PLACEMENT_FIRST; /* first segment of multi-segment message */
1182 oh->sequence = seq;
1183 oh->length = 0; /* 256 bytes */
1184
1185 noh = (struct abis_om_nokia_hdr *)oh->data;
1186
1187 noh->msg_type = msg_type;
1188 noh->spare = 0;
1189 noh->reference = htons(ref);
1190 memcpy(noh->data, data, len_to_send);
1191 } else {
1192 /* segment in between */
1193 oh = (struct abis_om_hdr *)msgb_put(msg,
1194 sizeof
1195 (struct
1196 abis_om_hdr)
1197 +
1198 len_to_send);
1199
1200 oh->mdisc = ABIS_OM_MDISC_FOM;
1201 oh->placement = ABIS_OM_PLACEMENT_MIDDLE; /* segment of multi-segment message */
1202 oh->sequence = seq;
1203 oh->length = 0; /* 256 bytes */
1204
1205 memcpy(oh->data, data, len_to_send);
1206 }
1207 } else {
1208
1209 len_to_send = len_remain;
1210
1211 /* check if message fits in a single segment */
1212
1213 if (seq == 0)
1214 return abis_nm_send(bts, msg_type, ref, data,
1215 len_to_send);
1216
1217 /* last segment */
1218
1219 oh = (struct abis_om_hdr *)msgb_put(msg,
1220 sizeof(struct
1221 abis_om_hdr)
1222 + len_to_send);
1223
1224 oh->mdisc = ABIS_OM_MDISC_FOM;
1225 oh->placement = ABIS_OM_PLACEMENT_LAST; /* last segment of multi-segment message */
1226 oh->sequence = seq;
1227 oh->length = len_to_send;
1228
1229 memcpy(oh->data, data, len_to_send);
1230 }
1231
1232 DEBUGPC(DNM, "Sending multi-segment %d\n", seq);
1233
1234 ret = abis_nm_sendmsg(bts, msg);
1235 if (ret < 0)
1236 return ret;
1237
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001238 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001239
1240 /* next segment */
1241 len_remain -= len_to_send;
1242 data += len_to_send;
1243 seq++;
1244 }
1245 return ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001246}
1247
1248/* TODO: put in a separate file ? */
1249
1250static int abis_nm_send_config(struct gsm_bts *bts, uint8_t bts_type)
1251{
Harald Weltebda367c2011-07-28 00:03:49 +02001252 struct gsm_bts_trx *trx;
1253 uint8_t config[2048]; /* TODO: might be too small if lots of TRX are used */
1254 int len = 0;
1255 int idx = 0;
1256 int ret;
1257 int hopping = 0;
1258 int need_hopping = 0;
1259
1260 memset(config, 0, sizeof(config));
1261
1262 llist_for_each_entry(trx, &bts->trx_list, list) {
1263#if 0 /* debugging */
1264 printf("TRX\n");
1265 printf(" arfcn: %d\n", trx->arfcn);
1266 printf(" bsic: %d\n", trx->bts->bsic);
1267 uint8_t ca[20];
1268 memset(ca, 0xFF, sizeof(ca));
1269 ret = generate_cell_chan_list(ca, trx->bts);
1270 printf(" ca (%d): %s\n", ret, osmo_hexdump(ca, sizeof(ca)));
1271 int i;
1272 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
1273 struct gsm_bts_trx_ts *ts = &trx->ts[i];
1274
1275 printf(" pchan %d: %d\n", i, ts->pchan);
1276 }
Dieter Spaar16646022011-07-28 00:01:50 +02001277#endif
Harald Weltebda367c2011-07-28 00:03:49 +02001278 ret = make_fu_config(trx, idx + 1, config + len, &hopping);
1279 need_hopping |= hopping;
1280 len += ret;
1281
1282 idx++;
1283 }
1284
1285 ret = make_bts_config(bts_type, idx, config + len, need_hopping);
1286 len += ret;
1287
1288#if 0 /* debugging */
1289 dump_elements(config, len);
1290#endif
1291
1292 return abis_nm_send_multi_segments(bts, NOKIA_MSG_CONF_DATA, 1, config,
1293 len);
Dieter Spaar16646022011-07-28 00:01:50 +02001294}
1295
1296#define GET_NEXT_BYTE if(idx >= len) return 0; \
Harald Weltebda367c2011-07-28 00:03:49 +02001297 ub = data[idx++];
Dieter Spaar16646022011-07-28 00:01:50 +02001298
Harald Weltebda367c2011-07-28 00:03:49 +02001299static int find_element(uint8_t * data, int len, uint16_t id, uint8_t * value,
1300 int max_value)
1301{
1302 uint8_t ub;
1303 int idx = 0;
1304 int found = 0;
1305 int constructed;
1306 uint16_t id_value;
1307
1308 for (;;) {
1309
1310 GET_NEXT_BYTE;
1311
1312 /* encoding bit, construced means that other elements are contained */
1313 constructed = ((ub & 0x20) ? 1 : 0);
1314
1315 if ((ub & 0x1F) == 0x1F) {
1316 /* fixed pattern, ID follows */
1317 GET_NEXT_BYTE; /* ID */
1318 id_value = ub & 0x7F;
1319 if (ub & 0x80) {
1320 /* extension bit */
1321 GET_NEXT_BYTE; /* ID low part */
1322 id_value = (id_value << 7) | (ub & 0x7F);
1323 }
1324 if (id_value == id)
1325 found = 1;
1326 } else {
1327 id_value = (ub & 0x3F);
1328 if (id_value == id)
1329 found = 1;
1330 }
1331
1332 GET_NEXT_BYTE; /* length */
1333
1334 if (found) {
1335 /* get data */
1336 uint8_t n = ub;
1337 uint8_t i;
1338 for (i = 0; i < n; i++) {
1339 GET_NEXT_BYTE;
1340 if (max_value <= 0)
1341 return -1; /* buffer too small */
1342 *value = ub;
1343 value++;
1344 max_value--;
1345 }
1346 return n; /* length */
1347 } else {
1348 /* skip data */
1349 uint8_t n = ub;
1350 uint8_t i;
1351 for (i = 0; i < n; i++) {
1352 GET_NEXT_BYTE;
1353 }
1354 }
1355 }
1356 return 0; /* not found */
Dieter Spaar16646022011-07-28 00:01:50 +02001357}
1358
Harald Weltebda367c2011-07-28 00:03:49 +02001359static int dump_elements(uint8_t * data, int len)
1360{
1361 uint8_t ub;
1362 int idx = 0;
1363 int constructed;
1364 uint16_t id_value;
1365 static char indent[100] = ""; /* TODO: move static to BTS context */
Dieter Spaar16646022011-07-28 00:01:50 +02001366
Harald Weltebda367c2011-07-28 00:03:49 +02001367 for (;;) {
1368
1369 GET_NEXT_BYTE;
1370
1371 /* encoding bit, construced means that other elements are contained */
1372 constructed = ((ub & 0x20) ? 1 : 0);
1373
1374 if ((ub & 0x1F) == 0x1F) {
1375 /* fixed pattern, ID follows */
1376 GET_NEXT_BYTE; /* ID */
1377 id_value = ub & 0x7F;
1378 if (ub & 0x80) {
1379 /* extension bit */
1380 GET_NEXT_BYTE; /* ID low part */
1381 id_value = (id_value << 7) | (ub & 0x7F);
1382 }
1383
1384 } else {
1385 id_value = (ub & 0x3F);
1386 }
1387
1388 GET_NEXT_BYTE; /* length */
1389
1390 printf("%s--ID = 0x%02X (%s) %s\n", indent, id_value,
1391 get_element_name_string(id_value),
1392 constructed ? "** constructed **" : "");
1393 printf("%s length = %d\n", indent, ub);
1394 printf("%s %s\n", indent, osmo_hexdump(data + idx, ub));
1395
1396 if (constructed) {
1397 int indent_len = strlen(indent);
1398 strcat(indent, " ");
1399
1400 dump_elements(data + idx, ub);
1401
1402 indent[indent_len] = 0;
1403 }
1404 /* skip data */
1405 uint8_t n = ub;
1406 uint8_t i;
1407 for (i = 0; i < n; i++) {
1408 GET_NEXT_BYTE;
1409 }
1410 }
1411 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001412}
1413
1414/* TODO: put in a separate file ? */
1415
1416/* taken from abis_nm.c */
1417
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001418static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts)
Dieter Spaar16646022011-07-28 00:01:50 +02001419{
Harald Weltebda367c2011-07-28 00:03:49 +02001420 int wait = 0;
1421 struct msgb *msg;
1422 /* the queue is empty */
1423 while (!llist_empty(&bts->abis_queue)) {
1424 msg = msgb_dequeue(&bts->abis_queue);
1425 wait = OBSC_NM_W_ACK_CB(msg);
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001426 abis_sendmsg(msg);
Dieter Spaar16646022011-07-28 00:01:50 +02001427
Harald Weltebda367c2011-07-28 00:03:49 +02001428 if (wait)
1429 break;
1430 }
Dieter Spaar16646022011-07-28 00:01:50 +02001431
Harald Weltebda367c2011-07-28 00:03:49 +02001432 bts->abis_nm_pend = wait;
Dieter Spaar16646022011-07-28 00:01:50 +02001433}
1434
1435/* TODO: put in a separate file ? */
1436
1437/* timer for restarting OML after BTS reset */
1438
1439static void reset_timer_cb(void *_bts)
1440{
Harald Weltebda367c2011-07-28 00:03:49 +02001441 struct gsm_bts *bts = _bts;
1442 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1443 struct e1inp_line *line;
1444
Harald Weltec8755af2011-07-28 00:22:17 +02001445 bts->nokia.wait_reset = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001446
1447 /* OML link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001448 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001449 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001450 LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to "
Harald Weltebda367c2011-07-28 00:03:49 +02001451 "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
1452 return;
1453 }
1454
1455 start_sabm_in_line(line, 0, -1); /* stop all first */
1456 start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */
Dieter Spaar16646022011-07-28 00:01:50 +02001457}
1458
1459/* TODO: put in a separate file ? */
1460
1461/*
1462 This is how the configuration is done:
Dieter Spaar16646022011-07-28 00:01:50 +02001463 - start OML link
Dieter Spaar16646022011-07-28 00:01:50 +02001464 - reset BTS
Dieter Spaar16646022011-07-28 00:01:50 +02001465 - receive ACK, wait some time and restart OML link
Dieter Spaar16646022011-07-28 00:01:50 +02001466 - receive OMU STARTED message, send START DOWNLOAD REQ
Dieter Spaar16646022011-07-28 00:01:50 +02001467 - receive CNF REQ message, send CONF DATA
Dieter Spaar16646022011-07-28 00:01:50 +02001468 - receive ACK, start RSL link(s)
Dieter Spaar16646022011-07-28 00:01:50 +02001469 ACK some other messages received from the BTS.
Harald Weltecde57942011-07-28 00:13:46 +02001470
Dieter Spaar16646022011-07-28 00:01:50 +02001471 Probably its also possible to configure the BTS without a reset, this
1472 has not been tested yet.
1473*/
1474
1475static int abis_nm_rcvmsg_fom(struct msgb *mb)
1476{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001477 struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)mb->dst;
1478 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltebda367c2011-07-28 00:03:49 +02001479 struct abis_om_hdr *oh = msgb_l2(mb);
1480 struct abis_om_nokia_hdr *noh = msgb_l3(mb);
1481 uint8_t mt = noh->msg_type;
1482 int ret = 0;
1483 uint16_t ref = ntohs(noh->reference);
Harald Weltebda367c2011-07-28 00:03:49 +02001484 uint8_t info[256];
1485 uint8_t ack = 0xFF;
1486 uint8_t severity = 0xFF;
1487 int str_len;
1488 int len_data;
Dieter Spaar16646022011-07-28 00:01:50 +02001489
Harald Weltec8755af2011-07-28 00:22:17 +02001490 if (bts->nokia.wait_reset) {
Harald Weltebda367c2011-07-28 00:03:49 +02001491 LOGP(DNM, LOGL_INFO,
1492 "Ignore message while waiting for reset\n");
1493 return ret;
1494 }
Dieter Spaar16646022011-07-28 00:01:50 +02001495
Harald Weltebda367c2011-07-28 00:03:49 +02001496 if (oh->length < sizeof(struct abis_om_nokia_hdr)) {
1497 LOGP(DNM, LOGL_ERROR, "Message too short\n");
1498 return -EINVAL;
1499 }
1500
1501 len_data = oh->length - sizeof(struct abis_om_nokia_hdr);
1502 LOGP(DNM, LOGL_INFO, "(0x%02X) %s\n", mt, get_msg_type_name_string(mt));
1503#if 0 /* debugging */
1504 dump_elements(noh->data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001505#endif
Dieter Spaar16646022011-07-28 00:01:50 +02001506
Harald Weltebda367c2011-07-28 00:03:49 +02001507 switch (mt) {
1508 case NOKIA_MSG_OMU_STARTED:
Harald Welte9d2f3772011-07-28 00:19:06 +02001509 if (find_element(noh->data, len_data,
1510 NOKIA_EI_BTS_TYPE, &bts->nokia.bts_type,
1511 sizeof(uint8_t)) == sizeof(uint8_t))
1512 LOGP(DNM, LOGL_INFO, "BTS type = %d (%s)\n",
1513 bts->nokia.bts_type,
1514 get_bts_type_string(bts->nokia.bts_type));
Harald Weltebda367c2011-07-28 00:03:49 +02001515 else
1516 LOGP(DNM, LOGL_ERROR, "BTS type not found\n");
1517 /* send START_DOWNLOAD_REQ */
1518 abis_nm_download_req(bts, ref);
1519 break;
1520 case NOKIA_MSG_MF_REQ:
1521 break;
1522 case NOKIA_MSG_CONF_REQ:
1523 /* send ACK */
1524 abis_nm_ack(bts, ref);
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001525 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001526 /* send CONF_DATA */
Harald Welte9d2f3772011-07-28 00:19:06 +02001527 abis_nm_send_config(bts, bts->nokia.bts_type);
1528 bts->nokia.configured = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001529 break;
1530 case NOKIA_MSG_ACK:
1531 if (find_element
1532 (noh->data, len_data, NOKIA_EI_ACK, &ack,
1533 sizeof(uint8_t)) == sizeof(uint8_t)) {
1534 LOGP(DNM, LOGL_INFO, "ACK = %d\n", ack);
1535 if (ack != 1) {
1536 LOGP(DNM, LOGL_ERROR, "No ACK received (%d)\n",
1537 ack);
1538 /* TODO: properly handle failures (NACK) */
1539 }
1540 } else
1541 LOGP(DNM, LOGL_ERROR, "ACK not found\n");
Dieter Spaar16646022011-07-28 00:01:50 +02001542
Harald Weltebda367c2011-07-28 00:03:49 +02001543 /* TODO: the assumption for the following is that no NACK was received */
1544
1545 /* ACK for reset message ? */
Harald Weltec8755af2011-07-28 00:22:17 +02001546 if (bts->nokia.do_reset != 0) {
1547 bts->nokia.do_reset = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001548
1549 /*
1550 TODO: For the InSite processing the received data is
1551 blocked in the driver during reset.
1552 Otherwise the LAPD module might assert because the InSite
1553 sends garbage on the E1 line during reset.
1554 This is done by looking at "wait_reset" in the driver
1555 (function handle_ts1_read()) and ignoring the received data.
1556 It seems to be necessary for the MetroSite too.
1557 */
Harald Weltec8755af2011-07-28 00:22:17 +02001558 bts->nokia.wait_reset = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001559
Harald Weltec8755af2011-07-28 00:22:17 +02001560 bts->nokia.reset_timer.cb = &reset_timer_cb;
1561 bts->nokia.reset_timer.data = bts;
1562 osmo_timer_schedule(&bts->nokia.reset_timer, RESET_INTERVAL);
Harald Weltebda367c2011-07-28 00:03:49 +02001563
1564 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1565 struct e1inp_line *line;
1566 /* OML link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001567 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001568 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001569 LOGP(DLINP, LOGL_ERROR,
Harald Weltebda367c2011-07-28 00:03:49 +02001570 "BTS %u OML link referring to "
1571 "non-existing E1 line %u\n", bts->nr,
1572 e1_link->e1_nr);
1573 return -ENOMEM;
1574 }
1575
1576 start_sabm_in_line(line, 0, -1); /* stop all first */
1577 }
1578
1579 /* ACK for CONF DATA message ? */
Harald Welte9d2f3772011-07-28 00:19:06 +02001580 if (bts->nokia.configured != 0) {
Harald Weltebda367c2011-07-28 00:03:49 +02001581 /* start TRX (RSL link) */
1582
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001583 struct gsm_e1_subslot *e1_link =
1584 &sign_link->trx->rsl_e1_link;
Harald Weltebda367c2011-07-28 00:03:49 +02001585 struct e1inp_line *line;
1586
Harald Welte9d2f3772011-07-28 00:19:06 +02001587 bts->nokia.configured = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001588
1589 /* RSL Link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001590 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001591 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001592 LOGP(DLINP, LOGL_ERROR,
Harald Weltebda367c2011-07-28 00:03:49 +02001593 "TRX (%u/%u) RSL link referring "
1594 "to non-existing E1 line %u\n",
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001595 sign_link->trx->bts->nr, sign_link->trx->nr,
Harald Weltebda367c2011-07-28 00:03:49 +02001596 e1_link->e1_nr);
1597 return -ENOMEM;
1598 }
1599 /* start TRX */
1600 start_sabm_in_line(line, 1, SAPI_RSL); /* start only RSL */
1601 }
1602 break;
1603 case NOKIA_MSG_STATE_CHANGED:
1604 /* send ACK */
1605 abis_nm_ack(bts, ref);
1606 break;
1607 case NOKIA_MSG_CONF_COMPLETE:
1608 /* send ACK */
1609 abis_nm_ack(bts, ref);
1610 break;
1611 case NOKIA_MSG_BLOCK_CTRL_REQ: /* seems to be send when something goes wrong !? */
1612 /* send ACK (do we have to send an ACK ?) */
1613 abis_nm_ack(bts, ref);
1614 break;
1615 case NOKIA_MSG_ALARM:
1616 find_element(noh->data, len_data, NOKIA_EI_SEVERITY, &severity,
1617 sizeof(severity));
1618 /* TODO: there might be alarms with both elements set */
1619 str_len =
1620 find_element(noh->data, len_data, NOKIA_EI_ADD_INFO, info,
1621 sizeof(info));
1622 if (str_len > 0) {
1623 info[str_len] = 0;
1624 LOGP(DNM, LOGL_INFO, "ALARM Severity %s (%d) : %s\n",
1625 get_severity_string(severity), severity, info);
1626 } else { /* nothing found, try details */
1627 str_len =
1628 find_element(noh->data, len_data,
1629 NOKIA_EI_ALARM_DETAIL, info,
1630 sizeof(info));
1631 if (str_len > 0) {
1632 uint16_t code;
1633 info[str_len] = 0;
1634 code = (info[0] << 8) + info[1];
1635 LOGP(DNM, LOGL_INFO,
1636 "ALARM Severity %s (%d), code 0x%X : %s\n",
1637 get_severity_string(severity), severity,
1638 code, info + 2);
1639 }
1640 }
1641 /* send ACK */
1642 abis_nm_ack(bts, ref);
1643 break;
1644 }
1645
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001646 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001647
1648 return ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001649}
1650
1651/* TODO: put in a separate file ? */
1652
1653int abis_nokia_rcvmsg(struct msgb *msg)
1654{
Harald Weltebda367c2011-07-28 00:03:49 +02001655 struct abis_om_hdr *oh = msgb_l2(msg);
1656 int rc = 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001657
Harald Weltebda367c2011-07-28 00:03:49 +02001658 /* Various consistency checks */
1659 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
1660 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
1661 oh->placement);
1662 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1663 return -EINVAL;
1664 }
1665 if (oh->sequence != 0) {
1666 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
1667 oh->sequence);
1668 return -EINVAL;
1669 }
1670 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Dieter Spaar16646022011-07-28 00:01:50 +02001671
Harald Weltebda367c2011-07-28 00:03:49 +02001672 switch (oh->mdisc) {
1673 case ABIS_OM_MDISC_FOM:
1674 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_FOM\n");
1675 rc = abis_nm_rcvmsg_fom(msg);
1676 break;
1677 case ABIS_OM_MDISC_MANUF:
1678 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_MANUF\n");
1679 break;
1680 case ABIS_OM_MDISC_MMI:
1681 case ABIS_OM_MDISC_TRAU:
1682 LOGP(DNM, LOGL_ERROR,
1683 "unimplemented ABIS OML message discriminator 0x%x\n",
1684 oh->mdisc);
1685 break;
1686 default:
1687 LOGP(DNM, LOGL_ERROR,
1688 "unknown ABIS OML message discriminator 0x%x\n",
1689 oh->mdisc);
1690 return -EINVAL;
1691 }
Dieter Spaar16646022011-07-28 00:01:50 +02001692
Harald Weltebda367c2011-07-28 00:03:49 +02001693 msgb_free(msg);
1694 return rc;
Dieter Spaar16646022011-07-28 00:01:50 +02001695}
1696
1697static int bts_model_nokia_site_start(struct gsm_network *net);
1698
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001699static void bts_model_nokia_site_e1line_bind_ops(struct e1inp_line *line)
1700{
1701 e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
1702}
1703
Dieter Spaar16646022011-07-28 00:01:50 +02001704static struct gsm_bts_model model_nokia_site = {
Harald Weltebda367c2011-07-28 00:03:49 +02001705 .type = GSM_BTS_TYPE_NOKIA_SITE,
1706 .name = "nokia_site",
1707 .start = bts_model_nokia_site_start,
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001708 .oml_rcvmsg = &abis_nokia_rcvmsg,
1709 .e1line_bind_ops = &bts_model_nokia_site_e1line_bind_ops,
Dieter Spaar16646022011-07-28 00:01:50 +02001710};
1711
1712static struct gsm_network *my_net;
1713
1714static int bts_model_nokia_site_start(struct gsm_network *net)
1715{
Harald Weltebda367c2011-07-28 00:03:49 +02001716 model_nokia_site.features.data = &model_nokia_site._features_data[0];
1717 model_nokia_site.features.data_len =
1718 sizeof(model_nokia_site._features_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001719
Harald Weltebda367c2011-07-28 00:03:49 +02001720 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HOPPING);
1721 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HSCSD);
Dieter Spaar16646022011-07-28 00:01:50 +02001722
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001723 osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
1724 osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL);
Harald Weltebda367c2011-07-28 00:03:49 +02001725 osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
Dieter Spaar16646022011-07-28 00:01:50 +02001726
Harald Weltebda367c2011-07-28 00:03:49 +02001727 my_net = net;
1728
1729 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001730}
1731
1732int bts_model_nokia_site_init(void)
1733{
Harald Weltebda367c2011-07-28 00:03:49 +02001734 return gsm_bts_model_register(&model_nokia_site);
Dieter Spaar16646022011-07-28 00:01:50 +02001735}