blob: b3e12e97ab3c56c54d2391fb0378e8c3b3892594 [file] [log] [blame]
Harald Welte59b04682009-06-10 05:40:52 +08001/* GSM Network Management (OML) messages on the A-bis interface
2 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25#include <errno.h>
26#include <unistd.h>
27#include <stdio.h>
28#include <fcntl.h>
29#include <stdlib.h>
30#include <libgen.h>
31#include <time.h>
32#include <limits.h>
33
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38
39#include <openbsc/gsm_data.h>
40#include <openbsc/debug.h>
41#include <openbsc/msgb.h>
42#include <openbsc/tlv.h>
43#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
Harald Weltea8379772009-06-20 22:36:41 +020046#include <openbsc/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080047
48#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
50
51/* unidirectional messages from BTS to BSC */
52static const enum abis_nm_msgtype reports[] = {
53 NM_MT_SW_ACTIVATED_REP,
54 NM_MT_TEST_REP,
55 NM_MT_STATECHG_EVENT_REP,
56 NM_MT_FAILURE_EVENT_REP,
57};
58
59/* messages without ACK/NACK */
60static const enum abis_nm_msgtype no_ack_nack[] = {
61 NM_MT_MEAS_RES_REQ,
62 NM_MT_STOP_MEAS,
63 NM_MT_START_MEAS,
64};
65
66/* Messages related to software load */
67static const enum abis_nm_msgtype sw_load_msgs[] = {
68 NM_MT_LOAD_INIT_ACK,
69 NM_MT_LOAD_INIT_NACK,
70 NM_MT_LOAD_SEG_ACK,
71 NM_MT_LOAD_ABORT,
72 NM_MT_LOAD_END_ACK,
73 NM_MT_LOAD_END_NACK,
74 //NM_MT_SW_ACT_REQ,
75 NM_MT_ACTIVATE_SW_ACK,
76 NM_MT_ACTIVATE_SW_NACK,
77 NM_MT_SW_ACTIVATED_REP,
78};
79
80static const enum abis_nm_msgtype nacks[] = {
81 NM_MT_LOAD_INIT_NACK,
82 NM_MT_LOAD_END_NACK,
83 NM_MT_SW_ACT_REQ_NACK,
84 NM_MT_ACTIVATE_SW_NACK,
85 NM_MT_ESTABLISH_TEI_NACK,
86 NM_MT_CONN_TERR_SIGN_NACK,
87 NM_MT_DISC_TERR_SIGN_NACK,
88 NM_MT_CONN_TERR_TRAF_NACK,
89 NM_MT_DISC_TERR_TRAF_NACK,
90 NM_MT_CONN_MDROP_LINK_NACK,
91 NM_MT_DISC_MDROP_LINK_NACK,
92 NM_MT_SET_BTS_ATTR_NACK,
93 NM_MT_SET_RADIO_ATTR_NACK,
94 NM_MT_SET_CHAN_ATTR_NACK,
95 NM_MT_PERF_TEST_NACK,
96 NM_MT_SEND_TEST_REP_NACK,
97 NM_MT_STOP_TEST_NACK,
98 NM_MT_STOP_EVENT_REP_NACK,
99 NM_MT_REST_EVENT_REP_NACK,
100 NM_MT_CHG_ADM_STATE_NACK,
101 NM_MT_CHG_ADM_STATE_REQ_NACK,
102 NM_MT_REP_OUTST_ALARMS_NACK,
103 NM_MT_CHANGEOVER_NACK,
104 NM_MT_OPSTART_NACK,
105 NM_MT_REINIT_NACK,
106 NM_MT_SET_SITE_OUT_NACK,
107 NM_MT_CHG_HW_CONF_NACK,
108 NM_MT_GET_ATTR_NACK,
109 NM_MT_SET_ALARM_THRES_NACK,
110 NM_MT_BS11_BEGIN_DB_TX_NACK,
111 NM_MT_BS11_END_DB_TX_NACK,
112 NM_MT_BS11_CREATE_OBJ_NACK,
113 NM_MT_BS11_DELETE_OBJ_NACK,
114};
115
116static const char *nack_names[0xff] = {
117 [NM_MT_LOAD_INIT_NACK] = "SOFTWARE LOAD INIT",
118 [NM_MT_LOAD_END_NACK] = "SOFTWARE LOAD END",
119 [NM_MT_SW_ACT_REQ_NACK] = "SOFTWARE ACTIVATE REQUEST",
120 [NM_MT_ACTIVATE_SW_NACK] = "ACTIVATE SOFTWARE",
121 [NM_MT_ESTABLISH_TEI_NACK] = "ESTABLISH TEI",
122 [NM_MT_CONN_TERR_SIGN_NACK] = "CONNECT TERRESTRIAL SIGNALLING",
123 [NM_MT_DISC_TERR_SIGN_NACK] = "DISCONNECT TERRESTRIAL SIGNALLING",
124 [NM_MT_CONN_TERR_TRAF_NACK] = "CONNECT TERRESTRIAL TRAFFIC",
125 [NM_MT_DISC_TERR_TRAF_NACK] = "DISCONNECT TERRESTRIAL TRAFFIC",
126 [NM_MT_CONN_MDROP_LINK_NACK] = "CONNECT MULTI-DROP LINK",
127 [NM_MT_DISC_MDROP_LINK_NACK] = "DISCONNECT MULTI-DROP LINK",
128 [NM_MT_SET_BTS_ATTR_NACK] = "SET BTS ATTRIBUTE",
129 [NM_MT_SET_RADIO_ATTR_NACK] = "SET RADIO ATTRIBUTE",
130 [NM_MT_SET_CHAN_ATTR_NACK] = "SET CHANNEL ATTRIBUTE",
131 [NM_MT_PERF_TEST_NACK] = "PERFORM TEST",
132 [NM_MT_SEND_TEST_REP_NACK] = "SEND TEST REPORT",
133 [NM_MT_STOP_TEST_NACK] = "STOP TEST",
134 [NM_MT_STOP_EVENT_REP_NACK] = "STOP EVENT REPORT",
135 [NM_MT_REST_EVENT_REP_NACK] = "RESET EVENT REPORT",
136 [NM_MT_CHG_ADM_STATE_NACK] = "CHANGE ADMINISTRATIVE STATE",
137 [NM_MT_CHG_ADM_STATE_REQ_NACK] = "CHANGE ADMINISTRATIVE STATE REQUEST",
138 [NM_MT_REP_OUTST_ALARMS_NACK] = "REPORT OUTSTANDING ALARMS",
139 [NM_MT_CHANGEOVER_NACK] = "CHANGEOVER",
140 [NM_MT_OPSTART_NACK] = "OPSTART",
141 [NM_MT_REINIT_NACK] = "REINIT",
142 [NM_MT_SET_SITE_OUT_NACK] = "SET SITE OUTPUT",
143 [NM_MT_CHG_HW_CONF_NACK] = "CHANGE HARDWARE CONFIGURATION",
144 [NM_MT_GET_ATTR_NACK] = "GET ATTRIBUTE",
145 [NM_MT_SET_ALARM_THRES_NACK] = "SET ALARM THRESHOLD",
146 [NM_MT_BS11_BEGIN_DB_TX_NACK] = "BS11 BEGIN DATABASE TRANSMISSION",
147 [NM_MT_BS11_END_DB_TX_NACK] = "BS11 END DATABASE TRANSMISSION",
148 [NM_MT_BS11_CREATE_OBJ_NACK] = "BS11 CREATE OBJECT",
149 [NM_MT_BS11_DELETE_OBJ_NACK] = "BS11 DELETE OBJECT",
150};
151
152/* Chapter 9.4.36 */
153static const char *nack_cause_names[] = {
154 /* General Nack Causes */
155 [NM_NACK_INCORR_STRUCT] = "Incorrect message structure",
156 [NM_NACK_MSGTYPE_INVAL] = "Invalid message type value",
157 [NM_NACK_OBJCLASS_INVAL] = "Invalid Object class value",
158 [NM_NACK_OBJCLASS_NOTSUPP] = "Object class not supported",
159 [NM_NACK_BTSNR_UNKN] = "BTS no. unknown",
160 [NM_NACK_TRXNR_UNKN] = "Baseband Transceiver no. unknown",
161 [NM_NACK_OBJINST_UNKN] = "Object Instance unknown",
162 [NM_NACK_ATTRID_INVAL] = "Invalid attribute identifier value",
163 [NM_NACK_ATTRID_NOTSUPP] = "Attribute identifier not supported",
164 [NM_NACK_PARAM_RANGE] = "Parameter value outside permitted range",
165 [NM_NACK_ATTRLIST_INCONSISTENT] = "Inconsistency in attribute list",
166 [NM_NACK_SPEC_IMPL_NOTSUPP] = "Specified implementation not supported",
167 [NM_NACK_CANT_PERFORM] = "Message cannot be performed",
168 /* Specific Nack Causes */
169 [NM_NACK_RES_NOTIMPL] = "Resource not implemented",
170 [NM_NACK_RES_NOTAVAIL] = "Resource not available",
171 [NM_NACK_FREQ_NOTAVAIL] = "Frequency not available",
172 [NM_NACK_TEST_NOTSUPP] = "Test not supported",
173 [NM_NACK_CAPACITY_RESTR] = "Capacity restrictions",
174 [NM_NACK_PHYSCFG_NOTPERFORM] = "Physical configuration cannot be performed",
175 [NM_NACK_TEST_NOTINIT] = "Test not initiated",
176 [NM_NACK_PHYSCFG_NOTRESTORE] = "Physical configuration cannot be restored",
177 [NM_NACK_TEST_NOSUCH] = "No such test",
178 [NM_NACK_TEST_NOSTOP] = "Test cannot be stopped",
179 [NM_NACK_MSGINCONSIST_PHYSCFG] = "Message inconsistent with physical configuration",
180 [NM_NACK_FILE_INCOMPLETE] = "Complete file notreceived",
181 [NM_NACK_FILE_NOTAVAIL] = "File not available at destination",
Harald Weltec3217a12009-06-26 13:21:57 +0200182 [NM_NACK_FILE_NOTACTIVATE] = "File cannot be activate",
Harald Welte59b04682009-06-10 05:40:52 +0800183 [NM_NACK_REQ_NOT_GRANT] = "Request not granted",
184 [NM_NACK_WAIT] = "Wait",
185 [NM_NACK_NOTH_REPORT_EXIST] = "Nothing reportable existing",
186 [NM_NACK_MEAS_NOTSUPP] = "Measurement not supported",
187 [NM_NACK_MEAS_NOTSTART] = "Measurement not started",
188};
189
190static char namebuf[255];
191static const char *nack_cause_name(u_int8_t cause)
192{
193 if (cause < ARRAY_SIZE(nack_cause_names) && nack_cause_names[cause])
194 return nack_cause_names[cause];
195
196 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
197 return namebuf;
198}
199
200/* Chapter 9.4.16: Event Type */
201static const char *event_type_names[] = {
202 [NM_EVT_COMM_FAIL] = "communication failure",
203 [NM_EVT_QOS_FAIL] = "quality of service failure",
204 [NM_EVT_PROC_FAIL] = "processing failure",
205 [NM_EVT_EQUIP_FAIL] = "equipment failure",
206 [NM_EVT_ENV_FAIL] = "environment failure",
207};
208
209static const char *event_type_name(u_int8_t cause)
210{
211 if (cause < ARRAY_SIZE(event_type_names) && event_type_names[cause])
212 return event_type_names[cause];
213
214 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
215 return namebuf;
216}
217
218/* Chapter 9.4.63: Perceived Severity */
219static const char *severity_names[] = {
220 [NM_SEVER_CEASED] = "failure ceased",
221 [NM_SEVER_CRITICAL] = "critical failure",
222 [NM_SEVER_MAJOR] = "major failure",
223 [NM_SEVER_MINOR] = "minor failure",
224 [NM_SEVER_WARNING] = "warning level failure",
225 [NM_SEVER_INDETERMINATE] = "indeterminate failure",
226};
227
228static const char *severity_name(u_int8_t cause)
229{
230 if (cause < ARRAY_SIZE(severity_names) && severity_names[cause])
231 return severity_names[cause];
232
233 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
234 return namebuf;
235}
236
237/* Attributes that the BSC can set, not only get, according to Section 9.4 */
238static const enum abis_nm_attr nm_att_settable[] = {
239 NM_ATT_ADD_INFO,
240 NM_ATT_ADD_TEXT,
241 NM_ATT_DEST,
242 NM_ATT_EVENT_TYPE,
243 NM_ATT_FILE_DATA,
244 NM_ATT_GET_ARI,
245 NM_ATT_HW_CONF_CHG,
246 NM_ATT_LIST_REQ_ATTR,
247 NM_ATT_MDROP_LINK,
248 NM_ATT_MDROP_NEXT,
249 NM_ATT_NACK_CAUSES,
250 NM_ATT_OUTST_ALARM,
251 NM_ATT_PHYS_CONF,
252 NM_ATT_PROB_CAUSE,
253 NM_ATT_RAD_SUBC,
254 NM_ATT_SOURCE,
255 NM_ATT_SPEC_PROB,
256 NM_ATT_START_TIME,
257 NM_ATT_TEST_DUR,
258 NM_ATT_TEST_NO,
259 NM_ATT_TEST_REPORT,
260 NM_ATT_WINDOW_SIZE,
261 NM_ATT_SEVERITY,
262 NM_ATT_MEAS_RES,
263 NM_ATT_MEAS_TYPE,
264};
265
266static const struct tlv_definition nm_att_tlvdef = {
267 .def = {
268 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
269 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
270 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
271 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
272 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
273 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
274 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
275 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
276 [NM_ATT_BSIC] = { TLV_TYPE_TV },
277 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
278 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
279 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
280 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
281 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
282 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
283 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
284 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
285 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
286 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
287 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
288 [NM_ATT_HSN] = { TLV_TYPE_TV },
289 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
290 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
291 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
292 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
293 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
294 [NM_ATT_MAIO] = { TLV_TYPE_TV },
295 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
297 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
298 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
299 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
300 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
301 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
302 [NM_ATT_NY1] = { TLV_TYPE_TV },
303 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
304 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
305 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
306 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
307 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
308 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
309 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
310 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
311 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
312 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
313 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
314 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
315 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
316 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
317 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
318 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
319 [NM_ATT_TEI] = { TLV_TYPE_TV },
320 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
321 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
322 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
323 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
324 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
325 [NM_ATT_TSC] = { TLV_TYPE_TV },
326 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
327 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
328 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
329 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
330 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Welte59b04682009-06-10 05:40:52 +0800331 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
332 /* BS11 specifics */
333 [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV },
334 [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV },
335 [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV },
336 [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV },
337 [0xd5] = { TLV_TYPE_TLV },
338 [0xa8] = { TLV_TYPE_TLV },
339 [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV },
340 [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV },
341 [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV },
342 [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV },
343 [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV },
344 [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 },
345 [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV },
346 [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },
347 [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV },
348 [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
349 [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV },
350 [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV },
351 [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV },
352 [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV },
353 [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV },
354 [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV },
355 [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV },
356 /* ip.access specifics */
Harald Welte4206d982009-07-12 09:33:54 +0200357 [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
358 [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
Harald Weltedb1e7442009-08-06 17:57:23 +0200359 [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
360 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, },
361 [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
362 [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
363 [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
364 [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
365 [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
366 [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
367 [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
368 [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
369 [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
Harald Welte4206d982009-07-12 09:33:54 +0200370 [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
Harald Welte90a93cf2009-07-03 12:46:27 +0200371 [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
372 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
Harald Welte4206d982009-07-12 09:33:54 +0200373 [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
Harald Weltedb1e7442009-08-06 17:57:23 +0200374 [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
375 [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
376 [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
377 [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
378 [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
379 [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
380 [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
381 [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
382 [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
383 [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
384 [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
385 [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
386 [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
Harald Welte90a93cf2009-07-03 12:46:27 +0200387 [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
Harald Weltedb1e7442009-08-06 17:57:23 +0200388 [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
389 [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
390 [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
391 [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
392 [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
393 [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
394 [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
395 [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
396 [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
397 [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
398 [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
399 [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
Harald Welte90a93cf2009-07-03 12:46:27 +0200400 //[0x95] = { TLV_TYPE_FIXED, 2 },
Harald Welte59b04682009-06-10 05:40:52 +0800401 [0x85] = { TLV_TYPE_TV },
402
403 },
404};
405
Harald Welte35cd5e92009-08-10 12:21:22 +0200406static const enum abis_nm_chan_comb chcomb4pchan[] = {
407 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
408 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
409 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
410 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
411 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Welte37884ed2009-10-24 10:25:50 +0200412 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
413 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte35cd5e92009-08-10 12:21:22 +0200414 /* FIXME: bounds check */
415};
416
417int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
418{
419 if (pchan < ARRAY_SIZE(chcomb4pchan))
420 return chcomb4pchan[pchan];
421
422 return -EINVAL;
423}
424
Harald Welte59b04682009-06-10 05:40:52 +0800425int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
426{
427 return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
428}
429
430static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
431{
432 int i;
433
434 for (i = 0; i < size; i++) {
435 if (arr[i] == mt)
436 return 1;
437 }
438
439 return 0;
440}
441
442#if 0
443/* is this msgtype the usual ACK/NACK type ? */
444static int is_ack_nack(enum abis_nm_msgtype mt)
445{
446 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
447}
448#endif
449
450/* is this msgtype a report ? */
451static int is_report(enum abis_nm_msgtype mt)
452{
453 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
454}
455
456#define MT_ACK(x) (x+1)
457#define MT_NACK(x) (x+2)
458
459static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
460{
461 oh->mdisc = ABIS_OM_MDISC_FOM;
462 oh->placement = ABIS_OM_PLACEMENT_ONLY;
463 oh->sequence = 0;
464 oh->length = len;
465}
466
467static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
468 u_int8_t msg_type, u_int8_t obj_class,
469 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
470{
471 struct abis_om_fom_hdr *foh =
472 (struct abis_om_fom_hdr *) oh->data;
473
474 fill_om_hdr(oh, len+sizeof(*foh));
475 foh->msg_type = msg_type;
476 foh->obj_class = obj_class;
477 foh->obj_inst.bts_nr = bts_nr;
478 foh->obj_inst.trx_nr = trx_nr;
479 foh->obj_inst.ts_nr = ts_nr;
480}
481
482static struct msgb *nm_msgb_alloc(void)
483{
Harald Welte9cfc9352009-06-26 19:39:35 +0200484 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
485 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800486}
487
488/* Send a OML NM Message from BSC to BTS */
489int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
490{
491 msg->trx = bts->c0;
492
493 return _abis_nm_sendmsg(msg);
494}
495
496static int abis_nm_rcvmsg_sw(struct msgb *mb);
497
498static const char *obj_class_name(u_int8_t oc)
499{
500 switch (oc) {
501 case NM_OC_SITE_MANAGER:
502 return "SITE MANAGER";
503 case NM_OC_BTS:
504 return "BTS";
505 case NM_OC_RADIO_CARRIER:
506 return "RADIO CARRIER";
507 case NM_OC_BASEB_TRANSC:
508 return "BASEBAND TRANSCEIVER";
509 case NM_OC_CHANNEL:
510 return "CHANNEL";
511 case NM_OC_BS11_ADJC:
512 return "ADJC";
513 case NM_OC_BS11_HANDOVER:
514 return "HANDOVER";
515 case NM_OC_BS11_PWR_CTRL:
516 return "POWER CONTROL";
517 case NM_OC_BS11_BTSE:
518 return "BTSE";
519 case NM_OC_BS11_RACK:
520 return "RACK";
521 case NM_OC_BS11_TEST:
522 return "TEST";
523 case NM_OC_BS11_ENVABTSE:
524 return "ENVABTSE";
525 case NM_OC_BS11_BPORT:
526 return "BPORT";
527 case NM_OC_GPRS_NSE:
528 return "GPRS NSE";
529 case NM_OC_GPRS_CELL:
530 return "GPRS CELL";
Harald Welte8f92cce2009-07-12 10:56:06 +0200531 case NM_OC_GPRS_NSVC:
532 return "GPRS NSVC";
Harald Welte59b04682009-06-10 05:40:52 +0800533 case NM_OC_BS11:
534 return "SIEMENSHW";
535 }
536
537 return "UNKNOWN";
538}
539
540const char *nm_opstate_name(u_int8_t os)
541{
542 switch (os) {
Harald Welte2c87ec12009-12-24 10:06:33 +0100543 case NM_OPSTATE_DISABLED:
Harald Welte59b04682009-06-10 05:40:52 +0800544 return "Disabled";
Harald Welte2c87ec12009-12-24 10:06:33 +0100545 case NM_OPSTATE_ENABLED:
Harald Welte59b04682009-06-10 05:40:52 +0800546 return "Enabled";
Harald Welte2c87ec12009-12-24 10:06:33 +0100547 case NM_OPSTATE_NULL:
Harald Welte59b04682009-06-10 05:40:52 +0800548 return "NULL";
549 default:
550 return "RFU";
551 }
552}
553
554/* Chapter 9.4.7 */
555static const char *avail_names[] = {
556 "In test",
557 "Failed",
558 "Power off",
559 "Off line",
560 "<not used>",
561 "Dependency",
562 "Degraded",
563 "Not installed",
564};
565
566const char *nm_avail_name(u_int8_t avail)
567{
568 if (avail == 0xff)
569 return "OK";
570 if (avail >= ARRAY_SIZE(avail_names))
571 return "UNKNOWN";
572 return avail_names[avail];
573}
574
Harald Weltebeeae412009-11-12 14:48:42 +0100575static struct value_string test_names[] = {
576 /* FIXME: standard test names */
577 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
578 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
579 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
580 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
581 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
582 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
583 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
584 { 0, NULL }
585};
586
Harald Welte59b04682009-06-10 05:40:52 +0800587const char *nm_adm_name(u_int8_t adm)
588{
589 switch (adm) {
590 case 1:
591 return "Locked";
592 case 2:
593 return "Unlocked";
594 case 3:
595 return "Shutdown";
596 default:
597 return "<not used>";
598 }
599}
600
Harald Welteb7284a92009-10-20 09:56:18 +0200601static void debugp_foh(struct abis_om_fom_hdr *foh)
602{
603 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
604 obj_class_name(foh->obj_class), foh->obj_class,
605 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
606 foh->obj_inst.ts_nr);
607}
608
Harald Welte59b04682009-06-10 05:40:52 +0800609/* obtain the gsm_nm_state data structure for a given object instance */
610static struct gsm_nm_state *
611objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
612 struct abis_om_obj_inst *obj_inst)
613{
614 struct gsm_bts_trx *trx;
615 struct gsm_nm_state *nm_state = NULL;
616
617 switch (obj_class) {
618 case NM_OC_BTS:
619 nm_state = &bts->nm_state;
620 break;
621 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100622 if (obj_inst->trx_nr >= bts->num_trx) {
623 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800624 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100625 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200626 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800627 nm_state = &trx->nm_state;
628 break;
629 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100630 if (obj_inst->trx_nr >= bts->num_trx) {
631 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800632 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100633 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200634 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800635 nm_state = &trx->bb_transc.nm_state;
636 break;
637 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100638 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100639 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800640 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100641 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200642 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800643 if (obj_inst->ts_nr >= TRX_NR_TS)
644 return NULL;
645 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
646 break;
647 case NM_OC_SITE_MANAGER:
648 nm_state = &bts->site_mgr.nm_state;
649 break;
650 case NM_OC_BS11:
651 switch (obj_inst->bts_nr) {
652 case BS11_OBJ_CCLK:
653 nm_state = &bts->bs11.cclk.nm_state;
654 break;
655 case BS11_OBJ_BBSIG:
656 if (obj_inst->ts_nr > bts->num_trx)
657 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200658 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800659 nm_state = &trx->bs11.bbsig.nm_state;
660 break;
661 case BS11_OBJ_PA:
662 if (obj_inst->ts_nr > bts->num_trx)
663 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200664 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800665 nm_state = &trx->bs11.pa.nm_state;
666 break;
667 default:
668 return NULL;
669 }
670 case NM_OC_BS11_RACK:
671 nm_state = &bts->bs11.rack.nm_state;
672 break;
673 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100674 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte59b04682009-06-10 05:40:52 +0800675 return NULL;
676 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
677 break;
Harald Welte439e1282009-10-24 10:19:14 +0200678 case NM_OC_GPRS_NSE:
679 nm_state = &bts->gprs.nse.nm_state;
680 break;
681 case NM_OC_GPRS_CELL:
682 nm_state = &bts->gprs.cell.nm_state;
683 break;
684 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100685 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200686 return NULL;
687 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
688 break;
Harald Welte59b04682009-06-10 05:40:52 +0800689 }
690 return nm_state;
691}
692
693/* obtain the in-memory data structure of a given object instance */
694static void *
695objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
696 struct abis_om_obj_inst *obj_inst)
697{
698 struct gsm_bts_trx *trx;
699 void *obj = NULL;
700
701 switch (obj_class) {
702 case NM_OC_BTS:
703 obj = bts;
704 break;
705 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100706 if (obj_inst->trx_nr >= bts->num_trx) {
707 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800708 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100709 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200710 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800711 obj = trx;
712 break;
713 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100714 if (obj_inst->trx_nr >= bts->num_trx) {
715 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800716 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100717 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200718 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800719 obj = &trx->bb_transc;
720 break;
721 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100722 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100723 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800724 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100725 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200726 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800727 if (obj_inst->ts_nr >= TRX_NR_TS)
728 return NULL;
729 obj = &trx->ts[obj_inst->ts_nr];
730 break;
731 case NM_OC_SITE_MANAGER:
732 obj = &bts->site_mgr;
733 break;
Harald Welte439e1282009-10-24 10:19:14 +0200734 case NM_OC_GPRS_NSE:
735 obj = &bts->gprs.nse;
736 break;
737 case NM_OC_GPRS_CELL:
738 obj = &bts->gprs.cell;
739 break;
740 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100741 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200742 return NULL;
743 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
744 break;
Harald Welte59b04682009-06-10 05:40:52 +0800745 }
746 return obj;
747}
748
749/* Update the administrative state of a given object in our in-memory data
750 * structures and send an event to the higher layer */
751static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
752 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
753{
754 struct gsm_nm_state *nm_state, new_state;
755 void *obj;
756 int rc;
757
758 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte3d9ecf72009-11-13 12:10:18 +0100759 if (!obj)
760 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800761 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
762 if (!nm_state)
763 return -1;
764
765 new_state = *nm_state;
766 new_state.administrative = adm_state;
767
768 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
769
770 nm_state->administrative = adm_state;
771
772 return rc;
773}
774
775static int abis_nm_rx_statechg_rep(struct msgb *mb)
776{
777 struct abis_om_hdr *oh = msgb_l2(mb);
778 struct abis_om_fom_hdr *foh = msgb_l3(mb);
779 struct gsm_bts *bts = mb->trx->bts;
780 struct tlv_parsed tp;
781 struct gsm_nm_state *nm_state, new_state;
782 int rc;
783
784 DEBUGPC(DNM, "STATE CHG: ");
785
786 memset(&new_state, 0, sizeof(new_state));
787
788 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
789 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100790 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800791 return -EINVAL;
792 }
793
794 new_state = *nm_state;
795
796 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
797 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
798 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
799 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
800 }
801 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
802 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
803 new_state.availability = 0xff;
804 else
805 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
806 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
807 new_state.availability);
808 }
809 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
810 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther460fb3b2009-10-22 15:44:30 +0200811 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800812 }
813 DEBUGPC(DNM, "\n");
814
815 if (memcmp(&new_state, nm_state, sizeof(new_state))) {
816 /* Update the operational state of a given object in our in-memory data
817 * structures and send an event to the higher layer */
818 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
819 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
820 *nm_state = new_state;
821 }
822#if 0
823 if (op_state == 1) {
824 /* try to enable objects that are disabled */
825 abis_nm_opstart(bts, foh->obj_class,
826 foh->obj_inst.bts_nr,
827 foh->obj_inst.trx_nr,
828 foh->obj_inst.ts_nr);
829 }
830#endif
831 return 0;
832}
833
834static int rx_fail_evt_rep(struct msgb *mb)
835{
836 struct abis_om_hdr *oh = msgb_l2(mb);
837 struct abis_om_fom_hdr *foh = msgb_l3(mb);
838 struct tlv_parsed tp;
839
840 DEBUGPC(DNM, "Failure Event Report ");
841
842 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
843
844 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
845 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
846 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
847 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
848
849 DEBUGPC(DNM, "\n");
850
851 return 0;
852}
853
854static int abis_nm_rcvmsg_report(struct msgb *mb)
855{
856 struct abis_om_fom_hdr *foh = msgb_l3(mb);
857 u_int8_t mt = foh->msg_type;
858
Harald Welteb7284a92009-10-20 09:56:18 +0200859 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800860
861 //nmh->cfg->report_cb(mb, foh);
862
863 switch (mt) {
864 case NM_MT_STATECHG_EVENT_REP:
865 return abis_nm_rx_statechg_rep(mb);
866 break;
867 case NM_MT_SW_ACTIVATED_REP:
868 DEBUGPC(DNM, "Software Activated Report\n");
869 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
870 break;
871 case NM_MT_FAILURE_EVENT_REP:
872 rx_fail_evt_rep(mb);
873 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
874 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200875 case NM_MT_TEST_REP:
876 DEBUGPC(DNM, "Test Report\n");
877 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
878 break;
Harald Welte59b04682009-06-10 05:40:52 +0800879 default:
880 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
881 break;
882
883 };
884
885 return 0;
886}
887
888/* Activate the specified software into the BTS */
889static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
Mike Haben322fc582009-10-01 14:56:13 +0200890 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800891{
892 struct abis_om_hdr *oh;
893 struct msgb *msg = nm_msgb_alloc();
894 u_int8_t len = swdesc_len;
895 u_int8_t *trailer;
896
897 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
898 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
899
900 trailer = msgb_put(msg, swdesc_len);
901 memcpy(trailer, sw_desc, swdesc_len);
902
903 return abis_nm_sendmsg(bts, msg);
904}
905
906static int abis_nm_rx_sw_act_req(struct msgb *mb)
907{
908 struct abis_om_hdr *oh = msgb_l2(mb);
909 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200910 struct tlv_parsed tp;
911 const u_int8_t *sw_config;
912 int sw_config_len;
913 int file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800914 int nack = 0;
915 int ret;
916
Harald Welteb7284a92009-10-20 09:56:18 +0200917 debugp_foh(foh);
918
919 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800920
921 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
922 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
923 nack = 1;
924 } else
925 DEBUGPC(DNM, "ACKing and Activating\n");
926
927 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
928 foh->obj_inst.bts_nr,
929 foh->obj_inst.trx_nr,
930 foh->obj_inst.ts_nr, nack,
931 foh->data, oh->length-sizeof(*foh));
932
933 if (nack)
934 return ret;
935
Mike Haben322fc582009-10-01 14:56:13 +0200936 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
937 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
938 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
939 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
940 DEBUGP(DNM, "SW config not found! Can't continue.\n");
941 return -EINVAL;
942 } else {
943 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
944 }
945
946 if (sw_config[0] != NM_ATT_SW_DESCR)
947 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
948 if (sw_config[1] != NM_ATT_FILE_ID)
949 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
950 file_id_len = sw_config[2] * 256 + sw_config[3];
951
952 /* Assumes first SW file in list is the one to be activated */
953 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte59b04682009-06-10 05:40:52 +0800954 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
955 foh->obj_inst.bts_nr,
956 foh->obj_inst.trx_nr,
957 foh->obj_inst.ts_nr,
Mike Haben322fc582009-10-01 14:56:13 +0200958 sw_config + 4,
959 file_id_len);
Harald Welte59b04682009-06-10 05:40:52 +0800960}
961
962/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
963static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
964{
965 struct abis_om_hdr *oh = msgb_l2(mb);
966 struct abis_om_fom_hdr *foh = msgb_l3(mb);
967 struct tlv_parsed tp;
968 u_int8_t adm_state;
969
970 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
971 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
972 return -EINVAL;
973
974 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
975
976 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
977}
978
979static int abis_nm_rx_lmt_event(struct msgb *mb)
980{
981 struct abis_om_hdr *oh = msgb_l2(mb);
982 struct abis_om_fom_hdr *foh = msgb_l3(mb);
983 struct tlv_parsed tp;
984
985 DEBUGP(DNM, "LMT Event ");
986 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
987 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
988 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
989 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
990 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
991 }
992 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
993 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
994 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
995 DEBUGPC(DNM, "Level=%u ", level);
996 }
997 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
998 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
999 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1000 DEBUGPC(DNM, "Username=%s ", name);
1001 }
1002 DEBUGPC(DNM, "\n");
1003 /* FIXME: parse LMT LOGON TIME */
1004 return 0;
1005}
1006
1007/* Receive a OML NM Message from BTS */
1008static int abis_nm_rcvmsg_fom(struct msgb *mb)
1009{
1010 struct abis_om_hdr *oh = msgb_l2(mb);
1011 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1012 u_int8_t mt = foh->msg_type;
1013
1014 /* check for unsolicited message */
1015 if (is_report(mt))
1016 return abis_nm_rcvmsg_report(mb);
1017
1018 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1019 return abis_nm_rcvmsg_sw(mb);
1020
1021 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
1022 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +02001023
Harald Welteb7284a92009-10-20 09:56:18 +02001024 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +02001025
Harald Welte59b04682009-06-10 05:40:52 +08001026 if (nack_names[mt])
Harald Welte935d10b2009-10-08 20:18:59 +02001027 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte59b04682009-06-10 05:40:52 +08001028 /* FIXME: NACK cause */
1029 else
Harald Welte935d10b2009-10-08 20:18:59 +02001030 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte59b04682009-06-10 05:40:52 +08001031
1032 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1033 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1034 DEBUGPC(DNM, "CAUSE=%s\n",
1035 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1036 else
1037 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001038
Harald Welte6a21c732009-11-17 06:09:56 +01001039 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001040 return 0;
Harald Welte59b04682009-06-10 05:40:52 +08001041 }
1042#if 0
1043 /* check if last message is to be acked */
1044 if (is_ack_nack(nmh->last_msgtype)) {
1045 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +01001046 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001047 /* we got our ACK, continue sending the next msg */
1048 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1049 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +01001050 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001051 /* FIXME: somehow signal this to the caller */
1052 } else {
1053 /* really strange things happen */
1054 return -EINVAL;
1055 }
1056 }
1057#endif
1058
1059 switch (mt) {
1060 case NM_MT_CHG_ADM_STATE_ACK:
1061 return abis_nm_rx_chg_adm_state_ack(mb);
1062 break;
1063 case NM_MT_SW_ACT_REQ:
1064 return abis_nm_rx_sw_act_req(mb);
1065 break;
1066 case NM_MT_BS11_LMT_SESSION:
1067 return abis_nm_rx_lmt_event(mb);
1068 break;
Harald Welte204317e2009-08-06 17:58:31 +02001069 case NM_MT_CONN_MDROP_LINK_ACK:
1070 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1071 break;
Harald Welte59b04682009-06-10 05:40:52 +08001072 }
1073
1074 return 0;
1075}
1076
1077static int abis_nm_rx_ipacc(struct msgb *mb);
1078
1079static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1080{
1081 int rc;
1082 int bts_type = mb->trx->bts->type;
1083
1084 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001085 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001086 rc = abis_nm_rx_ipacc(mb);
1087 break;
1088 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001089 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1090 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001091 rc = 0;
1092 break;
1093 }
1094
1095 return rc;
1096}
1097
1098/* High-Level API */
1099/* Entry-point where L2 OML from BTS enters the NM code */
1100int abis_nm_rcvmsg(struct msgb *msg)
1101{
1102 struct abis_om_hdr *oh = msgb_l2(msg);
1103 int rc = 0;
1104
1105 /* Various consistency checks */
1106 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001107 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001108 oh->placement);
1109 return -EINVAL;
1110 }
1111 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001112 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001113 oh->sequence);
1114 return -EINVAL;
1115 }
1116#if 0
1117 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1118 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1119 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001120 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001121 oh->length + sizeof(*oh), l2_len);
1122 return -EINVAL;
1123 }
1124 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001125 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte59b04682009-06-10 05:40:52 +08001126#endif
1127 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1128
1129 switch (oh->mdisc) {
1130 case ABIS_OM_MDISC_FOM:
1131 rc = abis_nm_rcvmsg_fom(msg);
1132 break;
1133 case ABIS_OM_MDISC_MANUF:
1134 rc = abis_nm_rcvmsg_manuf(msg);
1135 break;
1136 case ABIS_OM_MDISC_MMI:
1137 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001138 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001139 oh->mdisc);
1140 break;
1141 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001142 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001143 oh->mdisc);
1144 return -EINVAL;
1145 }
1146
1147 msgb_free(msg);
1148 return rc;
1149}
1150
1151#if 0
1152/* initialized all resources */
1153struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1154{
1155 struct abis_nm_h *nmh;
1156
1157 nmh = malloc(sizeof(*nmh));
1158 if (!nmh)
1159 return NULL;
1160
1161 nmh->cfg = cfg;
1162
1163 return nmh;
1164}
1165
1166/* free all resources */
1167void abis_nm_fini(struct abis_nm_h *nmh)
1168{
1169 free(nmh);
1170}
1171#endif
1172
1173/* Here we are trying to define a high-level API that can be used by
1174 * the actual BSC implementation. However, the architecture is currently
1175 * still under design. Ideally the calls to this API would be synchronous,
1176 * while the underlying stack behind the APi runs in a traditional select
1177 * based state machine.
1178 */
1179
1180/* 6.2 Software Load: */
1181enum sw_state {
1182 SW_STATE_NONE,
1183 SW_STATE_WAIT_INITACK,
1184 SW_STATE_WAIT_SEGACK,
1185 SW_STATE_WAIT_ENDACK,
1186 SW_STATE_WAIT_ACTACK,
1187 SW_STATE_ERROR,
1188};
1189
1190struct abis_nm_sw {
1191 struct gsm_bts *bts;
1192 gsm_cbfn *cbfn;
1193 void *cb_data;
1194 int forced;
1195
1196 /* this will become part of the SW LOAD INITIATE */
1197 u_int8_t obj_class;
1198 u_int8_t obj_instance[3];
1199
1200 u_int8_t file_id[255];
1201 u_int8_t file_id_len;
1202
1203 u_int8_t file_version[255];
1204 u_int8_t file_version_len;
1205
1206 u_int8_t window_size;
1207 u_int8_t seg_in_window;
1208
1209 int fd;
1210 FILE *stream;
1211 enum sw_state state;
1212 int last_seg;
1213};
1214
1215static struct abis_nm_sw g_sw;
1216
1217/* 6.2.1 / 8.3.1: Load Data Initiate */
1218static int sw_load_init(struct abis_nm_sw *sw)
1219{
1220 struct abis_om_hdr *oh;
1221 struct msgb *msg = nm_msgb_alloc();
1222 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1223
1224 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1225 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1226 sw->obj_instance[0], sw->obj_instance[1],
1227 sw->obj_instance[2]);
1228
1229 /* FIXME: this is BS11 specific format */
1230 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1231 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1232 sw->file_version);
1233 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1234
1235 return abis_nm_sendmsg(sw->bts, msg);
1236}
1237
1238static int is_last_line(FILE *stream)
1239{
1240 char next_seg_buf[256];
1241 long pos;
1242
1243 /* check if we're sending the last line */
1244 pos = ftell(stream);
1245 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1246 fseek(stream, pos, SEEK_SET);
1247 return 1;
1248 }
1249
1250 fseek(stream, pos, SEEK_SET);
1251 return 0;
1252}
1253
1254/* 6.2.2 / 8.3.2 Load Data Segment */
1255static int sw_load_segment(struct abis_nm_sw *sw)
1256{
1257 struct abis_om_hdr *oh;
1258 struct msgb *msg = nm_msgb_alloc();
1259 char seg_buf[256];
1260 char *line_buf = seg_buf+2;
1261 unsigned char *tlv;
1262 u_int8_t len;
1263
1264 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1265
1266 switch (sw->bts->type) {
1267 case GSM_BTS_TYPE_BS11:
1268 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1269 perror("fgets reading segment");
1270 return -EINVAL;
1271 }
1272 seg_buf[0] = 0x00;
1273
1274 /* check if we're sending the last line */
1275 sw->last_seg = is_last_line(sw->stream);
1276 if (sw->last_seg)
1277 seg_buf[1] = 0;
1278 else
1279 seg_buf[1] = 1 + sw->seg_in_window++;
1280
1281 len = strlen(line_buf) + 2;
1282 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1283 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1284 /* BS11 wants CR + LF in excess of the TLV length !?! */
1285 tlv[1] -= 2;
1286
1287 /* we only now know the exact length for the OM hdr */
1288 len = strlen(line_buf)+2;
1289 break;
1290 default:
1291 /* FIXME: Other BTS types */
1292 return -1;
1293 }
1294
1295 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1296 sw->obj_instance[0], sw->obj_instance[1],
1297 sw->obj_instance[2]);
1298
1299 return abis_nm_sendmsg(sw->bts, msg);
1300}
1301
1302/* 6.2.4 / 8.3.4 Load Data End */
1303static int sw_load_end(struct abis_nm_sw *sw)
1304{
1305 struct abis_om_hdr *oh;
1306 struct msgb *msg = nm_msgb_alloc();
1307 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1308
1309 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1310 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1311 sw->obj_instance[0], sw->obj_instance[1],
1312 sw->obj_instance[2]);
1313
1314 /* FIXME: this is BS11 specific format */
1315 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1316 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1317 sw->file_version);
1318
1319 return abis_nm_sendmsg(sw->bts, msg);
1320}
1321
1322/* Activate the specified software into the BTS */
1323static int sw_activate(struct abis_nm_sw *sw)
1324{
1325 struct abis_om_hdr *oh;
1326 struct msgb *msg = nm_msgb_alloc();
1327 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1328
1329 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1330 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1331 sw->obj_instance[0], sw->obj_instance[1],
1332 sw->obj_instance[2]);
1333
1334 /* FIXME: this is BS11 specific format */
1335 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1336 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1337 sw->file_version);
1338
1339 return abis_nm_sendmsg(sw->bts, msg);
1340}
1341
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001342struct sdp_firmware {
1343 char magic[4];
1344 char more_magic[4];
1345 unsigned int header_length;
1346 unsigned int file_length;
1347} __attribute__ ((packed));
1348
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001349static int parse_sdp_header(struct abis_nm_sw *sw)
1350{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001351 struct sdp_firmware firmware_header;
1352 int rc;
1353 struct stat stat;
1354
1355 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1356 if (rc != sizeof(firmware_header)) {
1357 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1358 return -1;
1359 }
1360
1361 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1362 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1363 return -1;
1364 }
1365
1366 if (firmware_header.more_magic[0] != 0x10 ||
1367 firmware_header.more_magic[1] != 0x02 ||
1368 firmware_header.more_magic[2] != 0x00 ||
1369 firmware_header.more_magic[3] != 0x00) {
1370 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1371 return -1;
1372 }
1373
1374
1375 if (fstat(sw->fd, &stat) == -1) {
1376 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1377 return -1;
1378 }
1379
1380 if (ntohl(firmware_header.file_length) != stat.st_size) {
1381 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1382 return -1;
1383 }
1384
1385 /* go back to the start as we checked the whole filesize.. */
1386 lseek(sw->fd, 0l, SEEK_SET);
1387 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1388 "There might be checksums in the file that are not\n"
1389 "verified and incomplete firmware might be flashed.\n"
1390 "There is absolutely no WARRANTY that flashing will\n"
1391 "work.\n");
1392 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001393}
1394
Harald Welte59b04682009-06-10 05:40:52 +08001395static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1396{
1397 char file_id[12+1];
1398 char file_version[80+1];
1399 int rc;
1400
1401 sw->fd = open(fname, O_RDONLY);
1402 if (sw->fd < 0)
1403 return sw->fd;
1404
1405 switch (sw->bts->type) {
1406 case GSM_BTS_TYPE_BS11:
1407 sw->stream = fdopen(sw->fd, "r");
1408 if (!sw->stream) {
1409 perror("fdopen");
1410 return -1;
1411 }
1412 /* read first line and parse file ID and VERSION */
1413 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
1414 file_id, file_version);
1415 if (rc != 2) {
1416 perror("parsing header line of software file");
1417 return -1;
1418 }
1419 strcpy((char *)sw->file_id, file_id);
1420 sw->file_id_len = strlen(file_id);
1421 strcpy((char *)sw->file_version, file_version);
1422 sw->file_version_len = strlen(file_version);
1423 /* rewind to start of file */
1424 rewind(sw->stream);
1425 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001426 case GSM_BTS_TYPE_NANOBTS:
1427 sw->stream = fdopen(sw->fd, "r");
1428 if (!sw->stream) {
1429 perror("fdopen");
1430 return -1;
1431 }
1432
1433 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001434 rc = parse_sdp_header(sw);
1435 if (rc < 0) {
1436 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1437 return -1;
1438 }
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001439 break;
Harald Welte59b04682009-06-10 05:40:52 +08001440 default:
1441 /* We don't know how to treat them yet */
1442 close(sw->fd);
1443 return -EINVAL;
1444 }
1445
1446 return 0;
1447}
1448
1449static void sw_close_file(struct abis_nm_sw *sw)
1450{
1451 switch (sw->bts->type) {
1452 case GSM_BTS_TYPE_BS11:
1453 fclose(sw->stream);
1454 break;
1455 default:
1456 close(sw->fd);
1457 break;
1458 }
1459}
1460
1461/* Fill the window */
1462static int sw_fill_window(struct abis_nm_sw *sw)
1463{
1464 int rc;
1465
1466 while (sw->seg_in_window < sw->window_size) {
1467 rc = sw_load_segment(sw);
1468 if (rc < 0)
1469 return rc;
1470 if (sw->last_seg)
1471 break;
1472 }
1473 return 0;
1474}
1475
1476/* callback function from abis_nm_rcvmsg() handler */
1477static int abis_nm_rcvmsg_sw(struct msgb *mb)
1478{
1479 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1480 int rc = -1;
1481 struct abis_nm_sw *sw = &g_sw;
1482 enum sw_state old_state = sw->state;
1483
1484 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1485
1486 switch (sw->state) {
1487 case SW_STATE_WAIT_INITACK:
1488 switch (foh->msg_type) {
1489 case NM_MT_LOAD_INIT_ACK:
1490 /* fill window with segments */
1491 if (sw->cbfn)
1492 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1493 NM_MT_LOAD_INIT_ACK, mb,
1494 sw->cb_data, NULL);
1495 rc = sw_fill_window(sw);
1496 sw->state = SW_STATE_WAIT_SEGACK;
1497 break;
1498 case NM_MT_LOAD_INIT_NACK:
1499 if (sw->forced) {
1500 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1501 "Init NACK\n");
1502 if (sw->cbfn)
1503 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1504 NM_MT_LOAD_INIT_ACK, mb,
1505 sw->cb_data, NULL);
1506 rc = sw_fill_window(sw);
1507 sw->state = SW_STATE_WAIT_SEGACK;
1508 } else {
1509 DEBUGP(DNM, "Software Load Init NACK\n");
1510 /* FIXME: cause */
1511 if (sw->cbfn)
1512 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1513 NM_MT_LOAD_INIT_NACK, mb,
1514 sw->cb_data, NULL);
1515 sw->state = SW_STATE_ERROR;
1516 }
1517 break;
1518 }
1519 break;
1520 case SW_STATE_WAIT_SEGACK:
1521 switch (foh->msg_type) {
1522 case NM_MT_LOAD_SEG_ACK:
1523 if (sw->cbfn)
1524 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1525 NM_MT_LOAD_SEG_ACK, mb,
1526 sw->cb_data, NULL);
1527 sw->seg_in_window = 0;
1528 if (!sw->last_seg) {
1529 /* fill window with more segments */
1530 rc = sw_fill_window(sw);
1531 sw->state = SW_STATE_WAIT_SEGACK;
1532 } else {
1533 /* end the transfer */
1534 sw->state = SW_STATE_WAIT_ENDACK;
1535 rc = sw_load_end(sw);
1536 }
1537 break;
1538 }
1539 break;
1540 case SW_STATE_WAIT_ENDACK:
1541 switch (foh->msg_type) {
1542 case NM_MT_LOAD_END_ACK:
1543 sw_close_file(sw);
1544 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1545 sw->bts->nr);
1546 sw->state = SW_STATE_NONE;
1547 if (sw->cbfn)
1548 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1549 NM_MT_LOAD_END_ACK, mb,
1550 sw->cb_data, NULL);
1551 break;
1552 case NM_MT_LOAD_END_NACK:
1553 if (sw->forced) {
1554 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1555 "End NACK\n");
1556 sw->state = SW_STATE_NONE;
1557 if (sw->cbfn)
1558 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1559 NM_MT_LOAD_END_ACK, mb,
1560 sw->cb_data, NULL);
1561 } else {
1562 DEBUGP(DNM, "Software Load End NACK\n");
1563 /* FIXME: cause */
1564 sw->state = SW_STATE_ERROR;
1565 if (sw->cbfn)
1566 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1567 NM_MT_LOAD_END_NACK, mb,
1568 sw->cb_data, NULL);
1569 }
1570 break;
1571 }
1572 case SW_STATE_WAIT_ACTACK:
1573 switch (foh->msg_type) {
1574 case NM_MT_ACTIVATE_SW_ACK:
1575 /* we're done */
1576 DEBUGP(DNM, "Activate Software DONE!\n");
1577 sw->state = SW_STATE_NONE;
1578 rc = 0;
1579 if (sw->cbfn)
1580 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1581 NM_MT_ACTIVATE_SW_ACK, mb,
1582 sw->cb_data, NULL);
1583 break;
1584 case NM_MT_ACTIVATE_SW_NACK:
1585 DEBUGP(DNM, "Activate Software NACK\n");
1586 /* FIXME: cause */
1587 sw->state = SW_STATE_ERROR;
1588 if (sw->cbfn)
1589 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1590 NM_MT_ACTIVATE_SW_NACK, mb,
1591 sw->cb_data, NULL);
1592 break;
1593 }
1594 case SW_STATE_NONE:
1595 switch (foh->msg_type) {
1596 case NM_MT_ACTIVATE_SW_ACK:
1597 rc = 0;
1598 break;
1599 }
1600 break;
1601 case SW_STATE_ERROR:
1602 break;
1603 }
1604
1605 if (rc)
1606 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1607 foh->msg_type, old_state, sw->state);
1608
1609 return rc;
1610}
1611
1612/* Load the specified software into the BTS */
1613int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
1614 u_int8_t win_size, int forced,
1615 gsm_cbfn *cbfn, void *cb_data)
1616{
1617 struct abis_nm_sw *sw = &g_sw;
1618 int rc;
1619
1620 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1621 bts->nr, fname);
1622
1623 if (sw->state != SW_STATE_NONE)
1624 return -EBUSY;
1625
1626 sw->bts = bts;
1627 sw->obj_class = NM_OC_SITE_MANAGER;
1628 sw->obj_instance[0] = 0xff;
1629 sw->obj_instance[1] = 0xff;
1630 sw->obj_instance[2] = 0xff;
1631 sw->window_size = win_size;
1632 sw->state = SW_STATE_WAIT_INITACK;
1633 sw->cbfn = cbfn;
1634 sw->cb_data = cb_data;
1635 sw->forced = forced;
1636
1637 rc = sw_open_file(sw, fname);
1638 if (rc < 0) {
1639 sw->state = SW_STATE_NONE;
1640 return rc;
1641 }
1642
1643 return sw_load_init(sw);
1644}
1645
1646int abis_nm_software_load_status(struct gsm_bts *bts)
1647{
1648 struct abis_nm_sw *sw = &g_sw;
1649 struct stat st;
1650 int rc, percent;
1651
1652 rc = fstat(sw->fd, &st);
1653 if (rc < 0) {
1654 perror("ERROR during stat");
1655 return rc;
1656 }
1657
1658 percent = (ftell(sw->stream) * 100) / st.st_size;
1659 return percent;
1660}
1661
1662/* Activate the specified software into the BTS */
1663int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1664 gsm_cbfn *cbfn, void *cb_data)
1665{
1666 struct abis_nm_sw *sw = &g_sw;
1667 int rc;
1668
1669 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1670 bts->nr, fname);
1671
1672 if (sw->state != SW_STATE_NONE)
1673 return -EBUSY;
1674
1675 sw->bts = bts;
1676 sw->obj_class = NM_OC_SITE_MANAGER;
1677 sw->obj_instance[0] = 0xff;
1678 sw->obj_instance[1] = 0xff;
1679 sw->obj_instance[2] = 0xff;
1680 sw->state = SW_STATE_WAIT_ACTACK;
1681 sw->cbfn = cbfn;
1682 sw->cb_data = cb_data;
1683
1684 /* Open the file in order to fill some sw struct members */
1685 rc = sw_open_file(sw, fname);
1686 if (rc < 0) {
1687 sw->state = SW_STATE_NONE;
1688 return rc;
1689 }
1690 sw_close_file(sw);
1691
1692 return sw_activate(sw);
1693}
1694
1695static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1696 u_int8_t ts_nr, u_int8_t subslot_nr)
1697{
1698 ch->attrib = NM_ATT_ABIS_CHANNEL;
1699 ch->bts_port = bts_port;
1700 ch->timeslot = ts_nr;
1701 ch->subslot = subslot_nr;
1702}
1703
1704int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1705 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1706 u_int8_t tei)
1707{
1708 struct abis_om_hdr *oh;
1709 struct abis_nm_channel *ch;
1710 u_int8_t len = sizeof(*ch) + 2;
1711 struct msgb *msg = nm_msgb_alloc();
1712
1713 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1714 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1715 bts->bts_nr, trx_nr, 0xff);
1716
1717 msgb_tv_put(msg, NM_ATT_TEI, tei);
1718
1719 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1720 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1721
1722 return abis_nm_sendmsg(bts, msg);
1723}
1724
1725/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1726int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1727 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1728{
1729 struct gsm_bts *bts = trx->bts;
1730 struct abis_om_hdr *oh;
1731 struct abis_nm_channel *ch;
1732 struct msgb *msg = nm_msgb_alloc();
1733
1734 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1735 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1736 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1737
1738 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1739 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1740
1741 return abis_nm_sendmsg(bts, msg);
1742}
1743
1744#if 0
1745int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1746 struct abis_nm_abis_channel *chan)
1747{
1748}
1749#endif
1750
1751int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1752 u_int8_t e1_port, u_int8_t e1_timeslot,
1753 u_int8_t e1_subslot)
1754{
1755 struct gsm_bts *bts = ts->trx->bts;
1756 struct abis_om_hdr *oh;
1757 struct abis_nm_channel *ch;
1758 struct msgb *msg = nm_msgb_alloc();
1759
1760 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1761 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1762 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1763
1764 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1765 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1766
1767 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1768 gsm_ts_name(ts),
1769 e1_port, e1_timeslot, e1_subslot);
1770
1771 return abis_nm_sendmsg(bts, msg);
1772}
1773
1774#if 0
1775int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1776 struct abis_nm_abis_channel *chan,
1777 u_int8_t subchan)
1778{
1779}
1780#endif
1781
1782/* Chapter 8.6.1 */
1783int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1784{
1785 struct abis_om_hdr *oh;
1786 struct msgb *msg = nm_msgb_alloc();
1787 u_int8_t *cur;
1788
1789 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1790
1791 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1792 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1793 cur = msgb_put(msg, attr_len);
1794 memcpy(cur, attr, attr_len);
1795
1796 return abis_nm_sendmsg(bts, msg);
1797}
1798
1799/* Chapter 8.6.2 */
1800int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1801{
1802 struct abis_om_hdr *oh;
1803 struct msgb *msg = nm_msgb_alloc();
1804 u_int8_t *cur;
1805
1806 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1807
1808 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1809 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1810 trx->bts->bts_nr, trx->nr, 0xff);
1811 cur = msgb_put(msg, attr_len);
1812 memcpy(cur, attr, attr_len);
1813
1814 return abis_nm_sendmsg(trx->bts, msg);
1815}
1816
Harald Weltef2eb2782009-08-09 21:49:48 +02001817static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1818{
1819 int i;
1820
1821 /* As it turns out, the BS-11 has some very peculiar restrictions
1822 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301823 switch (ts->trx->bts->type) {
1824 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001825 switch (chan_comb) {
1826 case NM_CHANC_TCHHalf:
1827 case NM_CHANC_TCHHalf2:
1828 /* not supported */
1829 return -EINVAL;
1830 case NM_CHANC_SDCCH:
1831 /* only one SDCCH/8 per TRX */
1832 for (i = 0; i < TRX_NR_TS; i++) {
1833 if (i == ts->nr)
1834 continue;
1835 if (ts->trx->ts[i].nm_chan_comb ==
1836 NM_CHANC_SDCCH)
1837 return -EINVAL;
1838 }
1839 /* not allowed for TS0 of BCCH-TRX */
1840 if (ts->trx == ts->trx->bts->c0 &&
1841 ts->nr == 0)
1842 return -EINVAL;
1843 /* not on the same TRX that has a BCCH+SDCCH4
1844 * combination */
1845 if (ts->trx == ts->trx->bts->c0 &&
1846 (ts->trx->ts[0].nm_chan_comb == 5 ||
1847 ts->trx->ts[0].nm_chan_comb == 8))
1848 return -EINVAL;
1849 break;
1850 case NM_CHANC_mainBCCH:
1851 case NM_CHANC_BCCHComb:
1852 /* allowed only for TS0 of C0 */
1853 if (ts->trx != ts->trx->bts->c0 ||
1854 ts->nr != 0)
1855 return -EINVAL;
1856 break;
1857 case NM_CHANC_BCCH:
1858 /* allowed only for TS 2/4/6 of C0 */
1859 if (ts->trx != ts->trx->bts->c0)
1860 return -EINVAL;
1861 if (ts->nr != 2 && ts->nr != 4 &&
1862 ts->nr != 6)
1863 return -EINVAL;
1864 break;
1865 case 8: /* this is not like 08.58, but in fact
1866 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1867 /* FIXME: only one CBCH allowed per cell */
1868 break;
1869 }
Harald Welte76ba8812009-12-02 02:45:23 +05301870 break;
1871 case GSM_BTS_TYPE_NANOBTS:
1872 switch (ts->nr) {
1873 case 0:
1874 if (ts->trx->nr == 0) {
1875 /* only on TRX0 */
1876 switch (chan_comb) {
1877 case NM_CHANC_BCCH:
1878 case NM_CHANC_mainBCCH:
1879 case NM_CHANC_BCCHComb:
1880 return 0;
1881 break;
1882 default:
1883 return -EINVAL;
1884 }
1885 } else {
1886 switch (chan_comb) {
1887 case NM_CHANC_TCHFull:
1888 case NM_CHANC_TCHHalf:
1889 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1890 return 0;
1891 default:
1892 return -EINVAL;
1893 }
1894 }
1895 break;
1896 case 1:
1897 if (ts->trx->nr == 0) {
1898 switch (chan_comb) {
1899 case NM_CHANC_SDCCH_CBCH:
1900 if (ts->trx->ts[0].nm_chan_comb ==
1901 NM_CHANC_mainBCCH)
1902 return 0;
1903 return -EINVAL;
1904 case NM_CHANC_SDCCH:
1905 case NM_CHANC_TCHFull:
1906 case NM_CHANC_TCHHalf:
1907 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1908 case NM_CHANC_IPAC_TCHFull_PDCH:
1909 return 0;
1910 }
1911 } else {
1912 switch (chan_comb) {
1913 case NM_CHANC_SDCCH:
1914 case NM_CHANC_TCHFull:
1915 case NM_CHANC_TCHHalf:
1916 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1917 return 0;
1918 default:
1919 return -EINVAL;
1920 }
1921 }
1922 break;
1923 case 2:
1924 case 3:
1925 case 4:
1926 case 5:
1927 case 6:
1928 case 7:
1929 switch (chan_comb) {
1930 case NM_CHANC_TCHFull:
1931 case NM_CHANC_TCHHalf:
1932 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1933 return 0;
1934 case NM_CHANC_IPAC_PDCH:
1935 case NM_CHANC_IPAC_TCHFull_PDCH:
1936 if (ts->trx->nr == 0)
1937 return 0;
1938 else
1939 return -EINVAL;
1940 }
1941 break;
1942 }
1943 return -EINVAL;
1944 default:
1945 /* unknown BTS type */
1946 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001947 }
1948 return 0;
1949}
1950
Harald Welte59b04682009-06-10 05:40:52 +08001951/* Chapter 8.6.3 */
1952int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1953{
1954 struct gsm_bts *bts = ts->trx->bts;
1955 struct abis_om_hdr *oh;
1956 u_int16_t arfcn = htons(ts->trx->arfcn);
1957 u_int8_t zero = 0x00;
1958 struct msgb *msg = nm_msgb_alloc();
1959 u_int8_t len = 2 + 2;
1960
1961 if (bts->type == GSM_BTS_TYPE_BS11)
1962 len += 4 + 2 + 2 + 3;
1963
1964 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001965 if (verify_chan_comb(ts, chan_comb) < 0) {
1966 msgb_free(msg);
1967 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1968 return -EINVAL;
1969 }
1970 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001971
1972 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1973 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1974 NM_OC_CHANNEL, bts->bts_nr,
1975 ts->trx->nr, ts->nr);
1976 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
1977 if (bts->type == GSM_BTS_TYPE_BS11)
1978 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
1979 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
1980 if (bts->type == GSM_BTS_TYPE_BS11) {
1981 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1982 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1983 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02001984 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001985 if (bts->type == GSM_BTS_TYPE_BS11)
1986 msgb_tlv_put(msg, 0x59, 1, &zero);
1987
1988 return abis_nm_sendmsg(bts, msg);
1989}
1990
1991int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
1992 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
1993{
1994 struct abis_om_hdr *oh;
1995 struct msgb *msg = nm_msgb_alloc();
1996 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1997 u_int8_t len = att_len;
1998
1999 if (nack) {
2000 len += 2;
2001 msgtype = NM_MT_SW_ACT_REQ_NACK;
2002 }
2003
2004 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2005 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2006
2007 if (attr) {
2008 u_int8_t *ptr = msgb_put(msg, att_len);
2009 memcpy(ptr, attr, att_len);
2010 }
2011 if (nack)
2012 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2013
2014 return abis_nm_sendmsg(bts, msg);
2015}
2016
2017int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2018{
2019 struct msgb *msg = nm_msgb_alloc();
2020 struct abis_om_hdr *oh;
2021 u_int8_t *data;
2022
2023 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2024 fill_om_hdr(oh, len);
2025 data = msgb_put(msg, len);
2026 memcpy(data, rawmsg, len);
2027
2028 return abis_nm_sendmsg(bts, msg);
2029}
2030
2031/* Siemens specific commands */
2032static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2033{
2034 struct abis_om_hdr *oh;
2035 struct msgb *msg = nm_msgb_alloc();
2036
2037 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2038 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2039 0xff, 0xff, 0xff);
2040
2041 return abis_nm_sendmsg(bts, msg);
2042}
2043
2044/* Chapter 8.9.2 */
2045int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2046{
2047 struct abis_om_hdr *oh;
2048 struct msgb *msg = nm_msgb_alloc();
2049
Harald Welte59b04682009-06-10 05:40:52 +08002050 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2051 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2052
Harald Welteb7284a92009-10-20 09:56:18 +02002053 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2054 DEBUGPC(DNM, "Sending OPSTART\n");
2055
Harald Welte59b04682009-06-10 05:40:52 +08002056 return abis_nm_sendmsg(bts, msg);
2057}
2058
2059/* Chapter 8.8.5 */
2060int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002061 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002062{
2063 struct abis_om_hdr *oh;
2064 struct msgb *msg = nm_msgb_alloc();
2065
2066 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2067 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2068 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2069
2070 return abis_nm_sendmsg(bts, msg);
2071}
2072
Harald Welte204317e2009-08-06 17:58:31 +02002073int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2074 u_int8_t e1_port1, u_int8_t ts1)
2075{
2076 struct abis_om_hdr *oh;
2077 struct msgb *msg = nm_msgb_alloc();
2078 u_int8_t *attr;
2079
2080 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2081 e1_port0, ts0, e1_port1, ts1);
2082
2083 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2084 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2085 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2086
2087 attr = msgb_put(msg, 3);
2088 attr[0] = NM_ATT_MDROP_LINK;
2089 attr[1] = e1_port0;
2090 attr[2] = ts0;
2091
2092 attr = msgb_put(msg, 3);
2093 attr[0] = NM_ATT_MDROP_NEXT;
2094 attr[1] = e1_port1;
2095 attr[2] = ts1;
2096
2097 return abis_nm_sendmsg(bts, msg);
2098}
Harald Welte59b04682009-06-10 05:40:52 +08002099
Harald Welte0bf8e302009-08-08 00:02:36 +02002100/* Chapter 8.7.1 */
2101int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2102 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2103 u_int8_t test_nr, u_int8_t auton_report,
2104 u_int8_t *phys_config, u_int16_t phys_config_len)
2105{
2106 struct abis_om_hdr *oh;
2107 struct msgb *msg = nm_msgb_alloc();
2108 int len = 4; /* 2 TV attributes */
2109
2110 DEBUGP(DNM, "PEFORM TEST\n");
2111
2112 if (phys_config_len)
2113 len += 3 + phys_config_len;
2114
2115 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2116 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2117 obj_class, bts_nr, trx_nr, ts_nr);
2118 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2119 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2120 if (phys_config_len)
2121 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2122 phys_config);
2123
2124 return abis_nm_sendmsg(bts, msg);
2125}
2126
Harald Welte59b04682009-06-10 05:40:52 +08002127int abis_nm_event_reports(struct gsm_bts *bts, int on)
2128{
2129 if (on == 0)
2130 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2131 else
2132 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2133}
2134
2135/* Siemens (or BS-11) specific commands */
2136
2137int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2138{
2139 if (reconnect == 0)
2140 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2141 else
2142 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2143}
2144
2145int abis_nm_bs11_restart(struct gsm_bts *bts)
2146{
2147 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2148}
2149
2150
2151struct bs11_date_time {
2152 u_int16_t year;
2153 u_int8_t month;
2154 u_int8_t day;
2155 u_int8_t hour;
2156 u_int8_t min;
2157 u_int8_t sec;
2158} __attribute__((packed));
2159
2160
2161void get_bs11_date_time(struct bs11_date_time *aet)
2162{
2163 time_t t;
2164 struct tm *tm;
2165
2166 t = time(NULL);
2167 tm = localtime(&t);
2168 aet->sec = tm->tm_sec;
2169 aet->min = tm->tm_min;
2170 aet->hour = tm->tm_hour;
2171 aet->day = tm->tm_mday;
2172 aet->month = tm->tm_mon;
2173 aet->year = htons(1900 + tm->tm_year);
2174}
2175
2176int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2177{
2178 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2179}
2180
2181int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2182{
2183 if (begin)
2184 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2185 else
2186 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2187}
2188
2189int abis_nm_bs11_create_object(struct gsm_bts *bts,
2190 enum abis_bs11_objtype type, u_int8_t idx,
2191 u_int8_t attr_len, const u_int8_t *attr)
2192{
2193 struct abis_om_hdr *oh;
2194 struct msgb *msg = nm_msgb_alloc();
2195 u_int8_t *cur;
2196
2197 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2198 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2199 NM_OC_BS11, type, 0, idx);
2200 cur = msgb_put(msg, attr_len);
2201 memcpy(cur, attr, attr_len);
2202
2203 return abis_nm_sendmsg(bts, msg);
2204}
2205
2206int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2207 enum abis_bs11_objtype type, u_int8_t idx)
2208{
2209 struct abis_om_hdr *oh;
2210 struct msgb *msg = nm_msgb_alloc();
2211
2212 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2213 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2214 NM_OC_BS11, type, 0, idx);
2215
2216 return abis_nm_sendmsg(bts, msg);
2217}
2218
2219int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2220{
2221 struct abis_om_hdr *oh;
2222 struct msgb *msg = nm_msgb_alloc();
2223 u_int8_t zero = 0x00;
2224
2225 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2226 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2227 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2228 msgb_tlv_put(msg, 0x99, 1, &zero);
2229
2230 return abis_nm_sendmsg(bts, msg);
2231}
2232
2233int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2234{
2235 struct abis_om_hdr *oh;
2236 struct msgb *msg = nm_msgb_alloc();
2237
2238 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2239 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002240 idx, 0xff, 0xff);
2241
2242 return abis_nm_sendmsg(bts, msg);
2243}
2244
2245int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2246{
2247 struct abis_om_hdr *oh;
2248 struct msgb *msg = nm_msgb_alloc();
2249
2250 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2251 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2252 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002253
2254 return abis_nm_sendmsg(bts, msg);
2255}
2256
2257static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2258int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2259{
2260 struct abis_om_hdr *oh;
2261 struct msgb *msg = nm_msgb_alloc();
2262
2263 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2264 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2265 0xff, 0xff, 0xff);
2266 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2267
2268 return abis_nm_sendmsg(bts, msg);
2269}
2270
2271/* like abis_nm_conn_terr_traf + set_tei */
2272int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2273 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2274 u_int8_t tei)
2275{
2276 struct abis_om_hdr *oh;
2277 struct abis_nm_channel *ch;
2278 struct msgb *msg = nm_msgb_alloc();
2279
2280 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2281 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2282 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2283
2284 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2285 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2286 msgb_tv_put(msg, NM_ATT_TEI, tei);
2287
2288 return abis_nm_sendmsg(bts, msg);
2289}
2290
2291int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2292{
2293 struct abis_om_hdr *oh;
2294 struct msgb *msg = nm_msgb_alloc();
2295
2296 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2297 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2298 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2299 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2300
2301 return abis_nm_sendmsg(trx->bts, msg);
2302}
2303
2304int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2305{
2306 struct abis_om_hdr *oh;
2307 struct msgb *msg = nm_msgb_alloc();
2308 u_int8_t attr = NM_ATT_BS11_TXPWR;
2309
2310 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2311 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2312 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2313 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2314
2315 return abis_nm_sendmsg(trx->bts, msg);
2316}
2317
2318int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2319{
2320 struct abis_om_hdr *oh;
2321 struct msgb *msg = nm_msgb_alloc();
2322 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2323
2324 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2325 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2326 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2327 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2328
2329 return abis_nm_sendmsg(bts, msg);
2330}
2331
2332int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2333{
2334 struct abis_om_hdr *oh;
2335 struct msgb *msg = nm_msgb_alloc();
2336 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2337 NM_ATT_BS11_CCLK_TYPE };
2338
2339 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2340 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2341 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2342 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2343
2344 return abis_nm_sendmsg(bts, msg);
2345
2346}
2347
2348//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
2349static const u_int8_t bs11_logon_c8[] = { 0x02 };
2350static const u_int8_t bs11_logon_c9[] = "FACTORY";
2351
2352int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2353{
2354 struct abis_om_hdr *oh;
2355 struct msgb *msg = nm_msgb_alloc();
2356 struct bs11_date_time bdt;
2357
2358 get_bs11_date_time(&bdt);
2359
2360 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2361 if (on) {
2362 u_int8_t len = 3*2 + sizeof(bdt)
2363 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
2364 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2365 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2366 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2367 sizeof(bdt), (u_int8_t *) &bdt);
2368 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2369 sizeof(bs11_logon_c8), bs11_logon_c8);
2370 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2371 sizeof(bs11_logon_c9), bs11_logon_c9);
2372 } else {
2373 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2374 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2375 }
2376
2377 return abis_nm_sendmsg(bts, msg);
2378}
2379
2380int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2381{
2382 struct abis_om_hdr *oh;
2383 struct msgb *msg;
2384
2385 if (strlen(password) != 10)
2386 return -EINVAL;
2387
2388 msg = nm_msgb_alloc();
2389 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2390 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2391 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2392 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2393
2394 return abis_nm_sendmsg(bts, msg);
2395}
2396
2397/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2398int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2399{
2400 struct abis_om_hdr *oh;
2401 struct msgb *msg;
2402 u_int8_t tlv_value;
2403
2404 msg = nm_msgb_alloc();
2405 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2406 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2407 BS11_OBJ_LI, 0x00, 0x00);
2408
2409 if (locked)
2410 tlv_value = BS11_LI_PLL_LOCKED;
2411 else
2412 tlv_value = BS11_LI_PLL_STANDALONE;
2413
2414 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2415
2416 return abis_nm_sendmsg(bts, msg);
2417}
2418
2419int abis_nm_bs11_get_state(struct gsm_bts *bts)
2420{
2421 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2422}
2423
2424/* BS11 SWL */
2425
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002426void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002427
Harald Welte59b04682009-06-10 05:40:52 +08002428struct abis_nm_bs11_sw {
2429 struct gsm_bts *bts;
2430 char swl_fname[PATH_MAX];
2431 u_int8_t win_size;
2432 int forced;
2433 struct llist_head file_list;
2434 gsm_cbfn *user_cb; /* specified by the user */
2435};
2436static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2437
2438struct file_list_entry {
2439 struct llist_head list;
2440 char fname[PATH_MAX];
2441};
2442
2443struct file_list_entry *fl_dequeue(struct llist_head *queue)
2444{
2445 struct llist_head *lh;
2446
2447 if (llist_empty(queue))
2448 return NULL;
2449
2450 lh = queue->next;
2451 llist_del(lh);
2452
2453 return llist_entry(lh, struct file_list_entry, list);
2454}
2455
2456static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2457{
2458 char linebuf[255];
2459 struct llist_head *lh, *lh2;
2460 FILE *swl;
2461 int rc = 0;
2462
2463 swl = fopen(bs11_sw->swl_fname, "r");
2464 if (!swl)
2465 return -ENODEV;
2466
2467 /* zero the stale file list, if any */
2468 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2469 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002470 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002471 }
2472
2473 while (fgets(linebuf, sizeof(linebuf), swl)) {
2474 char file_id[12+1];
2475 char file_version[80+1];
2476 struct file_list_entry *fle;
2477 static char dir[PATH_MAX];
2478
2479 if (strlen(linebuf) < 4)
2480 continue;
2481
2482 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2483 if (rc < 0) {
2484 perror("ERR parsing SWL file");
2485 rc = -EINVAL;
2486 goto out;
2487 }
2488 if (rc < 2)
2489 continue;
2490
Harald Welte857e00d2009-06-26 20:25:23 +02002491 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002492 if (!fle) {
2493 rc = -ENOMEM;
2494 goto out;
2495 }
Harald Welte59b04682009-06-10 05:40:52 +08002496
2497 /* construct new filename */
2498 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2499 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2500 strcat(fle->fname, "/");
2501 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2502
2503 llist_add_tail(&fle->list, &bs11_sw->file_list);
2504 }
2505
2506out:
2507 fclose(swl);
2508 return rc;
2509}
2510
2511/* bs11 swload specific callback, passed to abis_nm core swload */
2512static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2513 struct msgb *msg, void *data, void *param)
2514{
2515 struct abis_nm_bs11_sw *bs11_sw = data;
2516 struct file_list_entry *fle;
2517 int rc = 0;
2518
2519 switch (event) {
2520 case NM_MT_LOAD_END_ACK:
2521 fle = fl_dequeue(&bs11_sw->file_list);
2522 if (fle) {
2523 /* start download the next file of our file list */
2524 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2525 bs11_sw->win_size,
2526 bs11_sw->forced,
2527 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002528 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002529 } else {
2530 /* activate the SWL */
2531 rc = abis_nm_software_activate(bs11_sw->bts,
2532 bs11_sw->swl_fname,
2533 bs11_swload_cbfn,
2534 bs11_sw);
2535 }
2536 break;
2537 case NM_MT_LOAD_SEG_ACK:
2538 case NM_MT_LOAD_END_NACK:
2539 case NM_MT_LOAD_INIT_ACK:
2540 case NM_MT_LOAD_INIT_NACK:
2541 case NM_MT_ACTIVATE_SW_NACK:
2542 case NM_MT_ACTIVATE_SW_ACK:
2543 default:
2544 /* fallthrough to the user callback */
2545 if (bs11_sw->user_cb)
2546 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2547 break;
2548 }
2549
2550 return rc;
2551}
2552
2553/* Siemens provides a SWL file that is a mere listing of all the other
2554 * files that are part of a software release. We need to upload first
2555 * the list file, and then each file that is listed in the list file */
2556int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2557 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2558{
2559 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2560 struct file_list_entry *fle;
2561 int rc = 0;
2562
2563 INIT_LLIST_HEAD(&bs11_sw->file_list);
2564 bs11_sw->bts = bts;
2565 bs11_sw->win_size = win_size;
2566 bs11_sw->user_cb = cbfn;
2567 bs11_sw->forced = forced;
2568
2569 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2570 rc = bs11_read_swl_file(bs11_sw);
2571 if (rc < 0)
2572 return rc;
2573
2574 /* dequeue next item in file list */
2575 fle = fl_dequeue(&bs11_sw->file_list);
2576 if (!fle)
2577 return -EINVAL;
2578
2579 /* start download the next file of our file list */
2580 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
2581 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002582 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002583 return rc;
2584}
2585
2586#if 0
2587static u_int8_t req_attr_btse[] = {
2588 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2589 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2590 NM_ATT_BS11_LMT_USER_NAME,
2591
2592 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2593
2594 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2595
2596 NM_ATT_BS11_SW_LOAD_STORED };
2597
2598static u_int8_t req_attr_btsm[] = {
2599 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2600 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2601 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2602 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2603#endif
2604
2605static u_int8_t req_attr[] = {
2606 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2607 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2608 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2609
2610int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2611{
2612 struct abis_om_hdr *oh;
2613 struct msgb *msg = nm_msgb_alloc();
2614
2615 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2616 /* SiemensHW CCTRL object */
2617 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2618 0x03, 0x00, 0x00);
2619 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2620
2621 return abis_nm_sendmsg(bts, msg);
2622}
2623
2624int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2625{
2626 struct abis_om_hdr *oh;
2627 struct msgb *msg = nm_msgb_alloc();
2628 struct bs11_date_time aet;
2629
2630 get_bs11_date_time(&aet);
2631 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2632 /* SiemensHW CCTRL object */
2633 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2634 0xff, 0xff, 0xff);
2635 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2636
2637 return abis_nm_sendmsg(bts, msg);
2638}
2639
Daniel Willmann5655afe2009-08-10 11:49:36 +02002640int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2641{
2642 struct abis_om_hdr *oh;
2643 struct msgb *msg = nm_msgb_alloc();
2644 struct bs11_date_time aet;
2645
2646 get_bs11_date_time(&aet);
2647 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2648 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2649 bport, 0xff, 0x02);
2650 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2651
2652 return abis_nm_sendmsg(bts, msg);
2653}
2654
Harald Welte59b04682009-06-10 05:40:52 +08002655/* ip.access nanoBTS specific commands */
2656static const char ipaccess_magic[] = "com.ipaccess";
2657
2658
2659static int abis_nm_rx_ipacc(struct msgb *msg)
2660{
2661 struct abis_om_hdr *oh = msgb_l2(msg);
2662 struct abis_om_fom_hdr *foh;
2663 u_int8_t idstrlen = oh->data[0];
2664 struct tlv_parsed tp;
2665
2666 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002667 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002668 return -EINVAL;
2669 }
2670
2671 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
2672 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
2673
Harald Welteb7284a92009-10-20 09:56:18 +02002674 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002675
Harald Welte5aeedd42009-10-19 22:11:11 +02002676 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002677
2678 switch (foh->msg_type) {
2679 case NM_MT_IPACC_RSL_CONNECT_ACK:
2680 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte4206d982009-07-12 09:33:54 +02002681 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte59b04682009-06-10 05:40:52 +08002682 DEBUGPC(DNM, "IP=%s ",
2683 inet_ntoa(*((struct in_addr *)
Harald Welte4206d982009-07-12 09:33:54 +02002684 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2685 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002686 DEBUGPC(DNM, "PORT=%u ",
2687 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002688 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002689 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2690 DEBUGPC(DNM, "STREAM=0x%02x ",
2691 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002692 DEBUGPC(DNM, "\n");
2693 break;
2694 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002695 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002696 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2697 DEBUGPC(DNM, " CAUSE=%s\n",
2698 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2699 else
2700 DEBUGPC(DNM, "\n");
2701 break;
2702 case NM_MT_IPACC_SET_NVATTR_ACK:
2703 DEBUGPC(DNM, "SET NVATTR ACK\n");
2704 /* FIXME: decode and show the actual attributes */
2705 break;
2706 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002707 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002708 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Weltede4477a2009-12-24 12:20:20 +01002709 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002710 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2711 else
Harald Weltede4477a2009-12-24 12:20:20 +01002712 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002713 break;
Harald Welte21460f02009-07-03 11:26:45 +02002714 case NM_MT_IPACC_GET_NVATTR_ACK:
2715 DEBUGPC(DNM, "GET NVATTR ACK\n");
2716 /* FIXME: decode and show the actual attributes */
2717 break;
2718 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002719 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002720 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Weltede4477a2009-12-24 12:20:20 +01002721 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002722 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2723 else
Harald Weltede4477a2009-12-24 12:20:20 +01002724 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002725 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002726 case NM_MT_IPACC_SET_ATTR_ACK:
2727 DEBUGPC(DNM, "SET ATTR ACK\n");
2728 break;
2729 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002730 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002731 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Weltede4477a2009-12-24 12:20:20 +01002732 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002733 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2734 else
Harald Weltede4477a2009-12-24 12:20:20 +01002735 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002736 break;
Harald Welte59b04682009-06-10 05:40:52 +08002737 default:
2738 DEBUGPC(DNM, "unknown\n");
2739 break;
2740 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002741
2742 /* signal handling */
2743 switch (foh->msg_type) {
2744 case NM_MT_IPACC_RSL_CONNECT_NACK:
2745 case NM_MT_IPACC_SET_NVATTR_NACK:
2746 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte6a21c732009-11-17 06:09:56 +01002747 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002748 break;
2749 default:
2750 break;
2751 }
2752
Harald Welte59b04682009-06-10 05:40:52 +08002753 return 0;
2754}
2755
2756/* send an ip-access manufacturer specific message */
2757int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2758 u_int8_t obj_class, u_int8_t bts_nr,
2759 u_int8_t trx_nr, u_int8_t ts_nr,
2760 u_int8_t *attr, int attr_len)
2761{
2762 struct msgb *msg = nm_msgb_alloc();
2763 struct abis_om_hdr *oh;
2764 struct abis_om_fom_hdr *foh;
2765 u_int8_t *data;
2766
2767 /* construct the 12.21 OM header, observe the erroneous length */
2768 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2769 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2770 oh->mdisc = ABIS_OM_MDISC_MANUF;
2771
2772 /* add the ip.access magic */
2773 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2774 *data++ = sizeof(ipaccess_magic);
2775 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2776
2777 /* fill the 12.21 FOM header */
2778 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2779 foh->msg_type = msg_type;
2780 foh->obj_class = obj_class;
2781 foh->obj_inst.bts_nr = bts_nr;
2782 foh->obj_inst.trx_nr = trx_nr;
2783 foh->obj_inst.ts_nr = ts_nr;
2784
2785 if (attr && attr_len) {
2786 data = msgb_put(msg, attr_len);
2787 memcpy(data, attr, attr_len);
2788 }
2789
2790 return abis_nm_sendmsg(bts, msg);
2791}
2792
2793/* set some attributes in NVRAM */
2794int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2795 int attr_len)
2796{
2797 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2798 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2799 attr_len);
2800}
2801
Harald Welte5aeedd42009-10-19 22:11:11 +02002802int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2803 u_int32_t ip, u_int16_t port, u_int8_t stream)
2804{
2805 struct in_addr ia;
2806 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2807 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2808 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2809
2810 int attr_len = sizeof(attr);
2811
2812 ia.s_addr = htonl(ip);
2813 attr[1] = stream;
2814 attr[3] = port >> 8;
2815 attr[4] = port & 0xff;
2816 *(u_int32_t *)(attr+6) = ia.s_addr;
2817
2818 /* if ip == 0, we use the default IP */
2819 if (ip == 0)
2820 attr_len -= 5;
2821
2822 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002823 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002824
2825 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2826 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2827 trx->nr, 0xff, attr, attr_len);
2828}
2829
Harald Welte59b04682009-06-10 05:40:52 +08002830/* restart / reboot an ip.access nanoBTS */
2831int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2832{
2833 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2834}
Harald Welte0dfc6232009-10-24 10:20:41 +02002835
2836int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2837 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2838 u_int8_t *attr, u_int8_t attr_len)
2839{
2840 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2841 obj_class, bts_nr, trx_nr, ts_nr,
2842 attr, attr_len);
2843}
Harald Weltebeeae412009-11-12 14:48:42 +01002844
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002845void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2846{
2847 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2848
2849 trx->rf_locked = locked;
2850 if (!trx->bts || !trx->bts->oml_link)
2851 return;
2852
2853 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2854 trx->bts->bts_nr, trx->nr, 0xff,
2855 new_state);
2856}
2857
Harald Weltebeeae412009-11-12 14:48:42 +01002858static const char *ipacc_testres_names[] = {
2859 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2860 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2861 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2862 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2863 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2864};
2865
2866const char *ipacc_testres_name(u_int8_t res)
2867{
2868 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2869 ipacc_testres_names[res])
2870 return ipacc_testres_names[res];
2871
2872 return "unknown";
2873}
2874
Harald Weltebfc21092009-11-13 11:56:05 +01002875void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2876{
2877 cid->mcc = (buf[0] & 0xf) * 100;
2878 cid->mcc += (buf[0] >> 4) * 10;
2879 cid->mcc += (buf[1] & 0xf) * 1;
2880
2881 if (buf[1] >> 4 == 0xf) {
2882 cid->mnc = (buf[2] & 0xf) * 10;
2883 cid->mnc += (buf[2] >> 4) * 1;
2884 } else {
2885 cid->mnc = (buf[2] & 0xf) * 100;
2886 cid->mnc += (buf[2] >> 4) * 10;
2887 cid->mnc += (buf[1] >> 4) * 1;
2888 }
2889
Harald Welte161b4be2009-11-13 14:41:52 +01002890 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2891 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002892}
2893
Harald Weltebeeae412009-11-12 14:48:42 +01002894/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2895int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2896{
2897 u_int8_t *cur = buf;
2898 u_int16_t len;
2899
2900 memset(binf, 0, sizeof(binf));
2901
2902 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2903 return -EINVAL;
2904 cur++;
2905
2906 len = ntohs(*(u_int16_t *)cur);
2907 cur += 2;
2908
2909 binf->info_type = ntohs(*(u_int16_t *)cur);
2910 cur += 2;
2911
2912 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2913 binf->freq_qual = *cur >> 2;
2914
2915 binf->arfcn = *cur++ & 3 << 8;
2916 binf->arfcn |= *cur++;
2917
2918 if (binf->info_type & IPAC_BINF_RXLEV)
2919 binf->rx_lev = *cur & 0x3f;
2920 cur++;
2921
2922 if (binf->info_type & IPAC_BINF_RXQUAL)
2923 binf->rx_qual = *cur & 0x7;
2924 cur++;
2925
2926 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2927 binf->freq_err = ntohs(*(u_int16_t *)cur);
2928 cur += 2;
2929
2930 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2931 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2932 cur += 2;
2933
2934 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2935 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2936 cur += 4;
2937
2938 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte161b4be2009-11-13 14:41:52 +01002939 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002940 cur++;
2941
Harald Weltebfc21092009-11-13 11:56:05 +01002942 ipac_parse_cgi(&binf->cgi, cur);
2943 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002944
2945 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2946 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2947 cur += sizeof(binf->ba_list_si2);
2948 }
2949
2950 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2951 memcpy(binf->ba_list_si2bis, cur,
2952 sizeof(binf->ba_list_si2bis));
2953 cur += sizeof(binf->ba_list_si2bis);
2954 }
2955
2956 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2957 memcpy(binf->ba_list_si2ter, cur,
2958 sizeof(binf->ba_list_si2ter));
2959 cur += sizeof(binf->ba_list_si2ter);
2960 }
2961
2962 return 0;
2963}
2964
2965