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