blob: 7a67fdf3bb18bf03ae609c1c9227bd56360be905 [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
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100602int nm_is_running(struct gsm_nm_state *s) {
603 return (s->operational == NM_OPSTATE_ENABLED) && (
604 (s->availability == NM_AVSTATE_OK) ||
605 (s->availability == 0xff)
606 );
607}
608
Harald Welteb7284a92009-10-20 09:56:18 +0200609static void debugp_foh(struct abis_om_fom_hdr *foh)
610{
611 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
612 obj_class_name(foh->obj_class), foh->obj_class,
613 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
614 foh->obj_inst.ts_nr);
615}
616
Harald Welte59b04682009-06-10 05:40:52 +0800617/* obtain the gsm_nm_state data structure for a given object instance */
618static struct gsm_nm_state *
619objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
620 struct abis_om_obj_inst *obj_inst)
621{
622 struct gsm_bts_trx *trx;
623 struct gsm_nm_state *nm_state = NULL;
624
625 switch (obj_class) {
626 case NM_OC_BTS:
627 nm_state = &bts->nm_state;
628 break;
629 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100630 if (obj_inst->trx_nr >= bts->num_trx) {
631 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800632 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100633 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200634 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800635 nm_state = &trx->nm_state;
636 break;
637 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100638 if (obj_inst->trx_nr >= bts->num_trx) {
639 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800640 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100641 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200642 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800643 nm_state = &trx->bb_transc.nm_state;
644 break;
645 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100646 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100647 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800648 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100649 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200650 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800651 if (obj_inst->ts_nr >= TRX_NR_TS)
652 return NULL;
653 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
654 break;
655 case NM_OC_SITE_MANAGER:
656 nm_state = &bts->site_mgr.nm_state;
657 break;
658 case NM_OC_BS11:
659 switch (obj_inst->bts_nr) {
660 case BS11_OBJ_CCLK:
661 nm_state = &bts->bs11.cclk.nm_state;
662 break;
663 case BS11_OBJ_BBSIG:
664 if (obj_inst->ts_nr > bts->num_trx)
665 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200666 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800667 nm_state = &trx->bs11.bbsig.nm_state;
668 break;
669 case BS11_OBJ_PA:
670 if (obj_inst->ts_nr > bts->num_trx)
671 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200672 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800673 nm_state = &trx->bs11.pa.nm_state;
674 break;
675 default:
676 return NULL;
677 }
678 case NM_OC_BS11_RACK:
679 nm_state = &bts->bs11.rack.nm_state;
680 break;
681 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100682 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte59b04682009-06-10 05:40:52 +0800683 return NULL;
684 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
685 break;
Harald Welte439e1282009-10-24 10:19:14 +0200686 case NM_OC_GPRS_NSE:
687 nm_state = &bts->gprs.nse.nm_state;
688 break;
689 case NM_OC_GPRS_CELL:
690 nm_state = &bts->gprs.cell.nm_state;
691 break;
692 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100693 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200694 return NULL;
695 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
696 break;
Harald Welte59b04682009-06-10 05:40:52 +0800697 }
698 return nm_state;
699}
700
701/* obtain the in-memory data structure of a given object instance */
702static void *
703objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
704 struct abis_om_obj_inst *obj_inst)
705{
706 struct gsm_bts_trx *trx;
707 void *obj = NULL;
708
709 switch (obj_class) {
710 case NM_OC_BTS:
711 obj = bts;
712 break;
713 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100714 if (obj_inst->trx_nr >= bts->num_trx) {
715 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800716 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100717 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200718 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800719 obj = trx;
720 break;
721 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100722 if (obj_inst->trx_nr >= bts->num_trx) {
723 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800724 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100725 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200726 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800727 obj = &trx->bb_transc;
728 break;
729 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100730 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100731 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800732 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100733 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200734 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800735 if (obj_inst->ts_nr >= TRX_NR_TS)
736 return NULL;
737 obj = &trx->ts[obj_inst->ts_nr];
738 break;
739 case NM_OC_SITE_MANAGER:
740 obj = &bts->site_mgr;
741 break;
Harald Welte439e1282009-10-24 10:19:14 +0200742 case NM_OC_GPRS_NSE:
743 obj = &bts->gprs.nse;
744 break;
745 case NM_OC_GPRS_CELL:
746 obj = &bts->gprs.cell;
747 break;
748 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100749 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200750 return NULL;
751 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
752 break;
Harald Welte59b04682009-06-10 05:40:52 +0800753 }
754 return obj;
755}
756
757/* Update the administrative state of a given object in our in-memory data
758 * structures and send an event to the higher layer */
759static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
760 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
761{
762 struct gsm_nm_state *nm_state, new_state;
763 void *obj;
764 int rc;
765
766 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte3d9ecf72009-11-13 12:10:18 +0100767 if (!obj)
768 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800769 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
770 if (!nm_state)
771 return -1;
772
773 new_state = *nm_state;
774 new_state.administrative = adm_state;
775
776 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
777
778 nm_state->administrative = adm_state;
779
780 return rc;
781}
782
783static int abis_nm_rx_statechg_rep(struct msgb *mb)
784{
785 struct abis_om_hdr *oh = msgb_l2(mb);
786 struct abis_om_fom_hdr *foh = msgb_l3(mb);
787 struct gsm_bts *bts = mb->trx->bts;
788 struct tlv_parsed tp;
789 struct gsm_nm_state *nm_state, new_state;
790 int rc;
791
792 DEBUGPC(DNM, "STATE CHG: ");
793
794 memset(&new_state, 0, sizeof(new_state));
795
796 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
797 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100798 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800799 return -EINVAL;
800 }
801
802 new_state = *nm_state;
803
804 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
805 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
806 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
807 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
808 }
809 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
810 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
811 new_state.availability = 0xff;
812 else
813 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
814 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
815 new_state.availability);
816 }
817 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
818 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther460fb3b2009-10-22 15:44:30 +0200819 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800820 }
821 DEBUGPC(DNM, "\n");
822
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100823 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
824 new_state.operational != nm_state->operational ||
825 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800826 /* Update the operational state of a given object in our in-memory data
827 * structures and send an event to the higher layer */
828 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
829 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100830 nm_state->operational = new_state.operational;
831 nm_state->availability = new_state.availability;
832 if (nm_state->administrative == 0)
833 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800834 }
835#if 0
836 if (op_state == 1) {
837 /* try to enable objects that are disabled */
838 abis_nm_opstart(bts, foh->obj_class,
839 foh->obj_inst.bts_nr,
840 foh->obj_inst.trx_nr,
841 foh->obj_inst.ts_nr);
842 }
843#endif
844 return 0;
845}
846
847static int rx_fail_evt_rep(struct msgb *mb)
848{
849 struct abis_om_hdr *oh = msgb_l2(mb);
850 struct abis_om_fom_hdr *foh = msgb_l3(mb);
851 struct tlv_parsed tp;
852
853 DEBUGPC(DNM, "Failure Event Report ");
854
855 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
856
857 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
858 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
859 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
860 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
861
862 DEBUGPC(DNM, "\n");
863
864 return 0;
865}
866
867static int abis_nm_rcvmsg_report(struct msgb *mb)
868{
869 struct abis_om_fom_hdr *foh = msgb_l3(mb);
870 u_int8_t mt = foh->msg_type;
871
Harald Welteb7284a92009-10-20 09:56:18 +0200872 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800873
874 //nmh->cfg->report_cb(mb, foh);
875
876 switch (mt) {
877 case NM_MT_STATECHG_EVENT_REP:
878 return abis_nm_rx_statechg_rep(mb);
879 break;
880 case NM_MT_SW_ACTIVATED_REP:
881 DEBUGPC(DNM, "Software Activated Report\n");
882 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
883 break;
884 case NM_MT_FAILURE_EVENT_REP:
885 rx_fail_evt_rep(mb);
886 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
887 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200888 case NM_MT_TEST_REP:
889 DEBUGPC(DNM, "Test Report\n");
890 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
891 break;
Harald Welte59b04682009-06-10 05:40:52 +0800892 default:
893 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
894 break;
895
896 };
897
898 return 0;
899}
900
901/* Activate the specified software into the BTS */
902static 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 +0200903 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800904{
905 struct abis_om_hdr *oh;
906 struct msgb *msg = nm_msgb_alloc();
907 u_int8_t len = swdesc_len;
908 u_int8_t *trailer;
909
910 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
911 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
912
913 trailer = msgb_put(msg, swdesc_len);
914 memcpy(trailer, sw_desc, swdesc_len);
915
916 return abis_nm_sendmsg(bts, msg);
917}
918
919static int abis_nm_rx_sw_act_req(struct msgb *mb)
920{
921 struct abis_om_hdr *oh = msgb_l2(mb);
922 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200923 struct tlv_parsed tp;
924 const u_int8_t *sw_config;
925 int sw_config_len;
926 int file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800927 int nack = 0;
928 int ret;
929
Harald Welteb7284a92009-10-20 09:56:18 +0200930 debugp_foh(foh);
931
932 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800933
934 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
935 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
936 nack = 1;
937 } else
938 DEBUGPC(DNM, "ACKing and Activating\n");
939
940 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
941 foh->obj_inst.bts_nr,
942 foh->obj_inst.trx_nr,
943 foh->obj_inst.ts_nr, nack,
944 foh->data, oh->length-sizeof(*foh));
945
946 if (nack)
947 return ret;
948
Mike Haben322fc582009-10-01 14:56:13 +0200949 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
950 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
951 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
952 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
953 DEBUGP(DNM, "SW config not found! Can't continue.\n");
954 return -EINVAL;
955 } else {
956 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
957 }
958
959 if (sw_config[0] != NM_ATT_SW_DESCR)
960 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
961 if (sw_config[1] != NM_ATT_FILE_ID)
962 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
963 file_id_len = sw_config[2] * 256 + sw_config[3];
964
965 /* Assumes first SW file in list is the one to be activated */
966 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte59b04682009-06-10 05:40:52 +0800967 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
968 foh->obj_inst.bts_nr,
969 foh->obj_inst.trx_nr,
970 foh->obj_inst.ts_nr,
Mike Haben322fc582009-10-01 14:56:13 +0200971 sw_config + 4,
972 file_id_len);
Harald Welte59b04682009-06-10 05:40:52 +0800973}
974
975/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
976static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
977{
978 struct abis_om_hdr *oh = msgb_l2(mb);
979 struct abis_om_fom_hdr *foh = msgb_l3(mb);
980 struct tlv_parsed tp;
981 u_int8_t adm_state;
982
983 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
984 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
985 return -EINVAL;
986
987 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
988
989 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
990}
991
992static int abis_nm_rx_lmt_event(struct msgb *mb)
993{
994 struct abis_om_hdr *oh = msgb_l2(mb);
995 struct abis_om_fom_hdr *foh = msgb_l3(mb);
996 struct tlv_parsed tp;
997
998 DEBUGP(DNM, "LMT Event ");
999 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1000 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
1001 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
1002 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
1003 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
1004 }
1005 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
1006 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
1007 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
1008 DEBUGPC(DNM, "Level=%u ", level);
1009 }
1010 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
1011 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
1012 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1013 DEBUGPC(DNM, "Username=%s ", name);
1014 }
1015 DEBUGPC(DNM, "\n");
1016 /* FIXME: parse LMT LOGON TIME */
1017 return 0;
1018}
1019
1020/* Receive a OML NM Message from BTS */
1021static int abis_nm_rcvmsg_fom(struct msgb *mb)
1022{
1023 struct abis_om_hdr *oh = msgb_l2(mb);
1024 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1025 u_int8_t mt = foh->msg_type;
1026
1027 /* check for unsolicited message */
1028 if (is_report(mt))
1029 return abis_nm_rcvmsg_report(mb);
1030
1031 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1032 return abis_nm_rcvmsg_sw(mb);
1033
1034 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
1035 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +02001036
Harald Welteb7284a92009-10-20 09:56:18 +02001037 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +02001038
Harald Welte59b04682009-06-10 05:40:52 +08001039 if (nack_names[mt])
Harald Welte935d10b2009-10-08 20:18:59 +02001040 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte59b04682009-06-10 05:40:52 +08001041 /* FIXME: NACK cause */
1042 else
Harald Welte935d10b2009-10-08 20:18:59 +02001043 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte59b04682009-06-10 05:40:52 +08001044
1045 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1046 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1047 DEBUGPC(DNM, "CAUSE=%s\n",
1048 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1049 else
1050 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001051
Harald Welte6a21c732009-11-17 06:09:56 +01001052 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001053 return 0;
Harald Welte59b04682009-06-10 05:40:52 +08001054 }
1055#if 0
1056 /* check if last message is to be acked */
1057 if (is_ack_nack(nmh->last_msgtype)) {
1058 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +01001059 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001060 /* we got our ACK, continue sending the next msg */
1061 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1062 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +01001063 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001064 /* FIXME: somehow signal this to the caller */
1065 } else {
1066 /* really strange things happen */
1067 return -EINVAL;
1068 }
1069 }
1070#endif
1071
1072 switch (mt) {
1073 case NM_MT_CHG_ADM_STATE_ACK:
1074 return abis_nm_rx_chg_adm_state_ack(mb);
1075 break;
1076 case NM_MT_SW_ACT_REQ:
1077 return abis_nm_rx_sw_act_req(mb);
1078 break;
1079 case NM_MT_BS11_LMT_SESSION:
1080 return abis_nm_rx_lmt_event(mb);
1081 break;
Harald Welte204317e2009-08-06 17:58:31 +02001082 case NM_MT_CONN_MDROP_LINK_ACK:
1083 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1084 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001085 case NM_MT_IPACC_RESTART_ACK:
1086 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1087 break;
1088 case NM_MT_IPACC_RESTART_NACK:
1089 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1090 break;
Harald Welte59b04682009-06-10 05:40:52 +08001091 }
1092
1093 return 0;
1094}
1095
1096static int abis_nm_rx_ipacc(struct msgb *mb);
1097
1098static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1099{
1100 int rc;
1101 int bts_type = mb->trx->bts->type;
1102
1103 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001104 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001105 rc = abis_nm_rx_ipacc(mb);
1106 break;
1107 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001108 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1109 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001110 rc = 0;
1111 break;
1112 }
1113
1114 return rc;
1115}
1116
1117/* High-Level API */
1118/* Entry-point where L2 OML from BTS enters the NM code */
1119int abis_nm_rcvmsg(struct msgb *msg)
1120{
1121 struct abis_om_hdr *oh = msgb_l2(msg);
1122 int rc = 0;
1123
1124 /* Various consistency checks */
1125 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001126 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001127 oh->placement);
1128 return -EINVAL;
1129 }
1130 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001131 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001132 oh->sequence);
1133 return -EINVAL;
1134 }
1135#if 0
1136 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1137 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1138 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001139 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001140 oh->length + sizeof(*oh), l2_len);
1141 return -EINVAL;
1142 }
1143 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001144 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 +08001145#endif
1146 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1147
1148 switch (oh->mdisc) {
1149 case ABIS_OM_MDISC_FOM:
1150 rc = abis_nm_rcvmsg_fom(msg);
1151 break;
1152 case ABIS_OM_MDISC_MANUF:
1153 rc = abis_nm_rcvmsg_manuf(msg);
1154 break;
1155 case ABIS_OM_MDISC_MMI:
1156 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001157 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001158 oh->mdisc);
1159 break;
1160 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001161 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001162 oh->mdisc);
1163 return -EINVAL;
1164 }
1165
1166 msgb_free(msg);
1167 return rc;
1168}
1169
1170#if 0
1171/* initialized all resources */
1172struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1173{
1174 struct abis_nm_h *nmh;
1175
1176 nmh = malloc(sizeof(*nmh));
1177 if (!nmh)
1178 return NULL;
1179
1180 nmh->cfg = cfg;
1181
1182 return nmh;
1183}
1184
1185/* free all resources */
1186void abis_nm_fini(struct abis_nm_h *nmh)
1187{
1188 free(nmh);
1189}
1190#endif
1191
1192/* Here we are trying to define a high-level API that can be used by
1193 * the actual BSC implementation. However, the architecture is currently
1194 * still under design. Ideally the calls to this API would be synchronous,
1195 * while the underlying stack behind the APi runs in a traditional select
1196 * based state machine.
1197 */
1198
1199/* 6.2 Software Load: */
1200enum sw_state {
1201 SW_STATE_NONE,
1202 SW_STATE_WAIT_INITACK,
1203 SW_STATE_WAIT_SEGACK,
1204 SW_STATE_WAIT_ENDACK,
1205 SW_STATE_WAIT_ACTACK,
1206 SW_STATE_ERROR,
1207};
1208
1209struct abis_nm_sw {
1210 struct gsm_bts *bts;
1211 gsm_cbfn *cbfn;
1212 void *cb_data;
1213 int forced;
1214
1215 /* this will become part of the SW LOAD INITIATE */
1216 u_int8_t obj_class;
1217 u_int8_t obj_instance[3];
1218
1219 u_int8_t file_id[255];
1220 u_int8_t file_id_len;
1221
1222 u_int8_t file_version[255];
1223 u_int8_t file_version_len;
1224
1225 u_int8_t window_size;
1226 u_int8_t seg_in_window;
1227
1228 int fd;
1229 FILE *stream;
1230 enum sw_state state;
1231 int last_seg;
1232};
1233
1234static struct abis_nm_sw g_sw;
1235
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001236static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1237{
1238 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1239 msgb_v_put(msg, NM_ATT_SW_DESCR);
1240 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1241 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1242 sw->file_version);
1243 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1244 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1245 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1246 sw->file_version);
1247 } else {
1248 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1249 }
1250}
1251
Harald Welte59b04682009-06-10 05:40:52 +08001252/* 6.2.1 / 8.3.1: Load Data Initiate */
1253static int sw_load_init(struct abis_nm_sw *sw)
1254{
1255 struct abis_om_hdr *oh;
1256 struct msgb *msg = nm_msgb_alloc();
1257 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1258
1259 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1260 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1261 sw->obj_instance[0], sw->obj_instance[1],
1262 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001263
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001264 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001265 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1266
1267 return abis_nm_sendmsg(sw->bts, msg);
1268}
1269
1270static int is_last_line(FILE *stream)
1271{
1272 char next_seg_buf[256];
1273 long pos;
1274
1275 /* check if we're sending the last line */
1276 pos = ftell(stream);
1277 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1278 fseek(stream, pos, SEEK_SET);
1279 return 1;
1280 }
1281
1282 fseek(stream, pos, SEEK_SET);
1283 return 0;
1284}
1285
1286/* 6.2.2 / 8.3.2 Load Data Segment */
1287static int sw_load_segment(struct abis_nm_sw *sw)
1288{
1289 struct abis_om_hdr *oh;
1290 struct msgb *msg = nm_msgb_alloc();
1291 char seg_buf[256];
1292 char *line_buf = seg_buf+2;
1293 unsigned char *tlv;
1294 u_int8_t len;
1295
1296 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1297
1298 switch (sw->bts->type) {
1299 case GSM_BTS_TYPE_BS11:
1300 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1301 perror("fgets reading segment");
1302 return -EINVAL;
1303 }
1304 seg_buf[0] = 0x00;
1305
1306 /* check if we're sending the last line */
1307 sw->last_seg = is_last_line(sw->stream);
1308 if (sw->last_seg)
1309 seg_buf[1] = 0;
1310 else
1311 seg_buf[1] = 1 + sw->seg_in_window++;
1312
1313 len = strlen(line_buf) + 2;
1314 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1315 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1316 /* BS11 wants CR + LF in excess of the TLV length !?! */
1317 tlv[1] -= 2;
1318
1319 /* we only now know the exact length for the OM hdr */
1320 len = strlen(line_buf)+2;
1321 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001322 case GSM_BTS_TYPE_NANOBTS: {
1323 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1324 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1325 if (len < 0) {
1326 perror("read failed");
1327 return -EINVAL;
1328 }
1329
1330 if (len != IPACC_SEGMENT_SIZE)
1331 sw->last_seg = 1;
1332
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001333 ++sw->seg_in_window;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001334 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1335 len += 3;
1336 break;
1337 }
Harald Welte59b04682009-06-10 05:40:52 +08001338 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001339 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001340 /* FIXME: Other BTS types */
1341 return -1;
1342 }
1343
1344 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1345 sw->obj_instance[0], sw->obj_instance[1],
1346 sw->obj_instance[2]);
1347
1348 return abis_nm_sendmsg(sw->bts, msg);
1349}
1350
1351/* 6.2.4 / 8.3.4 Load Data End */
1352static int sw_load_end(struct abis_nm_sw *sw)
1353{
1354 struct abis_om_hdr *oh;
1355 struct msgb *msg = nm_msgb_alloc();
1356 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1357
1358 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1359 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1360 sw->obj_instance[0], sw->obj_instance[1],
1361 sw->obj_instance[2]);
1362
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001363 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001364 return abis_nm_sendmsg(sw->bts, msg);
1365}
1366
1367/* Activate the specified software into the BTS */
1368static int sw_activate(struct abis_nm_sw *sw)
1369{
1370 struct abis_om_hdr *oh;
1371 struct msgb *msg = nm_msgb_alloc();
1372 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1373
1374 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1375 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1376 sw->obj_instance[0], sw->obj_instance[1],
1377 sw->obj_instance[2]);
1378
1379 /* FIXME: this is BS11 specific format */
1380 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1381 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1382 sw->file_version);
1383
1384 return abis_nm_sendmsg(sw->bts, msg);
1385}
1386
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001387struct sdp_firmware {
1388 char magic[4];
1389 char more_magic[4];
1390 unsigned int header_length;
1391 unsigned int file_length;
1392} __attribute__ ((packed));
1393
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001394static int parse_sdp_header(struct abis_nm_sw *sw)
1395{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001396 struct sdp_firmware firmware_header;
1397 int rc;
1398 struct stat stat;
1399
1400 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1401 if (rc != sizeof(firmware_header)) {
1402 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1403 return -1;
1404 }
1405
1406 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1407 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1408 return -1;
1409 }
1410
1411 if (firmware_header.more_magic[0] != 0x10 ||
1412 firmware_header.more_magic[1] != 0x02 ||
1413 firmware_header.more_magic[2] != 0x00 ||
1414 firmware_header.more_magic[3] != 0x00) {
1415 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1416 return -1;
1417 }
1418
1419
1420 if (fstat(sw->fd, &stat) == -1) {
1421 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1422 return -1;
1423 }
1424
1425 if (ntohl(firmware_header.file_length) != stat.st_size) {
1426 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1427 return -1;
1428 }
1429
1430 /* go back to the start as we checked the whole filesize.. */
1431 lseek(sw->fd, 0l, SEEK_SET);
1432 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1433 "There might be checksums in the file that are not\n"
1434 "verified and incomplete firmware might be flashed.\n"
1435 "There is absolutely no WARRANTY that flashing will\n"
1436 "work.\n");
1437 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001438}
1439
Harald Welte59b04682009-06-10 05:40:52 +08001440static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1441{
1442 char file_id[12+1];
1443 char file_version[80+1];
1444 int rc;
1445
1446 sw->fd = open(fname, O_RDONLY);
1447 if (sw->fd < 0)
1448 return sw->fd;
1449
1450 switch (sw->bts->type) {
1451 case GSM_BTS_TYPE_BS11:
1452 sw->stream = fdopen(sw->fd, "r");
1453 if (!sw->stream) {
1454 perror("fdopen");
1455 return -1;
1456 }
1457 /* read first line and parse file ID and VERSION */
1458 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
1459 file_id, file_version);
1460 if (rc != 2) {
1461 perror("parsing header line of software file");
1462 return -1;
1463 }
1464 strcpy((char *)sw->file_id, file_id);
1465 sw->file_id_len = strlen(file_id);
1466 strcpy((char *)sw->file_version, file_version);
1467 sw->file_version_len = strlen(file_version);
1468 /* rewind to start of file */
1469 rewind(sw->stream);
1470 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001471 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001472 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001473 rc = parse_sdp_header(sw);
1474 if (rc < 0) {
1475 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1476 return -1;
1477 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001478
1479 strcpy((char *)sw->file_id, "id");
1480 sw->file_id_len = 3;
1481 strcpy((char *)sw->file_version, "version");
1482 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001483 break;
Harald Welte59b04682009-06-10 05:40:52 +08001484 default:
1485 /* We don't know how to treat them yet */
1486 close(sw->fd);
1487 return -EINVAL;
1488 }
1489
1490 return 0;
1491}
1492
1493static void sw_close_file(struct abis_nm_sw *sw)
1494{
1495 switch (sw->bts->type) {
1496 case GSM_BTS_TYPE_BS11:
1497 fclose(sw->stream);
1498 break;
1499 default:
1500 close(sw->fd);
1501 break;
1502 }
1503}
1504
1505/* Fill the window */
1506static int sw_fill_window(struct abis_nm_sw *sw)
1507{
1508 int rc;
1509
1510 while (sw->seg_in_window < sw->window_size) {
1511 rc = sw_load_segment(sw);
1512 if (rc < 0)
1513 return rc;
1514 if (sw->last_seg)
1515 break;
1516 }
1517 return 0;
1518}
1519
1520/* callback function from abis_nm_rcvmsg() handler */
1521static int abis_nm_rcvmsg_sw(struct msgb *mb)
1522{
1523 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1524 int rc = -1;
1525 struct abis_nm_sw *sw = &g_sw;
1526 enum sw_state old_state = sw->state;
1527
1528 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1529
1530 switch (sw->state) {
1531 case SW_STATE_WAIT_INITACK:
1532 switch (foh->msg_type) {
1533 case NM_MT_LOAD_INIT_ACK:
1534 /* fill window with segments */
1535 if (sw->cbfn)
1536 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1537 NM_MT_LOAD_INIT_ACK, mb,
1538 sw->cb_data, NULL);
1539 rc = sw_fill_window(sw);
1540 sw->state = SW_STATE_WAIT_SEGACK;
1541 break;
1542 case NM_MT_LOAD_INIT_NACK:
1543 if (sw->forced) {
1544 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1545 "Init NACK\n");
1546 if (sw->cbfn)
1547 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1548 NM_MT_LOAD_INIT_ACK, mb,
1549 sw->cb_data, NULL);
1550 rc = sw_fill_window(sw);
1551 sw->state = SW_STATE_WAIT_SEGACK;
1552 } else {
1553 DEBUGP(DNM, "Software Load Init NACK\n");
1554 /* FIXME: cause */
1555 if (sw->cbfn)
1556 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1557 NM_MT_LOAD_INIT_NACK, mb,
1558 sw->cb_data, NULL);
1559 sw->state = SW_STATE_ERROR;
1560 }
1561 break;
1562 }
1563 break;
1564 case SW_STATE_WAIT_SEGACK:
1565 switch (foh->msg_type) {
1566 case NM_MT_LOAD_SEG_ACK:
1567 if (sw->cbfn)
1568 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1569 NM_MT_LOAD_SEG_ACK, mb,
1570 sw->cb_data, NULL);
1571 sw->seg_in_window = 0;
1572 if (!sw->last_seg) {
1573 /* fill window with more segments */
1574 rc = sw_fill_window(sw);
1575 sw->state = SW_STATE_WAIT_SEGACK;
1576 } else {
1577 /* end the transfer */
1578 sw->state = SW_STATE_WAIT_ENDACK;
1579 rc = sw_load_end(sw);
1580 }
1581 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001582 case NM_MT_LOAD_ABORT:
1583 if (sw->cbfn)
1584 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1585 NM_MT_LOAD_ABORT, mb,
1586 sw->cb_data, NULL);
1587 break;
Harald Welte59b04682009-06-10 05:40:52 +08001588 }
1589 break;
1590 case SW_STATE_WAIT_ENDACK:
1591 switch (foh->msg_type) {
1592 case NM_MT_LOAD_END_ACK:
1593 sw_close_file(sw);
1594 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1595 sw->bts->nr);
1596 sw->state = SW_STATE_NONE;
1597 if (sw->cbfn)
1598 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1599 NM_MT_LOAD_END_ACK, mb,
1600 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001601 rc = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001602 break;
1603 case NM_MT_LOAD_END_NACK:
1604 if (sw->forced) {
1605 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1606 "End NACK\n");
1607 sw->state = SW_STATE_NONE;
1608 if (sw->cbfn)
1609 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1610 NM_MT_LOAD_END_ACK, mb,
1611 sw->cb_data, NULL);
1612 } else {
1613 DEBUGP(DNM, "Software Load End NACK\n");
1614 /* FIXME: cause */
1615 sw->state = SW_STATE_ERROR;
1616 if (sw->cbfn)
1617 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1618 NM_MT_LOAD_END_NACK, mb,
1619 sw->cb_data, NULL);
1620 }
1621 break;
1622 }
1623 case SW_STATE_WAIT_ACTACK:
1624 switch (foh->msg_type) {
1625 case NM_MT_ACTIVATE_SW_ACK:
1626 /* we're done */
1627 DEBUGP(DNM, "Activate Software DONE!\n");
1628 sw->state = SW_STATE_NONE;
1629 rc = 0;
1630 if (sw->cbfn)
1631 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1632 NM_MT_ACTIVATE_SW_ACK, mb,
1633 sw->cb_data, NULL);
1634 break;
1635 case NM_MT_ACTIVATE_SW_NACK:
1636 DEBUGP(DNM, "Activate Software NACK\n");
1637 /* FIXME: cause */
1638 sw->state = SW_STATE_ERROR;
1639 if (sw->cbfn)
1640 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1641 NM_MT_ACTIVATE_SW_NACK, mb,
1642 sw->cb_data, NULL);
1643 break;
1644 }
1645 case SW_STATE_NONE:
1646 switch (foh->msg_type) {
1647 case NM_MT_ACTIVATE_SW_ACK:
1648 rc = 0;
1649 break;
1650 }
1651 break;
1652 case SW_STATE_ERROR:
1653 break;
1654 }
1655
1656 if (rc)
1657 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1658 foh->msg_type, old_state, sw->state);
1659
1660 return rc;
1661}
1662
1663/* Load the specified software into the BTS */
1664int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
1665 u_int8_t win_size, int forced,
1666 gsm_cbfn *cbfn, void *cb_data)
1667{
1668 struct abis_nm_sw *sw = &g_sw;
1669 int rc;
1670
1671 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1672 bts->nr, fname);
1673
1674 if (sw->state != SW_STATE_NONE)
1675 return -EBUSY;
1676
1677 sw->bts = bts;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001678
1679 switch (bts->type) {
1680 case GSM_BTS_TYPE_BS11:
1681 sw->obj_class = NM_OC_SITE_MANAGER;
1682 sw->obj_instance[0] = 0xff;
1683 sw->obj_instance[1] = 0xff;
1684 sw->obj_instance[2] = 0xff;
1685 break;
1686 case GSM_BTS_TYPE_NANOBTS:
1687 sw->obj_class = NM_OC_BASEB_TRANSC;
1688 sw->obj_instance[0] = 0x00;
1689 sw->obj_instance[1] = 0x00;
1690 sw->obj_instance[2] = 0xff;
1691 break;
1692 case GSM_BTS_TYPE_UNKNOWN:
1693 default:
1694 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1695 return -1;
1696 break;
1697 }
Harald Welte59b04682009-06-10 05:40:52 +08001698 sw->window_size = win_size;
1699 sw->state = SW_STATE_WAIT_INITACK;
1700 sw->cbfn = cbfn;
1701 sw->cb_data = cb_data;
1702 sw->forced = forced;
1703
1704 rc = sw_open_file(sw, fname);
1705 if (rc < 0) {
1706 sw->state = SW_STATE_NONE;
1707 return rc;
1708 }
1709
1710 return sw_load_init(sw);
1711}
1712
1713int abis_nm_software_load_status(struct gsm_bts *bts)
1714{
1715 struct abis_nm_sw *sw = &g_sw;
1716 struct stat st;
1717 int rc, percent;
1718
1719 rc = fstat(sw->fd, &st);
1720 if (rc < 0) {
1721 perror("ERROR during stat");
1722 return rc;
1723 }
1724
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001725 if (sw->stream)
1726 percent = (ftell(sw->stream) * 100) / st.st_size;
1727 else
1728 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001729 return percent;
1730}
1731
1732/* Activate the specified software into the BTS */
1733int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1734 gsm_cbfn *cbfn, void *cb_data)
1735{
1736 struct abis_nm_sw *sw = &g_sw;
1737 int rc;
1738
1739 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1740 bts->nr, fname);
1741
1742 if (sw->state != SW_STATE_NONE)
1743 return -EBUSY;
1744
1745 sw->bts = bts;
1746 sw->obj_class = NM_OC_SITE_MANAGER;
1747 sw->obj_instance[0] = 0xff;
1748 sw->obj_instance[1] = 0xff;
1749 sw->obj_instance[2] = 0xff;
1750 sw->state = SW_STATE_WAIT_ACTACK;
1751 sw->cbfn = cbfn;
1752 sw->cb_data = cb_data;
1753
1754 /* Open the file in order to fill some sw struct members */
1755 rc = sw_open_file(sw, fname);
1756 if (rc < 0) {
1757 sw->state = SW_STATE_NONE;
1758 return rc;
1759 }
1760 sw_close_file(sw);
1761
1762 return sw_activate(sw);
1763}
1764
1765static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1766 u_int8_t ts_nr, u_int8_t subslot_nr)
1767{
1768 ch->attrib = NM_ATT_ABIS_CHANNEL;
1769 ch->bts_port = bts_port;
1770 ch->timeslot = ts_nr;
1771 ch->subslot = subslot_nr;
1772}
1773
1774int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1775 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1776 u_int8_t tei)
1777{
1778 struct abis_om_hdr *oh;
1779 struct abis_nm_channel *ch;
1780 u_int8_t len = sizeof(*ch) + 2;
1781 struct msgb *msg = nm_msgb_alloc();
1782
1783 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1784 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1785 bts->bts_nr, trx_nr, 0xff);
1786
1787 msgb_tv_put(msg, NM_ATT_TEI, tei);
1788
1789 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1790 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1791
1792 return abis_nm_sendmsg(bts, msg);
1793}
1794
1795/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1796int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1797 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1798{
1799 struct gsm_bts *bts = 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_SIGN,
1806 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
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 return abis_nm_sendmsg(bts, msg);
1812}
1813
1814#if 0
1815int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1816 struct abis_nm_abis_channel *chan)
1817{
1818}
1819#endif
1820
1821int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1822 u_int8_t e1_port, u_int8_t e1_timeslot,
1823 u_int8_t e1_subslot)
1824{
1825 struct gsm_bts *bts = ts->trx->bts;
1826 struct abis_om_hdr *oh;
1827 struct abis_nm_channel *ch;
1828 struct msgb *msg = nm_msgb_alloc();
1829
1830 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1831 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1832 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1833
1834 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1835 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1836
1837 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1838 gsm_ts_name(ts),
1839 e1_port, e1_timeslot, e1_subslot);
1840
1841 return abis_nm_sendmsg(bts, msg);
1842}
1843
1844#if 0
1845int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1846 struct abis_nm_abis_channel *chan,
1847 u_int8_t subchan)
1848{
1849}
1850#endif
1851
1852/* Chapter 8.6.1 */
1853int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1854{
1855 struct abis_om_hdr *oh;
1856 struct msgb *msg = nm_msgb_alloc();
1857 u_int8_t *cur;
1858
1859 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1860
1861 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1862 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1863 cur = msgb_put(msg, attr_len);
1864 memcpy(cur, attr, attr_len);
1865
1866 return abis_nm_sendmsg(bts, msg);
1867}
1868
1869/* Chapter 8.6.2 */
1870int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1871{
1872 struct abis_om_hdr *oh;
1873 struct msgb *msg = nm_msgb_alloc();
1874 u_int8_t *cur;
1875
1876 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1877
1878 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1879 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1880 trx->bts->bts_nr, trx->nr, 0xff);
1881 cur = msgb_put(msg, attr_len);
1882 memcpy(cur, attr, attr_len);
1883
1884 return abis_nm_sendmsg(trx->bts, msg);
1885}
1886
Harald Weltef2eb2782009-08-09 21:49:48 +02001887static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1888{
1889 int i;
1890
1891 /* As it turns out, the BS-11 has some very peculiar restrictions
1892 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301893 switch (ts->trx->bts->type) {
1894 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001895 switch (chan_comb) {
1896 case NM_CHANC_TCHHalf:
1897 case NM_CHANC_TCHHalf2:
1898 /* not supported */
1899 return -EINVAL;
1900 case NM_CHANC_SDCCH:
1901 /* only one SDCCH/8 per TRX */
1902 for (i = 0; i < TRX_NR_TS; i++) {
1903 if (i == ts->nr)
1904 continue;
1905 if (ts->trx->ts[i].nm_chan_comb ==
1906 NM_CHANC_SDCCH)
1907 return -EINVAL;
1908 }
1909 /* not allowed for TS0 of BCCH-TRX */
1910 if (ts->trx == ts->trx->bts->c0 &&
1911 ts->nr == 0)
1912 return -EINVAL;
1913 /* not on the same TRX that has a BCCH+SDCCH4
1914 * combination */
1915 if (ts->trx == ts->trx->bts->c0 &&
1916 (ts->trx->ts[0].nm_chan_comb == 5 ||
1917 ts->trx->ts[0].nm_chan_comb == 8))
1918 return -EINVAL;
1919 break;
1920 case NM_CHANC_mainBCCH:
1921 case NM_CHANC_BCCHComb:
1922 /* allowed only for TS0 of C0 */
1923 if (ts->trx != ts->trx->bts->c0 ||
1924 ts->nr != 0)
1925 return -EINVAL;
1926 break;
1927 case NM_CHANC_BCCH:
1928 /* allowed only for TS 2/4/6 of C0 */
1929 if (ts->trx != ts->trx->bts->c0)
1930 return -EINVAL;
1931 if (ts->nr != 2 && ts->nr != 4 &&
1932 ts->nr != 6)
1933 return -EINVAL;
1934 break;
1935 case 8: /* this is not like 08.58, but in fact
1936 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1937 /* FIXME: only one CBCH allowed per cell */
1938 break;
1939 }
Harald Welte76ba8812009-12-02 02:45:23 +05301940 break;
1941 case GSM_BTS_TYPE_NANOBTS:
1942 switch (ts->nr) {
1943 case 0:
1944 if (ts->trx->nr == 0) {
1945 /* only on TRX0 */
1946 switch (chan_comb) {
1947 case NM_CHANC_BCCH:
1948 case NM_CHANC_mainBCCH:
1949 case NM_CHANC_BCCHComb:
1950 return 0;
1951 break;
1952 default:
1953 return -EINVAL;
1954 }
1955 } else {
1956 switch (chan_comb) {
1957 case NM_CHANC_TCHFull:
1958 case NM_CHANC_TCHHalf:
1959 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1960 return 0;
1961 default:
1962 return -EINVAL;
1963 }
1964 }
1965 break;
1966 case 1:
1967 if (ts->trx->nr == 0) {
1968 switch (chan_comb) {
1969 case NM_CHANC_SDCCH_CBCH:
1970 if (ts->trx->ts[0].nm_chan_comb ==
1971 NM_CHANC_mainBCCH)
1972 return 0;
1973 return -EINVAL;
1974 case NM_CHANC_SDCCH:
1975 case NM_CHANC_TCHFull:
1976 case NM_CHANC_TCHHalf:
1977 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1978 case NM_CHANC_IPAC_TCHFull_PDCH:
1979 return 0;
1980 }
1981 } else {
1982 switch (chan_comb) {
1983 case NM_CHANC_SDCCH:
1984 case NM_CHANC_TCHFull:
1985 case NM_CHANC_TCHHalf:
1986 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1987 return 0;
1988 default:
1989 return -EINVAL;
1990 }
1991 }
1992 break;
1993 case 2:
1994 case 3:
1995 case 4:
1996 case 5:
1997 case 6:
1998 case 7:
1999 switch (chan_comb) {
2000 case NM_CHANC_TCHFull:
2001 case NM_CHANC_TCHHalf:
2002 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2003 return 0;
2004 case NM_CHANC_IPAC_PDCH:
2005 case NM_CHANC_IPAC_TCHFull_PDCH:
2006 if (ts->trx->nr == 0)
2007 return 0;
2008 else
2009 return -EINVAL;
2010 }
2011 break;
2012 }
2013 return -EINVAL;
2014 default:
2015 /* unknown BTS type */
2016 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02002017 }
2018 return 0;
2019}
2020
Harald Welte59b04682009-06-10 05:40:52 +08002021/* Chapter 8.6.3 */
2022int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2023{
2024 struct gsm_bts *bts = ts->trx->bts;
2025 struct abis_om_hdr *oh;
2026 u_int16_t arfcn = htons(ts->trx->arfcn);
2027 u_int8_t zero = 0x00;
2028 struct msgb *msg = nm_msgb_alloc();
2029 u_int8_t len = 2 + 2;
2030
2031 if (bts->type == GSM_BTS_TYPE_BS11)
2032 len += 4 + 2 + 2 + 3;
2033
2034 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02002035 if (verify_chan_comb(ts, chan_comb) < 0) {
2036 msgb_free(msg);
2037 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2038 return -EINVAL;
2039 }
2040 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08002041
2042 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2043 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
2044 NM_OC_CHANNEL, bts->bts_nr,
2045 ts->trx->nr, ts->nr);
2046 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
2047 if (bts->type == GSM_BTS_TYPE_BS11)
2048 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
2049 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
2050 if (bts->type == GSM_BTS_TYPE_BS11) {
2051 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2052 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2053 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02002054 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08002055 if (bts->type == GSM_BTS_TYPE_BS11)
2056 msgb_tlv_put(msg, 0x59, 1, &zero);
2057
2058 return abis_nm_sendmsg(bts, msg);
2059}
2060
2061int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
2062 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
2063{
2064 struct abis_om_hdr *oh;
2065 struct msgb *msg = nm_msgb_alloc();
2066 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2067 u_int8_t len = att_len;
2068
2069 if (nack) {
2070 len += 2;
2071 msgtype = NM_MT_SW_ACT_REQ_NACK;
2072 }
2073
2074 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2075 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2076
2077 if (attr) {
2078 u_int8_t *ptr = msgb_put(msg, att_len);
2079 memcpy(ptr, attr, att_len);
2080 }
2081 if (nack)
2082 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2083
2084 return abis_nm_sendmsg(bts, msg);
2085}
2086
2087int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2088{
2089 struct msgb *msg = nm_msgb_alloc();
2090 struct abis_om_hdr *oh;
2091 u_int8_t *data;
2092
2093 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2094 fill_om_hdr(oh, len);
2095 data = msgb_put(msg, len);
2096 memcpy(data, rawmsg, len);
2097
2098 return abis_nm_sendmsg(bts, msg);
2099}
2100
2101/* Siemens specific commands */
2102static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2103{
2104 struct abis_om_hdr *oh;
2105 struct msgb *msg = nm_msgb_alloc();
2106
2107 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2108 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2109 0xff, 0xff, 0xff);
2110
2111 return abis_nm_sendmsg(bts, msg);
2112}
2113
2114/* Chapter 8.9.2 */
2115int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2116{
2117 struct abis_om_hdr *oh;
2118 struct msgb *msg = nm_msgb_alloc();
2119
Harald Welte59b04682009-06-10 05:40:52 +08002120 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2121 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2122
Harald Welteb7284a92009-10-20 09:56:18 +02002123 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2124 DEBUGPC(DNM, "Sending OPSTART\n");
2125
Harald Welte59b04682009-06-10 05:40:52 +08002126 return abis_nm_sendmsg(bts, msg);
2127}
2128
2129/* Chapter 8.8.5 */
2130int 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 +02002131 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002132{
2133 struct abis_om_hdr *oh;
2134 struct msgb *msg = nm_msgb_alloc();
2135
2136 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2137 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2138 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2139
2140 return abis_nm_sendmsg(bts, msg);
2141}
2142
Harald Welte204317e2009-08-06 17:58:31 +02002143int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2144 u_int8_t e1_port1, u_int8_t ts1)
2145{
2146 struct abis_om_hdr *oh;
2147 struct msgb *msg = nm_msgb_alloc();
2148 u_int8_t *attr;
2149
2150 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2151 e1_port0, ts0, e1_port1, ts1);
2152
2153 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2154 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2155 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2156
2157 attr = msgb_put(msg, 3);
2158 attr[0] = NM_ATT_MDROP_LINK;
2159 attr[1] = e1_port0;
2160 attr[2] = ts0;
2161
2162 attr = msgb_put(msg, 3);
2163 attr[0] = NM_ATT_MDROP_NEXT;
2164 attr[1] = e1_port1;
2165 attr[2] = ts1;
2166
2167 return abis_nm_sendmsg(bts, msg);
2168}
Harald Welte59b04682009-06-10 05:40:52 +08002169
Harald Welte0bf8e302009-08-08 00:02:36 +02002170/* Chapter 8.7.1 */
2171int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2172 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2173 u_int8_t test_nr, u_int8_t auton_report,
2174 u_int8_t *phys_config, u_int16_t phys_config_len)
2175{
2176 struct abis_om_hdr *oh;
2177 struct msgb *msg = nm_msgb_alloc();
2178 int len = 4; /* 2 TV attributes */
2179
2180 DEBUGP(DNM, "PEFORM TEST\n");
2181
2182 if (phys_config_len)
2183 len += 3 + phys_config_len;
2184
2185 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2186 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2187 obj_class, bts_nr, trx_nr, ts_nr);
2188 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2189 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2190 if (phys_config_len)
2191 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2192 phys_config);
2193
2194 return abis_nm_sendmsg(bts, msg);
2195}
2196
Harald Welte59b04682009-06-10 05:40:52 +08002197int abis_nm_event_reports(struct gsm_bts *bts, int on)
2198{
2199 if (on == 0)
2200 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2201 else
2202 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2203}
2204
2205/* Siemens (or BS-11) specific commands */
2206
2207int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2208{
2209 if (reconnect == 0)
2210 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2211 else
2212 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2213}
2214
2215int abis_nm_bs11_restart(struct gsm_bts *bts)
2216{
2217 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2218}
2219
2220
2221struct bs11_date_time {
2222 u_int16_t year;
2223 u_int8_t month;
2224 u_int8_t day;
2225 u_int8_t hour;
2226 u_int8_t min;
2227 u_int8_t sec;
2228} __attribute__((packed));
2229
2230
2231void get_bs11_date_time(struct bs11_date_time *aet)
2232{
2233 time_t t;
2234 struct tm *tm;
2235
2236 t = time(NULL);
2237 tm = localtime(&t);
2238 aet->sec = tm->tm_sec;
2239 aet->min = tm->tm_min;
2240 aet->hour = tm->tm_hour;
2241 aet->day = tm->tm_mday;
2242 aet->month = tm->tm_mon;
2243 aet->year = htons(1900 + tm->tm_year);
2244}
2245
2246int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2247{
2248 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2249}
2250
2251int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2252{
2253 if (begin)
2254 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2255 else
2256 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2257}
2258
2259int abis_nm_bs11_create_object(struct gsm_bts *bts,
2260 enum abis_bs11_objtype type, u_int8_t idx,
2261 u_int8_t attr_len, const u_int8_t *attr)
2262{
2263 struct abis_om_hdr *oh;
2264 struct msgb *msg = nm_msgb_alloc();
2265 u_int8_t *cur;
2266
2267 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2268 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2269 NM_OC_BS11, type, 0, idx);
2270 cur = msgb_put(msg, attr_len);
2271 memcpy(cur, attr, attr_len);
2272
2273 return abis_nm_sendmsg(bts, msg);
2274}
2275
2276int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2277 enum abis_bs11_objtype type, 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_DELETE_OBJ,
2284 NM_OC_BS11, type, 0, idx);
2285
2286 return abis_nm_sendmsg(bts, msg);
2287}
2288
2289int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2290{
2291 struct abis_om_hdr *oh;
2292 struct msgb *msg = nm_msgb_alloc();
2293 u_int8_t zero = 0x00;
2294
2295 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2296 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2297 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2298 msgb_tlv_put(msg, 0x99, 1, &zero);
2299
2300 return abis_nm_sendmsg(bts, msg);
2301}
2302
2303int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2304{
2305 struct abis_om_hdr *oh;
2306 struct msgb *msg = nm_msgb_alloc();
2307
2308 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2309 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002310 idx, 0xff, 0xff);
2311
2312 return abis_nm_sendmsg(bts, msg);
2313}
2314
2315int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2316{
2317 struct abis_om_hdr *oh;
2318 struct msgb *msg = nm_msgb_alloc();
2319
2320 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2321 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2322 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002323
2324 return abis_nm_sendmsg(bts, msg);
2325}
2326
2327static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2328int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2329{
2330 struct abis_om_hdr *oh;
2331 struct msgb *msg = nm_msgb_alloc();
2332
2333 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2334 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2335 0xff, 0xff, 0xff);
2336 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2337
2338 return abis_nm_sendmsg(bts, msg);
2339}
2340
2341/* like abis_nm_conn_terr_traf + set_tei */
2342int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2343 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2344 u_int8_t tei)
2345{
2346 struct abis_om_hdr *oh;
2347 struct abis_nm_channel *ch;
2348 struct msgb *msg = nm_msgb_alloc();
2349
2350 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2351 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2352 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2353
2354 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2355 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2356 msgb_tv_put(msg, NM_ATT_TEI, tei);
2357
2358 return abis_nm_sendmsg(bts, msg);
2359}
2360
2361int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2362{
2363 struct abis_om_hdr *oh;
2364 struct msgb *msg = nm_msgb_alloc();
2365
2366 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2367 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2368 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2369 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2370
2371 return abis_nm_sendmsg(trx->bts, msg);
2372}
2373
2374int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2375{
2376 struct abis_om_hdr *oh;
2377 struct msgb *msg = nm_msgb_alloc();
2378 u_int8_t attr = NM_ATT_BS11_TXPWR;
2379
2380 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2381 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2382 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2383 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2384
2385 return abis_nm_sendmsg(trx->bts, msg);
2386}
2387
2388int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2389{
2390 struct abis_om_hdr *oh;
2391 struct msgb *msg = nm_msgb_alloc();
2392 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2393
2394 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2395 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2396 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2397 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2398
2399 return abis_nm_sendmsg(bts, msg);
2400}
2401
2402int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2403{
2404 struct abis_om_hdr *oh;
2405 struct msgb *msg = nm_msgb_alloc();
2406 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2407 NM_ATT_BS11_CCLK_TYPE };
2408
2409 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2410 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2411 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2412 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2413
2414 return abis_nm_sendmsg(bts, msg);
2415
2416}
2417
2418//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
2419static const u_int8_t bs11_logon_c8[] = { 0x02 };
2420static const u_int8_t bs11_logon_c9[] = "FACTORY";
2421
2422int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2423{
2424 struct abis_om_hdr *oh;
2425 struct msgb *msg = nm_msgb_alloc();
2426 struct bs11_date_time bdt;
2427
2428 get_bs11_date_time(&bdt);
2429
2430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2431 if (on) {
2432 u_int8_t len = 3*2 + sizeof(bdt)
2433 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
2434 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2435 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2436 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2437 sizeof(bdt), (u_int8_t *) &bdt);
2438 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2439 sizeof(bs11_logon_c8), bs11_logon_c8);
2440 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2441 sizeof(bs11_logon_c9), bs11_logon_c9);
2442 } else {
2443 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2444 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2445 }
2446
2447 return abis_nm_sendmsg(bts, msg);
2448}
2449
2450int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2451{
2452 struct abis_om_hdr *oh;
2453 struct msgb *msg;
2454
2455 if (strlen(password) != 10)
2456 return -EINVAL;
2457
2458 msg = nm_msgb_alloc();
2459 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2460 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2461 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2462 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2463
2464 return abis_nm_sendmsg(bts, msg);
2465}
2466
2467/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2468int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2469{
2470 struct abis_om_hdr *oh;
2471 struct msgb *msg;
2472 u_int8_t tlv_value;
2473
2474 msg = nm_msgb_alloc();
2475 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2476 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2477 BS11_OBJ_LI, 0x00, 0x00);
2478
2479 if (locked)
2480 tlv_value = BS11_LI_PLL_LOCKED;
2481 else
2482 tlv_value = BS11_LI_PLL_STANDALONE;
2483
2484 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2485
2486 return abis_nm_sendmsg(bts, msg);
2487}
2488
2489int abis_nm_bs11_get_state(struct gsm_bts *bts)
2490{
2491 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2492}
2493
2494/* BS11 SWL */
2495
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002496void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002497
Harald Welte59b04682009-06-10 05:40:52 +08002498struct abis_nm_bs11_sw {
2499 struct gsm_bts *bts;
2500 char swl_fname[PATH_MAX];
2501 u_int8_t win_size;
2502 int forced;
2503 struct llist_head file_list;
2504 gsm_cbfn *user_cb; /* specified by the user */
2505};
2506static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2507
2508struct file_list_entry {
2509 struct llist_head list;
2510 char fname[PATH_MAX];
2511};
2512
2513struct file_list_entry *fl_dequeue(struct llist_head *queue)
2514{
2515 struct llist_head *lh;
2516
2517 if (llist_empty(queue))
2518 return NULL;
2519
2520 lh = queue->next;
2521 llist_del(lh);
2522
2523 return llist_entry(lh, struct file_list_entry, list);
2524}
2525
2526static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2527{
2528 char linebuf[255];
2529 struct llist_head *lh, *lh2;
2530 FILE *swl;
2531 int rc = 0;
2532
2533 swl = fopen(bs11_sw->swl_fname, "r");
2534 if (!swl)
2535 return -ENODEV;
2536
2537 /* zero the stale file list, if any */
2538 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2539 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002540 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002541 }
2542
2543 while (fgets(linebuf, sizeof(linebuf), swl)) {
2544 char file_id[12+1];
2545 char file_version[80+1];
2546 struct file_list_entry *fle;
2547 static char dir[PATH_MAX];
2548
2549 if (strlen(linebuf) < 4)
2550 continue;
2551
2552 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2553 if (rc < 0) {
2554 perror("ERR parsing SWL file");
2555 rc = -EINVAL;
2556 goto out;
2557 }
2558 if (rc < 2)
2559 continue;
2560
Harald Welte857e00d2009-06-26 20:25:23 +02002561 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002562 if (!fle) {
2563 rc = -ENOMEM;
2564 goto out;
2565 }
Harald Welte59b04682009-06-10 05:40:52 +08002566
2567 /* construct new filename */
2568 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2569 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2570 strcat(fle->fname, "/");
2571 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2572
2573 llist_add_tail(&fle->list, &bs11_sw->file_list);
2574 }
2575
2576out:
2577 fclose(swl);
2578 return rc;
2579}
2580
2581/* bs11 swload specific callback, passed to abis_nm core swload */
2582static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2583 struct msgb *msg, void *data, void *param)
2584{
2585 struct abis_nm_bs11_sw *bs11_sw = data;
2586 struct file_list_entry *fle;
2587 int rc = 0;
2588
2589 switch (event) {
2590 case NM_MT_LOAD_END_ACK:
2591 fle = fl_dequeue(&bs11_sw->file_list);
2592 if (fle) {
2593 /* start download the next file of our file list */
2594 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2595 bs11_sw->win_size,
2596 bs11_sw->forced,
2597 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002598 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002599 } else {
2600 /* activate the SWL */
2601 rc = abis_nm_software_activate(bs11_sw->bts,
2602 bs11_sw->swl_fname,
2603 bs11_swload_cbfn,
2604 bs11_sw);
2605 }
2606 break;
2607 case NM_MT_LOAD_SEG_ACK:
2608 case NM_MT_LOAD_END_NACK:
2609 case NM_MT_LOAD_INIT_ACK:
2610 case NM_MT_LOAD_INIT_NACK:
2611 case NM_MT_ACTIVATE_SW_NACK:
2612 case NM_MT_ACTIVATE_SW_ACK:
2613 default:
2614 /* fallthrough to the user callback */
2615 if (bs11_sw->user_cb)
2616 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2617 break;
2618 }
2619
2620 return rc;
2621}
2622
2623/* Siemens provides a SWL file that is a mere listing of all the other
2624 * files that are part of a software release. We need to upload first
2625 * the list file, and then each file that is listed in the list file */
2626int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2627 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2628{
2629 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2630 struct file_list_entry *fle;
2631 int rc = 0;
2632
2633 INIT_LLIST_HEAD(&bs11_sw->file_list);
2634 bs11_sw->bts = bts;
2635 bs11_sw->win_size = win_size;
2636 bs11_sw->user_cb = cbfn;
2637 bs11_sw->forced = forced;
2638
2639 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2640 rc = bs11_read_swl_file(bs11_sw);
2641 if (rc < 0)
2642 return rc;
2643
2644 /* dequeue next item in file list */
2645 fle = fl_dequeue(&bs11_sw->file_list);
2646 if (!fle)
2647 return -EINVAL;
2648
2649 /* start download the next file of our file list */
2650 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
2651 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002652 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002653 return rc;
2654}
2655
2656#if 0
2657static u_int8_t req_attr_btse[] = {
2658 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2659 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2660 NM_ATT_BS11_LMT_USER_NAME,
2661
2662 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2663
2664 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2665
2666 NM_ATT_BS11_SW_LOAD_STORED };
2667
2668static u_int8_t req_attr_btsm[] = {
2669 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2670 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2671 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2672 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2673#endif
2674
2675static u_int8_t req_attr[] = {
2676 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2677 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2678 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2679
2680int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2681{
2682 struct abis_om_hdr *oh;
2683 struct msgb *msg = nm_msgb_alloc();
2684
2685 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2686 /* SiemensHW CCTRL object */
2687 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2688 0x03, 0x00, 0x00);
2689 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2690
2691 return abis_nm_sendmsg(bts, msg);
2692}
2693
2694int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2695{
2696 struct abis_om_hdr *oh;
2697 struct msgb *msg = nm_msgb_alloc();
2698 struct bs11_date_time aet;
2699
2700 get_bs11_date_time(&aet);
2701 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2702 /* SiemensHW CCTRL object */
2703 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2704 0xff, 0xff, 0xff);
2705 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2706
2707 return abis_nm_sendmsg(bts, msg);
2708}
2709
Daniel Willmann5655afe2009-08-10 11:49:36 +02002710int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2711{
2712 struct abis_om_hdr *oh;
2713 struct msgb *msg = nm_msgb_alloc();
2714 struct bs11_date_time aet;
2715
2716 get_bs11_date_time(&aet);
2717 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2718 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2719 bport, 0xff, 0x02);
2720 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2721
2722 return abis_nm_sendmsg(bts, msg);
2723}
2724
Harald Welte59b04682009-06-10 05:40:52 +08002725/* ip.access nanoBTS specific commands */
2726static const char ipaccess_magic[] = "com.ipaccess";
2727
2728
2729static int abis_nm_rx_ipacc(struct msgb *msg)
2730{
2731 struct abis_om_hdr *oh = msgb_l2(msg);
2732 struct abis_om_fom_hdr *foh;
2733 u_int8_t idstrlen = oh->data[0];
2734 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002735 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002736
2737 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002738 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002739 return -EINVAL;
2740 }
2741
2742 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
2743 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
2744
Harald Welteb7284a92009-10-20 09:56:18 +02002745 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002746
Harald Welte5aeedd42009-10-19 22:11:11 +02002747 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002748
2749 switch (foh->msg_type) {
2750 case NM_MT_IPACC_RSL_CONNECT_ACK:
2751 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte4206d982009-07-12 09:33:54 +02002752 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte59b04682009-06-10 05:40:52 +08002753 DEBUGPC(DNM, "IP=%s ",
2754 inet_ntoa(*((struct in_addr *)
Harald Welte4206d982009-07-12 09:33:54 +02002755 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2756 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002757 DEBUGPC(DNM, "PORT=%u ",
2758 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002759 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002760 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2761 DEBUGPC(DNM, "STREAM=0x%02x ",
2762 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002763 DEBUGPC(DNM, "\n");
2764 break;
2765 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002766 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002767 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2768 DEBUGPC(DNM, " CAUSE=%s\n",
2769 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2770 else
2771 DEBUGPC(DNM, "\n");
2772 break;
2773 case NM_MT_IPACC_SET_NVATTR_ACK:
2774 DEBUGPC(DNM, "SET NVATTR ACK\n");
2775 /* FIXME: decode and show the actual attributes */
2776 break;
2777 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002778 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002779 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Weltede4477a2009-12-24 12:20:20 +01002780 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002781 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2782 else
Harald Weltede4477a2009-12-24 12:20:20 +01002783 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002784 break;
Harald Welte21460f02009-07-03 11:26:45 +02002785 case NM_MT_IPACC_GET_NVATTR_ACK:
2786 DEBUGPC(DNM, "GET NVATTR ACK\n");
2787 /* FIXME: decode and show the actual attributes */
2788 break;
2789 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002790 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002791 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Weltede4477a2009-12-24 12:20:20 +01002792 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002793 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2794 else
Harald Weltede4477a2009-12-24 12:20:20 +01002795 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002796 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002797 case NM_MT_IPACC_SET_ATTR_ACK:
2798 DEBUGPC(DNM, "SET ATTR ACK\n");
2799 break;
2800 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002801 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002802 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Weltede4477a2009-12-24 12:20:20 +01002803 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002804 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2805 else
Harald Weltede4477a2009-12-24 12:20:20 +01002806 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002807 break;
Harald Welte59b04682009-06-10 05:40:52 +08002808 default:
2809 DEBUGPC(DNM, "unknown\n");
2810 break;
2811 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002812
2813 /* signal handling */
2814 switch (foh->msg_type) {
2815 case NM_MT_IPACC_RSL_CONNECT_NACK:
2816 case NM_MT_IPACC_SET_NVATTR_NACK:
2817 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002818 signal.bts = msg->trx->bts;
2819 signal.msg_type = foh->msg_type;
2820 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002821 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002822 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002823 signal.bts = msg->trx->bts;
2824 signal.msg_type = foh->msg_type;
2825 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002826 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002827 default:
2828 break;
2829 }
2830
Harald Welte59b04682009-06-10 05:40:52 +08002831 return 0;
2832}
2833
2834/* send an ip-access manufacturer specific message */
2835int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2836 u_int8_t obj_class, u_int8_t bts_nr,
2837 u_int8_t trx_nr, u_int8_t ts_nr,
2838 u_int8_t *attr, int attr_len)
2839{
2840 struct msgb *msg = nm_msgb_alloc();
2841 struct abis_om_hdr *oh;
2842 struct abis_om_fom_hdr *foh;
2843 u_int8_t *data;
2844
2845 /* construct the 12.21 OM header, observe the erroneous length */
2846 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2847 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2848 oh->mdisc = ABIS_OM_MDISC_MANUF;
2849
2850 /* add the ip.access magic */
2851 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2852 *data++ = sizeof(ipaccess_magic);
2853 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2854
2855 /* fill the 12.21 FOM header */
2856 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2857 foh->msg_type = msg_type;
2858 foh->obj_class = obj_class;
2859 foh->obj_inst.bts_nr = bts_nr;
2860 foh->obj_inst.trx_nr = trx_nr;
2861 foh->obj_inst.ts_nr = ts_nr;
2862
2863 if (attr && attr_len) {
2864 data = msgb_put(msg, attr_len);
2865 memcpy(data, attr, attr_len);
2866 }
2867
2868 return abis_nm_sendmsg(bts, msg);
2869}
2870
2871/* set some attributes in NVRAM */
2872int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2873 int attr_len)
2874{
2875 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2876 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2877 attr_len);
2878}
2879
Harald Welte5aeedd42009-10-19 22:11:11 +02002880int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2881 u_int32_t ip, u_int16_t port, u_int8_t stream)
2882{
2883 struct in_addr ia;
2884 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2885 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2886 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2887
2888 int attr_len = sizeof(attr);
2889
2890 ia.s_addr = htonl(ip);
2891 attr[1] = stream;
2892 attr[3] = port >> 8;
2893 attr[4] = port & 0xff;
2894 *(u_int32_t *)(attr+6) = ia.s_addr;
2895
2896 /* if ip == 0, we use the default IP */
2897 if (ip == 0)
2898 attr_len -= 5;
2899
2900 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002901 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002902
2903 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2904 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2905 trx->nr, 0xff, attr, attr_len);
2906}
2907
Harald Welte59b04682009-06-10 05:40:52 +08002908/* restart / reboot an ip.access nanoBTS */
2909int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2910{
2911 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2912}
Harald Welte0dfc6232009-10-24 10:20:41 +02002913
2914int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2915 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2916 u_int8_t *attr, u_int8_t attr_len)
2917{
2918 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2919 obj_class, bts_nr, trx_nr, ts_nr,
2920 attr, attr_len);
2921}
Harald Weltebeeae412009-11-12 14:48:42 +01002922
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002923void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2924{
2925 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2926
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01002927 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002928 if (!trx->bts || !trx->bts->oml_link)
2929 return;
2930
2931 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2932 trx->bts->bts_nr, trx->nr, 0xff,
2933 new_state);
2934}
2935
Harald Weltebeeae412009-11-12 14:48:42 +01002936static const char *ipacc_testres_names[] = {
2937 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2938 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2939 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2940 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2941 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2942};
2943
2944const char *ipacc_testres_name(u_int8_t res)
2945{
2946 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2947 ipacc_testres_names[res])
2948 return ipacc_testres_names[res];
2949
2950 return "unknown";
2951}
2952
Harald Weltebfc21092009-11-13 11:56:05 +01002953void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2954{
2955 cid->mcc = (buf[0] & 0xf) * 100;
2956 cid->mcc += (buf[0] >> 4) * 10;
2957 cid->mcc += (buf[1] & 0xf) * 1;
2958
2959 if (buf[1] >> 4 == 0xf) {
2960 cid->mnc = (buf[2] & 0xf) * 10;
2961 cid->mnc += (buf[2] >> 4) * 1;
2962 } else {
2963 cid->mnc = (buf[2] & 0xf) * 100;
2964 cid->mnc += (buf[2] >> 4) * 10;
2965 cid->mnc += (buf[1] >> 4) * 1;
2966 }
2967
Harald Welte161b4be2009-11-13 14:41:52 +01002968 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2969 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002970}
2971
Harald Weltebeeae412009-11-12 14:48:42 +01002972/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2973int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2974{
2975 u_int8_t *cur = buf;
2976 u_int16_t len;
2977
2978 memset(binf, 0, sizeof(binf));
2979
2980 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2981 return -EINVAL;
2982 cur++;
2983
2984 len = ntohs(*(u_int16_t *)cur);
2985 cur += 2;
2986
2987 binf->info_type = ntohs(*(u_int16_t *)cur);
2988 cur += 2;
2989
2990 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2991 binf->freq_qual = *cur >> 2;
2992
2993 binf->arfcn = *cur++ & 3 << 8;
2994 binf->arfcn |= *cur++;
2995
2996 if (binf->info_type & IPAC_BINF_RXLEV)
2997 binf->rx_lev = *cur & 0x3f;
2998 cur++;
2999
3000 if (binf->info_type & IPAC_BINF_RXQUAL)
3001 binf->rx_qual = *cur & 0x7;
3002 cur++;
3003
3004 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3005 binf->freq_err = ntohs(*(u_int16_t *)cur);
3006 cur += 2;
3007
3008 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3009 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3010 cur += 2;
3011
3012 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3013 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3014 cur += 4;
3015
3016 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte161b4be2009-11-13 14:41:52 +01003017 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01003018 cur++;
3019
Harald Weltebfc21092009-11-13 11:56:05 +01003020 ipac_parse_cgi(&binf->cgi, cur);
3021 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01003022
3023 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3024 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3025 cur += sizeof(binf->ba_list_si2);
3026 }
3027
3028 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3029 memcpy(binf->ba_list_si2bis, cur,
3030 sizeof(binf->ba_list_si2bis));
3031 cur += sizeof(binf->ba_list_si2bis);
3032 }
3033
3034 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3035 memcpy(binf->ba_list_si2ter, cur,
3036 sizeof(binf->ba_list_si2ter));
3037 cur += sizeof(binf->ba_list_si2ter);
3038 }
3039
3040 return 0;
3041}
3042
3043