blob: 36e3fac4fbffcfb9d577485ac136df1aa68420c1 [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
Sylvain Munaut2192ed82011-10-17 14:05:19 +020045#define RESET_INTERVAL 15, 0 /* 15 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);
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +020054static int dump_elements(uint8_t * data, int len) __attribute__((unused));
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
Sylvain Munautc9519462011-10-17 14:04:55 +020060 if (!bts->nokia.skip_reset) {
61 if (!bts->nokia.did_reset)
62 abis_nm_reset(bts, 1);
63 } else
64 bts->nokia.did_reset = 1;
Dieter Spaar16646022011-07-28 00:01:50 +020065}
66
67static void bootstrap_om_trx(struct gsm_bts_trx *trx)
68{
Harald Weltebda367c2011-07-28 00:03:49 +020069 LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
70 trx->bts->nr, trx->nr);
Dieter Spaar16646022011-07-28 00:01:50 +020071}
72
73static int shutdown_om(struct gsm_bts *bts)
74{
Harald Weltebda367c2011-07-28 00:03:49 +020075 /* TODO !? */
76 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +020077}
78
79#define SAPI_OML 62
80#define SAPI_RSL 0
81
Harald Weltecde57942011-07-28 00:13:46 +020082/*
Dieter Spaar16646022011-07-28 00:01:50 +020083
84 Tell LAPD to start start the SAP (send SABM requests) for all signalling
Harald Weltecde57942011-07-28 00:13:46 +020085 timeslots in this line
86
87 Attention: this has to be adapted for mISDN
Dieter Spaar16646022011-07-28 00:01:50 +020088*/
Harald Weltebda367c2011-07-28 00:03:49 +020089
Andreas Eversbergc57e6ed2011-09-26 11:44:22 +020090static void start_sabm_in_line(struct e1inp_line *line, int start, int sapi)
Dieter Spaar16646022011-07-28 00:01:50 +020091{
Harald Weltebda367c2011-07-28 00:03:49 +020092 struct e1inp_sign_link *link;
93 int i;
Dieter Spaar16646022011-07-28 00:01:50 +020094
Harald Weltebda367c2011-07-28 00:03:49 +020095 for (i = 0; i < ARRAY_SIZE(line->ts); i++) {
96 struct e1inp_ts *ts = &line->ts[i];
Dieter Spaar16646022011-07-28 00:01:50 +020097
Harald Weltebda367c2011-07-28 00:03:49 +020098 if (ts->type != E1INP_TS_TYPE_SIGN)
99 continue;
Dieter Spaar16646022011-07-28 00:01:50 +0200100
Harald Weltebda367c2011-07-28 00:03:49 +0200101 llist_for_each_entry(link, &ts->sign.sign_links, list) {
102 if (sapi != -1 && link->sapi != sapi)
103 continue;
104
105#if 0 /* debugging */
106 printf("sap start/stop (%d): %d tei=%d sapi=%d\n",
107 start, i + 1, link->tei, link->sapi);
Dieter Spaar16646022011-07-28 00:01:50 +0200108#endif
Harald Weltebda367c2011-07-28 00:03:49 +0200109
Andreas.Eversbergbb5c5942011-11-02 22:22:24 +0100110 if (start) {
111 ts->lapd->profile.t200_sec = 1;
112 ts->lapd->profile.t200_usec = 0;
Harald Welteb4d913d2011-08-26 19:14:55 +0200113 lapd_sap_start(ts->lapd, link->tei,
Harald Weltebda367c2011-07-28 00:03:49 +0200114 link->sapi);
Andreas.Eversbergbb5c5942011-11-02 22:22:24 +0100115 } else
Harald Welteb4d913d2011-08-26 19:14:55 +0200116 lapd_sap_stop(ts->lapd, link->tei,
Harald Weltebda367c2011-07-28 00:03:49 +0200117 link->sapi);
118 }
119 }
Dieter Spaar16646022011-07-28 00:01:50 +0200120}
121
122/* Callback function to be called every time we receive a signal from INPUT */
123static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200124 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200125{
Harald Weltebda367c2011-07-28 00:03:49 +0200126 struct gsm_bts *bts;
Dieter Spaar16646022011-07-28 00:01:50 +0200127
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200128 if (subsys != SS_L_GLOBAL)
Harald Weltebda367c2011-07-28 00:03:49 +0200129 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200130
Harald Weltebda367c2011-07-28 00:03:49 +0200131 switch (signal) {
132 case S_GLOBAL_BTS_CLOSE_OM:
133 bts = signal_data;
134 if (bts->type == GSM_BTS_TYPE_NOKIA_SITE)
135 shutdown_om(signal_data);
136 break;
137 }
Dieter Spaar16646022011-07-28 00:01:50 +0200138
Harald Weltebda367c2011-07-28 00:03:49 +0200139 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200140}
141
142/* Callback function to be called every time we receive a signal from INPUT */
143static int inp_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200144 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200145{
Harald Weltebda367c2011-07-28 00:03:49 +0200146 struct input_signal_data *isd = signal_data;
Dieter Spaar16646022011-07-28 00:01:50 +0200147
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200148 if (subsys != SS_L_INPUT)
Harald Weltebda367c2011-07-28 00:03:49 +0200149 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200150
Harald Weltebda367c2011-07-28 00:03:49 +0200151 switch (signal) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200152 case S_L_INP_LINE_INIT:
Harald Weltebda367c2011-07-28 00:03:49 +0200153 start_sabm_in_line(isd->line, 1, SAPI_OML); /* start only OML */
154 break;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200155 case S_L_INP_TEI_DN:
Harald Weltebda367c2011-07-28 00:03:49 +0200156 break;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200157 case S_L_INP_TEI_UP:
Harald Weltebda367c2011-07-28 00:03:49 +0200158 switch (isd->link_type) {
159 case E1INP_SIGN_OML:
160 if (isd->trx->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
161 break;
Dieter Spaar16646022011-07-28 00:01:50 +0200162
Harald Weltebda367c2011-07-28 00:03:49 +0200163 if (isd->tei == isd->trx->bts->oml_tei)
164 bootstrap_om_bts(isd->trx->bts);
165 else
166 bootstrap_om_trx(isd->trx);
167 break;
168 }
169 break;
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200170 case S_L_INP_TEI_UNKNOWN:
Pablo Neira Ayuso2962c202011-08-10 00:48:10 +0200171 /* We are receiving LAPD frames with one TEI that we do not
172 * seem to know, likely that we (the BSC) stopped working
173 * and lost our local states. However, the BTS is already
174 * configured, we try to take over the RSL links. */
175 start_sabm_in_line(isd->line, 1, SAPI_RSL);
176 break;
Harald Weltebda367c2011-07-28 00:03:49 +0200177 }
178
179 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200180}
181
182static void nm_statechg_evt(unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200183 struct nm_statechg_signal_data *nsd)
Dieter Spaar16646022011-07-28 00:01:50 +0200184{
Harald Weltebda367c2011-07-28 00:03:49 +0200185 if (nsd->bts->type != GSM_BTS_TYPE_NOKIA_SITE)
186 return;
Dieter Spaar16646022011-07-28 00:01:50 +0200187}
188
189static int nm_sig_cb(unsigned int subsys, unsigned int signal,
Harald Weltebda367c2011-07-28 00:03:49 +0200190 void *handler_data, void *signal_data)
Dieter Spaar16646022011-07-28 00:01:50 +0200191{
Harald Weltebda367c2011-07-28 00:03:49 +0200192 if (subsys != SS_NM)
193 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200194
Harald Weltebda367c2011-07-28 00:03:49 +0200195 switch (signal) {
196 case S_NM_STATECHG_OPER:
197 case S_NM_STATECHG_ADM:
198 nm_statechg_evt(signal, signal_data);
199 break;
200 default:
201 break;
202 }
Dieter Spaar16646022011-07-28 00:01:50 +0200203
Harald Weltebda367c2011-07-28 00:03:49 +0200204 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200205}
206
207/* TODO: put in a separate file ? */
208
Harald Welte44d26112011-07-28 00:43:13 +0200209static const struct value_string nokia_msgt_name[] = {
210 { 0x80, "NOKIA_BTS_CONF_DATA" },
211 { 0x81, "NOKIA_BTS_ACK" },
212 { 0x82, "NOKIA_BTS_OMU_STARTED" },
213 { 0x83, "NOKIA_BTS_START_DOWNLOAD_REQ" },
214 { 0x84, "NOKIA_BTS_MF_REQ" },
215 { 0x85, "NOKIA_BTS_AF_REQ" },
216 { 0x86, "NOKIA_BTS_RESET_REQ" },
217 { 0x87, "NOKIA_reserved" },
218 { 0x88, "NOKIA_BTS_CONF_REQ" },
219 { 0x89, "NOKIA_BTS_TEST_REQ" },
220 { 0x8A, "NOKIA_BTS_TEST_REPORT" },
221 { 0x8B, "NOKIA_reserved" },
222 { 0x8C, "NOKIA_reserved" },
223 { 0x8D, "NOKIA_reserved" },
224 { 0x8E, "NOKIA_BTS_CONF_COMPL" },
225 { 0x8F, "NOKIA_reserved" },
226 { 0x90, "NOKIA_BTS_STM_TEST_REQ" },
227 { 0x91, "NOKIA_BTS_STM_TEST_REPORT" },
228 { 0x92, "NOKIA_BTS_TRANSMISSION_COMMAND" },
229 { 0x93, "NOKIA_BTS_TRANSMISSION_ANSWER" },
230 { 0x94, "NOKIA_BTS_HW_DB_UPLOAD_REQ" },
231 { 0x95, "NOKIA_BTS_START_HW_DB_DOWNLOAD_REQ" },
232 { 0x96, "NOKIA_BTS_HW_DB_SAVE_REQ" },
233 { 0x97, "NOKIA_BTS_FLASH_ERASURE_REQ" },
234 { 0x98, "NOKIA_BTS_HW_DB_DOWNLOAD_REQ" },
235 { 0x99, "NOKIA_BTS_PWR_SUPPLY_CONTROL" },
236 { 0x9A, "NOKIA_BTS_ATTRIBUTE_REQ" },
237 { 0x9B, "NOKIA_BTS_ATTRIBUTE_REPORT" },
238 { 0x9C, "NOKIA_BTS_HW_REQ" },
239 { 0x9D, "NOKIA_BTS_HW_REPORT" },
240 { 0x9E, "NOKIA_BTS_RTE_TEST_REQ" },
241 { 0x9F, "NOKIA_BTS_RTE_TEST_REPORT" },
242 { 0xA0, "NOKIA_BTS_HW_DB_VERIFICATION_REQ" },
243 { 0xA1, "NOKIA_BTS_CLOCK_REQ" },
244 { 0xA2, "NOKIA_AC_CIRCUIT_REQ_NACK" },
245 { 0xA3, "NOKIA_AC_INTERRUPTED" },
246 { 0xA4, "NOKIA_BTS_NEW_TRE_INFO" },
247 { 0xA5, "NOKIA_AC_BSC_CIRCUITS_ALLOCATED" },
248 { 0xA6, "NOKIA_BTS_TRE_POLL_LIST" },
249 { 0xA7, "NOKIA_AC_CIRCUIT_REQ" },
250 { 0xA8, "NOKIA_BTS_BLOCK_CTRL_REQ" },
251 { 0xA9, "NOKIA_BTS_GSM_TIME_REQ" },
252 { 0xAA, "NOKIA_BTS_GSM_TIME" },
253 { 0xAB, "NOKIA_BTS_OUTPUT_CONTROL" },
254 { 0xAC, "NOKIA_BTS_STATE_CHANGED" },
255 { 0xAD, "NOKIA_BTS_SW_SAVE_REQ" },
256 { 0xAE, "NOKIA_BTS_ALARM" },
257 { 0xAF, "NOKIA_BTS_CHA_ADM_STATE" },
258 { 0xB0, "NOKIA_AC_POOL_SIZE_REPORT" },
259 { 0xB1, "NOKIA_AC_POOL_SIZE_INQUIRY" },
260 { 0xB2, "NOKIA_BTS_COMMISS_TEST_COMPLETED" },
261 { 0xB3, "NOKIA_BTS_COMMISS_TEST_REQ" },
262 { 0xB4, "NOKIA_BTS_TRANSP_BTS_TO_BSC" },
263 { 0xB5, "NOKIA_BTS_TRANSP_BSC_TO_BTS" },
264 { 0xB6, "NOKIA_BTS_LCS_COMMAND" },
265 { 0xB7, "NOKIA_BTS_LCS_ANSWER" },
266 { 0xB8, "NOKIA_BTS_LMU_FN_OFFSET_COMMAND" },
267 { 0xB9, "NOKIA_BTS_LMU_FN_OFFSET_ANSWER" },
268 { 0, NULL }
269};
270
271static const char *get_msg_type_name_string(uint8_t msg_type)
Dieter Spaar16646022011-07-28 00:01:50 +0200272{
Harald Welte44d26112011-07-28 00:43:13 +0200273 return get_value_string(nokia_msgt_name, msg_type);
Dieter Spaar16646022011-07-28 00:01:50 +0200274}
275
Harald Welte44d26112011-07-28 00:43:13 +0200276static const struct value_string nokia_element_name[] = {
277 { 0x01, "Ny1" },
278 { 0x02, "T3105_F" },
279 { 0x03, "Interference band limits" },
280 { 0x04, "Interference report timer in secs" },
281 { 0x05, "Channel configuration per TS" },
282 { 0x06, "BSIC" },
283 { 0x07, "RACH report timer in secs" },
284 { 0x08, "Hardware database status" },
285 { 0x09, "BTS RX level" },
286 { 0x0A, "ARFN" },
287 { 0x0B, "STM antenna attenuation" },
288 { 0x0C, "Cell allocation bitmap" },
289 { 0x0D, "Radio definition per TS" },
290 { 0x0E, "Frame number" },
291 { 0x0F, "Antenna diversity" },
292 { 0x10, "T3105_D" },
293 { 0x11, "File format" },
294 { 0x12, "Last File" },
295 { 0x13, "BTS type" },
296 { 0x14, "Erasure mode" },
297 { 0x15, "Hopping mode" },
298 { 0x16, "Floating TRX" },
299 { 0x17, "Power supplies" },
300 { 0x18, "Reset type" },
301 { 0x19, "Averaging period" },
302 { 0x1A, "RBER2" },
303 { 0x1B, "LAC" },
304 { 0x1C, "CI" },
305 { 0x1D, "Failure parameters" },
306 { 0x1E, "(RF max power reduction)" },
307 { 0x1F, "Measured RX_SENS" },
308 { 0x20, "Extended cell radius" },
309 { 0x21, "reserved" },
310 { 0x22, "Success-Failure" },
311 { 0x23, "Ack-Nack" },
312 { 0x24, "OMU test results" },
313 { 0x25, "File identity" },
314 { 0x26, "Generation and version code" },
315 { 0x27, "SW description" },
316 { 0x28, "BCCH LEV" },
317 { 0x29, "Test type" },
318 { 0x2A, "Subscriber number" },
319 { 0x2B, "reserved" },
320 { 0x2C, "HSN" },
321 { 0x2D, "reserved" },
322 { 0x2E, "MS RXLEV" },
323 { 0x2F, "MS TXLEV" },
324 { 0x30, "RXQUAL" },
325 { 0x31, "RX SENS" },
326 { 0x32, "Alarm block" },
327 { 0x33, "Neighbouring BCCH levels" },
328 { 0x34, "STM report type" },
329 { 0x35, "MA" },
330 { 0x36, "MAIO" },
331 { 0x37, "H_FLAG" },
332 { 0x38, "TCH_ARFN" },
333 { 0x39, "Clock output" },
334 { 0x3A, "Transmitted power" },
335 { 0x3B, "Clock sync" },
336 { 0x3C, "TMS protocol discriminator" },
337 { 0x3D, "TMS protocol data" },
338 { 0x3E, "FER" },
339 { 0x3F, "SWR result" },
340 { 0x40, "Object identity" },
341 { 0x41, "STM RX Antenna Test" },
342 { 0x42, "reserved" },
343 { 0x43, "reserved" },
344 { 0x44, "Object current state" },
345 { 0x45, "reserved" },
346 { 0x46, "FU channel configuration" },
347 { 0x47, "reserved" },
348 { 0x48, "ARFN of a CU" },
349 { 0x49, "FU radio definition" },
350 { 0x4A, "reserved" },
351 { 0x4B, "Severity" },
352 { 0x4C, "Diversity selection" },
353 { 0x4D, "RX antenna test" },
354 { 0x4E, "RX antenna supervision period" },
355 { 0x4F, "RX antenna state" },
356 { 0x50, "Sector configuration" },
357 { 0x51, "Additional info" },
358 { 0x52, "SWR parameters" },
359 { 0x53, "HW inquiry mode" },
360 { 0x54, "reserved" },
361 { 0x55, "Availability status" },
362 { 0x56, "reserved" },
363 { 0x57, "EAC inputs" },
364 { 0x58, "EAC outputs" },
365 { 0x59, "reserved" },
366 { 0x5A, "Position" },
367 { 0x5B, "HW unit identity" },
368 { 0x5C, "RF test signal attenuation" },
369 { 0x5D, "Operational state" },
370 { 0x5E, "Logical object identity" },
371 { 0x5F, "reserved" },
372 { 0x60, "BS_TXPWR_OM" },
373 { 0x61, "Loop_Duration" },
374 { 0x62, "LNA_Path_Selection" },
375 { 0x63, "Serial number" },
376 { 0x64, "HW version" },
377 { 0x65, "Obj. identity and obj. state" },
378 { 0x66, "reserved" },
379 { 0x67, "EAC input definition" },
380 { 0x68, "EAC id and text" },
381 { 0x69, "HW unit status" },
382 { 0x6A, "SW release version" },
383 { 0x6B, "FW version" },
384 { 0x6C, "Bit_Error_Ratio" },
385 { 0x6D, "RXLEV_with_Attenuation" },
386 { 0x6E, "RXLEV_without_Attenuation" },
387 { 0x6F, "reserved" },
388 { 0x70, "CU_Results" },
389 { 0x71, "reserved" },
390 { 0x72, "LNA_Path_Results" },
391 { 0x73, "RTE Results" },
392 { 0x74, "Real Time" },
393 { 0x75, "RX diversity selection" },
394 { 0x76, "EAC input config" },
395 { 0x77, "Feature support" },
396 { 0x78, "File version" },
397 { 0x79, "Outputs" },
398 { 0x7A, "FU parameters" },
399 { 0x7B, "Diagnostic info" },
400 { 0x7C, "FU BSIC" },
401 { 0x7D, "TRX Configuration" },
402 { 0x7E, "Download status" },
403 { 0x7F, "RX difference limit" },
404 { 0x80, "TRX HW capability" },
405 { 0x81, "Common HW config" },
406 { 0x82, "Autoconfiguration pool size" },
407 { 0x83, "TRE diagnostic info" },
408 { 0x84, "TRE object identity" },
409 { 0x85, "New TRE Info" },
410 { 0x86, "Acknowledgement period" },
411 { 0x87, "Synchronization mode" },
412 { 0x88, "reserved" },
413 { 0x89, "Block Control Data" },
414 { 0x8A, "SW load mode" },
415 { 0x8B, "Recommended recovery action" },
416 { 0x8C, "BSC BCF id" },
417 { 0x8D, "Q1 baud rate" },
418 { 0x8E, "Allocation status" },
419 { 0x8F, "Functional entity number" },
420 { 0x90, "Transmission delay" },
421 { 0x91, "Loop Duration ms" },
422 { 0x92, "Logical channel" },
423 { 0x93, "Q1 address" },
424 { 0x94, "Alarm detail" },
425 { 0x95, "Cabinet type" },
426 { 0x96, "HW unit existence" },
427 { 0x97, "RF power parameters" },
428 { 0x98, "Message scenario" },
429 { 0x99, "HW unit max amount" },
430 { 0x9A, "Master TRX" },
431 { 0x9B, "Transparent data" },
432 { 0x9C, "BSC topology info" },
433 { 0x9D, "Air i/f modulation" },
434 { 0x9E, "LCS Q1 command data" },
435 { 0x9F, "Frame number offset" },
436 { 0xA0, "Abis TSL" },
437 { 0xA1, "Dynamic pool info" },
438 { 0xA2, "LCS LLP data" },
439 { 0xA3, "LCS Q1 answer data" },
440 { 0xA4, "DFCA FU Radio Definition" },
441 { 0xA5, "Antenna hopping" },
442 { 0xA6, "Field record sequence number" },
443 { 0xA7, "Timeslot offslot" },
444 { 0xA8, "EPCR capability" },
445 { 0xA9, "Connectsite optional element" },
446 { 0xAA, "TSC" },
447 { 0xAB, "Special TX Power Setting" },
448 { 0xAC, "Optional sync settings" },
449 { 0xFA, "Abis If parameters" },
450 { 0, NULL }
451};
452
453static const char *get_element_name_string(uint16_t element)
Dieter Spaar16646022011-07-28 00:01:50 +0200454{
Harald Welte44d26112011-07-28 00:43:13 +0200455 return get_value_string(nokia_element_name, element);
Dieter Spaar16646022011-07-28 00:01:50 +0200456}
457
Harald Welte3c3003f2011-07-28 00:28:20 +0200458static const struct value_string nokia_bts_types[] = {
459 { 0x0a, "MetroSite GSM 900" },
460 { 0x0b, "MetroSite GSM 1800" },
461 { 0x0c, "MetroSite GSM 1900 (PCS)" },
462 { 0x0d, "MetroSite GSM 900 & 1800" },
463 { 0x0e, "InSite GSM 900" },
464 { 0x0f, "InSite GSM 1800" },
465 { 0x10, "InSite GSM 1900" },
466 { 0x11, "UltraSite GSM 900" },
467 { 0x12, "UltraSite GSM 1800" },
468 { 0x13, "UltraSite GSM/US-TDMA 1900" },
469 { 0x14, "UltraSite GSM 900 & 1800" },
470 { 0x16, "UltraSite GSM/US-TDMA 850" },
471 { 0x18, "MetroSite GSM/US-TDMA 850" },
472 { 0x19, "UltraSite GSM 800/1900" },
473 { 0, NULL }
474};
475
476static const char *get_bts_type_string(uint8_t type)
Dieter Spaar16646022011-07-28 00:01:50 +0200477{
Harald Welte3c3003f2011-07-28 00:28:20 +0200478 return get_value_string(nokia_bts_types, type);
Dieter Spaar16646022011-07-28 00:01:50 +0200479}
480
Harald Welte3c3003f2011-07-28 00:28:20 +0200481static const struct value_string nokia_severity[] = {
482 { 0, "indeterminate" },
483 { 1, "critical" },
484 { 2, "major" },
485 { 3, "minor" },
486 { 4, "warning" },
487 { 0, NULL }
488};
489
490static const char *get_severity_string(uint8_t severity)
Dieter Spaar16646022011-07-28 00:01:50 +0200491{
Harald Welte3c3003f2011-07-28 00:28:20 +0200492 return get_value_string(nokia_severity, severity);
Dieter Spaar16646022011-07-28 00:01:50 +0200493}
494
495/* TODO: put in a separate file ? */
496
497/* some message IDs */
498
499#define NOKIA_MSG_CONF_DATA 128
500#define NOKIA_MSG_ACK 129
501#define NOKIA_MSG_OMU_STARTED 130
502#define NOKIA_MSG_START_DOWNLOAD_REQ 131
503#define NOKIA_MSG_MF_REQ 132
504#define NOKIA_MSG_RESET_REQ 134
505#define NOKIA_MSG_CONF_REQ 136
506#define NOKIA_MSG_CONF_COMPLETE 142
507#define NOKIA_MSG_BLOCK_CTRL_REQ 168
508#define NOKIA_MSG_STATE_CHANGED 172
509#define NOKIA_MSG_ALARM 174
510
511/* some element IDs */
512
513#define NOKIA_EI_BTS_TYPE 0x13
514#define NOKIA_EI_ACK 0x23
515#define NOKIA_EI_ADD_INFO 0x51
516#define NOKIA_EI_SEVERITY 0x4B
517#define NOKIA_EI_ALARM_DETAIL 0x94
518
519#define OM_ALLOC_SIZE 1024
520#define OM_HEADROOM_SIZE 128
521
Harald Weltebda367c2011-07-28 00:03:49 +0200522static uint8_t fu_config_template[] = {
523 0x7F, 0x7A, 0x39,
524 /* ID = 0x7A (FU parameters) ## constructed ## */
525 /* length = 57 */
526 /* [3] */
Dieter Spaar16646022011-07-28 00:01:50 +0200527
Harald Weltebda367c2011-07-28 00:03:49 +0200528 0x5F, 0x40, 0x04,
529 /* ID = 0x40 (Object identity) */
530 /* length = 4 */
531 /* [6] */
532 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200533
Harald Weltebda367c2011-07-28 00:03:49 +0200534 0x41, 0x02,
535 /* ID = 0x01 (Ny1) */
536 /* length = 2 */
537 /* [12] */
538 0x00, 0x05,
Dieter Spaar16646022011-07-28 00:01:50 +0200539
Harald Weltebda367c2011-07-28 00:03:49 +0200540 0x42, 0x02,
541 /* ID = 0x02 (T3105_F) */
542 /* length = 2 */
543 /* [16] */
Harald Welte67161f22012-06-03 13:01:47 +0200544 0x00, 0x28, /* FIXME: use net->T3105 */
Dieter Spaar16646022011-07-28 00:01:50 +0200545
Harald Weltebda367c2011-07-28 00:03:49 +0200546 0x50, 0x02,
547 /* ID = 0x10 (T3105_D) */
548 /* length = 2 */
549 /* [20] */
Harald Welte67161f22012-06-03 13:01:47 +0200550 0x00, 0x28, /* FIXME: use net->T3105 */
Dieter Spaar16646022011-07-28 00:01:50 +0200551
Harald Weltebda367c2011-07-28 00:03:49 +0200552 0x43, 0x05,
553 /* ID = 0x03 (Interference band limits) */
554 /* length = 5 */
555 /* [24] */
556 0x0F, 0x1B, 0x27, 0x33, 0x3F,
Dieter Spaar16646022011-07-28 00:01:50 +0200557
Harald Weltebda367c2011-07-28 00:03:49 +0200558 0x44, 0x02,
559 /* ID = 0x04 (Interference report timer in secs) */
560 /* length = 2 */
561 /* [31] */
562 0x00, 0x10,
Dieter Spaar16646022011-07-28 00:01:50 +0200563
Harald Weltebda367c2011-07-28 00:03:49 +0200564 0x47, 0x01,
565 /* ID = 0x07 (RACH report timer in secs) */
566 /* length = 1 */
567 /* [35] */
568 0x1E,
Dieter Spaar16646022011-07-28 00:01:50 +0200569
Harald Weltebda367c2011-07-28 00:03:49 +0200570 0x4C, 0x10,
571 /* ID = 0x0C (Cell allocation bitmap) ####### */
572 /* length = 16 */
573 /* [38] */
574 0x8F, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200576
Harald Weltebda367c2011-07-28 00:03:49 +0200577 0x59, 0x01,
578 /* ID = 0x19 (Averaging period) */
579 /* length = 1 */
580 /* [56] */
581 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +0200582
Harald Weltebda367c2011-07-28 00:03:49 +0200583 0x5E, 0x01,
584 /* ID = 0x1E ((RF max power reduction)) */
585 /* length = 1 */
586 /* [59] */
587 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200588
Harald Weltebda367c2011-07-28 00:03:49 +0200589 0x7F, 0x46, 0x11,
590 /* ID = 0x46 (FU channel configuration) ## constructed ## */
591 /* length = 17 */
592 /* [63] */
Dieter Spaar16646022011-07-28 00:01:50 +0200593
Harald Weltebda367c2011-07-28 00:03:49 +0200594 0x5F, 0x40, 0x04,
595 /* ID = 0x40 (Object identity) */
596 /* length = 4 */
597 /* [66] */
598 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200599
Harald Weltebda367c2011-07-28 00:03:49 +0200600 0x45, 0x08,
601 /* ID = 0x05 (Channel configuration per TS) */
602 /* length = 8 */
603 /* [72] */
604 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
Dieter Spaar16646022011-07-28 00:01:50 +0200605
Harald Weltebda367c2011-07-28 00:03:49 +0200606 0x7F, 0x65, 0x0B,
607 /* ID = 0x65 (Obj. identity and obj. state) ## constructed ## */
608 /* length = 11 */
609 /* [83] */
Dieter Spaar16646022011-07-28 00:01:50 +0200610
Harald Weltebda367c2011-07-28 00:03:49 +0200611 0x5F, 0x40, 0x04,
612 /* ID = 0x40 (Object identity) */
613 /* length = 4 */
614 /* [86] */
615 0x00, 0x04, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200616
Harald Weltebda367c2011-07-28 00:03:49 +0200617 0x5F, 0x44, 0x01,
618 /* ID = 0x44 (Object current state) */
619 /* length = 1 */
620 /* [93] */
621 0x03,
Dieter Spaar16646022011-07-28 00:01:50 +0200622
Harald Weltebda367c2011-07-28 00:03:49 +0200623 0x7F, 0x7C, 0x0A,
624 /* ID = 0x7C (FU BSIC) ## constructed ## */
625 /* length = 10 */
626 /* [97] */
Dieter Spaar16646022011-07-28 00:01:50 +0200627
Harald Weltebda367c2011-07-28 00:03:49 +0200628 0x5F, 0x40, 0x04,
629 /* ID = 0x40 (Object identity) */
630 /* length = 4 */
631 /* [100] */
632 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200633
Harald Weltebda367c2011-07-28 00:03:49 +0200634 0x46, 0x01,
635 /* ID = 0x06 (BSIC) */
636 /* length = 1 */
637 /* [106] */
638 0x00,
Dieter Spaar16646022011-07-28 00:01:50 +0200639
Harald Weltebda367c2011-07-28 00:03:49 +0200640 0x7F, 0x48, 0x0B,
641 /* ID = 0x48 (ARFN of a CU) ## constructed ## */
642 /* length = 11 */
643 /* [110] */
Dieter Spaar16646022011-07-28 00:01:50 +0200644
Harald Weltebda367c2011-07-28 00:03:49 +0200645 0x5F, 0x40, 0x04,
646 /* ID = 0x40 (Object identity) */
647 /* length = 4 */
648 /* [113] */
649 0x00, 0x08, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200650
Harald Weltebda367c2011-07-28 00:03:49 +0200651 0x4A, 0x02,
652 /* ID = 0x0A (ARFN) ####### */
653 /* length = 2 */
654 /* [119] */
655 0x03, 0x62,
Dieter Spaar16646022011-07-28 00:01:50 +0200656
Harald Weltebda367c2011-07-28 00:03:49 +0200657 0x7F, 0x49, 0x59,
658 /* ID = 0x49 (FU radio definition) ## constructed ## */
659 /* length = 89 */
660 /* [124] */
Dieter Spaar16646022011-07-28 00:01:50 +0200661
Harald Weltebda367c2011-07-28 00:03:49 +0200662 0x5F, 0x40, 0x04,
663 /* ID = 0x40 (Object identity) */
664 /* length = 4 */
665 /* [127] */
666 0x00, 0x07, 0x01, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +0200667
Harald Weltebda367c2011-07-28 00:03:49 +0200668 0x4D, 0x50,
669 /* ID = 0x0D (Radio definition per TS) ####### */
670 /* length = 80 */
671 /* [133] */
672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MA */
673 0x03, 0x62, /* HSN, MAIO or ARFCN if no hopping */
674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675 0x03, 0x62,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 0x03, 0x62,
678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0x03, 0x62,
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x03, 0x62,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x03, 0x62,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x03, 0x62,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687 0x03, 0x62,
Dieter Spaar16646022011-07-28 00:01:50 +0200688};
689
690/* TODO: put in a separate file ? */
691
692/*
Harald Weltecde57942011-07-28 00:13:46 +0200693 build the configuration for each TRX
Dieter Spaar16646022011-07-28 00:01:50 +0200694*/
695
Harald Weltebda367c2011-07-28 00:03:49 +0200696static int make_fu_config(struct gsm_bts_trx *trx, uint8_t id,
697 uint8_t * fu_config, int *hopping)
Dieter Spaar16646022011-07-28 00:01:50 +0200698{
Harald Weltebda367c2011-07-28 00:03:49 +0200699 int i;
Dieter Spaar16646022011-07-28 00:01:50 +0200700
Harald Weltebda367c2011-07-28 00:03:49 +0200701 *hopping = 0;
702
703 memcpy(fu_config, fu_config_template, sizeof(fu_config_template));
704
705 /* set ID */
706
707 fu_config[6 + 2] = id;
708 fu_config[66 + 2] = id;
709 fu_config[86 + 2] = id;
710 fu_config[100 + 2] = id;
711 fu_config[113 + 2] = id;
712 fu_config[127 + 2] = id;
713
714 /* set ARFCN */
715
716 uint16_t arfcn = trx->arfcn;
717
718 fu_config[119] = arfcn >> 8;
719 fu_config[119 + 1] = arfcn & 0xFF;
720
721 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
722 struct gsm_bts_trx_ts *ts = &trx->ts[i];
723
724 if (ts->hopping.enabled) {
725 /* reverse order */
726 int j;
727 for (j = 0; j < ts->hopping.ma_len; j++)
728 fu_config[133 + (i * 10) + (7 - j)] =
729 ts->hopping.ma_data[j];
730 fu_config[133 + 8 + (i * 10)] = ts->hopping.hsn;
731 fu_config[133 + 8 + 1 + (i * 10)] = ts->hopping.maio;
732 *hopping = 1;
733 } else {
734 fu_config[133 + 8 + (i * 10)] = arfcn >> 8;
735 fu_config[133 + 8 + 1 + (i * 10)] = arfcn & 0xFF;
736 }
737 }
738
739 /* set BSIC */
740
Harald Weltecde57942011-07-28 00:13:46 +0200741 /*
Harald Weltebda367c2011-07-28 00:03:49 +0200742 Attention: all TRX except the first one seem to get the TSC
743 from the CHANNEL ACTIVATION command (in CHANNEL IDENTIFICATION,
Harald Weltecde57942011-07-28 00:13:46 +0200744 GSM 04.08 CHANNEL DESCRIPTION).
745 There was a bug in rsl_chan_activate_lchan() setting this parameter.
Harald Weltebda367c2011-07-28 00:03:49 +0200746 */
747
748 uint8_t bsic = trx->bts->bsic;
749
750 fu_config[106] = bsic;
751
752 /* set CA */
753
754 if (generate_cell_chan_list(&fu_config[38], trx->bts) != 0) {
755 fprintf(stderr, "generate_cell_chan_list failed\n");
756 return 0;
757 }
758
759 /* set channel configuration */
760
761 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
762 struct gsm_bts_trx_ts *ts = &trx->ts[i];
763 uint8_t chan_config;
764
765 /*
766 0 = FCCH + SCH + BCCH + CCCH
767 1 = FCCH + SCH + BCCH + CCCH + SDCCH/4 + SACCH/4
768 2 = BCCH + CCCH (This combination is not used in any BTS)
769 3 = FCCH + SCH + BCCH + CCCH + SDCCH/4 with SDCCH2 used as CBCH
770 4 = SDCCH/8 + SACCH/8
771 5 = SDCCH/8 with SDCCH2 used as CBCH
772 6 = TCH/F + FACCH/F + SACCH/F
773 7 = E-RACH (Talk family)
774 9 = Dual rate (capability for TCH/F and TCH/H)
775 10 = reserved for BTS internal use
Harald Weltecde57942011-07-28 00:13:46 +0200776 11 = PBCCH + PCCCH + PDTCH + PACCH + PTCCH (can be used in GPRS release 2).
777 0xFF = spare TS
Harald Weltebda367c2011-07-28 00:03:49 +0200778 */
779
780 if (ts->pchan == GSM_PCHAN_NONE)
781 chan_config = 0xFF;
782 else if (ts->pchan == GSM_PCHAN_CCCH)
783 chan_config = 0;
784 else if (ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
785 chan_config = 1;
786 else if (ts->pchan == GSM_PCHAN_TCH_F)
787 chan_config = 6; /* 9 should work too */
788 else if (ts->pchan == GSM_PCHAN_TCH_H)
789 chan_config = 9;
790 else if (ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C)
791 chan_config = 4;
792 else if (ts->pchan == GSM_PCHAN_PDCH)
793 chan_config = 11;
794 else {
795 fprintf(stderr,
796 "unsupported channel config %d for timeslot %d\n",
797 ts->pchan, i);
798 return 0;
799 }
800
801 fu_config[72 + i] = chan_config;
802 }
803 return sizeof(fu_config_template);
Dieter Spaar16646022011-07-28 00:01:50 +0200804}
805
806/* TODO: put in a separate file ? */
807
Harald Weltebda367c2011-07-28 00:03:49 +0200808static uint8_t bts_config_1[] = {
809 0x4E, 0x02,
810 /* ID = 0x0E (Frame number) */
811 /* length = 2 */
812 /* [2] */
813 0xFF, 0xFF,
814
815 0x5F, 0x4E, 0x02,
816 /* ID = 0x4E (RX antenna supervision period) */
817 /* length = 2 */
818 /* [7] */
819 0xFF, 0xFF,
820
821 0x5F, 0x50, 0x02,
822 /* ID = 0x50 (Sector configuration) */
823 /* length = 2 */
824 /* [12] */
825 0x01, 0x01,
826};
827
828static uint8_t bts_config_2[] = {
829 0x55, 0x02,
830 /* ID = 0x15 (Hopping mode) */
831 /* length = 2 */
832 /* [2] */
833 0x01, 0x00,
834
835 0x5F, 0x75, 0x02,
836 /* ID = 0x75 (RX diversity selection) */
837 /* length = 2 */
838 /* [7] */
839 0x01, 0x01,
840};
841
842static uint8_t bts_config_3[] = {
843 0x5F, 0x20, 0x02,
844 /* ID = 0x20 (Extended cell radius) */
845 /* length = 2 */
846 /* [3] */
847 0x01, 0x00,
848};
849
850static uint8_t bts_config_4[] = {
851 0x5F, 0x74, 0x09,
852 /* ID = 0x74 (Real Time) */
853 /* length = 9 */
854 /* [3] year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
855 0x07, 0xDB, 0x06, 0x02, 0x0B, 0x20, 0x0C, 0x00,
856 0x00,
857
858 0x5F, 0x76, 0x03,
859 /* ID = 0x76 (EAC input config) */
860 /* length = 3 */
861 /* [15] */
862 0x01, 0x01, 0x00,
863
864 0x5F, 0x76, 0x03,
865 /* ID = 0x76 (EAC input config) */
866 /* length = 3 */
867 /* [21] */
868 0x02, 0x01, 0x00,
869
870 0x5F, 0x76, 0x03,
871 /* ID = 0x76 (EAC input config) */
872 /* length = 3 */
873 /* [27] */
874 0x03, 0x01, 0x00,
875
876 0x5F, 0x76, 0x03,
877 /* ID = 0x76 (EAC input config) */
878 /* length = 3 */
879 /* [33] */
880 0x04, 0x01, 0x00,
881
882 0x5F, 0x76, 0x03,
883 /* ID = 0x76 (EAC input config) */
884 /* length = 3 */
885 /* [39] */
886 0x05, 0x01, 0x00,
887
888 0x5F, 0x76, 0x03,
889 /* ID = 0x76 (EAC input config) */
890 /* length = 3 */
891 /* [45] */
892 0x06, 0x01, 0x00,
893
894 0x5F, 0x76, 0x03,
895 /* ID = 0x76 (EAC input config) */
896 /* length = 3 */
897 /* [51] */
898 0x07, 0x01, 0x00,
899
900 0x5F, 0x76, 0x03,
901 /* ID = 0x76 (EAC input config) */
902 /* length = 3 */
903 /* [57] */
904 0x08, 0x01, 0x00,
905
906 0x5F, 0x76, 0x03,
907 /* ID = 0x76 (EAC input config) */
908 /* length = 3 */
909 /* [63] */
910 0x09, 0x01, 0x00,
911
912 0x5F, 0x76, 0x03,
913 /* ID = 0x76 (EAC input config) */
914 /* length = 3 */
915 /* [69] */
916 0x0A, 0x01, 0x00,
917};
918
919static uint8_t bts_config_insite[] = {
920 0x4E, 0x02,
921 /* ID = 0x0E (Frame number) */
922 /* length = 2 */
923 /* [2] */
924 0xFF, 0xFF,
925
926 0x5F, 0x4E, 0x02,
927 /* ID = 0x4E (RX antenna supervision period) */
928 /* length = 2 */
929 /* [7] */
930 0xFF, 0xFF,
931
932 0x5F, 0x50, 0x02,
933 /* ID = 0x50 (Sector configuration) */
934 /* length = 2 */
935 /* [12] */
936 0x01, 0x01,
937
938 0x55, 0x02,
939 /* ID = 0x15 (Hopping mode) */
940 /* length = 2 */
941 /* [16] */
942 0x01, 0x00,
943
944 0x5F, 0x20, 0x02,
945 /* ID = 0x20 (Extended cell radius) */
946 /* length = 2 */
947 /* [21] */
948 0x01, 0x00,
949
950 0x5F, 0x74, 0x09,
951 /* ID = 0x74 (Real Time) */
952 /* length = 9 */
953 /* [26] */
954 0x07, 0xDB, 0x07, 0x0A, 0x0F, 0x09, 0x0B, 0x00,
955 0x00,
956};
957
958void set_real_time(uint8_t * real_time)
Dieter Spaar16646022011-07-28 00:01:50 +0200959{
Harald Weltebda367c2011-07-28 00:03:49 +0200960 time_t t;
961 struct tm *tm;
Dieter Spaar16646022011-07-28 00:01:50 +0200962
Harald Weltebda367c2011-07-28 00:03:49 +0200963 t = time(NULL);
964 tm = localtime(&t);
Dieter Spaar16646022011-07-28 00:01:50 +0200965
Harald Weltebda367c2011-07-28 00:03:49 +0200966 /* year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */
Dieter Spaar16646022011-07-28 00:01:50 +0200967
Harald Weltebda367c2011-07-28 00:03:49 +0200968 real_time[0] = (1900 + tm->tm_year) >> 8;
969 real_time[1] = (1900 + tm->tm_year) & 0xFF;
970 real_time[2] = tm->tm_mon + 1;
971 real_time[3] = tm->tm_mday;
972 real_time[4] = tm->tm_hour;
973 real_time[5] = tm->tm_min;
974 real_time[6] = tm->tm_sec;
975 real_time[7] = 0;
976 real_time[8] = 0;
Dieter Spaar16646022011-07-28 00:01:50 +0200977}
978
979/* TODO: put in a separate file ? */
980
981/*
Dieter Spaar16646022011-07-28 00:01:50 +0200982 build the configuration data
Dieter Spaar16646022011-07-28 00:01:50 +0200983*/
984
Harald Weltebda367c2011-07-28 00:03:49 +0200985static int make_bts_config(uint8_t bts_type, int n_trx, uint8_t * fu_config,
986 int need_hopping)
Dieter Spaar16646022011-07-28 00:01:50 +0200987{
Harald Weltebda367c2011-07-28 00:03:49 +0200988 /* is it an InSite BTS ? */
989 if (bts_type == 0x0E || bts_type == 0x0F || bts_type == 0x10) { /* TODO */
990 if (n_trx != 1) {
991 fprintf(stderr, "InSite has only one TRX\n");
992 return 0;
993 }
994 if (need_hopping != 0) {
995 fprintf(stderr, "InSite does not support hopping\n");
996 return 0;
997 }
998 memcpy(fu_config, bts_config_insite, sizeof(bts_config_insite));
999 set_real_time(&fu_config[26]);
1000 return sizeof(bts_config_insite);
1001 }
Dieter Spaar16646022011-07-28 00:01:50 +02001002
Harald Weltebda367c2011-07-28 00:03:49 +02001003 int len = 0;
1004 int i;
1005
1006 memcpy(fu_config + len, bts_config_1, sizeof(bts_config_1));
1007
1008 /* set sector configuration */
1009 fu_config[len + 12 - 1] = 1 + n_trx; /* len */
1010 for (i = 0; i < n_trx; i++)
1011 fu_config[len + 12 + 1 + i] = ((i + 1) & 0xFF);
1012
1013 len += (sizeof(bts_config_1) + (n_trx - 1));
1014
1015 memcpy(fu_config + len, bts_config_2, sizeof(bts_config_2));
1016 /* set hopping mode (Baseband and RF hopping work for the MetroSite) */
1017 if (need_hopping)
1018 fu_config[len + 2 + 1] = 1; /* 0: no hopping, 1: Baseband hopping, 2: RF hopping */
1019 len += sizeof(bts_config_2);
1020
1021 /* set extended cell radius for each TRX */
1022 for (i = 0; i < n_trx; i++) {
1023 memcpy(fu_config + len, bts_config_3, sizeof(bts_config_3));
1024 fu_config[len + 3] = ((i + 1) & 0xFF);
1025 len += sizeof(bts_config_3);
1026 }
1027
1028 memcpy(fu_config + len, bts_config_4, sizeof(bts_config_4));
1029 set_real_time(&fu_config[len + 3]);
1030 len += sizeof(bts_config_4);
1031
1032 return len;
Dieter Spaar16646022011-07-28 00:01:50 +02001033}
1034
1035/* TODO: put in a separate file ? */
1036
1037static struct msgb *nm_msgb_alloc(void)
1038{
Harald Weltebda367c2011-07-28 00:03:49 +02001039 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML");
Dieter Spaar16646022011-07-28 00:01:50 +02001040}
1041
1042/* TODO: put in a separate file ? */
1043
1044struct abis_om_nokia_hdr {
Harald Weltebda367c2011-07-28 00:03:49 +02001045 uint8_t msg_type;
1046 uint8_t spare;
1047 uint16_t reference;
1048 uint8_t data[0];
Dieter Spaar16646022011-07-28 00:01:50 +02001049} __attribute__ ((packed));
1050
1051#define ABIS_OM_NOKIA_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_nokia_hdr))
1052
Harald Weltebda367c2011-07-28 00:03:49 +02001053static int abis_nm_send(struct gsm_bts *bts, uint8_t msg_type, uint16_t ref,
1054 uint8_t * data, int len_data)
Dieter Spaar16646022011-07-28 00:01:50 +02001055{
Harald Weltebda367c2011-07-28 00:03:49 +02001056 struct abis_om_hdr *oh;
1057 struct abis_om_nokia_hdr *noh;
1058 struct msgb *msg = nm_msgb_alloc();
Dieter Spaar16646022011-07-28 00:01:50 +02001059
Harald Weltebda367c2011-07-28 00:03:49 +02001060 oh = (struct abis_om_hdr *)msgb_put(msg,
1061 ABIS_OM_NOKIA_HDR_SIZE + len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001062
Harald Weltebda367c2011-07-28 00:03:49 +02001063 oh->mdisc = ABIS_OM_MDISC_FOM;
1064 oh->placement = ABIS_OM_PLACEMENT_ONLY;
1065 oh->sequence = 0;
1066 oh->length = sizeof(struct abis_om_nokia_hdr) + len_data;
1067
1068 noh = (struct abis_om_nokia_hdr *)oh->data;
1069
1070 noh->msg_type = msg_type;
1071 noh->spare = 0;
1072 noh->reference = htons(ref);
1073 memcpy(noh->data, data, len_data);
1074
1075 DEBUGPC(DNM, "Sending %s\n", get_msg_type_name_string(msg_type));
1076
1077 return abis_nm_sendmsg(bts, msg);
Dieter Spaar16646022011-07-28 00:01:50 +02001078}
1079
1080/* TODO: put in a separate file ? */
1081
1082static uint8_t download_req[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001083 0x5F, 0x25, 0x0B,
1084 /* ID = 0x25 (File identity) */
1085 /* length = 11 */
1086 /* [3] */
1087 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
1088 0x2A, 0x2A, 0x2A,
Dieter Spaar16646022011-07-28 00:01:50 +02001089
Harald Weltebda367c2011-07-28 00:03:49 +02001090 0x5F, 0x78, 0x03,
1091 /* ID = 0x78 (File version) */
1092 /* length = 3 */
1093 /* [17] */
1094 0x2A, 0x2A, 0x2A,
Dieter Spaar16646022011-07-28 00:01:50 +02001095
Harald Weltebda367c2011-07-28 00:03:49 +02001096 0x5F, 0x81, 0x0A, 0x01,
1097 /* ID = 0x8A (SW load mode) */
1098 /* length = 1 */
1099 /* [24] */
1100 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001101
Harald Weltebda367c2011-07-28 00:03:49 +02001102 0x5F, 0x81, 0x06, 0x01,
1103 /* ID = 0x86 (Acknowledgement period) */
1104 /* length = 1 */
1105 /* [29] */
1106 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001107};
1108
1109static int abis_nm_download_req(struct gsm_bts *bts, uint16_t ref)
1110{
Harald Weltebda367c2011-07-28 00:03:49 +02001111 uint8_t *data = download_req;
1112 int len_data = sizeof(download_req);
1113
1114 return abis_nm_send(bts, NOKIA_MSG_START_DOWNLOAD_REQ, ref, data,
1115 len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001116}
1117
1118/* TODO: put in a separate file ? */
1119
1120static uint8_t ack[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001121 0x5F, 0x23, 0x01,
1122 /* ID = 0x23 (Ack-Nack) */
1123 /* length = 1 */
1124 /* [3] */
1125 0x01,
Dieter Spaar16646022011-07-28 00:01:50 +02001126};
1127
1128static int abis_nm_ack(struct gsm_bts *bts, uint16_t ref)
1129{
Harald Weltebda367c2011-07-28 00:03:49 +02001130 uint8_t *data = ack;
1131 int len_data = sizeof(ack);
1132
1133 return abis_nm_send(bts, NOKIA_MSG_ACK, ref, data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001134}
1135
1136/* TODO: put in a separate file ? */
1137
1138static uint8_t reset[] = {
Harald Weltebda367c2011-07-28 00:03:49 +02001139 0x5F, 0x40, 0x04,
1140 /* ID = 0x40 (Object identity) */
1141 /* length = 4 */
1142 /* [3] */
1143 0x00, 0x01, 0xFF, 0xFF,
Dieter Spaar16646022011-07-28 00:01:50 +02001144};
1145
1146static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref)
1147{
Harald Weltebda367c2011-07-28 00:03:49 +02001148 uint8_t *data = reset;
1149 int len_data = sizeof(reset);
1150
1151 return abis_nm_send(bts, NOKIA_MSG_RESET_REQ, ref, data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001152}
1153
1154/* TODO: put in a separate file ? */
1155
Harald Weltebda367c2011-07-28 00:03:49 +02001156static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type,
1157 uint16_t ref, uint8_t * data, int len)
Dieter Spaar16646022011-07-28 00:01:50 +02001158{
Harald Weltebda367c2011-07-28 00:03:49 +02001159 int len_remain, len_to_send, max_send;
1160 int seq = 0;
1161 int ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001162
Harald Weltebda367c2011-07-28 00:03:49 +02001163 len_remain = len;
1164
1165 while (len_remain) {
1166 struct abis_om_hdr *oh;
1167 struct abis_om_nokia_hdr *noh;
1168 struct msgb *msg = nm_msgb_alloc();
1169
1170 if (seq == 0)
1171 max_send = 256 - sizeof(struct abis_om_nokia_hdr);
1172 else
1173 max_send = 256;
1174
1175 if (len_remain > max_send) {
1176 len_to_send = max_send;
1177
1178 if (seq == 0) {
1179 /* first segment */
1180 oh = (struct abis_om_hdr *)msgb_put(msg,
1181 ABIS_OM_NOKIA_HDR_SIZE
1182 +
1183 len_to_send);
1184
1185 oh->mdisc = ABIS_OM_MDISC_FOM;
1186 oh->placement = ABIS_OM_PLACEMENT_FIRST; /* first segment of multi-segment message */
1187 oh->sequence = seq;
1188 oh->length = 0; /* 256 bytes */
1189
1190 noh = (struct abis_om_nokia_hdr *)oh->data;
1191
1192 noh->msg_type = msg_type;
1193 noh->spare = 0;
1194 noh->reference = htons(ref);
1195 memcpy(noh->data, data, len_to_send);
1196 } else {
1197 /* segment in between */
1198 oh = (struct abis_om_hdr *)msgb_put(msg,
1199 sizeof
1200 (struct
1201 abis_om_hdr)
1202 +
1203 len_to_send);
1204
1205 oh->mdisc = ABIS_OM_MDISC_FOM;
1206 oh->placement = ABIS_OM_PLACEMENT_MIDDLE; /* segment of multi-segment message */
1207 oh->sequence = seq;
1208 oh->length = 0; /* 256 bytes */
1209
1210 memcpy(oh->data, data, len_to_send);
1211 }
1212 } else {
1213
1214 len_to_send = len_remain;
1215
1216 /* check if message fits in a single segment */
1217
1218 if (seq == 0)
1219 return abis_nm_send(bts, msg_type, ref, data,
1220 len_to_send);
1221
1222 /* last segment */
1223
1224 oh = (struct abis_om_hdr *)msgb_put(msg,
1225 sizeof(struct
1226 abis_om_hdr)
1227 + len_to_send);
1228
1229 oh->mdisc = ABIS_OM_MDISC_FOM;
1230 oh->placement = ABIS_OM_PLACEMENT_LAST; /* last segment of multi-segment message */
1231 oh->sequence = seq;
1232 oh->length = len_to_send;
1233
1234 memcpy(oh->data, data, len_to_send);
1235 }
1236
1237 DEBUGPC(DNM, "Sending multi-segment %d\n", seq);
1238
1239 ret = abis_nm_sendmsg(bts, msg);
1240 if (ret < 0)
1241 return ret;
1242
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001243 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001244
1245 /* next segment */
1246 len_remain -= len_to_send;
1247 data += len_to_send;
1248 seq++;
1249 }
1250 return ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001251}
1252
1253/* TODO: put in a separate file ? */
1254
1255static int abis_nm_send_config(struct gsm_bts *bts, uint8_t bts_type)
1256{
Harald Weltebda367c2011-07-28 00:03:49 +02001257 struct gsm_bts_trx *trx;
1258 uint8_t config[2048]; /* TODO: might be too small if lots of TRX are used */
1259 int len = 0;
1260 int idx = 0;
1261 int ret;
1262 int hopping = 0;
1263 int need_hopping = 0;
1264
1265 memset(config, 0, sizeof(config));
1266
1267 llist_for_each_entry(trx, &bts->trx_list, list) {
1268#if 0 /* debugging */
1269 printf("TRX\n");
1270 printf(" arfcn: %d\n", trx->arfcn);
1271 printf(" bsic: %d\n", trx->bts->bsic);
1272 uint8_t ca[20];
1273 memset(ca, 0xFF, sizeof(ca));
1274 ret = generate_cell_chan_list(ca, trx->bts);
1275 printf(" ca (%d): %s\n", ret, osmo_hexdump(ca, sizeof(ca)));
1276 int i;
1277 for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
1278 struct gsm_bts_trx_ts *ts = &trx->ts[i];
1279
1280 printf(" pchan %d: %d\n", i, ts->pchan);
1281 }
Dieter Spaar16646022011-07-28 00:01:50 +02001282#endif
Harald Weltebda367c2011-07-28 00:03:49 +02001283 ret = make_fu_config(trx, idx + 1, config + len, &hopping);
1284 need_hopping |= hopping;
1285 len += ret;
1286
1287 idx++;
1288 }
1289
1290 ret = make_bts_config(bts_type, idx, config + len, need_hopping);
1291 len += ret;
1292
1293#if 0 /* debugging */
1294 dump_elements(config, len);
1295#endif
1296
1297 return abis_nm_send_multi_segments(bts, NOKIA_MSG_CONF_DATA, 1, config,
1298 len);
Dieter Spaar16646022011-07-28 00:01:50 +02001299}
1300
1301#define GET_NEXT_BYTE if(idx >= len) return 0; \
Harald Weltebda367c2011-07-28 00:03:49 +02001302 ub = data[idx++];
Dieter Spaar16646022011-07-28 00:01:50 +02001303
Harald Weltebda367c2011-07-28 00:03:49 +02001304static int find_element(uint8_t * data, int len, uint16_t id, uint8_t * value,
1305 int max_value)
1306{
1307 uint8_t ub;
1308 int idx = 0;
1309 int found = 0;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02001310 int constructed __attribute__((unused));
Harald Weltebda367c2011-07-28 00:03:49 +02001311 uint16_t id_value;
1312
1313 for (;;) {
1314
1315 GET_NEXT_BYTE;
1316
1317 /* encoding bit, construced means that other elements are contained */
1318 constructed = ((ub & 0x20) ? 1 : 0);
1319
1320 if ((ub & 0x1F) == 0x1F) {
1321 /* fixed pattern, ID follows */
1322 GET_NEXT_BYTE; /* ID */
1323 id_value = ub & 0x7F;
1324 if (ub & 0x80) {
1325 /* extension bit */
1326 GET_NEXT_BYTE; /* ID low part */
1327 id_value = (id_value << 7) | (ub & 0x7F);
1328 }
1329 if (id_value == id)
1330 found = 1;
1331 } else {
1332 id_value = (ub & 0x3F);
1333 if (id_value == id)
1334 found = 1;
1335 }
1336
1337 GET_NEXT_BYTE; /* length */
1338
1339 if (found) {
1340 /* get data */
1341 uint8_t n = ub;
1342 uint8_t i;
1343 for (i = 0; i < n; i++) {
1344 GET_NEXT_BYTE;
1345 if (max_value <= 0)
1346 return -1; /* buffer too small */
1347 *value = ub;
1348 value++;
1349 max_value--;
1350 }
1351 return n; /* length */
1352 } else {
1353 /* skip data */
1354 uint8_t n = ub;
1355 uint8_t i;
1356 for (i = 0; i < n; i++) {
1357 GET_NEXT_BYTE;
1358 }
1359 }
1360 }
1361 return 0; /* not found */
Dieter Spaar16646022011-07-28 00:01:50 +02001362}
1363
Harald Weltebda367c2011-07-28 00:03:49 +02001364static int dump_elements(uint8_t * data, int len)
1365{
1366 uint8_t ub;
1367 int idx = 0;
1368 int constructed;
1369 uint16_t id_value;
1370 static char indent[100] = ""; /* TODO: move static to BTS context */
Dieter Spaar16646022011-07-28 00:01:50 +02001371
Harald Weltebda367c2011-07-28 00:03:49 +02001372 for (;;) {
1373
1374 GET_NEXT_BYTE;
1375
1376 /* encoding bit, construced means that other elements are contained */
1377 constructed = ((ub & 0x20) ? 1 : 0);
1378
1379 if ((ub & 0x1F) == 0x1F) {
1380 /* fixed pattern, ID follows */
1381 GET_NEXT_BYTE; /* ID */
1382 id_value = ub & 0x7F;
1383 if (ub & 0x80) {
1384 /* extension bit */
1385 GET_NEXT_BYTE; /* ID low part */
1386 id_value = (id_value << 7) | (ub & 0x7F);
1387 }
1388
1389 } else {
1390 id_value = (ub & 0x3F);
1391 }
1392
1393 GET_NEXT_BYTE; /* length */
1394
1395 printf("%s--ID = 0x%02X (%s) %s\n", indent, id_value,
1396 get_element_name_string(id_value),
1397 constructed ? "** constructed **" : "");
1398 printf("%s length = %d\n", indent, ub);
1399 printf("%s %s\n", indent, osmo_hexdump(data + idx, ub));
1400
1401 if (constructed) {
1402 int indent_len = strlen(indent);
1403 strcat(indent, " ");
1404
1405 dump_elements(data + idx, ub);
1406
1407 indent[indent_len] = 0;
1408 }
1409 /* skip data */
1410 uint8_t n = ub;
1411 uint8_t i;
1412 for (i = 0; i < n; i++) {
1413 GET_NEXT_BYTE;
1414 }
1415 }
1416 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001417}
1418
1419/* TODO: put in a separate file ? */
1420
1421/* taken from abis_nm.c */
1422
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001423static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts)
Dieter Spaar16646022011-07-28 00:01:50 +02001424{
Harald Weltebda367c2011-07-28 00:03:49 +02001425 int wait = 0;
1426 struct msgb *msg;
1427 /* the queue is empty */
1428 while (!llist_empty(&bts->abis_queue)) {
1429 msg = msgb_dequeue(&bts->abis_queue);
1430 wait = OBSC_NM_W_ACK_CB(msg);
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001431 abis_sendmsg(msg);
Dieter Spaar16646022011-07-28 00:01:50 +02001432
Harald Weltebda367c2011-07-28 00:03:49 +02001433 if (wait)
1434 break;
1435 }
Dieter Spaar16646022011-07-28 00:01:50 +02001436
Harald Weltebda367c2011-07-28 00:03:49 +02001437 bts->abis_nm_pend = wait;
Dieter Spaar16646022011-07-28 00:01:50 +02001438}
1439
1440/* TODO: put in a separate file ? */
1441
1442/* timer for restarting OML after BTS reset */
1443
1444static void reset_timer_cb(void *_bts)
1445{
Harald Weltebda367c2011-07-28 00:03:49 +02001446 struct gsm_bts *bts = _bts;
1447 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1448 struct e1inp_line *line;
1449
Harald Weltec8755af2011-07-28 00:22:17 +02001450 bts->nokia.wait_reset = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001451
1452 /* OML link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001453 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001454 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001455 LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to "
Harald Weltebda367c2011-07-28 00:03:49 +02001456 "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
1457 return;
1458 }
1459
1460 start_sabm_in_line(line, 0, -1); /* stop all first */
1461 start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */
Dieter Spaar16646022011-07-28 00:01:50 +02001462}
1463
1464/* TODO: put in a separate file ? */
1465
1466/*
1467 This is how the configuration is done:
Dieter Spaar16646022011-07-28 00:01:50 +02001468 - start OML link
Dieter Spaar16646022011-07-28 00:01:50 +02001469 - reset BTS
Dieter Spaar16646022011-07-28 00:01:50 +02001470 - receive ACK, wait some time and restart OML link
Dieter Spaar16646022011-07-28 00:01:50 +02001471 - receive OMU STARTED message, send START DOWNLOAD REQ
Dieter Spaar16646022011-07-28 00:01:50 +02001472 - receive CNF REQ message, send CONF DATA
Dieter Spaar16646022011-07-28 00:01:50 +02001473 - receive ACK, start RSL link(s)
Dieter Spaar16646022011-07-28 00:01:50 +02001474 ACK some other messages received from the BTS.
Harald Weltecde57942011-07-28 00:13:46 +02001475
Dieter Spaar16646022011-07-28 00:01:50 +02001476 Probably its also possible to configure the BTS without a reset, this
1477 has not been tested yet.
1478*/
1479
1480static int abis_nm_rcvmsg_fom(struct msgb *mb)
1481{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001482 struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)mb->dst;
1483 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltebda367c2011-07-28 00:03:49 +02001484 struct abis_om_hdr *oh = msgb_l2(mb);
1485 struct abis_om_nokia_hdr *noh = msgb_l3(mb);
1486 uint8_t mt = noh->msg_type;
1487 int ret = 0;
1488 uint16_t ref = ntohs(noh->reference);
Harald Weltebda367c2011-07-28 00:03:49 +02001489 uint8_t info[256];
1490 uint8_t ack = 0xFF;
1491 uint8_t severity = 0xFF;
1492 int str_len;
1493 int len_data;
Dieter Spaar16646022011-07-28 00:01:50 +02001494
Harald Weltec8755af2011-07-28 00:22:17 +02001495 if (bts->nokia.wait_reset) {
Harald Weltebda367c2011-07-28 00:03:49 +02001496 LOGP(DNM, LOGL_INFO,
1497 "Ignore message while waiting for reset\n");
1498 return ret;
1499 }
Dieter Spaar16646022011-07-28 00:01:50 +02001500
Harald Weltebda367c2011-07-28 00:03:49 +02001501 if (oh->length < sizeof(struct abis_om_nokia_hdr)) {
1502 LOGP(DNM, LOGL_ERROR, "Message too short\n");
1503 return -EINVAL;
1504 }
1505
1506 len_data = oh->length - sizeof(struct abis_om_nokia_hdr);
1507 LOGP(DNM, LOGL_INFO, "(0x%02X) %s\n", mt, get_msg_type_name_string(mt));
1508#if 0 /* debugging */
1509 dump_elements(noh->data, len_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001510#endif
Dieter Spaar16646022011-07-28 00:01:50 +02001511
Harald Weltebda367c2011-07-28 00:03:49 +02001512 switch (mt) {
1513 case NOKIA_MSG_OMU_STARTED:
Harald Welte9d2f3772011-07-28 00:19:06 +02001514 if (find_element(noh->data, len_data,
1515 NOKIA_EI_BTS_TYPE, &bts->nokia.bts_type,
1516 sizeof(uint8_t)) == sizeof(uint8_t))
1517 LOGP(DNM, LOGL_INFO, "BTS type = %d (%s)\n",
1518 bts->nokia.bts_type,
1519 get_bts_type_string(bts->nokia.bts_type));
Harald Weltebda367c2011-07-28 00:03:49 +02001520 else
1521 LOGP(DNM, LOGL_ERROR, "BTS type not found\n");
1522 /* send START_DOWNLOAD_REQ */
1523 abis_nm_download_req(bts, ref);
1524 break;
1525 case NOKIA_MSG_MF_REQ:
1526 break;
1527 case NOKIA_MSG_CONF_REQ:
1528 /* send ACK */
1529 abis_nm_ack(bts, ref);
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001530 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001531 /* send CONF_DATA */
Harald Welte9d2f3772011-07-28 00:19:06 +02001532 abis_nm_send_config(bts, bts->nokia.bts_type);
1533 bts->nokia.configured = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001534 break;
1535 case NOKIA_MSG_ACK:
1536 if (find_element
1537 (noh->data, len_data, NOKIA_EI_ACK, &ack,
1538 sizeof(uint8_t)) == sizeof(uint8_t)) {
1539 LOGP(DNM, LOGL_INFO, "ACK = %d\n", ack);
1540 if (ack != 1) {
1541 LOGP(DNM, LOGL_ERROR, "No ACK received (%d)\n",
1542 ack);
1543 /* TODO: properly handle failures (NACK) */
1544 }
1545 } else
1546 LOGP(DNM, LOGL_ERROR, "ACK not found\n");
Dieter Spaar16646022011-07-28 00:01:50 +02001547
Harald Weltebda367c2011-07-28 00:03:49 +02001548 /* TODO: the assumption for the following is that no NACK was received */
1549
1550 /* ACK for reset message ? */
Sylvain Munautc9519462011-10-17 14:04:55 +02001551 if (!bts->nokia.did_reset) {
1552 bts->nokia.did_reset = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001553
1554 /*
1555 TODO: For the InSite processing the received data is
1556 blocked in the driver during reset.
1557 Otherwise the LAPD module might assert because the InSite
1558 sends garbage on the E1 line during reset.
1559 This is done by looking at "wait_reset" in the driver
1560 (function handle_ts1_read()) and ignoring the received data.
1561 It seems to be necessary for the MetroSite too.
1562 */
Harald Weltec8755af2011-07-28 00:22:17 +02001563 bts->nokia.wait_reset = 1;
Harald Weltebda367c2011-07-28 00:03:49 +02001564
Harald Weltec8755af2011-07-28 00:22:17 +02001565 bts->nokia.reset_timer.cb = &reset_timer_cb;
1566 bts->nokia.reset_timer.data = bts;
1567 osmo_timer_schedule(&bts->nokia.reset_timer, RESET_INTERVAL);
Harald Weltebda367c2011-07-28 00:03:49 +02001568
1569 struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
1570 struct e1inp_line *line;
1571 /* OML link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001572 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001573 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001574 LOGP(DLINP, LOGL_ERROR,
Harald Weltebda367c2011-07-28 00:03:49 +02001575 "BTS %u OML link referring to "
1576 "non-existing E1 line %u\n", bts->nr,
1577 e1_link->e1_nr);
1578 return -ENOMEM;
1579 }
1580
1581 start_sabm_in_line(line, 0, -1); /* stop all first */
1582 }
1583
1584 /* ACK for CONF DATA message ? */
Harald Welte9d2f3772011-07-28 00:19:06 +02001585 if (bts->nokia.configured != 0) {
Harald Weltebda367c2011-07-28 00:03:49 +02001586 /* start TRX (RSL link) */
1587
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001588 struct gsm_e1_subslot *e1_link =
1589 &sign_link->trx->rsl_e1_link;
Harald Weltebda367c2011-07-28 00:03:49 +02001590 struct e1inp_line *line;
1591
Harald Welte9d2f3772011-07-28 00:19:06 +02001592 bts->nokia.configured = 0;
Harald Weltebda367c2011-07-28 00:03:49 +02001593
1594 /* RSL Link */
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001595 line = e1inp_line_find(e1_link->e1_nr);
Harald Weltebda367c2011-07-28 00:03:49 +02001596 if (!line) {
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001597 LOGP(DLINP, LOGL_ERROR,
Harald Weltebda367c2011-07-28 00:03:49 +02001598 "TRX (%u/%u) RSL link referring "
1599 "to non-existing E1 line %u\n",
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001600 sign_link->trx->bts->nr, sign_link->trx->nr,
Harald Weltebda367c2011-07-28 00:03:49 +02001601 e1_link->e1_nr);
1602 return -ENOMEM;
1603 }
1604 /* start TRX */
1605 start_sabm_in_line(line, 1, SAPI_RSL); /* start only RSL */
1606 }
1607 break;
1608 case NOKIA_MSG_STATE_CHANGED:
1609 /* send ACK */
1610 abis_nm_ack(bts, ref);
1611 break;
1612 case NOKIA_MSG_CONF_COMPLETE:
1613 /* send ACK */
1614 abis_nm_ack(bts, ref);
1615 break;
1616 case NOKIA_MSG_BLOCK_CTRL_REQ: /* seems to be send when something goes wrong !? */
1617 /* send ACK (do we have to send an ACK ?) */
1618 abis_nm_ack(bts, ref);
1619 break;
1620 case NOKIA_MSG_ALARM:
1621 find_element(noh->data, len_data, NOKIA_EI_SEVERITY, &severity,
1622 sizeof(severity));
1623 /* TODO: there might be alarms with both elements set */
1624 str_len =
1625 find_element(noh->data, len_data, NOKIA_EI_ADD_INFO, info,
1626 sizeof(info));
1627 if (str_len > 0) {
1628 info[str_len] = 0;
1629 LOGP(DNM, LOGL_INFO, "ALARM Severity %s (%d) : %s\n",
1630 get_severity_string(severity), severity, info);
1631 } else { /* nothing found, try details */
1632 str_len =
1633 find_element(noh->data, len_data,
1634 NOKIA_EI_ALARM_DETAIL, info,
1635 sizeof(info));
1636 if (str_len > 0) {
1637 uint16_t code;
1638 info[str_len] = 0;
1639 code = (info[0] << 8) + info[1];
1640 LOGP(DNM, LOGL_INFO,
1641 "ALARM Severity %s (%d), code 0x%X : %s\n",
1642 get_severity_string(severity), severity,
1643 code, info + 2);
1644 }
1645 }
1646 /* send ACK */
1647 abis_nm_ack(bts, ref);
1648 break;
1649 }
1650
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001651 nokia_abis_nm_queue_send_next(bts);
Harald Weltebda367c2011-07-28 00:03:49 +02001652
1653 return ret;
Dieter Spaar16646022011-07-28 00:01:50 +02001654}
1655
1656/* TODO: put in a separate file ? */
1657
1658int abis_nokia_rcvmsg(struct msgb *msg)
1659{
Harald Weltebda367c2011-07-28 00:03:49 +02001660 struct abis_om_hdr *oh = msgb_l2(msg);
1661 int rc = 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001662
Harald Weltebda367c2011-07-28 00:03:49 +02001663 /* Various consistency checks */
1664 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
1665 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
1666 oh->placement);
1667 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1668 return -EINVAL;
1669 }
1670 if (oh->sequence != 0) {
1671 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
1672 oh->sequence);
1673 return -EINVAL;
1674 }
1675 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Dieter Spaar16646022011-07-28 00:01:50 +02001676
Harald Weltebda367c2011-07-28 00:03:49 +02001677 switch (oh->mdisc) {
1678 case ABIS_OM_MDISC_FOM:
1679 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_FOM\n");
1680 rc = abis_nm_rcvmsg_fom(msg);
1681 break;
1682 case ABIS_OM_MDISC_MANUF:
1683 LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_MANUF\n");
1684 break;
1685 case ABIS_OM_MDISC_MMI:
1686 case ABIS_OM_MDISC_TRAU:
1687 LOGP(DNM, LOGL_ERROR,
1688 "unimplemented ABIS OML message discriminator 0x%x\n",
1689 oh->mdisc);
1690 break;
1691 default:
1692 LOGP(DNM, LOGL_ERROR,
1693 "unknown ABIS OML message discriminator 0x%x\n",
1694 oh->mdisc);
1695 return -EINVAL;
1696 }
Dieter Spaar16646022011-07-28 00:01:50 +02001697
Harald Weltebda367c2011-07-28 00:03:49 +02001698 msgb_free(msg);
1699 return rc;
Dieter Spaar16646022011-07-28 00:01:50 +02001700}
1701
1702static int bts_model_nokia_site_start(struct gsm_network *net);
1703
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001704static void bts_model_nokia_site_e1line_bind_ops(struct e1inp_line *line)
1705{
1706 e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
1707}
1708
Dieter Spaar16646022011-07-28 00:01:50 +02001709static struct gsm_bts_model model_nokia_site = {
Harald Weltebda367c2011-07-28 00:03:49 +02001710 .type = GSM_BTS_TYPE_NOKIA_SITE,
1711 .name = "nokia_site",
1712 .start = bts_model_nokia_site_start,
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001713 .oml_rcvmsg = &abis_nokia_rcvmsg,
1714 .e1line_bind_ops = &bts_model_nokia_site_e1line_bind_ops,
Dieter Spaar16646022011-07-28 00:01:50 +02001715};
1716
1717static struct gsm_network *my_net;
1718
1719static int bts_model_nokia_site_start(struct gsm_network *net)
1720{
Harald Weltebda367c2011-07-28 00:03:49 +02001721 model_nokia_site.features.data = &model_nokia_site._features_data[0];
1722 model_nokia_site.features.data_len =
1723 sizeof(model_nokia_site._features_data);
Dieter Spaar16646022011-07-28 00:01:50 +02001724
Harald Weltebda367c2011-07-28 00:03:49 +02001725 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HOPPING);
1726 gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HSCSD);
Dieter Spaar16646022011-07-28 00:01:50 +02001727
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +02001728 osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
1729 osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL);
Harald Weltebda367c2011-07-28 00:03:49 +02001730 osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
Dieter Spaar16646022011-07-28 00:01:50 +02001731
Harald Weltebda367c2011-07-28 00:03:49 +02001732 my_net = net;
1733
1734 return 0;
Dieter Spaar16646022011-07-28 00:01:50 +02001735}
1736
1737int bts_model_nokia_site_init(void)
1738{
Harald Weltebda367c2011-07-28 00:03:49 +02001739 return gsm_bts_model_register(&model_nokia_site);
Dieter Spaar16646022011-07-28 00:01:50 +02001740}