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