blob: b3e12e97ab3c56c54d2391fb0378e8c3b3892594 [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001/* 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
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * 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>
Harald Welte4724f992009-01-18 18:01:49 +000026#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000027#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000028#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000029#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000030#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000031#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000032#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000033
Harald Welte52b1f982008-12-23 20:25:15 +000034#include <sys/types.h>
Harald Welte4724f992009-01-18 18:01:49 +000035#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000036#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000037#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000038
Harald Welte8470bf22008-12-25 23:28:35 +000039#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>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020046#include <openbsc/talloc.h>
Harald Welte52b1f982008-12-23 20:25:15 +000047
Harald Welte8470bf22008-12-25 23:28:35 +000048#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Harald Welte52b1f982008-12-23 20:25:15 +000050
51/* unidirectional messages from BTS to BSC */
52static const enum abis_nm_msgtype reports[] = {
53 NM_MT_SW_ACTIVATED_REP,
54 NM_MT_TEST_REP,
55 NM_MT_STATECHG_EVENT_REP,
56 NM_MT_FAILURE_EVENT_REP,
57};
58
59/* messages without ACK/NACK */
60static const enum abis_nm_msgtype no_ack_nack[] = {
61 NM_MT_MEAS_RES_REQ,
62 NM_MT_STOP_MEAS,
63 NM_MT_START_MEAS,
64};
65
Harald Welte4724f992009-01-18 18:01:49 +000066/* Messages related to software load */
67static const enum abis_nm_msgtype sw_load_msgs[] = {
68 NM_MT_LOAD_INIT_ACK,
69 NM_MT_LOAD_INIT_NACK,
70 NM_MT_LOAD_SEG_ACK,
71 NM_MT_LOAD_ABORT,
72 NM_MT_LOAD_END_ACK,
73 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000074 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000075 NM_MT_ACTIVATE_SW_ACK,
76 NM_MT_ACTIVATE_SW_NACK,
77 NM_MT_SW_ACTIVATED_REP,
78};
79
Harald Weltee0590df2009-02-15 03:34:15 +000080static const enum abis_nm_msgtype nacks[] = {
81 NM_MT_LOAD_INIT_NACK,
82 NM_MT_LOAD_END_NACK,
83 NM_MT_SW_ACT_REQ_NACK,
84 NM_MT_ACTIVATE_SW_NACK,
85 NM_MT_ESTABLISH_TEI_NACK,
86 NM_MT_CONN_TERR_SIGN_NACK,
87 NM_MT_DISC_TERR_SIGN_NACK,
88 NM_MT_CONN_TERR_TRAF_NACK,
89 NM_MT_DISC_TERR_TRAF_NACK,
90 NM_MT_CONN_MDROP_LINK_NACK,
91 NM_MT_DISC_MDROP_LINK_NACK,
92 NM_MT_SET_BTS_ATTR_NACK,
93 NM_MT_SET_RADIO_ATTR_NACK,
94 NM_MT_SET_CHAN_ATTR_NACK,
95 NM_MT_PERF_TEST_NACK,
96 NM_MT_SEND_TEST_REP_NACK,
97 NM_MT_STOP_TEST_NACK,
98 NM_MT_STOP_EVENT_REP_NACK,
99 NM_MT_REST_EVENT_REP_NACK,
100 NM_MT_CHG_ADM_STATE_NACK,
101 NM_MT_CHG_ADM_STATE_REQ_NACK,
102 NM_MT_REP_OUTST_ALARMS_NACK,
103 NM_MT_CHANGEOVER_NACK,
104 NM_MT_OPSTART_NACK,
105 NM_MT_REINIT_NACK,
106 NM_MT_SET_SITE_OUT_NACK,
107 NM_MT_CHG_HW_CONF_NACK,
108 NM_MT_GET_ATTR_NACK,
109 NM_MT_SET_ALARM_THRES_NACK,
110 NM_MT_BS11_BEGIN_DB_TX_NACK,
111 NM_MT_BS11_END_DB_TX_NACK,
112 NM_MT_BS11_CREATE_OBJ_NACK,
113 NM_MT_BS11_DELETE_OBJ_NACK,
114};
Harald Welte78fc0d42009-02-19 02:50:57 +0000115
116static const char *nack_names[0xff] = {
117 [NM_MT_LOAD_INIT_NACK] = "SOFTWARE LOAD INIT",
118 [NM_MT_LOAD_END_NACK] = "SOFTWARE LOAD END",
119 [NM_MT_SW_ACT_REQ_NACK] = "SOFTWARE ACTIVATE REQUEST",
120 [NM_MT_ACTIVATE_SW_NACK] = "ACTIVATE SOFTWARE",
121 [NM_MT_ESTABLISH_TEI_NACK] = "ESTABLISH TEI",
122 [NM_MT_CONN_TERR_SIGN_NACK] = "CONNECT TERRESTRIAL SIGNALLING",
123 [NM_MT_DISC_TERR_SIGN_NACK] = "DISCONNECT TERRESTRIAL SIGNALLING",
124 [NM_MT_CONN_TERR_TRAF_NACK] = "CONNECT TERRESTRIAL TRAFFIC",
125 [NM_MT_DISC_TERR_TRAF_NACK] = "DISCONNECT TERRESTRIAL TRAFFIC",
126 [NM_MT_CONN_MDROP_LINK_NACK] = "CONNECT MULTI-DROP LINK",
127 [NM_MT_DISC_MDROP_LINK_NACK] = "DISCONNECT MULTI-DROP LINK",
128 [NM_MT_SET_BTS_ATTR_NACK] = "SET BTS ATTRIBUTE",
129 [NM_MT_SET_RADIO_ATTR_NACK] = "SET RADIO ATTRIBUTE",
130 [NM_MT_SET_CHAN_ATTR_NACK] = "SET CHANNEL ATTRIBUTE",
131 [NM_MT_PERF_TEST_NACK] = "PERFORM TEST",
132 [NM_MT_SEND_TEST_REP_NACK] = "SEND TEST REPORT",
133 [NM_MT_STOP_TEST_NACK] = "STOP TEST",
134 [NM_MT_STOP_EVENT_REP_NACK] = "STOP EVENT REPORT",
135 [NM_MT_REST_EVENT_REP_NACK] = "RESET EVENT REPORT",
136 [NM_MT_CHG_ADM_STATE_NACK] = "CHANGE ADMINISTRATIVE STATE",
137 [NM_MT_CHG_ADM_STATE_REQ_NACK] = "CHANGE ADMINISTRATIVE STATE REQUEST",
138 [NM_MT_REP_OUTST_ALARMS_NACK] = "REPORT OUTSTANDING ALARMS",
139 [NM_MT_CHANGEOVER_NACK] = "CHANGEOVER",
140 [NM_MT_OPSTART_NACK] = "OPSTART",
141 [NM_MT_REINIT_NACK] = "REINIT",
142 [NM_MT_SET_SITE_OUT_NACK] = "SET SITE OUTPUT",
143 [NM_MT_CHG_HW_CONF_NACK] = "CHANGE HARDWARE CONFIGURATION",
144 [NM_MT_GET_ATTR_NACK] = "GET ATTRIBUTE",
145 [NM_MT_SET_ALARM_THRES_NACK] = "SET ALARM THRESHOLD",
146 [NM_MT_BS11_BEGIN_DB_TX_NACK] = "BS11 BEGIN DATABASE TRANSMISSION",
147 [NM_MT_BS11_END_DB_TX_NACK] = "BS11 END DATABASE TRANSMISSION",
148 [NM_MT_BS11_CREATE_OBJ_NACK] = "BS11 CREATE OBJECT",
149 [NM_MT_BS11_DELETE_OBJ_NACK] = "BS11 DELETE OBJECT",
150};
151
Harald Welte6c96ba52009-05-01 13:03:40 +0000152/* Chapter 9.4.36 */
153static const char *nack_cause_names[] = {
154 /* General Nack Causes */
155 [NM_NACK_INCORR_STRUCT] = "Incorrect message structure",
156 [NM_NACK_MSGTYPE_INVAL] = "Invalid message type value",
157 [NM_NACK_OBJCLASS_INVAL] = "Invalid Object class value",
158 [NM_NACK_OBJCLASS_NOTSUPP] = "Object class not supported",
159 [NM_NACK_BTSNR_UNKN] = "BTS no. unknown",
160 [NM_NACK_TRXNR_UNKN] = "Baseband Transceiver no. unknown",
161 [NM_NACK_OBJINST_UNKN] = "Object Instance unknown",
162 [NM_NACK_ATTRID_INVAL] = "Invalid attribute identifier value",
163 [NM_NACK_ATTRID_NOTSUPP] = "Attribute identifier not supported",
164 [NM_NACK_PARAM_RANGE] = "Parameter value outside permitted range",
165 [NM_NACK_ATTRLIST_INCONSISTENT] = "Inconsistency in attribute list",
166 [NM_NACK_SPEC_IMPL_NOTSUPP] = "Specified implementation not supported",
167 [NM_NACK_CANT_PERFORM] = "Message cannot be performed",
168 /* Specific Nack Causes */
169 [NM_NACK_RES_NOTIMPL] = "Resource not implemented",
170 [NM_NACK_RES_NOTAVAIL] = "Resource not available",
171 [NM_NACK_FREQ_NOTAVAIL] = "Frequency not available",
172 [NM_NACK_TEST_NOTSUPP] = "Test not supported",
173 [NM_NACK_CAPACITY_RESTR] = "Capacity restrictions",
174 [NM_NACK_PHYSCFG_NOTPERFORM] = "Physical configuration cannot be performed",
175 [NM_NACK_TEST_NOTINIT] = "Test not initiated",
176 [NM_NACK_PHYSCFG_NOTRESTORE] = "Physical configuration cannot be restored",
177 [NM_NACK_TEST_NOSUCH] = "No such test",
178 [NM_NACK_TEST_NOSTOP] = "Test cannot be stopped",
179 [NM_NACK_MSGINCONSIST_PHYSCFG] = "Message inconsistent with physical configuration",
180 [NM_NACK_FILE_INCOMPLETE] = "Complete file notreceived",
181 [NM_NACK_FILE_NOTAVAIL] = "File not available at destination",
Harald Welte560982b2009-06-26 13:21:57 +0200182 [NM_NACK_FILE_NOTACTIVATE] = "File cannot be activate",
Harald Welte6c96ba52009-05-01 13:03:40 +0000183 [NM_NACK_REQ_NOT_GRANT] = "Request not granted",
184 [NM_NACK_WAIT] = "Wait",
185 [NM_NACK_NOTH_REPORT_EXIST] = "Nothing reportable existing",
186 [NM_NACK_MEAS_NOTSUPP] = "Measurement not supported",
187 [NM_NACK_MEAS_NOTSTART] = "Measurement not started",
188};
189
190static char namebuf[255];
191static const char *nack_cause_name(u_int8_t cause)
192{
193 if (cause < ARRAY_SIZE(nack_cause_names) && nack_cause_names[cause])
194 return nack_cause_names[cause];
195
196 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
197 return namebuf;
198}
199
Harald Welte0db97b22009-05-01 17:22:47 +0000200/* Chapter 9.4.16: Event Type */
201static const char *event_type_names[] = {
202 [NM_EVT_COMM_FAIL] = "communication failure",
203 [NM_EVT_QOS_FAIL] = "quality of service failure",
204 [NM_EVT_PROC_FAIL] = "processing failure",
205 [NM_EVT_EQUIP_FAIL] = "equipment failure",
206 [NM_EVT_ENV_FAIL] = "environment failure",
207};
208
209static const char *event_type_name(u_int8_t cause)
210{
211 if (cause < ARRAY_SIZE(event_type_names) && event_type_names[cause])
212 return event_type_names[cause];
213
214 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
215 return namebuf;
216}
217
218/* Chapter 9.4.63: Perceived Severity */
219static const char *severity_names[] = {
220 [NM_SEVER_CEASED] = "failure ceased",
221 [NM_SEVER_CRITICAL] = "critical failure",
222 [NM_SEVER_MAJOR] = "major failure",
223 [NM_SEVER_MINOR] = "minor failure",
224 [NM_SEVER_WARNING] = "warning level failure",
225 [NM_SEVER_INDETERMINATE] = "indeterminate failure",
226};
227
228static const char *severity_name(u_int8_t cause)
229{
230 if (cause < ARRAY_SIZE(severity_names) && severity_names[cause])
231 return severity_names[cause];
232
233 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
234 return namebuf;
235}
236
Harald Welte52b1f982008-12-23 20:25:15 +0000237/* Attributes that the BSC can set, not only get, according to Section 9.4 */
238static const enum abis_nm_attr nm_att_settable[] = {
239 NM_ATT_ADD_INFO,
240 NM_ATT_ADD_TEXT,
241 NM_ATT_DEST,
242 NM_ATT_EVENT_TYPE,
243 NM_ATT_FILE_DATA,
244 NM_ATT_GET_ARI,
245 NM_ATT_HW_CONF_CHG,
246 NM_ATT_LIST_REQ_ATTR,
247 NM_ATT_MDROP_LINK,
248 NM_ATT_MDROP_NEXT,
249 NM_ATT_NACK_CAUSES,
250 NM_ATT_OUTST_ALARM,
251 NM_ATT_PHYS_CONF,
252 NM_ATT_PROB_CAUSE,
253 NM_ATT_RAD_SUBC,
254 NM_ATT_SOURCE,
255 NM_ATT_SPEC_PROB,
256 NM_ATT_START_TIME,
257 NM_ATT_TEST_DUR,
258 NM_ATT_TEST_NO,
259 NM_ATT_TEST_REPORT,
260 NM_ATT_WINDOW_SIZE,
261 NM_ATT_SEVERITY,
262 NM_ATT_MEAS_RES,
263 NM_ATT_MEAS_TYPE,
264};
265
Harald Weltee0590df2009-02-15 03:34:15 +0000266static const struct tlv_definition nm_att_tlvdef = {
267 .def = {
268 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
269 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
270 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
271 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
272 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
273 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
274 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
275 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
276 [NM_ATT_BSIC] = { TLV_TYPE_TV },
277 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
278 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
279 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
280 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
281 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
282 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
283 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
284 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
285 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
286 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
287 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
288 [NM_ATT_HSN] = { TLV_TYPE_TV },
289 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
290 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
291 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
292 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
293 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
294 [NM_ATT_MAIO] = { TLV_TYPE_TV },
295 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
297 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
298 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
299 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
300 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
301 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
302 [NM_ATT_NY1] = { TLV_TYPE_TV },
303 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
304 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
305 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
306 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
307 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
308 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
309 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
310 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
311 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
312 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
313 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
314 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
315 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
316 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
317 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
318 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
319 [NM_ATT_TEI] = { TLV_TYPE_TV },
320 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
321 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
322 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
323 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
324 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
325 [NM_ATT_TSC] = { TLV_TYPE_TV },
326 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
327 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
328 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
329 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
330 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000331 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
332 /* BS11 specifics */
Harald Welte78fc0d42009-02-19 02:50:57 +0000333 [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV },
334 [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV },
335 [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV },
336 [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV },
337 [0xd5] = { TLV_TYPE_TLV },
338 [0xa8] = { TLV_TYPE_TLV },
Harald Weltee0590df2009-02-15 03:34:15 +0000339 [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV },
340 [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV },
341 [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV },
342 [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV },
343 [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV },
344 [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 },
345 [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV },
Harald Welteee670472009-02-22 21:58:49 +0000346 [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },
Harald Weltee0590df2009-02-15 03:34:15 +0000347 [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV },
348 [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
349 [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV },
Harald Welte03133942009-02-18 19:51:53 +0000350 [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV },
351 [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV },
Harald Welteaaf02d92009-04-29 13:25:57 +0000352 [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV },
Harald Weltea7cfa032009-04-29 22:33:02 +0000353 [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV },
Harald Welteef061952009-05-17 12:43:42 +0000354 [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV },
355 [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV },
Harald Welte677c21f2009-02-17 13:22:23 +0000356 /* ip.access specifics */
Harald Welte0efe9b72009-07-12 09:33:54 +0200357 [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
358 [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200359 [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
360 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, },
361 [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
362 [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
363 [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
364 [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
365 [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
366 [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
367 [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
368 [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
369 [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
Harald Welte0efe9b72009-07-12 09:33:54 +0200370 [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200371 [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
372 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
Harald Welte0efe9b72009-07-12 09:33:54 +0200373 [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200374 [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
375 [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
376 [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
377 [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
378 [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
379 [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
380 [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
381 [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
382 [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
383 [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
384 [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
385 [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
386 [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200387 [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200388 [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
389 [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
390 [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
391 [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
392 [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
393 [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
394 [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
395 [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
396 [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
397 [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
398 [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
399 [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200400 //[0x95] = { TLV_TYPE_FIXED, 2 },
Harald Welte677c21f2009-02-17 13:22:23 +0000401 [0x85] = { TLV_TYPE_TV },
402
Harald Weltee0590df2009-02-15 03:34:15 +0000403 },
404};
Harald Welte03133942009-02-18 19:51:53 +0000405
Harald Welte21bd3a52009-08-10 12:21:22 +0200406static const enum abis_nm_chan_comb chcomb4pchan[] = {
407 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
408 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
409 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
410 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
411 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200412 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
413 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200414 /* FIXME: bounds check */
415};
416
417int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
418{
419 if (pchan < ARRAY_SIZE(chcomb4pchan))
420 return chcomb4pchan[pchan];
421
422 return -EINVAL;
423}
424
Harald Welte03133942009-02-18 19:51:53 +0000425int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
426{
Harald Weltea4d49e92009-05-23 06:39:58 +0000427 return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000428}
Harald Weltee0590df2009-02-15 03:34:15 +0000429
Harald Welte52b1f982008-12-23 20:25:15 +0000430static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
431{
432 int i;
433
434 for (i = 0; i < size; i++) {
435 if (arr[i] == mt)
436 return 1;
437 }
438
439 return 0;
440}
441
Holger Freytherca362a62009-01-04 21:05:01 +0000442#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000443/* is this msgtype the usual ACK/NACK type ? */
444static int is_ack_nack(enum abis_nm_msgtype mt)
445{
446 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
447}
Holger Freytherca362a62009-01-04 21:05:01 +0000448#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000449
450/* is this msgtype a report ? */
451static int is_report(enum abis_nm_msgtype mt)
452{
Harald Welte8470bf22008-12-25 23:28:35 +0000453 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000454}
455
456#define MT_ACK(x) (x+1)
457#define MT_NACK(x) (x+2)
458
459static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
460{
461 oh->mdisc = ABIS_OM_MDISC_FOM;
462 oh->placement = ABIS_OM_PLACEMENT_ONLY;
463 oh->sequence = 0;
464 oh->length = len;
465}
466
467static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
468 u_int8_t msg_type, u_int8_t obj_class,
469 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
470{
471 struct abis_om_fom_hdr *foh =
472 (struct abis_om_fom_hdr *) oh->data;
473
Harald Welte702d8702008-12-26 20:25:35 +0000474 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000475 foh->msg_type = msg_type;
476 foh->obj_class = obj_class;
477 foh->obj_inst.bts_nr = bts_nr;
478 foh->obj_inst.trx_nr = trx_nr;
479 foh->obj_inst.ts_nr = ts_nr;
480}
481
Harald Welte8470bf22008-12-25 23:28:35 +0000482static struct msgb *nm_msgb_alloc(void)
483{
Harald Welte966636f2009-06-26 19:39:35 +0200484 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
485 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000486}
487
Harald Welte52b1f982008-12-23 20:25:15 +0000488/* Send a OML NM Message from BSC to BTS */
489int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
490{
Holger Freyther59639e82009-02-09 23:09:55 +0000491 msg->trx = bts->c0;
492
Harald Weltead384642008-12-26 10:20:07 +0000493 return _abis_nm_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000494}
495
Harald Welte4724f992009-01-18 18:01:49 +0000496static int abis_nm_rcvmsg_sw(struct msgb *mb);
497
Harald Welte34a99682009-02-13 02:41:40 +0000498static const char *obj_class_name(u_int8_t oc)
499{
Harald Welte7b26bcb2009-05-28 11:39:21 +0000500 switch (oc) {
501 case NM_OC_SITE_MANAGER:
502 return "SITE MANAGER";
503 case NM_OC_BTS:
504 return "BTS";
505 case NM_OC_RADIO_CARRIER:
506 return "RADIO CARRIER";
507 case NM_OC_BASEB_TRANSC:
508 return "BASEBAND TRANSCEIVER";
509 case NM_OC_CHANNEL:
Harald Weltebd8f7e32009-06-09 20:17:12 +0000510 return "CHANNEL";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000511 case NM_OC_BS11_ADJC:
512 return "ADJC";
513 case NM_OC_BS11_HANDOVER:
514 return "HANDOVER";
515 case NM_OC_BS11_PWR_CTRL:
516 return "POWER CONTROL";
517 case NM_OC_BS11_BTSE:
518 return "BTSE";
519 case NM_OC_BS11_RACK:
520 return "RACK";
521 case NM_OC_BS11_TEST:
522 return "TEST";
523 case NM_OC_BS11_ENVABTSE:
524 return "ENVABTSE";
525 case NM_OC_BS11_BPORT:
526 return "BPORT";
527 case NM_OC_GPRS_NSE:
528 return "GPRS NSE";
529 case NM_OC_GPRS_CELL:
530 return "GPRS CELL";
Harald Welted83a1272009-07-12 10:56:06 +0200531 case NM_OC_GPRS_NSVC:
532 return "GPRS NSVC";
Harald Welte8b697c72009-06-05 19:18:45 +0000533 case NM_OC_BS11:
534 return "SIEMENSHW";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000535 }
536
537 return "UNKNOWN";
Harald Welte34a99682009-02-13 02:41:40 +0000538}
539
Harald Welte4d87f242009-03-10 19:43:44 +0000540const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000541{
542 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100543 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000544 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100545 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000546 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100547 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000548 return "NULL";
549 default:
550 return "RFU";
551 }
552}
553
Harald Weltee0590df2009-02-15 03:34:15 +0000554/* Chapter 9.4.7 */
Harald Welte4d87f242009-03-10 19:43:44 +0000555static const char *avail_names[] = {
Harald Weltee0590df2009-02-15 03:34:15 +0000556 "In test",
557 "Failed",
558 "Power off",
559 "Off line",
560 "<not used>",
561 "Dependency",
562 "Degraded",
563 "Not installed",
564};
565
Harald Welte4d87f242009-03-10 19:43:44 +0000566const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000567{
Harald Welte0b8348d2009-02-18 03:43:01 +0000568 if (avail == 0xff)
569 return "OK";
Harald Weltee0590df2009-02-15 03:34:15 +0000570 if (avail >= ARRAY_SIZE(avail_names))
571 return "UNKNOWN";
572 return avail_names[avail];
573}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000574
Harald Welte0f255852009-11-12 14:48:42 +0100575static struct value_string test_names[] = {
576 /* FIXME: standard test names */
577 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
578 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
579 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
580 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
581 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
582 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
583 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
584 { 0, NULL }
585};
586
Harald Welte7b26bcb2009-05-28 11:39:21 +0000587const char *nm_adm_name(u_int8_t adm)
588{
589 switch (adm) {
590 case 1:
591 return "Locked";
592 case 2:
593 return "Unlocked";
594 case 3:
595 return "Shutdown";
596 default:
597 return "<not used>";
598 }
599}
Harald Weltee0590df2009-02-15 03:34:15 +0000600
Harald Weltea8bd6d42009-10-20 09:56:18 +0200601static void debugp_foh(struct abis_om_fom_hdr *foh)
602{
603 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
604 obj_class_name(foh->obj_class), foh->obj_class,
605 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
606 foh->obj_inst.ts_nr);
607}
608
Harald Weltee0590df2009-02-15 03:34:15 +0000609/* obtain the gsm_nm_state data structure for a given object instance */
610static struct gsm_nm_state *
611objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
612 struct abis_om_obj_inst *obj_inst)
613{
614 struct gsm_bts_trx *trx;
615 struct gsm_nm_state *nm_state = NULL;
616
617 switch (obj_class) {
618 case NM_OC_BTS:
619 nm_state = &bts->nm_state;
620 break;
621 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100622 if (obj_inst->trx_nr >= bts->num_trx) {
623 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000624 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100625 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200626 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000627 nm_state = &trx->nm_state;
628 break;
629 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100630 if (obj_inst->trx_nr >= bts->num_trx) {
631 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000632 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100633 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200634 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000635 nm_state = &trx->bb_transc.nm_state;
636 break;
637 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100638 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100639 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000640 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100641 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200642 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000643 if (obj_inst->ts_nr >= TRX_NR_TS)
644 return NULL;
645 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
646 break;
647 case NM_OC_SITE_MANAGER:
648 nm_state = &bts->site_mgr.nm_state;
649 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000650 case NM_OC_BS11:
651 switch (obj_inst->bts_nr) {
652 case BS11_OBJ_CCLK:
653 nm_state = &bts->bs11.cclk.nm_state;
654 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000655 case BS11_OBJ_BBSIG:
656 if (obj_inst->ts_nr > bts->num_trx)
657 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200658 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000659 nm_state = &trx->bs11.bbsig.nm_state;
660 break;
661 case BS11_OBJ_PA:
662 if (obj_inst->ts_nr > bts->num_trx)
663 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200664 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000665 nm_state = &trx->bs11.pa.nm_state;
666 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000667 default:
668 return NULL;
669 }
670 case NM_OC_BS11_RACK:
671 nm_state = &bts->bs11.rack.nm_state;
672 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000673 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100674 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000675 return NULL;
676 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
677 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200678 case NM_OC_GPRS_NSE:
679 nm_state = &bts->gprs.nse.nm_state;
680 break;
681 case NM_OC_GPRS_CELL:
682 nm_state = &bts->gprs.cell.nm_state;
683 break;
684 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100685 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200686 return NULL;
687 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
688 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000689 }
690 return nm_state;
691}
692
693/* obtain the in-memory data structure of a given object instance */
694static void *
695objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
696 struct abis_om_obj_inst *obj_inst)
697{
698 struct gsm_bts_trx *trx;
699 void *obj = NULL;
700
701 switch (obj_class) {
702 case NM_OC_BTS:
703 obj = bts;
704 break;
705 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100706 if (obj_inst->trx_nr >= bts->num_trx) {
707 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000708 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100709 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200710 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000711 obj = trx;
712 break;
713 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100714 if (obj_inst->trx_nr >= bts->num_trx) {
715 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000716 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100717 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200718 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000719 obj = &trx->bb_transc;
720 break;
721 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100722 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100723 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000724 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100725 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200726 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000727 if (obj_inst->ts_nr >= TRX_NR_TS)
728 return NULL;
729 obj = &trx->ts[obj_inst->ts_nr];
730 break;
731 case NM_OC_SITE_MANAGER:
732 obj = &bts->site_mgr;
733 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200734 case NM_OC_GPRS_NSE:
735 obj = &bts->gprs.nse;
736 break;
737 case NM_OC_GPRS_CELL:
738 obj = &bts->gprs.cell;
739 break;
740 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100741 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200742 return NULL;
743 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
744 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000745 }
746 return obj;
747}
748
749/* Update the administrative state of a given object in our in-memory data
750 * structures and send an event to the higher layer */
751static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
752 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
753{
Harald Welteaeedeb42009-05-01 13:08:14 +0000754 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000755 void *obj;
756 int rc;
757
Harald Weltee0590df2009-02-15 03:34:15 +0000758 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100759 if (!obj)
760 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000761 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
762 if (!nm_state)
763 return -1;
764
765 new_state = *nm_state;
766 new_state.administrative = adm_state;
767
768 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
769
770 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000771
772 return rc;
773}
774
Harald Welte97ed1e72009-02-06 13:38:02 +0000775static int abis_nm_rx_statechg_rep(struct msgb *mb)
776{
Harald Weltee0590df2009-02-15 03:34:15 +0000777 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000778 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000779 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000780 struct tlv_parsed tp;
781 struct gsm_nm_state *nm_state, new_state;
782 int rc;
783
Harald Welte23897662009-05-01 14:52:51 +0000784 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000785
Harald Welte8b697c72009-06-05 19:18:45 +0000786 memset(&new_state, 0, sizeof(new_state));
787
Harald Weltee0590df2009-02-15 03:34:15 +0000788 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
789 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100790 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000791 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000792 }
Harald Weltee0590df2009-02-15 03:34:15 +0000793
794 new_state = *nm_state;
795
Harald Welte03133942009-02-18 19:51:53 +0000796 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000797 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
798 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000799 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000800 }
801 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000802 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
803 new_state.availability = 0xff;
804 else
805 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000806 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000807 new_state.availability);
808 }
809 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
810 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200811 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000812 }
813 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000814
815 if (memcmp(&new_state, nm_state, sizeof(new_state))) {
816 /* Update the operational state of a given object in our in-memory data
817 * structures and send an event to the higher layer */
818 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
819 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
820 *nm_state = new_state;
821 }
822#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000823 if (op_state == 1) {
824 /* try to enable objects that are disabled */
825 abis_nm_opstart(bts, foh->obj_class,
826 foh->obj_inst.bts_nr,
827 foh->obj_inst.trx_nr,
828 foh->obj_inst.ts_nr);
829 }
Harald Weltee0590df2009-02-15 03:34:15 +0000830#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000831 return 0;
832}
833
Harald Welte0db97b22009-05-01 17:22:47 +0000834static int rx_fail_evt_rep(struct msgb *mb)
835{
836 struct abis_om_hdr *oh = msgb_l2(mb);
837 struct abis_om_fom_hdr *foh = msgb_l3(mb);
838 struct tlv_parsed tp;
839
840 DEBUGPC(DNM, "Failure Event Report ");
841
842 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
843
844 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
845 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
846 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
847 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
848
849 DEBUGPC(DNM, "\n");
850
851 return 0;
852}
853
Harald Welte97ed1e72009-02-06 13:38:02 +0000854static int abis_nm_rcvmsg_report(struct msgb *mb)
855{
856 struct abis_om_fom_hdr *foh = msgb_l3(mb);
857 u_int8_t mt = foh->msg_type;
858
Harald Weltea8bd6d42009-10-20 09:56:18 +0200859 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000860
Harald Welte97ed1e72009-02-06 13:38:02 +0000861 //nmh->cfg->report_cb(mb, foh);
862
863 switch (mt) {
864 case NM_MT_STATECHG_EVENT_REP:
865 return abis_nm_rx_statechg_rep(mb);
866 break;
Harald Welte34a99682009-02-13 02:41:40 +0000867 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000868 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000869 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000870 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000871 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000872 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000873 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000874 break;
Harald Weltec7310382009-08-08 00:02:36 +0200875 case NM_MT_TEST_REP:
876 DEBUGPC(DNM, "Test Report\n");
877 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
878 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000879 default:
Harald Welte23897662009-05-01 14:52:51 +0000880 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000881 break;
882
Harald Welte97ed1e72009-02-06 13:38:02 +0000883 };
884
Harald Welte97ed1e72009-02-06 13:38:02 +0000885 return 0;
886}
887
Harald Welte34a99682009-02-13 02:41:40 +0000888/* Activate the specified software into the BTS */
889static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
Mike Habena03f9772009-10-01 14:56:13 +0200890 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000891{
892 struct abis_om_hdr *oh;
893 struct msgb *msg = nm_msgb_alloc();
894 u_int8_t len = swdesc_len;
895 u_int8_t *trailer;
896
897 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
898 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
899
900 trailer = msgb_put(msg, swdesc_len);
901 memcpy(trailer, sw_desc, swdesc_len);
902
903 return abis_nm_sendmsg(bts, msg);
904}
905
906static int abis_nm_rx_sw_act_req(struct msgb *mb)
907{
908 struct abis_om_hdr *oh = msgb_l2(mb);
909 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200910 struct tlv_parsed tp;
911 const u_int8_t *sw_config;
912 int sw_config_len;
913 int file_id_len;
Harald Welte5c1e4582009-02-15 11:57:29 +0000914 int nack = 0;
Harald Welte34a99682009-02-13 02:41:40 +0000915 int ret;
916
Harald Weltea8bd6d42009-10-20 09:56:18 +0200917 debugp_foh(foh);
918
919 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000920
Harald Welte5c1e4582009-02-15 11:57:29 +0000921 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
922 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
923 nack = 1;
924 } else
925 DEBUGPC(DNM, "ACKing and Activating\n");
926
927 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000928 foh->obj_inst.bts_nr,
929 foh->obj_inst.trx_nr,
Harald Welte5c1e4582009-02-15 11:57:29 +0000930 foh->obj_inst.ts_nr, nack,
Harald Welte34a99682009-02-13 02:41:40 +0000931 foh->data, oh->length-sizeof(*foh));
932
Harald Welte5c1e4582009-02-15 11:57:29 +0000933 if (nack)
934 return ret;
935
Mike Habena03f9772009-10-01 14:56:13 +0200936 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
937 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
938 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
939 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
940 DEBUGP(DNM, "SW config not found! Can't continue.\n");
941 return -EINVAL;
942 } else {
943 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
944 }
945
946 if (sw_config[0] != NM_ATT_SW_DESCR)
947 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
948 if (sw_config[1] != NM_ATT_FILE_ID)
949 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
950 file_id_len = sw_config[2] * 256 + sw_config[3];
951
952 /* Assumes first SW file in list is the one to be activated */
953 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000954 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
955 foh->obj_inst.bts_nr,
956 foh->obj_inst.trx_nr,
957 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200958 sw_config + 4,
959 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000960}
961
Harald Weltee0590df2009-02-15 03:34:15 +0000962/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
963static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
964{
965 struct abis_om_hdr *oh = msgb_l2(mb);
966 struct abis_om_fom_hdr *foh = msgb_l3(mb);
967 struct tlv_parsed tp;
968 u_int8_t adm_state;
969
Harald Welte03133942009-02-18 19:51:53 +0000970 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000971 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
972 return -EINVAL;
973
974 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
975
976 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
977}
978
Harald Welteee670472009-02-22 21:58:49 +0000979static int abis_nm_rx_lmt_event(struct msgb *mb)
980{
981 struct abis_om_hdr *oh = msgb_l2(mb);
982 struct abis_om_fom_hdr *foh = msgb_l3(mb);
983 struct tlv_parsed tp;
984
985 DEBUGP(DNM, "LMT Event ");
986 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
987 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
988 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
989 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
990 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
991 }
992 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
993 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
994 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
995 DEBUGPC(DNM, "Level=%u ", level);
996 }
997 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
998 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
999 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1000 DEBUGPC(DNM, "Username=%s ", name);
1001 }
1002 DEBUGPC(DNM, "\n");
1003 /* FIXME: parse LMT LOGON TIME */
1004 return 0;
1005}
1006
Harald Welte52b1f982008-12-23 20:25:15 +00001007/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001008static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001009{
Harald Welte6c96ba52009-05-01 13:03:40 +00001010 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001011 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1012 u_int8_t mt = foh->msg_type;
1013
1014 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001015 if (is_report(mt))
1016 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001017
Harald Welte4724f992009-01-18 18:01:49 +00001018 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1019 return abis_nm_rcvmsg_sw(mb);
1020
Harald Welte78fc0d42009-02-19 02:50:57 +00001021 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +00001022 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001023
Harald Weltea8bd6d42009-10-20 09:56:18 +02001024 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001025
Harald Welte78fc0d42009-02-19 02:50:57 +00001026 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +02001027 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +00001028 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +00001029 else
Harald Welte4bd0a982009-10-08 20:18:59 +02001030 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +00001031
1032 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1033 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1034 DEBUGPC(DNM, "CAUSE=%s\n",
1035 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1036 else
1037 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001038
Harald Welted8cfc902009-11-17 06:09:56 +01001039 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001040 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001041 }
Harald Weltead384642008-12-26 10:20:07 +00001042#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001043 /* check if last message is to be acked */
1044 if (is_ack_nack(nmh->last_msgtype)) {
1045 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001046 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001047 /* we got our ACK, continue sending the next msg */
1048 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1049 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001050 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001051 /* FIXME: somehow signal this to the caller */
1052 } else {
1053 /* really strange things happen */
1054 return -EINVAL;
1055 }
1056 }
Harald Weltead384642008-12-26 10:20:07 +00001057#endif
1058
Harald Welte97ed1e72009-02-06 13:38:02 +00001059 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001060 case NM_MT_CHG_ADM_STATE_ACK:
1061 return abis_nm_rx_chg_adm_state_ack(mb);
1062 break;
Harald Welte34a99682009-02-13 02:41:40 +00001063 case NM_MT_SW_ACT_REQ:
1064 return abis_nm_rx_sw_act_req(mb);
1065 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001066 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001067 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001068 break;
Harald Welte1989c082009-08-06 17:58:31 +02001069 case NM_MT_CONN_MDROP_LINK_ACK:
1070 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1071 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001072 }
1073
Harald Weltead384642008-12-26 10:20:07 +00001074 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001075}
1076
Harald Welte677c21f2009-02-17 13:22:23 +00001077static int abis_nm_rx_ipacc(struct msgb *mb);
1078
1079static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1080{
1081 int rc;
1082 int bts_type = mb->trx->bts->type;
1083
1084 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001085 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001086 rc = abis_nm_rx_ipacc(mb);
1087 break;
1088 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001089 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1090 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001091 rc = 0;
1092 break;
1093 }
1094
1095 return rc;
1096}
1097
Harald Welte52b1f982008-12-23 20:25:15 +00001098/* High-Level API */
1099/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001100int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001101{
Harald Welte52b1f982008-12-23 20:25:15 +00001102 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001103 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001104
1105 /* Various consistency checks */
1106 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001107 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001108 oh->placement);
1109 return -EINVAL;
1110 }
1111 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001112 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001113 oh->sequence);
1114 return -EINVAL;
1115 }
Harald Welte702d8702008-12-26 20:25:35 +00001116#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001117 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1118 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001119 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001120 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001121 oh->length + sizeof(*oh), l2_len);
1122 return -EINVAL;
1123 }
Harald Welte702d8702008-12-26 20:25:35 +00001124 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001125 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte702d8702008-12-26 20:25:35 +00001126#endif
Harald Weltead384642008-12-26 10:20:07 +00001127 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001128
1129 switch (oh->mdisc) {
1130 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001131 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001132 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001133 case ABIS_OM_MDISC_MANUF:
1134 rc = abis_nm_rcvmsg_manuf(msg);
1135 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001136 case ABIS_OM_MDISC_MMI:
1137 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001138 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001139 oh->mdisc);
1140 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001141 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001142 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001143 oh->mdisc);
1144 return -EINVAL;
1145 }
1146
Harald Weltead384642008-12-26 10:20:07 +00001147 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001148 return rc;
1149}
1150
1151#if 0
1152/* initialized all resources */
1153struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1154{
1155 struct abis_nm_h *nmh;
1156
1157 nmh = malloc(sizeof(*nmh));
1158 if (!nmh)
1159 return NULL;
1160
1161 nmh->cfg = cfg;
1162
1163 return nmh;
1164}
1165
1166/* free all resources */
1167void abis_nm_fini(struct abis_nm_h *nmh)
1168{
1169 free(nmh);
1170}
1171#endif
1172
1173/* Here we are trying to define a high-level API that can be used by
1174 * the actual BSC implementation. However, the architecture is currently
1175 * still under design. Ideally the calls to this API would be synchronous,
1176 * while the underlying stack behind the APi runs in a traditional select
1177 * based state machine.
1178 */
1179
Harald Welte4724f992009-01-18 18:01:49 +00001180/* 6.2 Software Load: */
1181enum sw_state {
1182 SW_STATE_NONE,
1183 SW_STATE_WAIT_INITACK,
1184 SW_STATE_WAIT_SEGACK,
1185 SW_STATE_WAIT_ENDACK,
1186 SW_STATE_WAIT_ACTACK,
1187 SW_STATE_ERROR,
1188};
Harald Welte52b1f982008-12-23 20:25:15 +00001189
Harald Welte52b1f982008-12-23 20:25:15 +00001190struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001191 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001192 gsm_cbfn *cbfn;
1193 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001194 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001195
Harald Welte52b1f982008-12-23 20:25:15 +00001196 /* this will become part of the SW LOAD INITIATE */
1197 u_int8_t obj_class;
1198 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001199
1200 u_int8_t file_id[255];
1201 u_int8_t file_id_len;
1202
1203 u_int8_t file_version[255];
1204 u_int8_t file_version_len;
1205
1206 u_int8_t window_size;
1207 u_int8_t seg_in_window;
1208
1209 int fd;
1210 FILE *stream;
1211 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001212 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001213};
1214
Harald Welte4724f992009-01-18 18:01:49 +00001215static struct abis_nm_sw g_sw;
1216
1217/* 6.2.1 / 8.3.1: Load Data Initiate */
1218static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001219{
Harald Welte4724f992009-01-18 18:01:49 +00001220 struct abis_om_hdr *oh;
1221 struct msgb *msg = nm_msgb_alloc();
1222 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1223
1224 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1225 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1226 sw->obj_instance[0], sw->obj_instance[1],
1227 sw->obj_instance[2]);
1228
1229 /* FIXME: this is BS11 specific format */
1230 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1231 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1232 sw->file_version);
1233 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1234
1235 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001236}
1237
Harald Welte1602ade2009-01-29 21:12:39 +00001238static int is_last_line(FILE *stream)
1239{
1240 char next_seg_buf[256];
1241 long pos;
1242
1243 /* check if we're sending the last line */
1244 pos = ftell(stream);
1245 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1246 fseek(stream, pos, SEEK_SET);
1247 return 1;
1248 }
1249
1250 fseek(stream, pos, SEEK_SET);
1251 return 0;
1252}
1253
Harald Welte4724f992009-01-18 18:01:49 +00001254/* 6.2.2 / 8.3.2 Load Data Segment */
1255static int sw_load_segment(struct abis_nm_sw *sw)
1256{
1257 struct abis_om_hdr *oh;
1258 struct msgb *msg = nm_msgb_alloc();
1259 char seg_buf[256];
1260 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001261 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001262 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001263
1264 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001265
1266 switch (sw->bts->type) {
1267 case GSM_BTS_TYPE_BS11:
1268 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1269 perror("fgets reading segment");
1270 return -EINVAL;
1271 }
1272 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001273
1274 /* check if we're sending the last line */
1275 sw->last_seg = is_last_line(sw->stream);
1276 if (sw->last_seg)
1277 seg_buf[1] = 0;
1278 else
1279 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001280
1281 len = strlen(line_buf) + 2;
1282 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1283 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1284 /* BS11 wants CR + LF in excess of the TLV length !?! */
1285 tlv[1] -= 2;
1286
1287 /* we only now know the exact length for the OM hdr */
1288 len = strlen(line_buf)+2;
1289 break;
1290 default:
1291 /* FIXME: Other BTS types */
1292 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001293 }
Harald Welte4724f992009-01-18 18:01:49 +00001294
Harald Welte4724f992009-01-18 18:01:49 +00001295 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1296 sw->obj_instance[0], sw->obj_instance[1],
1297 sw->obj_instance[2]);
1298
1299 return abis_nm_sendmsg(sw->bts, msg);
1300}
1301
1302/* 6.2.4 / 8.3.4 Load Data End */
1303static int sw_load_end(struct abis_nm_sw *sw)
1304{
1305 struct abis_om_hdr *oh;
1306 struct msgb *msg = nm_msgb_alloc();
1307 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1308
1309 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1310 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1311 sw->obj_instance[0], sw->obj_instance[1],
1312 sw->obj_instance[2]);
1313
1314 /* FIXME: this is BS11 specific format */
1315 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1316 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1317 sw->file_version);
1318
1319 return abis_nm_sendmsg(sw->bts, msg);
1320}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001321
Harald Welte52b1f982008-12-23 20:25:15 +00001322/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001323static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001324{
Harald Welte4724f992009-01-18 18:01:49 +00001325 struct abis_om_hdr *oh;
1326 struct msgb *msg = nm_msgb_alloc();
1327 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001328
Harald Welte4724f992009-01-18 18:01:49 +00001329 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1330 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1331 sw->obj_instance[0], sw->obj_instance[1],
1332 sw->obj_instance[2]);
1333
1334 /* FIXME: this is BS11 specific format */
1335 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1336 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1337 sw->file_version);
1338
1339 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001340}
Harald Welte4724f992009-01-18 18:01:49 +00001341
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001342struct sdp_firmware {
1343 char magic[4];
1344 char more_magic[4];
1345 unsigned int header_length;
1346 unsigned int file_length;
1347} __attribute__ ((packed));
1348
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001349static int parse_sdp_header(struct abis_nm_sw *sw)
1350{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001351 struct sdp_firmware firmware_header;
1352 int rc;
1353 struct stat stat;
1354
1355 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1356 if (rc != sizeof(firmware_header)) {
1357 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1358 return -1;
1359 }
1360
1361 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1362 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1363 return -1;
1364 }
1365
1366 if (firmware_header.more_magic[0] != 0x10 ||
1367 firmware_header.more_magic[1] != 0x02 ||
1368 firmware_header.more_magic[2] != 0x00 ||
1369 firmware_header.more_magic[3] != 0x00) {
1370 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1371 return -1;
1372 }
1373
1374
1375 if (fstat(sw->fd, &stat) == -1) {
1376 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1377 return -1;
1378 }
1379
1380 if (ntohl(firmware_header.file_length) != stat.st_size) {
1381 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1382 return -1;
1383 }
1384
1385 /* go back to the start as we checked the whole filesize.. */
1386 lseek(sw->fd, 0l, SEEK_SET);
1387 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1388 "There might be checksums in the file that are not\n"
1389 "verified and incomplete firmware might be flashed.\n"
1390 "There is absolutely no WARRANTY that flashing will\n"
1391 "work.\n");
1392 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001393}
1394
Harald Welte4724f992009-01-18 18:01:49 +00001395static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1396{
1397 char file_id[12+1];
1398 char file_version[80+1];
1399 int rc;
1400
1401 sw->fd = open(fname, O_RDONLY);
1402 if (sw->fd < 0)
1403 return sw->fd;
1404
1405 switch (sw->bts->type) {
1406 case GSM_BTS_TYPE_BS11:
1407 sw->stream = fdopen(sw->fd, "r");
1408 if (!sw->stream) {
1409 perror("fdopen");
1410 return -1;
1411 }
1412 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001413 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001414 file_id, file_version);
1415 if (rc != 2) {
1416 perror("parsing header line of software file");
1417 return -1;
1418 }
1419 strcpy((char *)sw->file_id, file_id);
1420 sw->file_id_len = strlen(file_id);
1421 strcpy((char *)sw->file_version, file_version);
1422 sw->file_version_len = strlen(file_version);
1423 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001424 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001425 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001426 case GSM_BTS_TYPE_NANOBTS:
1427 sw->stream = fdopen(sw->fd, "r");
1428 if (!sw->stream) {
1429 perror("fdopen");
1430 return -1;
1431 }
1432
1433 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001434 rc = parse_sdp_header(sw);
1435 if (rc < 0) {
1436 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1437 return -1;
1438 }
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001439 break;
Harald Welte4724f992009-01-18 18:01:49 +00001440 default:
1441 /* We don't know how to treat them yet */
1442 close(sw->fd);
1443 return -EINVAL;
1444 }
1445
1446 return 0;
1447}
1448
1449static void sw_close_file(struct abis_nm_sw *sw)
1450{
1451 switch (sw->bts->type) {
1452 case GSM_BTS_TYPE_BS11:
1453 fclose(sw->stream);
1454 break;
1455 default:
1456 close(sw->fd);
1457 break;
1458 }
1459}
1460
1461/* Fill the window */
1462static int sw_fill_window(struct abis_nm_sw *sw)
1463{
1464 int rc;
1465
1466 while (sw->seg_in_window < sw->window_size) {
1467 rc = sw_load_segment(sw);
1468 if (rc < 0)
1469 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001470 if (sw->last_seg)
1471 break;
Harald Welte4724f992009-01-18 18:01:49 +00001472 }
1473 return 0;
1474}
1475
1476/* callback function from abis_nm_rcvmsg() handler */
1477static int abis_nm_rcvmsg_sw(struct msgb *mb)
1478{
1479 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1480 int rc = -1;
1481 struct abis_nm_sw *sw = &g_sw;
1482 enum sw_state old_state = sw->state;
1483
Harald Welte3ffd1372009-02-01 22:15:49 +00001484 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001485
1486 switch (sw->state) {
1487 case SW_STATE_WAIT_INITACK:
1488 switch (foh->msg_type) {
1489 case NM_MT_LOAD_INIT_ACK:
1490 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001491 if (sw->cbfn)
1492 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1493 NM_MT_LOAD_INIT_ACK, mb,
1494 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001495 rc = sw_fill_window(sw);
1496 sw->state = SW_STATE_WAIT_SEGACK;
1497 break;
1498 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001499 if (sw->forced) {
1500 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1501 "Init NACK\n");
1502 if (sw->cbfn)
1503 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1504 NM_MT_LOAD_INIT_ACK, mb,
1505 sw->cb_data, NULL);
1506 rc = sw_fill_window(sw);
1507 sw->state = SW_STATE_WAIT_SEGACK;
1508 } else {
1509 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001510 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001511 if (sw->cbfn)
1512 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1513 NM_MT_LOAD_INIT_NACK, mb,
1514 sw->cb_data, NULL);
1515 sw->state = SW_STATE_ERROR;
1516 }
Harald Welte4724f992009-01-18 18:01:49 +00001517 break;
1518 }
1519 break;
1520 case SW_STATE_WAIT_SEGACK:
1521 switch (foh->msg_type) {
1522 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001523 if (sw->cbfn)
1524 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1525 NM_MT_LOAD_SEG_ACK, mb,
1526 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001527 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001528 if (!sw->last_seg) {
1529 /* fill window with more segments */
1530 rc = sw_fill_window(sw);
1531 sw->state = SW_STATE_WAIT_SEGACK;
1532 } else {
1533 /* end the transfer */
1534 sw->state = SW_STATE_WAIT_ENDACK;
1535 rc = sw_load_end(sw);
1536 }
Harald Welte4724f992009-01-18 18:01:49 +00001537 break;
1538 }
1539 break;
1540 case SW_STATE_WAIT_ENDACK:
1541 switch (foh->msg_type) {
1542 case NM_MT_LOAD_END_ACK:
1543 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001544 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1545 sw->bts->nr);
1546 sw->state = SW_STATE_NONE;
1547 if (sw->cbfn)
1548 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1549 NM_MT_LOAD_END_ACK, mb,
1550 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001551 break;
1552 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001553 if (sw->forced) {
1554 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1555 "End NACK\n");
1556 sw->state = SW_STATE_NONE;
1557 if (sw->cbfn)
1558 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1559 NM_MT_LOAD_END_ACK, mb,
1560 sw->cb_data, NULL);
1561 } else {
1562 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001563 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001564 sw->state = SW_STATE_ERROR;
1565 if (sw->cbfn)
1566 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1567 NM_MT_LOAD_END_NACK, mb,
1568 sw->cb_data, NULL);
1569 }
Harald Welte4724f992009-01-18 18:01:49 +00001570 break;
1571 }
1572 case SW_STATE_WAIT_ACTACK:
1573 switch (foh->msg_type) {
1574 case NM_MT_ACTIVATE_SW_ACK:
1575 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001576 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001577 sw->state = SW_STATE_NONE;
1578 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001579 if (sw->cbfn)
1580 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1581 NM_MT_ACTIVATE_SW_ACK, mb,
1582 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001583 break;
1584 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001585 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001586 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001587 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001588 if (sw->cbfn)
1589 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1590 NM_MT_ACTIVATE_SW_NACK, mb,
1591 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001592 break;
1593 }
1594 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001595 switch (foh->msg_type) {
1596 case NM_MT_ACTIVATE_SW_ACK:
1597 rc = 0;
1598 break;
1599 }
1600 break;
Harald Welte4724f992009-01-18 18:01:49 +00001601 case SW_STATE_ERROR:
1602 break;
1603 }
1604
1605 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001606 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001607 foh->msg_type, old_state, sw->state);
1608
1609 return rc;
1610}
1611
1612/* Load the specified software into the BTS */
1613int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001614 u_int8_t win_size, int forced,
1615 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001616{
1617 struct abis_nm_sw *sw = &g_sw;
1618 int rc;
1619
Harald Welte5e4d1b32009-02-01 13:36:56 +00001620 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1621 bts->nr, fname);
1622
Harald Welte4724f992009-01-18 18:01:49 +00001623 if (sw->state != SW_STATE_NONE)
1624 return -EBUSY;
1625
1626 sw->bts = bts;
1627 sw->obj_class = NM_OC_SITE_MANAGER;
1628 sw->obj_instance[0] = 0xff;
1629 sw->obj_instance[1] = 0xff;
1630 sw->obj_instance[2] = 0xff;
1631 sw->window_size = win_size;
1632 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001633 sw->cbfn = cbfn;
1634 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001635 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001636
1637 rc = sw_open_file(sw, fname);
1638 if (rc < 0) {
1639 sw->state = SW_STATE_NONE;
1640 return rc;
1641 }
1642
1643 return sw_load_init(sw);
1644}
Harald Welte52b1f982008-12-23 20:25:15 +00001645
Harald Welte1602ade2009-01-29 21:12:39 +00001646int abis_nm_software_load_status(struct gsm_bts *bts)
1647{
1648 struct abis_nm_sw *sw = &g_sw;
1649 struct stat st;
1650 int rc, percent;
1651
1652 rc = fstat(sw->fd, &st);
1653 if (rc < 0) {
1654 perror("ERROR during stat");
1655 return rc;
1656 }
1657
1658 percent = (ftell(sw->stream) * 100) / st.st_size;
1659 return percent;
1660}
1661
Harald Welte5e4d1b32009-02-01 13:36:56 +00001662/* Activate the specified software into the BTS */
1663int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1664 gsm_cbfn *cbfn, void *cb_data)
1665{
1666 struct abis_nm_sw *sw = &g_sw;
1667 int rc;
1668
1669 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1670 bts->nr, fname);
1671
1672 if (sw->state != SW_STATE_NONE)
1673 return -EBUSY;
1674
1675 sw->bts = bts;
1676 sw->obj_class = NM_OC_SITE_MANAGER;
1677 sw->obj_instance[0] = 0xff;
1678 sw->obj_instance[1] = 0xff;
1679 sw->obj_instance[2] = 0xff;
1680 sw->state = SW_STATE_WAIT_ACTACK;
1681 sw->cbfn = cbfn;
1682 sw->cb_data = cb_data;
1683
1684 /* Open the file in order to fill some sw struct members */
1685 rc = sw_open_file(sw, fname);
1686 if (rc < 0) {
1687 sw->state = SW_STATE_NONE;
1688 return rc;
1689 }
1690 sw_close_file(sw);
1691
1692 return sw_activate(sw);
1693}
1694
Harald Welte8470bf22008-12-25 23:28:35 +00001695static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001696 u_int8_t ts_nr, u_int8_t subslot_nr)
1697{
Harald Welteadaf08b2009-01-18 11:08:10 +00001698 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001699 ch->bts_port = bts_port;
1700 ch->timeslot = ts_nr;
1701 ch->subslot = subslot_nr;
1702}
1703
1704int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1705 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1706 u_int8_t tei)
1707{
1708 struct abis_om_hdr *oh;
1709 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001710 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001711 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001712
1713 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1714 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1715 bts->bts_nr, trx_nr, 0xff);
1716
Harald Welte8470bf22008-12-25 23:28:35 +00001717 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001718
1719 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1720 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1721
1722 return abis_nm_sendmsg(bts, msg);
1723}
1724
1725/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1726int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1727 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1728{
Harald Welte8470bf22008-12-25 23:28:35 +00001729 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001730 struct abis_om_hdr *oh;
1731 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001732 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001733
1734 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001735 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001736 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1737
1738 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1739 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1740
1741 return abis_nm_sendmsg(bts, msg);
1742}
1743
1744#if 0
1745int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1746 struct abis_nm_abis_channel *chan)
1747{
1748}
1749#endif
1750
1751int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1752 u_int8_t e1_port, u_int8_t e1_timeslot,
1753 u_int8_t e1_subslot)
1754{
1755 struct gsm_bts *bts = ts->trx->bts;
1756 struct abis_om_hdr *oh;
1757 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001758 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001759
1760 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1761 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001762 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001763
1764 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1765 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1766
Harald Weltef325eb42009-02-19 17:07:39 +00001767 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1768 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001769 e1_port, e1_timeslot, e1_subslot);
1770
Harald Welte52b1f982008-12-23 20:25:15 +00001771 return abis_nm_sendmsg(bts, msg);
1772}
1773
1774#if 0
1775int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1776 struct abis_nm_abis_channel *chan,
1777 u_int8_t subchan)
1778{
1779}
1780#endif
1781
Harald Welte22af0db2009-02-14 15:41:08 +00001782/* Chapter 8.6.1 */
1783int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1784{
1785 struct abis_om_hdr *oh;
1786 struct msgb *msg = nm_msgb_alloc();
1787 u_int8_t *cur;
1788
1789 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1790
1791 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001792 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001793 cur = msgb_put(msg, attr_len);
1794 memcpy(cur, attr, attr_len);
1795
1796 return abis_nm_sendmsg(bts, msg);
1797}
1798
1799/* Chapter 8.6.2 */
1800int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1801{
1802 struct abis_om_hdr *oh;
1803 struct msgb *msg = nm_msgb_alloc();
1804 u_int8_t *cur;
1805
1806 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1807
1808 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1809 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001810 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001811 cur = msgb_put(msg, attr_len);
1812 memcpy(cur, attr, attr_len);
1813
1814 return abis_nm_sendmsg(trx->bts, msg);
1815}
1816
Harald Welte39c7deb2009-08-09 21:49:48 +02001817static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1818{
1819 int i;
1820
1821 /* As it turns out, the BS-11 has some very peculiar restrictions
1822 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301823 switch (ts->trx->bts->type) {
1824 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001825 switch (chan_comb) {
1826 case NM_CHANC_TCHHalf:
1827 case NM_CHANC_TCHHalf2:
1828 /* not supported */
1829 return -EINVAL;
1830 case NM_CHANC_SDCCH:
1831 /* only one SDCCH/8 per TRX */
1832 for (i = 0; i < TRX_NR_TS; i++) {
1833 if (i == ts->nr)
1834 continue;
1835 if (ts->trx->ts[i].nm_chan_comb ==
1836 NM_CHANC_SDCCH)
1837 return -EINVAL;
1838 }
1839 /* not allowed for TS0 of BCCH-TRX */
1840 if (ts->trx == ts->trx->bts->c0 &&
1841 ts->nr == 0)
1842 return -EINVAL;
1843 /* not on the same TRX that has a BCCH+SDCCH4
1844 * combination */
1845 if (ts->trx == ts->trx->bts->c0 &&
1846 (ts->trx->ts[0].nm_chan_comb == 5 ||
1847 ts->trx->ts[0].nm_chan_comb == 8))
1848 return -EINVAL;
1849 break;
1850 case NM_CHANC_mainBCCH:
1851 case NM_CHANC_BCCHComb:
1852 /* allowed only for TS0 of C0 */
1853 if (ts->trx != ts->trx->bts->c0 ||
1854 ts->nr != 0)
1855 return -EINVAL;
1856 break;
1857 case NM_CHANC_BCCH:
1858 /* allowed only for TS 2/4/6 of C0 */
1859 if (ts->trx != ts->trx->bts->c0)
1860 return -EINVAL;
1861 if (ts->nr != 2 && ts->nr != 4 &&
1862 ts->nr != 6)
1863 return -EINVAL;
1864 break;
1865 case 8: /* this is not like 08.58, but in fact
1866 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1867 /* FIXME: only one CBCH allowed per cell */
1868 break;
1869 }
Harald Welted6575f92009-12-02 02:45:23 +05301870 break;
1871 case GSM_BTS_TYPE_NANOBTS:
1872 switch (ts->nr) {
1873 case 0:
1874 if (ts->trx->nr == 0) {
1875 /* only on TRX0 */
1876 switch (chan_comb) {
1877 case NM_CHANC_BCCH:
1878 case NM_CHANC_mainBCCH:
1879 case NM_CHANC_BCCHComb:
1880 return 0;
1881 break;
1882 default:
1883 return -EINVAL;
1884 }
1885 } else {
1886 switch (chan_comb) {
1887 case NM_CHANC_TCHFull:
1888 case NM_CHANC_TCHHalf:
1889 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1890 return 0;
1891 default:
1892 return -EINVAL;
1893 }
1894 }
1895 break;
1896 case 1:
1897 if (ts->trx->nr == 0) {
1898 switch (chan_comb) {
1899 case NM_CHANC_SDCCH_CBCH:
1900 if (ts->trx->ts[0].nm_chan_comb ==
1901 NM_CHANC_mainBCCH)
1902 return 0;
1903 return -EINVAL;
1904 case NM_CHANC_SDCCH:
1905 case NM_CHANC_TCHFull:
1906 case NM_CHANC_TCHHalf:
1907 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1908 case NM_CHANC_IPAC_TCHFull_PDCH:
1909 return 0;
1910 }
1911 } else {
1912 switch (chan_comb) {
1913 case NM_CHANC_SDCCH:
1914 case NM_CHANC_TCHFull:
1915 case NM_CHANC_TCHHalf:
1916 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1917 return 0;
1918 default:
1919 return -EINVAL;
1920 }
1921 }
1922 break;
1923 case 2:
1924 case 3:
1925 case 4:
1926 case 5:
1927 case 6:
1928 case 7:
1929 switch (chan_comb) {
1930 case NM_CHANC_TCHFull:
1931 case NM_CHANC_TCHHalf:
1932 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1933 return 0;
1934 case NM_CHANC_IPAC_PDCH:
1935 case NM_CHANC_IPAC_TCHFull_PDCH:
1936 if (ts->trx->nr == 0)
1937 return 0;
1938 else
1939 return -EINVAL;
1940 }
1941 break;
1942 }
1943 return -EINVAL;
1944 default:
1945 /* unknown BTS type */
1946 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001947 }
1948 return 0;
1949}
1950
Harald Welte22af0db2009-02-14 15:41:08 +00001951/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001952int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1953{
1954 struct gsm_bts *bts = ts->trx->bts;
1955 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001956 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001957 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001958 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001959 u_int8_t len = 2 + 2;
1960
1961 if (bts->type == GSM_BTS_TYPE_BS11)
1962 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001963
Harald Weltef325eb42009-02-19 17:07:39 +00001964 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001965 if (verify_chan_comb(ts, chan_comb) < 0) {
1966 msgb_free(msg);
1967 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1968 return -EINVAL;
1969 }
1970 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001971
Harald Welte52b1f982008-12-23 20:25:15 +00001972 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001973 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001974 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001975 ts->trx->nr, ts->nr);
1976 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00001977 if (bts->type == GSM_BTS_TYPE_BS11)
1978 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001979 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00001980 if (bts->type == GSM_BTS_TYPE_BS11) {
1981 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1982 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1983 }
Harald Weltee6c22d92009-07-21 20:40:05 +02001984 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001985 if (bts->type == GSM_BTS_TYPE_BS11)
1986 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001987
1988 return abis_nm_sendmsg(bts, msg);
1989}
1990
Harald Welte34a99682009-02-13 02:41:40 +00001991int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
Harald Welte5c1e4582009-02-15 11:57:29 +00001992 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001993{
1994 struct abis_om_hdr *oh;
1995 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00001996 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1997 u_int8_t len = att_len;
1998
1999 if (nack) {
2000 len += 2;
2001 msgtype = NM_MT_SW_ACT_REQ_NACK;
2002 }
Harald Welte34a99682009-02-13 02:41:40 +00002003
2004 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002005 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2006
Harald Welte34a99682009-02-13 02:41:40 +00002007 if (attr) {
2008 u_int8_t *ptr = msgb_put(msg, att_len);
2009 memcpy(ptr, attr, att_len);
2010 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002011 if (nack)
2012 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002013
2014 return abis_nm_sendmsg(bts, msg);
2015}
2016
Harald Welte8470bf22008-12-25 23:28:35 +00002017int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002018{
Harald Welte8470bf22008-12-25 23:28:35 +00002019 struct msgb *msg = nm_msgb_alloc();
2020 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002021 u_int8_t *data;
2022
2023 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2024 fill_om_hdr(oh, len);
2025 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002026 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002027
2028 return abis_nm_sendmsg(bts, msg);
2029}
2030
2031/* Siemens specific commands */
2032static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2033{
2034 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002035 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002036
2037 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002038 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002039 0xff, 0xff, 0xff);
2040
2041 return abis_nm_sendmsg(bts, msg);
2042}
2043
Harald Welte34a99682009-02-13 02:41:40 +00002044/* Chapter 8.9.2 */
2045int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2046{
2047 struct abis_om_hdr *oh;
2048 struct msgb *msg = nm_msgb_alloc();
2049
2050 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2051 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2052
Harald Weltea8bd6d42009-10-20 09:56:18 +02002053 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2054 DEBUGPC(DNM, "Sending OPSTART\n");
2055
Harald Welte34a99682009-02-13 02:41:40 +00002056 return abis_nm_sendmsg(bts, msg);
2057}
2058
2059/* Chapter 8.8.5 */
2060int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002061 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002062{
2063 struct abis_om_hdr *oh;
2064 struct msgb *msg = nm_msgb_alloc();
2065
2066 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2067 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2068 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2069
2070 return abis_nm_sendmsg(bts, msg);
2071}
2072
Harald Welte1989c082009-08-06 17:58:31 +02002073int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2074 u_int8_t e1_port1, u_int8_t ts1)
2075{
2076 struct abis_om_hdr *oh;
2077 struct msgb *msg = nm_msgb_alloc();
2078 u_int8_t *attr;
2079
2080 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2081 e1_port0, ts0, e1_port1, ts1);
2082
2083 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2084 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2085 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2086
2087 attr = msgb_put(msg, 3);
2088 attr[0] = NM_ATT_MDROP_LINK;
2089 attr[1] = e1_port0;
2090 attr[2] = ts0;
2091
2092 attr = msgb_put(msg, 3);
2093 attr[0] = NM_ATT_MDROP_NEXT;
2094 attr[1] = e1_port1;
2095 attr[2] = ts1;
2096
2097 return abis_nm_sendmsg(bts, msg);
2098}
Harald Welte34a99682009-02-13 02:41:40 +00002099
Harald Weltec7310382009-08-08 00:02:36 +02002100/* Chapter 8.7.1 */
2101int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2102 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2103 u_int8_t test_nr, u_int8_t auton_report,
2104 u_int8_t *phys_config, u_int16_t phys_config_len)
2105{
2106 struct abis_om_hdr *oh;
2107 struct msgb *msg = nm_msgb_alloc();
2108 int len = 4; /* 2 TV attributes */
2109
2110 DEBUGP(DNM, "PEFORM TEST\n");
2111
2112 if (phys_config_len)
2113 len += 3 + phys_config_len;
2114
2115 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2116 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2117 obj_class, bts_nr, trx_nr, ts_nr);
2118 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2119 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2120 if (phys_config_len)
2121 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2122 phys_config);
2123
2124 return abis_nm_sendmsg(bts, msg);
2125}
2126
Harald Welte52b1f982008-12-23 20:25:15 +00002127int abis_nm_event_reports(struct gsm_bts *bts, int on)
2128{
2129 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002130 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002131 else
Harald Welte227d4072009-01-03 08:16:25 +00002132 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002133}
2134
Harald Welte47d88ae2009-01-04 12:02:08 +00002135/* Siemens (or BS-11) specific commands */
2136
Harald Welte3ffd1372009-02-01 22:15:49 +00002137int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2138{
2139 if (reconnect == 0)
2140 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2141 else
2142 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2143}
2144
Harald Welteb8427972009-02-05 19:27:17 +00002145int abis_nm_bs11_restart(struct gsm_bts *bts)
2146{
2147 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2148}
2149
2150
Harald Welte268bb402009-02-01 19:11:56 +00002151struct bs11_date_time {
2152 u_int16_t year;
2153 u_int8_t month;
2154 u_int8_t day;
2155 u_int8_t hour;
2156 u_int8_t min;
2157 u_int8_t sec;
2158} __attribute__((packed));
2159
2160
2161void get_bs11_date_time(struct bs11_date_time *aet)
2162{
2163 time_t t;
2164 struct tm *tm;
2165
2166 t = time(NULL);
2167 tm = localtime(&t);
2168 aet->sec = tm->tm_sec;
2169 aet->min = tm->tm_min;
2170 aet->hour = tm->tm_hour;
2171 aet->day = tm->tm_mday;
2172 aet->month = tm->tm_mon;
2173 aet->year = htons(1900 + tm->tm_year);
2174}
2175
Harald Welte05188ee2009-01-18 11:39:08 +00002176int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002177{
Harald Welte4668fda2009-01-03 08:19:29 +00002178 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002179}
2180
Harald Welte05188ee2009-01-18 11:39:08 +00002181int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002182{
2183 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002184 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002185 else
Harald Welte4668fda2009-01-03 08:19:29 +00002186 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002187}
Harald Welte47d88ae2009-01-04 12:02:08 +00002188
Harald Welte05188ee2009-01-18 11:39:08 +00002189int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002190 enum abis_bs11_objtype type, u_int8_t idx,
2191 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002192{
2193 struct abis_om_hdr *oh;
2194 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002195 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002196
2197 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002198 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002199 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002200 cur = msgb_put(msg, attr_len);
2201 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002202
2203 return abis_nm_sendmsg(bts, msg);
2204}
2205
Harald Welte78fc0d42009-02-19 02:50:57 +00002206int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2207 enum abis_bs11_objtype type, u_int8_t idx)
2208{
2209 struct abis_om_hdr *oh;
2210 struct msgb *msg = nm_msgb_alloc();
2211
2212 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2213 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2214 NM_OC_BS11, type, 0, idx);
2215
2216 return abis_nm_sendmsg(bts, msg);
2217}
2218
Harald Welte05188ee2009-01-18 11:39:08 +00002219int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002220{
2221 struct abis_om_hdr *oh;
2222 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002223 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002224
2225 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002226 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002227 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2228 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002229
2230 return abis_nm_sendmsg(bts, msg);
2231}
2232
Harald Welte05188ee2009-01-18 11:39:08 +00002233int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002234{
2235 struct abis_om_hdr *oh;
2236 struct msgb *msg = nm_msgb_alloc();
2237
2238 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2239 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002240 idx, 0xff, 0xff);
2241
2242 return abis_nm_sendmsg(bts, msg);
2243}
2244
2245int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2246{
2247 struct abis_om_hdr *oh;
2248 struct msgb *msg = nm_msgb_alloc();
2249
2250 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2251 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2252 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002253
2254 return abis_nm_sendmsg(bts, msg);
2255}
Harald Welte05188ee2009-01-18 11:39:08 +00002256
Harald Welte78fc0d42009-02-19 02:50:57 +00002257static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2258int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2259{
2260 struct abis_om_hdr *oh;
2261 struct msgb *msg = nm_msgb_alloc();
2262
2263 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2264 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2265 0xff, 0xff, 0xff);
2266 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2267
2268 return abis_nm_sendmsg(bts, msg);
2269}
2270
Harald Welteb6c92ae2009-02-21 20:15:32 +00002271/* like abis_nm_conn_terr_traf + set_tei */
2272int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2273 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2274 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002275{
2276 struct abis_om_hdr *oh;
2277 struct abis_nm_channel *ch;
2278 struct msgb *msg = nm_msgb_alloc();
2279
2280 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002281 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002282 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2283
2284 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2285 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002286 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002287
2288 return abis_nm_sendmsg(bts, msg);
2289}
2290
2291int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2292{
2293 struct abis_om_hdr *oh;
2294 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002295
2296 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002297 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002298 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2299 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2300
2301 return abis_nm_sendmsg(trx->bts, msg);
2302}
2303
Harald Welte78fc0d42009-02-19 02:50:57 +00002304int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2305{
2306 struct abis_om_hdr *oh;
2307 struct msgb *msg = nm_msgb_alloc();
2308 u_int8_t attr = NM_ATT_BS11_TXPWR;
2309
2310 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2311 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2312 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2313 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2314
2315 return abis_nm_sendmsg(trx->bts, msg);
2316}
2317
Harald Welteaaf02d92009-04-29 13:25:57 +00002318int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2319{
2320 struct abis_om_hdr *oh;
2321 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002322 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002323
2324 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2325 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2326 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002327 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002328
2329 return abis_nm_sendmsg(bts, msg);
2330}
2331
Harald Welteef061952009-05-17 12:43:42 +00002332int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2333{
2334 struct abis_om_hdr *oh;
2335 struct msgb *msg = nm_msgb_alloc();
2336 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2337 NM_ATT_BS11_CCLK_TYPE };
2338
2339 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2340 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2341 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2342 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2343
2344 return abis_nm_sendmsg(bts, msg);
2345
2346}
Harald Welteaaf02d92009-04-29 13:25:57 +00002347
Harald Welte268bb402009-02-01 19:11:56 +00002348//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +00002349static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +00002350static const u_int8_t bs11_logon_c9[] = "FACTORY";
2351
Harald Welte1bc09062009-01-18 14:17:52 +00002352int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002353{
2354 struct abis_om_hdr *oh;
2355 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002356 struct bs11_date_time bdt;
2357
2358 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002359
2360 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002361 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002362 u_int8_t len = 3*2 + sizeof(bdt)
Harald Welte6f676a32009-01-18 14:27:48 +00002363 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +00002364 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002365 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002366 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002367 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002368 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2369 sizeof(bs11_logon_c8), bs11_logon_c8);
2370 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2371 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +00002372 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002373 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002374 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002375 }
Harald Welte05188ee2009-01-18 11:39:08 +00002376
2377 return abis_nm_sendmsg(bts, msg);
2378}
Harald Welte1bc09062009-01-18 14:17:52 +00002379
2380int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2381{
2382 struct abis_om_hdr *oh;
2383 struct msgb *msg;
2384
2385 if (strlen(password) != 10)
2386 return -EINVAL;
2387
2388 msg = nm_msgb_alloc();
2389 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002390 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002391 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2392 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2393
2394 return abis_nm_sendmsg(bts, msg);
2395}
2396
Harald Weltee69f5fb2009-04-28 16:31:38 +00002397/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2398int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2399{
2400 struct abis_om_hdr *oh;
2401 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002402 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002403
2404 msg = nm_msgb_alloc();
2405 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2406 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2407 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002408
2409 if (locked)
2410 tlv_value = BS11_LI_PLL_LOCKED;
2411 else
2412 tlv_value = BS11_LI_PLL_STANDALONE;
2413
2414 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002415
2416 return abis_nm_sendmsg(bts, msg);
2417}
2418
Harald Welte1bc09062009-01-18 14:17:52 +00002419int abis_nm_bs11_get_state(struct gsm_bts *bts)
2420{
2421 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2422}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002423
2424/* BS11 SWL */
2425
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002426void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002427
Harald Welte5e4d1b32009-02-01 13:36:56 +00002428struct abis_nm_bs11_sw {
2429 struct gsm_bts *bts;
2430 char swl_fname[PATH_MAX];
2431 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002432 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002433 struct llist_head file_list;
2434 gsm_cbfn *user_cb; /* specified by the user */
2435};
2436static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2437
2438struct file_list_entry {
2439 struct llist_head list;
2440 char fname[PATH_MAX];
2441};
2442
2443struct file_list_entry *fl_dequeue(struct llist_head *queue)
2444{
2445 struct llist_head *lh;
2446
2447 if (llist_empty(queue))
2448 return NULL;
2449
2450 lh = queue->next;
2451 llist_del(lh);
2452
2453 return llist_entry(lh, struct file_list_entry, list);
2454}
2455
2456static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2457{
2458 char linebuf[255];
2459 struct llist_head *lh, *lh2;
2460 FILE *swl;
2461 int rc = 0;
2462
2463 swl = fopen(bs11_sw->swl_fname, "r");
2464 if (!swl)
2465 return -ENODEV;
2466
2467 /* zero the stale file list, if any */
2468 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2469 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002470 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002471 }
2472
2473 while (fgets(linebuf, sizeof(linebuf), swl)) {
2474 char file_id[12+1];
2475 char file_version[80+1];
2476 struct file_list_entry *fle;
2477 static char dir[PATH_MAX];
2478
2479 if (strlen(linebuf) < 4)
2480 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002481
Harald Welte5e4d1b32009-02-01 13:36:56 +00002482 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2483 if (rc < 0) {
2484 perror("ERR parsing SWL file");
2485 rc = -EINVAL;
2486 goto out;
2487 }
2488 if (rc < 2)
2489 continue;
2490
Harald Welte470ec292009-06-26 20:25:23 +02002491 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002492 if (!fle) {
2493 rc = -ENOMEM;
2494 goto out;
2495 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002496
2497 /* construct new filename */
2498 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2499 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2500 strcat(fle->fname, "/");
2501 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002502
2503 llist_add_tail(&fle->list, &bs11_sw->file_list);
2504 }
2505
2506out:
2507 fclose(swl);
2508 return rc;
2509}
2510
2511/* bs11 swload specific callback, passed to abis_nm core swload */
2512static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2513 struct msgb *msg, void *data, void *param)
2514{
2515 struct abis_nm_bs11_sw *bs11_sw = data;
2516 struct file_list_entry *fle;
2517 int rc = 0;
2518
Harald Welte5e4d1b32009-02-01 13:36:56 +00002519 switch (event) {
2520 case NM_MT_LOAD_END_ACK:
2521 fle = fl_dequeue(&bs11_sw->file_list);
2522 if (fle) {
2523 /* start download the next file of our file list */
2524 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2525 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002526 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002527 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002528 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002529 } else {
2530 /* activate the SWL */
2531 rc = abis_nm_software_activate(bs11_sw->bts,
2532 bs11_sw->swl_fname,
2533 bs11_swload_cbfn,
2534 bs11_sw);
2535 }
2536 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002537 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002538 case NM_MT_LOAD_END_NACK:
2539 case NM_MT_LOAD_INIT_ACK:
2540 case NM_MT_LOAD_INIT_NACK:
2541 case NM_MT_ACTIVATE_SW_NACK:
2542 case NM_MT_ACTIVATE_SW_ACK:
2543 default:
2544 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002545 if (bs11_sw->user_cb)
2546 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002547 break;
2548 }
2549
2550 return rc;
2551}
2552
2553/* Siemens provides a SWL file that is a mere listing of all the other
2554 * files that are part of a software release. We need to upload first
2555 * the list file, and then each file that is listed in the list file */
2556int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002557 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002558{
2559 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2560 struct file_list_entry *fle;
2561 int rc = 0;
2562
2563 INIT_LLIST_HEAD(&bs11_sw->file_list);
2564 bs11_sw->bts = bts;
2565 bs11_sw->win_size = win_size;
2566 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002567 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002568
2569 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2570 rc = bs11_read_swl_file(bs11_sw);
2571 if (rc < 0)
2572 return rc;
2573
2574 /* dequeue next item in file list */
2575 fle = fl_dequeue(&bs11_sw->file_list);
2576 if (!fle)
2577 return -EINVAL;
2578
2579 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002580 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002581 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002582 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002583 return rc;
2584}
2585
Harald Welte5083b0b2009-02-02 19:20:52 +00002586#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002587static u_int8_t req_attr_btse[] = {
2588 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2589 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2590 NM_ATT_BS11_LMT_USER_NAME,
2591
2592 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2593
2594 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2595
2596 NM_ATT_BS11_SW_LOAD_STORED };
2597
2598static u_int8_t req_attr_btsm[] = {
2599 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2600 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2601 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2602 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002603#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002604
2605static u_int8_t req_attr[] = {
2606 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2607 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002608 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002609
2610int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2611{
2612 struct abis_om_hdr *oh;
2613 struct msgb *msg = nm_msgb_alloc();
2614
2615 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2616 /* SiemensHW CCTRL object */
2617 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2618 0x03, 0x00, 0x00);
2619 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2620
2621 return abis_nm_sendmsg(bts, msg);
2622}
Harald Welte268bb402009-02-01 19:11:56 +00002623
2624int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2625{
2626 struct abis_om_hdr *oh;
2627 struct msgb *msg = nm_msgb_alloc();
2628 struct bs11_date_time aet;
2629
2630 get_bs11_date_time(&aet);
2631 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2632 /* SiemensHW CCTRL object */
2633 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2634 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002635 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002636
2637 return abis_nm_sendmsg(bts, msg);
2638}
Harald Welte5c1e4582009-02-15 11:57:29 +00002639
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002640int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2641{
2642 struct abis_om_hdr *oh;
2643 struct msgb *msg = nm_msgb_alloc();
2644 struct bs11_date_time aet;
2645
2646 get_bs11_date_time(&aet);
2647 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2648 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2649 bport, 0xff, 0x02);
2650 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2651
2652 return abis_nm_sendmsg(bts, msg);
2653}
2654
Harald Welte5c1e4582009-02-15 11:57:29 +00002655/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002656static const char ipaccess_magic[] = "com.ipaccess";
2657
Harald Welte677c21f2009-02-17 13:22:23 +00002658
2659static int abis_nm_rx_ipacc(struct msgb *msg)
2660{
2661 struct abis_om_hdr *oh = msgb_l2(msg);
2662 struct abis_om_fom_hdr *foh;
2663 u_int8_t idstrlen = oh->data[0];
2664 struct tlv_parsed tp;
2665
2666 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002667 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002668 return -EINVAL;
2669 }
2670
Harald Welte193fefc2009-04-30 15:16:27 +00002671 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002672 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002673
Harald Weltea8bd6d42009-10-20 09:56:18 +02002674 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002675
Harald Welte746d6092009-10-19 22:11:11 +02002676 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002677
Harald Welte677c21f2009-02-17 13:22:23 +00002678 switch (foh->msg_type) {
2679 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002680 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002681 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002682 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002683 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002684 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2685 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002686 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002687 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002688 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002689 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2690 DEBUGPC(DNM, "STREAM=0x%02x ",
2691 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002692 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002693 break;
2694 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002695 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002696 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002697 DEBUGPC(DNM, " CAUSE=%s\n",
2698 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002699 else
2700 DEBUGPC(DNM, "\n");
2701 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002702 case NM_MT_IPACC_SET_NVATTR_ACK:
2703 DEBUGPC(DNM, "SET NVATTR ACK\n");
2704 /* FIXME: decode and show the actual attributes */
2705 break;
2706 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002707 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002708 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002709 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002710 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2711 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002712 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002713 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002714 case NM_MT_IPACC_GET_NVATTR_ACK:
2715 DEBUGPC(DNM, "GET NVATTR ACK\n");
2716 /* FIXME: decode and show the actual attributes */
2717 break;
2718 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002719 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002720 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002721 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002722 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2723 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002724 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002725 break;
Harald Welte15c44172009-10-08 20:15:24 +02002726 case NM_MT_IPACC_SET_ATTR_ACK:
2727 DEBUGPC(DNM, "SET ATTR ACK\n");
2728 break;
2729 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002730 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002731 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002732 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002733 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2734 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002735 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002736 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002737 default:
2738 DEBUGPC(DNM, "unknown\n");
2739 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002740 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002741
2742 /* signal handling */
2743 switch (foh->msg_type) {
2744 case NM_MT_IPACC_RSL_CONNECT_NACK:
2745 case NM_MT_IPACC_SET_NVATTR_NACK:
2746 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welted8cfc902009-11-17 06:09:56 +01002747 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002748 break;
2749 default:
2750 break;
2751 }
2752
Harald Welte677c21f2009-02-17 13:22:23 +00002753 return 0;
2754}
2755
Harald Welte193fefc2009-04-30 15:16:27 +00002756/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002757int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2758 u_int8_t obj_class, u_int8_t bts_nr,
2759 u_int8_t trx_nr, u_int8_t ts_nr,
2760 u_int8_t *attr, int attr_len)
2761{
2762 struct msgb *msg = nm_msgb_alloc();
2763 struct abis_om_hdr *oh;
2764 struct abis_om_fom_hdr *foh;
2765 u_int8_t *data;
2766
2767 /* construct the 12.21 OM header, observe the erroneous length */
2768 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2769 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2770 oh->mdisc = ABIS_OM_MDISC_MANUF;
2771
2772 /* add the ip.access magic */
2773 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2774 *data++ = sizeof(ipaccess_magic);
2775 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2776
2777 /* fill the 12.21 FOM header */
2778 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2779 foh->msg_type = msg_type;
2780 foh->obj_class = obj_class;
2781 foh->obj_inst.bts_nr = bts_nr;
2782 foh->obj_inst.trx_nr = trx_nr;
2783 foh->obj_inst.ts_nr = ts_nr;
2784
2785 if (attr && attr_len) {
2786 data = msgb_put(msg, attr_len);
2787 memcpy(data, attr, attr_len);
2788 }
2789
2790 return abis_nm_sendmsg(bts, msg);
2791}
Harald Welte677c21f2009-02-17 13:22:23 +00002792
Harald Welte193fefc2009-04-30 15:16:27 +00002793/* set some attributes in NVRAM */
2794int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2795 int attr_len)
2796{
2797 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2798 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2799 attr_len);
2800}
2801
Harald Welte746d6092009-10-19 22:11:11 +02002802int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2803 u_int32_t ip, u_int16_t port, u_int8_t stream)
2804{
2805 struct in_addr ia;
2806 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2807 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2808 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2809
2810 int attr_len = sizeof(attr);
2811
2812 ia.s_addr = htonl(ip);
2813 attr[1] = stream;
2814 attr[3] = port >> 8;
2815 attr[4] = port & 0xff;
2816 *(u_int32_t *)(attr+6) = ia.s_addr;
2817
2818 /* if ip == 0, we use the default IP */
2819 if (ip == 0)
2820 attr_len -= 5;
2821
2822 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002823 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002824
2825 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2826 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2827 trx->nr, 0xff, attr, attr_len);
2828}
2829
Harald Welte193fefc2009-04-30 15:16:27 +00002830/* restart / reboot an ip.access nanoBTS */
2831int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2832{
2833 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2834}
Harald Weltedaef5212009-10-24 10:20:41 +02002835
2836int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2837 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2838 u_int8_t *attr, u_int8_t attr_len)
2839{
2840 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2841 obj_class, bts_nr, trx_nr, ts_nr,
2842 attr, attr_len);
2843}
Harald Welte0f255852009-11-12 14:48:42 +01002844
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002845void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2846{
2847 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2848
2849 trx->rf_locked = locked;
2850 if (!trx->bts || !trx->bts->oml_link)
2851 return;
2852
2853 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2854 trx->bts->bts_nr, trx->nr, 0xff,
2855 new_state);
2856}
2857
Harald Welte0f255852009-11-12 14:48:42 +01002858static const char *ipacc_testres_names[] = {
2859 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2860 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2861 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2862 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2863 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2864};
2865
2866const char *ipacc_testres_name(u_int8_t res)
2867{
2868 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2869 ipacc_testres_names[res])
2870 return ipacc_testres_names[res];
2871
2872 return "unknown";
2873}
2874
Harald Welteb40a38f2009-11-13 11:56:05 +01002875void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2876{
2877 cid->mcc = (buf[0] & 0xf) * 100;
2878 cid->mcc += (buf[0] >> 4) * 10;
2879 cid->mcc += (buf[1] & 0xf) * 1;
2880
2881 if (buf[1] >> 4 == 0xf) {
2882 cid->mnc = (buf[2] & 0xf) * 10;
2883 cid->mnc += (buf[2] >> 4) * 1;
2884 } else {
2885 cid->mnc = (buf[2] & 0xf) * 100;
2886 cid->mnc += (buf[2] >> 4) * 10;
2887 cid->mnc += (buf[1] >> 4) * 1;
2888 }
2889
Harald Welteaff237d2009-11-13 14:41:52 +01002890 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2891 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002892}
2893
Harald Welte0f255852009-11-12 14:48:42 +01002894/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2895int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2896{
2897 u_int8_t *cur = buf;
2898 u_int16_t len;
2899
2900 memset(binf, 0, sizeof(binf));
2901
2902 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2903 return -EINVAL;
2904 cur++;
2905
2906 len = ntohs(*(u_int16_t *)cur);
2907 cur += 2;
2908
2909 binf->info_type = ntohs(*(u_int16_t *)cur);
2910 cur += 2;
2911
2912 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2913 binf->freq_qual = *cur >> 2;
2914
2915 binf->arfcn = *cur++ & 3 << 8;
2916 binf->arfcn |= *cur++;
2917
2918 if (binf->info_type & IPAC_BINF_RXLEV)
2919 binf->rx_lev = *cur & 0x3f;
2920 cur++;
2921
2922 if (binf->info_type & IPAC_BINF_RXQUAL)
2923 binf->rx_qual = *cur & 0x7;
2924 cur++;
2925
2926 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2927 binf->freq_err = ntohs(*(u_int16_t *)cur);
2928 cur += 2;
2929
2930 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2931 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2932 cur += 2;
2933
2934 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2935 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2936 cur += 4;
2937
2938 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01002939 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002940 cur++;
2941
Harald Welteb40a38f2009-11-13 11:56:05 +01002942 ipac_parse_cgi(&binf->cgi, cur);
2943 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002944
2945 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2946 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2947 cur += sizeof(binf->ba_list_si2);
2948 }
2949
2950 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2951 memcpy(binf->ba_list_si2bis, cur,
2952 sizeof(binf->ba_list_si2bis));
2953 cur += sizeof(binf->ba_list_si2bis);
2954 }
2955
2956 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2957 memcpy(binf->ba_list_si2ter, cur,
2958 sizeof(binf->ba_list_si2ter));
2959 cur += sizeof(binf->ba_list_si2ter);
2960 }
2961
2962 return 0;
2963}
2964
2965