blob: c3b2c07699febb5d34a5bec0c88913dab1d4ef09 [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]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001228
1229 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1230 msgb_v_put(msg, NM_ATT_SW_DESCR);
1231 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1232 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1233 sw->file_version);
1234 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1235 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1236 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1237 sw->file_version);
1238 } else {
1239 return -1;
1240 }
Harald Welte4724f992009-01-18 18:01:49 +00001241 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1242
1243 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001244}
1245
Harald Welte1602ade2009-01-29 21:12:39 +00001246static int is_last_line(FILE *stream)
1247{
1248 char next_seg_buf[256];
1249 long pos;
1250
1251 /* check if we're sending the last line */
1252 pos = ftell(stream);
1253 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1254 fseek(stream, pos, SEEK_SET);
1255 return 1;
1256 }
1257
1258 fseek(stream, pos, SEEK_SET);
1259 return 0;
1260}
1261
Harald Welte4724f992009-01-18 18:01:49 +00001262/* 6.2.2 / 8.3.2 Load Data Segment */
1263static int sw_load_segment(struct abis_nm_sw *sw)
1264{
1265 struct abis_om_hdr *oh;
1266 struct msgb *msg = nm_msgb_alloc();
1267 char seg_buf[256];
1268 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001269 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001270 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001271
1272 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001273
1274 switch (sw->bts->type) {
1275 case GSM_BTS_TYPE_BS11:
1276 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1277 perror("fgets reading segment");
1278 return -EINVAL;
1279 }
1280 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001281
1282 /* check if we're sending the last line */
1283 sw->last_seg = is_last_line(sw->stream);
1284 if (sw->last_seg)
1285 seg_buf[1] = 0;
1286 else
1287 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001288
1289 len = strlen(line_buf) + 2;
1290 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1291 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1292 /* BS11 wants CR + LF in excess of the TLV length !?! */
1293 tlv[1] -= 2;
1294
1295 /* we only now know the exact length for the OM hdr */
1296 len = strlen(line_buf)+2;
1297 break;
1298 default:
1299 /* FIXME: Other BTS types */
1300 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001301 }
Harald Welte4724f992009-01-18 18:01:49 +00001302
Harald Welte4724f992009-01-18 18:01:49 +00001303 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1304 sw->obj_instance[0], sw->obj_instance[1],
1305 sw->obj_instance[2]);
1306
1307 return abis_nm_sendmsg(sw->bts, msg);
1308}
1309
1310/* 6.2.4 / 8.3.4 Load Data End */
1311static int sw_load_end(struct abis_nm_sw *sw)
1312{
1313 struct abis_om_hdr *oh;
1314 struct msgb *msg = nm_msgb_alloc();
1315 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1316
1317 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1318 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1319 sw->obj_instance[0], sw->obj_instance[1],
1320 sw->obj_instance[2]);
1321
1322 /* FIXME: this is BS11 specific format */
1323 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1324 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1325 sw->file_version);
1326
1327 return abis_nm_sendmsg(sw->bts, msg);
1328}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001329
Harald Welte52b1f982008-12-23 20:25:15 +00001330/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001331static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001332{
Harald Welte4724f992009-01-18 18:01:49 +00001333 struct abis_om_hdr *oh;
1334 struct msgb *msg = nm_msgb_alloc();
1335 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001336
Harald Welte4724f992009-01-18 18:01:49 +00001337 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1338 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1339 sw->obj_instance[0], sw->obj_instance[1],
1340 sw->obj_instance[2]);
1341
1342 /* FIXME: this is BS11 specific format */
1343 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1344 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1345 sw->file_version);
1346
1347 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001348}
Harald Welte4724f992009-01-18 18:01:49 +00001349
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001350struct sdp_firmware {
1351 char magic[4];
1352 char more_magic[4];
1353 unsigned int header_length;
1354 unsigned int file_length;
1355} __attribute__ ((packed));
1356
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001357static int parse_sdp_header(struct abis_nm_sw *sw)
1358{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001359 struct sdp_firmware firmware_header;
1360 int rc;
1361 struct stat stat;
1362
1363 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1364 if (rc != sizeof(firmware_header)) {
1365 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1366 return -1;
1367 }
1368
1369 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1370 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1371 return -1;
1372 }
1373
1374 if (firmware_header.more_magic[0] != 0x10 ||
1375 firmware_header.more_magic[1] != 0x02 ||
1376 firmware_header.more_magic[2] != 0x00 ||
1377 firmware_header.more_magic[3] != 0x00) {
1378 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1379 return -1;
1380 }
1381
1382
1383 if (fstat(sw->fd, &stat) == -1) {
1384 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1385 return -1;
1386 }
1387
1388 if (ntohl(firmware_header.file_length) != stat.st_size) {
1389 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1390 return -1;
1391 }
1392
1393 /* go back to the start as we checked the whole filesize.. */
1394 lseek(sw->fd, 0l, SEEK_SET);
1395 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1396 "There might be checksums in the file that are not\n"
1397 "verified and incomplete firmware might be flashed.\n"
1398 "There is absolutely no WARRANTY that flashing will\n"
1399 "work.\n");
1400 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001401}
1402
Harald Welte4724f992009-01-18 18:01:49 +00001403static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1404{
1405 char file_id[12+1];
1406 char file_version[80+1];
1407 int rc;
1408
1409 sw->fd = open(fname, O_RDONLY);
1410 if (sw->fd < 0)
1411 return sw->fd;
1412
1413 switch (sw->bts->type) {
1414 case GSM_BTS_TYPE_BS11:
1415 sw->stream = fdopen(sw->fd, "r");
1416 if (!sw->stream) {
1417 perror("fdopen");
1418 return -1;
1419 }
1420 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001421 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001422 file_id, file_version);
1423 if (rc != 2) {
1424 perror("parsing header line of software file");
1425 return -1;
1426 }
1427 strcpy((char *)sw->file_id, file_id);
1428 sw->file_id_len = strlen(file_id);
1429 strcpy((char *)sw->file_version, file_version);
1430 sw->file_version_len = strlen(file_version);
1431 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001432 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001433 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001434 case GSM_BTS_TYPE_NANOBTS:
1435 sw->stream = fdopen(sw->fd, "r");
1436 if (!sw->stream) {
1437 perror("fdopen");
1438 return -1;
1439 }
1440
1441 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001442 rc = parse_sdp_header(sw);
1443 if (rc < 0) {
1444 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1445 return -1;
1446 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001447
1448 strcpy((char *)sw->file_id, "id");
1449 sw->file_id_len = 3;
1450 strcpy((char *)sw->file_version, "version");
1451 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001452 break;
Harald Welte4724f992009-01-18 18:01:49 +00001453 default:
1454 /* We don't know how to treat them yet */
1455 close(sw->fd);
1456 return -EINVAL;
1457 }
1458
1459 return 0;
1460}
1461
1462static void sw_close_file(struct abis_nm_sw *sw)
1463{
1464 switch (sw->bts->type) {
1465 case GSM_BTS_TYPE_BS11:
1466 fclose(sw->stream);
1467 break;
1468 default:
1469 close(sw->fd);
1470 break;
1471 }
1472}
1473
1474/* Fill the window */
1475static int sw_fill_window(struct abis_nm_sw *sw)
1476{
1477 int rc;
1478
1479 while (sw->seg_in_window < sw->window_size) {
1480 rc = sw_load_segment(sw);
1481 if (rc < 0)
1482 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001483 if (sw->last_seg)
1484 break;
Harald Welte4724f992009-01-18 18:01:49 +00001485 }
1486 return 0;
1487}
1488
1489/* callback function from abis_nm_rcvmsg() handler */
1490static int abis_nm_rcvmsg_sw(struct msgb *mb)
1491{
1492 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1493 int rc = -1;
1494 struct abis_nm_sw *sw = &g_sw;
1495 enum sw_state old_state = sw->state;
1496
Harald Welte3ffd1372009-02-01 22:15:49 +00001497 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001498
1499 switch (sw->state) {
1500 case SW_STATE_WAIT_INITACK:
1501 switch (foh->msg_type) {
1502 case NM_MT_LOAD_INIT_ACK:
1503 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001504 if (sw->cbfn)
1505 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1506 NM_MT_LOAD_INIT_ACK, mb,
1507 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001508 rc = sw_fill_window(sw);
1509 sw->state = SW_STATE_WAIT_SEGACK;
1510 break;
1511 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001512 if (sw->forced) {
1513 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1514 "Init NACK\n");
1515 if (sw->cbfn)
1516 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1517 NM_MT_LOAD_INIT_ACK, mb,
1518 sw->cb_data, NULL);
1519 rc = sw_fill_window(sw);
1520 sw->state = SW_STATE_WAIT_SEGACK;
1521 } else {
1522 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001523 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001524 if (sw->cbfn)
1525 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1526 NM_MT_LOAD_INIT_NACK, mb,
1527 sw->cb_data, NULL);
1528 sw->state = SW_STATE_ERROR;
1529 }
Harald Welte4724f992009-01-18 18:01:49 +00001530 break;
1531 }
1532 break;
1533 case SW_STATE_WAIT_SEGACK:
1534 switch (foh->msg_type) {
1535 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001536 if (sw->cbfn)
1537 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1538 NM_MT_LOAD_SEG_ACK, mb,
1539 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001540 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001541 if (!sw->last_seg) {
1542 /* fill window with more segments */
1543 rc = sw_fill_window(sw);
1544 sw->state = SW_STATE_WAIT_SEGACK;
1545 } else {
1546 /* end the transfer */
1547 sw->state = SW_STATE_WAIT_ENDACK;
1548 rc = sw_load_end(sw);
1549 }
Harald Welte4724f992009-01-18 18:01:49 +00001550 break;
1551 }
1552 break;
1553 case SW_STATE_WAIT_ENDACK:
1554 switch (foh->msg_type) {
1555 case NM_MT_LOAD_END_ACK:
1556 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001557 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1558 sw->bts->nr);
1559 sw->state = SW_STATE_NONE;
1560 if (sw->cbfn)
1561 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1562 NM_MT_LOAD_END_ACK, mb,
1563 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001564 break;
1565 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001566 if (sw->forced) {
1567 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1568 "End NACK\n");
1569 sw->state = SW_STATE_NONE;
1570 if (sw->cbfn)
1571 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1572 NM_MT_LOAD_END_ACK, mb,
1573 sw->cb_data, NULL);
1574 } else {
1575 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001576 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001577 sw->state = SW_STATE_ERROR;
1578 if (sw->cbfn)
1579 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1580 NM_MT_LOAD_END_NACK, mb,
1581 sw->cb_data, NULL);
1582 }
Harald Welte4724f992009-01-18 18:01:49 +00001583 break;
1584 }
1585 case SW_STATE_WAIT_ACTACK:
1586 switch (foh->msg_type) {
1587 case NM_MT_ACTIVATE_SW_ACK:
1588 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001589 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001590 sw->state = SW_STATE_NONE;
1591 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001592 if (sw->cbfn)
1593 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1594 NM_MT_ACTIVATE_SW_ACK, mb,
1595 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001596 break;
1597 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001598 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001599 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001600 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001601 if (sw->cbfn)
1602 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1603 NM_MT_ACTIVATE_SW_NACK, mb,
1604 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001605 break;
1606 }
1607 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001608 switch (foh->msg_type) {
1609 case NM_MT_ACTIVATE_SW_ACK:
1610 rc = 0;
1611 break;
1612 }
1613 break;
Harald Welte4724f992009-01-18 18:01:49 +00001614 case SW_STATE_ERROR:
1615 break;
1616 }
1617
1618 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001619 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001620 foh->msg_type, old_state, sw->state);
1621
1622 return rc;
1623}
1624
1625/* Load the specified software into the BTS */
1626int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001627 u_int8_t win_size, int forced,
1628 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001629{
1630 struct abis_nm_sw *sw = &g_sw;
1631 int rc;
1632
Harald Welte5e4d1b32009-02-01 13:36:56 +00001633 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1634 bts->nr, fname);
1635
Harald Welte4724f992009-01-18 18:01:49 +00001636 if (sw->state != SW_STATE_NONE)
1637 return -EBUSY;
1638
1639 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001640
1641 switch (bts->type) {
1642 case GSM_BTS_TYPE_BS11:
1643 sw->obj_class = NM_OC_SITE_MANAGER;
1644 sw->obj_instance[0] = 0xff;
1645 sw->obj_instance[1] = 0xff;
1646 sw->obj_instance[2] = 0xff;
1647 break;
1648 case GSM_BTS_TYPE_NANOBTS:
1649 sw->obj_class = NM_OC_BASEB_TRANSC;
1650 sw->obj_instance[0] = 0x00;
1651 sw->obj_instance[1] = 0x00;
1652 sw->obj_instance[2] = 0xff;
1653 break;
1654 case GSM_BTS_TYPE_UNKNOWN:
1655 default:
1656 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1657 return -1;
1658 break;
1659 }
Harald Welte4724f992009-01-18 18:01:49 +00001660 sw->window_size = win_size;
1661 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001662 sw->cbfn = cbfn;
1663 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001664 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001665
1666 rc = sw_open_file(sw, fname);
1667 if (rc < 0) {
1668 sw->state = SW_STATE_NONE;
1669 return rc;
1670 }
1671
1672 return sw_load_init(sw);
1673}
Harald Welte52b1f982008-12-23 20:25:15 +00001674
Harald Welte1602ade2009-01-29 21:12:39 +00001675int abis_nm_software_load_status(struct gsm_bts *bts)
1676{
1677 struct abis_nm_sw *sw = &g_sw;
1678 struct stat st;
1679 int rc, percent;
1680
1681 rc = fstat(sw->fd, &st);
1682 if (rc < 0) {
1683 perror("ERROR during stat");
1684 return rc;
1685 }
1686
1687 percent = (ftell(sw->stream) * 100) / st.st_size;
1688 return percent;
1689}
1690
Harald Welte5e4d1b32009-02-01 13:36:56 +00001691/* Activate the specified software into the BTS */
1692int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1693 gsm_cbfn *cbfn, void *cb_data)
1694{
1695 struct abis_nm_sw *sw = &g_sw;
1696 int rc;
1697
1698 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1699 bts->nr, fname);
1700
1701 if (sw->state != SW_STATE_NONE)
1702 return -EBUSY;
1703
1704 sw->bts = bts;
1705 sw->obj_class = NM_OC_SITE_MANAGER;
1706 sw->obj_instance[0] = 0xff;
1707 sw->obj_instance[1] = 0xff;
1708 sw->obj_instance[2] = 0xff;
1709 sw->state = SW_STATE_WAIT_ACTACK;
1710 sw->cbfn = cbfn;
1711 sw->cb_data = cb_data;
1712
1713 /* Open the file in order to fill some sw struct members */
1714 rc = sw_open_file(sw, fname);
1715 if (rc < 0) {
1716 sw->state = SW_STATE_NONE;
1717 return rc;
1718 }
1719 sw_close_file(sw);
1720
1721 return sw_activate(sw);
1722}
1723
Harald Welte8470bf22008-12-25 23:28:35 +00001724static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001725 u_int8_t ts_nr, u_int8_t subslot_nr)
1726{
Harald Welteadaf08b2009-01-18 11:08:10 +00001727 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001728 ch->bts_port = bts_port;
1729 ch->timeslot = ts_nr;
1730 ch->subslot = subslot_nr;
1731}
1732
1733int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1734 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1735 u_int8_t tei)
1736{
1737 struct abis_om_hdr *oh;
1738 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001739 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001740 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001741
1742 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1743 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1744 bts->bts_nr, trx_nr, 0xff);
1745
Harald Welte8470bf22008-12-25 23:28:35 +00001746 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001747
1748 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1749 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1750
1751 return abis_nm_sendmsg(bts, msg);
1752}
1753
1754/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1755int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1756 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1757{
Harald Welte8470bf22008-12-25 23:28:35 +00001758 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001759 struct abis_om_hdr *oh;
1760 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001761 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001762
1763 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001764 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001765 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1766
1767 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1768 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1769
1770 return abis_nm_sendmsg(bts, msg);
1771}
1772
1773#if 0
1774int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1775 struct abis_nm_abis_channel *chan)
1776{
1777}
1778#endif
1779
1780int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1781 u_int8_t e1_port, u_int8_t e1_timeslot,
1782 u_int8_t e1_subslot)
1783{
1784 struct gsm_bts *bts = ts->trx->bts;
1785 struct abis_om_hdr *oh;
1786 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001787 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001788
1789 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1790 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001791 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001792
1793 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1794 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1795
Harald Weltef325eb42009-02-19 17:07:39 +00001796 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1797 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001798 e1_port, e1_timeslot, e1_subslot);
1799
Harald Welte52b1f982008-12-23 20:25:15 +00001800 return abis_nm_sendmsg(bts, msg);
1801}
1802
1803#if 0
1804int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1805 struct abis_nm_abis_channel *chan,
1806 u_int8_t subchan)
1807{
1808}
1809#endif
1810
Harald Welte22af0db2009-02-14 15:41:08 +00001811/* Chapter 8.6.1 */
1812int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1813{
1814 struct abis_om_hdr *oh;
1815 struct msgb *msg = nm_msgb_alloc();
1816 u_int8_t *cur;
1817
1818 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1819
1820 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001821 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 +00001822 cur = msgb_put(msg, attr_len);
1823 memcpy(cur, attr, attr_len);
1824
1825 return abis_nm_sendmsg(bts, msg);
1826}
1827
1828/* Chapter 8.6.2 */
1829int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1830{
1831 struct abis_om_hdr *oh;
1832 struct msgb *msg = nm_msgb_alloc();
1833 u_int8_t *cur;
1834
1835 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1836
1837 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1838 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001839 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001840 cur = msgb_put(msg, attr_len);
1841 memcpy(cur, attr, attr_len);
1842
1843 return abis_nm_sendmsg(trx->bts, msg);
1844}
1845
Harald Welte39c7deb2009-08-09 21:49:48 +02001846static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1847{
1848 int i;
1849
1850 /* As it turns out, the BS-11 has some very peculiar restrictions
1851 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301852 switch (ts->trx->bts->type) {
1853 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001854 switch (chan_comb) {
1855 case NM_CHANC_TCHHalf:
1856 case NM_CHANC_TCHHalf2:
1857 /* not supported */
1858 return -EINVAL;
1859 case NM_CHANC_SDCCH:
1860 /* only one SDCCH/8 per TRX */
1861 for (i = 0; i < TRX_NR_TS; i++) {
1862 if (i == ts->nr)
1863 continue;
1864 if (ts->trx->ts[i].nm_chan_comb ==
1865 NM_CHANC_SDCCH)
1866 return -EINVAL;
1867 }
1868 /* not allowed for TS0 of BCCH-TRX */
1869 if (ts->trx == ts->trx->bts->c0 &&
1870 ts->nr == 0)
1871 return -EINVAL;
1872 /* not on the same TRX that has a BCCH+SDCCH4
1873 * combination */
1874 if (ts->trx == ts->trx->bts->c0 &&
1875 (ts->trx->ts[0].nm_chan_comb == 5 ||
1876 ts->trx->ts[0].nm_chan_comb == 8))
1877 return -EINVAL;
1878 break;
1879 case NM_CHANC_mainBCCH:
1880 case NM_CHANC_BCCHComb:
1881 /* allowed only for TS0 of C0 */
1882 if (ts->trx != ts->trx->bts->c0 ||
1883 ts->nr != 0)
1884 return -EINVAL;
1885 break;
1886 case NM_CHANC_BCCH:
1887 /* allowed only for TS 2/4/6 of C0 */
1888 if (ts->trx != ts->trx->bts->c0)
1889 return -EINVAL;
1890 if (ts->nr != 2 && ts->nr != 4 &&
1891 ts->nr != 6)
1892 return -EINVAL;
1893 break;
1894 case 8: /* this is not like 08.58, but in fact
1895 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1896 /* FIXME: only one CBCH allowed per cell */
1897 break;
1898 }
Harald Welted6575f92009-12-02 02:45:23 +05301899 break;
1900 case GSM_BTS_TYPE_NANOBTS:
1901 switch (ts->nr) {
1902 case 0:
1903 if (ts->trx->nr == 0) {
1904 /* only on TRX0 */
1905 switch (chan_comb) {
1906 case NM_CHANC_BCCH:
1907 case NM_CHANC_mainBCCH:
1908 case NM_CHANC_BCCHComb:
1909 return 0;
1910 break;
1911 default:
1912 return -EINVAL;
1913 }
1914 } else {
1915 switch (chan_comb) {
1916 case NM_CHANC_TCHFull:
1917 case NM_CHANC_TCHHalf:
1918 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1919 return 0;
1920 default:
1921 return -EINVAL;
1922 }
1923 }
1924 break;
1925 case 1:
1926 if (ts->trx->nr == 0) {
1927 switch (chan_comb) {
1928 case NM_CHANC_SDCCH_CBCH:
1929 if (ts->trx->ts[0].nm_chan_comb ==
1930 NM_CHANC_mainBCCH)
1931 return 0;
1932 return -EINVAL;
1933 case NM_CHANC_SDCCH:
1934 case NM_CHANC_TCHFull:
1935 case NM_CHANC_TCHHalf:
1936 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1937 case NM_CHANC_IPAC_TCHFull_PDCH:
1938 return 0;
1939 }
1940 } else {
1941 switch (chan_comb) {
1942 case NM_CHANC_SDCCH:
1943 case NM_CHANC_TCHFull:
1944 case NM_CHANC_TCHHalf:
1945 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1946 return 0;
1947 default:
1948 return -EINVAL;
1949 }
1950 }
1951 break;
1952 case 2:
1953 case 3:
1954 case 4:
1955 case 5:
1956 case 6:
1957 case 7:
1958 switch (chan_comb) {
1959 case NM_CHANC_TCHFull:
1960 case NM_CHANC_TCHHalf:
1961 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1962 return 0;
1963 case NM_CHANC_IPAC_PDCH:
1964 case NM_CHANC_IPAC_TCHFull_PDCH:
1965 if (ts->trx->nr == 0)
1966 return 0;
1967 else
1968 return -EINVAL;
1969 }
1970 break;
1971 }
1972 return -EINVAL;
1973 default:
1974 /* unknown BTS type */
1975 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001976 }
1977 return 0;
1978}
1979
Harald Welte22af0db2009-02-14 15:41:08 +00001980/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001981int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1982{
1983 struct gsm_bts *bts = ts->trx->bts;
1984 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001985 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001986 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001987 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001988 u_int8_t len = 2 + 2;
1989
1990 if (bts->type == GSM_BTS_TYPE_BS11)
1991 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001992
Harald Weltef325eb42009-02-19 17:07:39 +00001993 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001994 if (verify_chan_comb(ts, chan_comb) < 0) {
1995 msgb_free(msg);
1996 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1997 return -EINVAL;
1998 }
1999 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002000
Harald Welte52b1f982008-12-23 20:25:15 +00002001 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002002 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002003 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002004 ts->trx->nr, ts->nr);
2005 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00002006 if (bts->type == GSM_BTS_TYPE_BS11)
2007 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002008 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00002009 if (bts->type == GSM_BTS_TYPE_BS11) {
2010 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2011 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2012 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002013 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002014 if (bts->type == GSM_BTS_TYPE_BS11)
2015 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002016
2017 return abis_nm_sendmsg(bts, msg);
2018}
2019
Harald Welte34a99682009-02-13 02:41:40 +00002020int 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 +00002021 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002022{
2023 struct abis_om_hdr *oh;
2024 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002025 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2026 u_int8_t len = att_len;
2027
2028 if (nack) {
2029 len += 2;
2030 msgtype = NM_MT_SW_ACT_REQ_NACK;
2031 }
Harald Welte34a99682009-02-13 02:41:40 +00002032
2033 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002034 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2035
Harald Welte34a99682009-02-13 02:41:40 +00002036 if (attr) {
2037 u_int8_t *ptr = msgb_put(msg, att_len);
2038 memcpy(ptr, attr, att_len);
2039 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002040 if (nack)
2041 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002042
2043 return abis_nm_sendmsg(bts, msg);
2044}
2045
Harald Welte8470bf22008-12-25 23:28:35 +00002046int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002047{
Harald Welte8470bf22008-12-25 23:28:35 +00002048 struct msgb *msg = nm_msgb_alloc();
2049 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002050 u_int8_t *data;
2051
2052 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2053 fill_om_hdr(oh, len);
2054 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002055 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002056
2057 return abis_nm_sendmsg(bts, msg);
2058}
2059
2060/* Siemens specific commands */
2061static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2062{
2063 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002064 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002065
2066 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002067 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002068 0xff, 0xff, 0xff);
2069
2070 return abis_nm_sendmsg(bts, msg);
2071}
2072
Harald Welte34a99682009-02-13 02:41:40 +00002073/* Chapter 8.9.2 */
2074int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2075{
2076 struct abis_om_hdr *oh;
2077 struct msgb *msg = nm_msgb_alloc();
2078
2079 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2080 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2081
Harald Weltea8bd6d42009-10-20 09:56:18 +02002082 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2083 DEBUGPC(DNM, "Sending OPSTART\n");
2084
Harald Welte34a99682009-02-13 02:41:40 +00002085 return abis_nm_sendmsg(bts, msg);
2086}
2087
2088/* Chapter 8.8.5 */
2089int 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 +02002090 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002091{
2092 struct abis_om_hdr *oh;
2093 struct msgb *msg = nm_msgb_alloc();
2094
2095 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2096 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2097 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2098
2099 return abis_nm_sendmsg(bts, msg);
2100}
2101
Harald Welte1989c082009-08-06 17:58:31 +02002102int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2103 u_int8_t e1_port1, u_int8_t ts1)
2104{
2105 struct abis_om_hdr *oh;
2106 struct msgb *msg = nm_msgb_alloc();
2107 u_int8_t *attr;
2108
2109 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2110 e1_port0, ts0, e1_port1, ts1);
2111
2112 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2113 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2114 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2115
2116 attr = msgb_put(msg, 3);
2117 attr[0] = NM_ATT_MDROP_LINK;
2118 attr[1] = e1_port0;
2119 attr[2] = ts0;
2120
2121 attr = msgb_put(msg, 3);
2122 attr[0] = NM_ATT_MDROP_NEXT;
2123 attr[1] = e1_port1;
2124 attr[2] = ts1;
2125
2126 return abis_nm_sendmsg(bts, msg);
2127}
Harald Welte34a99682009-02-13 02:41:40 +00002128
Harald Weltec7310382009-08-08 00:02:36 +02002129/* Chapter 8.7.1 */
2130int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2131 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2132 u_int8_t test_nr, u_int8_t auton_report,
2133 u_int8_t *phys_config, u_int16_t phys_config_len)
2134{
2135 struct abis_om_hdr *oh;
2136 struct msgb *msg = nm_msgb_alloc();
2137 int len = 4; /* 2 TV attributes */
2138
2139 DEBUGP(DNM, "PEFORM TEST\n");
2140
2141 if (phys_config_len)
2142 len += 3 + phys_config_len;
2143
2144 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2145 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2146 obj_class, bts_nr, trx_nr, ts_nr);
2147 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2148 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2149 if (phys_config_len)
2150 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2151 phys_config);
2152
2153 return abis_nm_sendmsg(bts, msg);
2154}
2155
Harald Welte52b1f982008-12-23 20:25:15 +00002156int abis_nm_event_reports(struct gsm_bts *bts, int on)
2157{
2158 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002159 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002160 else
Harald Welte227d4072009-01-03 08:16:25 +00002161 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002162}
2163
Harald Welte47d88ae2009-01-04 12:02:08 +00002164/* Siemens (or BS-11) specific commands */
2165
Harald Welte3ffd1372009-02-01 22:15:49 +00002166int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2167{
2168 if (reconnect == 0)
2169 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2170 else
2171 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2172}
2173
Harald Welteb8427972009-02-05 19:27:17 +00002174int abis_nm_bs11_restart(struct gsm_bts *bts)
2175{
2176 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2177}
2178
2179
Harald Welte268bb402009-02-01 19:11:56 +00002180struct bs11_date_time {
2181 u_int16_t year;
2182 u_int8_t month;
2183 u_int8_t day;
2184 u_int8_t hour;
2185 u_int8_t min;
2186 u_int8_t sec;
2187} __attribute__((packed));
2188
2189
2190void get_bs11_date_time(struct bs11_date_time *aet)
2191{
2192 time_t t;
2193 struct tm *tm;
2194
2195 t = time(NULL);
2196 tm = localtime(&t);
2197 aet->sec = tm->tm_sec;
2198 aet->min = tm->tm_min;
2199 aet->hour = tm->tm_hour;
2200 aet->day = tm->tm_mday;
2201 aet->month = tm->tm_mon;
2202 aet->year = htons(1900 + tm->tm_year);
2203}
2204
Harald Welte05188ee2009-01-18 11:39:08 +00002205int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002206{
Harald Welte4668fda2009-01-03 08:19:29 +00002207 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002208}
2209
Harald Welte05188ee2009-01-18 11:39:08 +00002210int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002211{
2212 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002213 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002214 else
Harald Welte4668fda2009-01-03 08:19:29 +00002215 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002216}
Harald Welte47d88ae2009-01-04 12:02:08 +00002217
Harald Welte05188ee2009-01-18 11:39:08 +00002218int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002219 enum abis_bs11_objtype type, u_int8_t idx,
2220 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002221{
2222 struct abis_om_hdr *oh;
2223 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002224 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002225
2226 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002227 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002228 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002229 cur = msgb_put(msg, attr_len);
2230 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002231
2232 return abis_nm_sendmsg(bts, msg);
2233}
2234
Harald Welte78fc0d42009-02-19 02:50:57 +00002235int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2236 enum abis_bs11_objtype type, u_int8_t idx)
2237{
2238 struct abis_om_hdr *oh;
2239 struct msgb *msg = nm_msgb_alloc();
2240
2241 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2242 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2243 NM_OC_BS11, type, 0, idx);
2244
2245 return abis_nm_sendmsg(bts, msg);
2246}
2247
Harald Welte05188ee2009-01-18 11:39:08 +00002248int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002249{
2250 struct abis_om_hdr *oh;
2251 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002252 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002253
2254 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002255 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002256 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2257 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002258
2259 return abis_nm_sendmsg(bts, msg);
2260}
2261
Harald Welte05188ee2009-01-18 11:39:08 +00002262int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002263{
2264 struct abis_om_hdr *oh;
2265 struct msgb *msg = nm_msgb_alloc();
2266
2267 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2268 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002269 idx, 0xff, 0xff);
2270
2271 return abis_nm_sendmsg(bts, msg);
2272}
2273
2274int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2275{
2276 struct abis_om_hdr *oh;
2277 struct msgb *msg = nm_msgb_alloc();
2278
2279 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2280 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2281 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002282
2283 return abis_nm_sendmsg(bts, msg);
2284}
Harald Welte05188ee2009-01-18 11:39:08 +00002285
Harald Welte78fc0d42009-02-19 02:50:57 +00002286static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2287int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2288{
2289 struct abis_om_hdr *oh;
2290 struct msgb *msg = nm_msgb_alloc();
2291
2292 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2293 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2294 0xff, 0xff, 0xff);
2295 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2296
2297 return abis_nm_sendmsg(bts, msg);
2298}
2299
Harald Welteb6c92ae2009-02-21 20:15:32 +00002300/* like abis_nm_conn_terr_traf + set_tei */
2301int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2302 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2303 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002304{
2305 struct abis_om_hdr *oh;
2306 struct abis_nm_channel *ch;
2307 struct msgb *msg = nm_msgb_alloc();
2308
2309 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002310 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002311 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2312
2313 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2314 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002315 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002316
2317 return abis_nm_sendmsg(bts, msg);
2318}
2319
2320int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2321{
2322 struct abis_om_hdr *oh;
2323 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002324
2325 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002326 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002327 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2328 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2329
2330 return abis_nm_sendmsg(trx->bts, msg);
2331}
2332
Harald Welte78fc0d42009-02-19 02:50:57 +00002333int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2334{
2335 struct abis_om_hdr *oh;
2336 struct msgb *msg = nm_msgb_alloc();
2337 u_int8_t attr = NM_ATT_BS11_TXPWR;
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_PA, 0x00, trx->nr);
2342 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2343
2344 return abis_nm_sendmsg(trx->bts, msg);
2345}
2346
Harald Welteaaf02d92009-04-29 13:25:57 +00002347int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2348{
2349 struct abis_om_hdr *oh;
2350 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002351 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002352
2353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2354 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2355 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002356 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002357
2358 return abis_nm_sendmsg(bts, msg);
2359}
2360
Harald Welteef061952009-05-17 12:43:42 +00002361int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2362{
2363 struct abis_om_hdr *oh;
2364 struct msgb *msg = nm_msgb_alloc();
2365 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2366 NM_ATT_BS11_CCLK_TYPE };
2367
2368 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2369 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2370 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2371 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2372
2373 return abis_nm_sendmsg(bts, msg);
2374
2375}
Harald Welteaaf02d92009-04-29 13:25:57 +00002376
Harald Welte268bb402009-02-01 19:11:56 +00002377//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +00002378static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +00002379static const u_int8_t bs11_logon_c9[] = "FACTORY";
2380
Harald Welte1bc09062009-01-18 14:17:52 +00002381int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002382{
2383 struct abis_om_hdr *oh;
2384 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002385 struct bs11_date_time bdt;
2386
2387 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002388
2389 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002390 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002391 u_int8_t len = 3*2 + sizeof(bdt)
Harald Welte6f676a32009-01-18 14:27:48 +00002392 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +00002393 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002394 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002395 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002396 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002397 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2398 sizeof(bs11_logon_c8), bs11_logon_c8);
2399 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2400 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +00002401 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002402 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002403 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002404 }
Harald Welte05188ee2009-01-18 11:39:08 +00002405
2406 return abis_nm_sendmsg(bts, msg);
2407}
Harald Welte1bc09062009-01-18 14:17:52 +00002408
2409int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2410{
2411 struct abis_om_hdr *oh;
2412 struct msgb *msg;
2413
2414 if (strlen(password) != 10)
2415 return -EINVAL;
2416
2417 msg = nm_msgb_alloc();
2418 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002419 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002420 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2421 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2422
2423 return abis_nm_sendmsg(bts, msg);
2424}
2425
Harald Weltee69f5fb2009-04-28 16:31:38 +00002426/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2427int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2428{
2429 struct abis_om_hdr *oh;
2430 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002431 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002432
2433 msg = nm_msgb_alloc();
2434 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2435 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2436 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002437
2438 if (locked)
2439 tlv_value = BS11_LI_PLL_LOCKED;
2440 else
2441 tlv_value = BS11_LI_PLL_STANDALONE;
2442
2443 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002444
2445 return abis_nm_sendmsg(bts, msg);
2446}
2447
Harald Welte1bc09062009-01-18 14:17:52 +00002448int abis_nm_bs11_get_state(struct gsm_bts *bts)
2449{
2450 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2451}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002452
2453/* BS11 SWL */
2454
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002455void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002456
Harald Welte5e4d1b32009-02-01 13:36:56 +00002457struct abis_nm_bs11_sw {
2458 struct gsm_bts *bts;
2459 char swl_fname[PATH_MAX];
2460 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002461 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002462 struct llist_head file_list;
2463 gsm_cbfn *user_cb; /* specified by the user */
2464};
2465static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2466
2467struct file_list_entry {
2468 struct llist_head list;
2469 char fname[PATH_MAX];
2470};
2471
2472struct file_list_entry *fl_dequeue(struct llist_head *queue)
2473{
2474 struct llist_head *lh;
2475
2476 if (llist_empty(queue))
2477 return NULL;
2478
2479 lh = queue->next;
2480 llist_del(lh);
2481
2482 return llist_entry(lh, struct file_list_entry, list);
2483}
2484
2485static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2486{
2487 char linebuf[255];
2488 struct llist_head *lh, *lh2;
2489 FILE *swl;
2490 int rc = 0;
2491
2492 swl = fopen(bs11_sw->swl_fname, "r");
2493 if (!swl)
2494 return -ENODEV;
2495
2496 /* zero the stale file list, if any */
2497 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2498 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002499 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002500 }
2501
2502 while (fgets(linebuf, sizeof(linebuf), swl)) {
2503 char file_id[12+1];
2504 char file_version[80+1];
2505 struct file_list_entry *fle;
2506 static char dir[PATH_MAX];
2507
2508 if (strlen(linebuf) < 4)
2509 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002510
Harald Welte5e4d1b32009-02-01 13:36:56 +00002511 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2512 if (rc < 0) {
2513 perror("ERR parsing SWL file");
2514 rc = -EINVAL;
2515 goto out;
2516 }
2517 if (rc < 2)
2518 continue;
2519
Harald Welte470ec292009-06-26 20:25:23 +02002520 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002521 if (!fle) {
2522 rc = -ENOMEM;
2523 goto out;
2524 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002525
2526 /* construct new filename */
2527 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2528 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2529 strcat(fle->fname, "/");
2530 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002531
2532 llist_add_tail(&fle->list, &bs11_sw->file_list);
2533 }
2534
2535out:
2536 fclose(swl);
2537 return rc;
2538}
2539
2540/* bs11 swload specific callback, passed to abis_nm core swload */
2541static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2542 struct msgb *msg, void *data, void *param)
2543{
2544 struct abis_nm_bs11_sw *bs11_sw = data;
2545 struct file_list_entry *fle;
2546 int rc = 0;
2547
Harald Welte5e4d1b32009-02-01 13:36:56 +00002548 switch (event) {
2549 case NM_MT_LOAD_END_ACK:
2550 fle = fl_dequeue(&bs11_sw->file_list);
2551 if (fle) {
2552 /* start download the next file of our file list */
2553 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2554 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002555 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002556 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002557 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002558 } else {
2559 /* activate the SWL */
2560 rc = abis_nm_software_activate(bs11_sw->bts,
2561 bs11_sw->swl_fname,
2562 bs11_swload_cbfn,
2563 bs11_sw);
2564 }
2565 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002566 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002567 case NM_MT_LOAD_END_NACK:
2568 case NM_MT_LOAD_INIT_ACK:
2569 case NM_MT_LOAD_INIT_NACK:
2570 case NM_MT_ACTIVATE_SW_NACK:
2571 case NM_MT_ACTIVATE_SW_ACK:
2572 default:
2573 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002574 if (bs11_sw->user_cb)
2575 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002576 break;
2577 }
2578
2579 return rc;
2580}
2581
2582/* Siemens provides a SWL file that is a mere listing of all the other
2583 * files that are part of a software release. We need to upload first
2584 * the list file, and then each file that is listed in the list file */
2585int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002586 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002587{
2588 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2589 struct file_list_entry *fle;
2590 int rc = 0;
2591
2592 INIT_LLIST_HEAD(&bs11_sw->file_list);
2593 bs11_sw->bts = bts;
2594 bs11_sw->win_size = win_size;
2595 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002596 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002597
2598 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2599 rc = bs11_read_swl_file(bs11_sw);
2600 if (rc < 0)
2601 return rc;
2602
2603 /* dequeue next item in file list */
2604 fle = fl_dequeue(&bs11_sw->file_list);
2605 if (!fle)
2606 return -EINVAL;
2607
2608 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002609 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002610 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002611 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002612 return rc;
2613}
2614
Harald Welte5083b0b2009-02-02 19:20:52 +00002615#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002616static u_int8_t req_attr_btse[] = {
2617 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2618 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2619 NM_ATT_BS11_LMT_USER_NAME,
2620
2621 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2622
2623 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2624
2625 NM_ATT_BS11_SW_LOAD_STORED };
2626
2627static u_int8_t req_attr_btsm[] = {
2628 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2629 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2630 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2631 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002632#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002633
2634static u_int8_t req_attr[] = {
2635 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2636 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002637 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002638
2639int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2640{
2641 struct abis_om_hdr *oh;
2642 struct msgb *msg = nm_msgb_alloc();
2643
2644 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2645 /* SiemensHW CCTRL object */
2646 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2647 0x03, 0x00, 0x00);
2648 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2649
2650 return abis_nm_sendmsg(bts, msg);
2651}
Harald Welte268bb402009-02-01 19:11:56 +00002652
2653int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2654{
2655 struct abis_om_hdr *oh;
2656 struct msgb *msg = nm_msgb_alloc();
2657 struct bs11_date_time aet;
2658
2659 get_bs11_date_time(&aet);
2660 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2661 /* SiemensHW CCTRL object */
2662 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2663 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002664 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002665
2666 return abis_nm_sendmsg(bts, msg);
2667}
Harald Welte5c1e4582009-02-15 11:57:29 +00002668
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002669int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2670{
2671 struct abis_om_hdr *oh;
2672 struct msgb *msg = nm_msgb_alloc();
2673 struct bs11_date_time aet;
2674
2675 get_bs11_date_time(&aet);
2676 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2677 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2678 bport, 0xff, 0x02);
2679 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2680
2681 return abis_nm_sendmsg(bts, msg);
2682}
2683
Harald Welte5c1e4582009-02-15 11:57:29 +00002684/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002685static const char ipaccess_magic[] = "com.ipaccess";
2686
Harald Welte677c21f2009-02-17 13:22:23 +00002687
2688static int abis_nm_rx_ipacc(struct msgb *msg)
2689{
2690 struct abis_om_hdr *oh = msgb_l2(msg);
2691 struct abis_om_fom_hdr *foh;
2692 u_int8_t idstrlen = oh->data[0];
2693 struct tlv_parsed tp;
2694
2695 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002696 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002697 return -EINVAL;
2698 }
2699
Harald Welte193fefc2009-04-30 15:16:27 +00002700 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002701 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002702
Harald Weltea8bd6d42009-10-20 09:56:18 +02002703 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002704
Harald Welte746d6092009-10-19 22:11:11 +02002705 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002706
Harald Welte677c21f2009-02-17 13:22:23 +00002707 switch (foh->msg_type) {
2708 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002709 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002710 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002711 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002712 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002713 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2714 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002715 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002716 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002717 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002718 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2719 DEBUGPC(DNM, "STREAM=0x%02x ",
2720 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002721 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002722 break;
2723 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002724 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002725 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002726 DEBUGPC(DNM, " CAUSE=%s\n",
2727 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002728 else
2729 DEBUGPC(DNM, "\n");
2730 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002731 case NM_MT_IPACC_SET_NVATTR_ACK:
2732 DEBUGPC(DNM, "SET NVATTR ACK\n");
2733 /* FIXME: decode and show the actual attributes */
2734 break;
2735 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002736 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002737 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002738 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002739 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2740 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002741 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002742 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002743 case NM_MT_IPACC_GET_NVATTR_ACK:
2744 DEBUGPC(DNM, "GET NVATTR ACK\n");
2745 /* FIXME: decode and show the actual attributes */
2746 break;
2747 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002748 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002749 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002750 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002751 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2752 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002753 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002754 break;
Harald Welte15c44172009-10-08 20:15:24 +02002755 case NM_MT_IPACC_SET_ATTR_ACK:
2756 DEBUGPC(DNM, "SET ATTR ACK\n");
2757 break;
2758 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002759 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002760 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002761 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002762 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2763 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002764 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002765 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002766 default:
2767 DEBUGPC(DNM, "unknown\n");
2768 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002769 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002770
2771 /* signal handling */
2772 switch (foh->msg_type) {
2773 case NM_MT_IPACC_RSL_CONNECT_NACK:
2774 case NM_MT_IPACC_SET_NVATTR_NACK:
2775 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welted8cfc902009-11-17 06:09:56 +01002776 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002777 break;
2778 default:
2779 break;
2780 }
2781
Harald Welte677c21f2009-02-17 13:22:23 +00002782 return 0;
2783}
2784
Harald Welte193fefc2009-04-30 15:16:27 +00002785/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002786int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2787 u_int8_t obj_class, u_int8_t bts_nr,
2788 u_int8_t trx_nr, u_int8_t ts_nr,
2789 u_int8_t *attr, int attr_len)
2790{
2791 struct msgb *msg = nm_msgb_alloc();
2792 struct abis_om_hdr *oh;
2793 struct abis_om_fom_hdr *foh;
2794 u_int8_t *data;
2795
2796 /* construct the 12.21 OM header, observe the erroneous length */
2797 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2798 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2799 oh->mdisc = ABIS_OM_MDISC_MANUF;
2800
2801 /* add the ip.access magic */
2802 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2803 *data++ = sizeof(ipaccess_magic);
2804 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2805
2806 /* fill the 12.21 FOM header */
2807 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2808 foh->msg_type = msg_type;
2809 foh->obj_class = obj_class;
2810 foh->obj_inst.bts_nr = bts_nr;
2811 foh->obj_inst.trx_nr = trx_nr;
2812 foh->obj_inst.ts_nr = ts_nr;
2813
2814 if (attr && attr_len) {
2815 data = msgb_put(msg, attr_len);
2816 memcpy(data, attr, attr_len);
2817 }
2818
2819 return abis_nm_sendmsg(bts, msg);
2820}
Harald Welte677c21f2009-02-17 13:22:23 +00002821
Harald Welte193fefc2009-04-30 15:16:27 +00002822/* set some attributes in NVRAM */
2823int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2824 int attr_len)
2825{
2826 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2827 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2828 attr_len);
2829}
2830
Harald Welte746d6092009-10-19 22:11:11 +02002831int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2832 u_int32_t ip, u_int16_t port, u_int8_t stream)
2833{
2834 struct in_addr ia;
2835 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2836 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2837 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2838
2839 int attr_len = sizeof(attr);
2840
2841 ia.s_addr = htonl(ip);
2842 attr[1] = stream;
2843 attr[3] = port >> 8;
2844 attr[4] = port & 0xff;
2845 *(u_int32_t *)(attr+6) = ia.s_addr;
2846
2847 /* if ip == 0, we use the default IP */
2848 if (ip == 0)
2849 attr_len -= 5;
2850
2851 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002852 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002853
2854 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2855 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2856 trx->nr, 0xff, attr, attr_len);
2857}
2858
Harald Welte193fefc2009-04-30 15:16:27 +00002859/* restart / reboot an ip.access nanoBTS */
2860int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2861{
2862 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2863}
Harald Weltedaef5212009-10-24 10:20:41 +02002864
2865int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2866 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2867 u_int8_t *attr, u_int8_t attr_len)
2868{
2869 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2870 obj_class, bts_nr, trx_nr, ts_nr,
2871 attr, attr_len);
2872}
Harald Welte0f255852009-11-12 14:48:42 +01002873
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002874void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2875{
2876 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2877
2878 trx->rf_locked = locked;
2879 if (!trx->bts || !trx->bts->oml_link)
2880 return;
2881
2882 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2883 trx->bts->bts_nr, trx->nr, 0xff,
2884 new_state);
2885}
2886
Harald Welte0f255852009-11-12 14:48:42 +01002887static const char *ipacc_testres_names[] = {
2888 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2889 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2890 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2891 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2892 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2893};
2894
2895const char *ipacc_testres_name(u_int8_t res)
2896{
2897 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2898 ipacc_testres_names[res])
2899 return ipacc_testres_names[res];
2900
2901 return "unknown";
2902}
2903
Harald Welteb40a38f2009-11-13 11:56:05 +01002904void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2905{
2906 cid->mcc = (buf[0] & 0xf) * 100;
2907 cid->mcc += (buf[0] >> 4) * 10;
2908 cid->mcc += (buf[1] & 0xf) * 1;
2909
2910 if (buf[1] >> 4 == 0xf) {
2911 cid->mnc = (buf[2] & 0xf) * 10;
2912 cid->mnc += (buf[2] >> 4) * 1;
2913 } else {
2914 cid->mnc = (buf[2] & 0xf) * 100;
2915 cid->mnc += (buf[2] >> 4) * 10;
2916 cid->mnc += (buf[1] >> 4) * 1;
2917 }
2918
Harald Welteaff237d2009-11-13 14:41:52 +01002919 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2920 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002921}
2922
Harald Welte0f255852009-11-12 14:48:42 +01002923/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2924int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2925{
2926 u_int8_t *cur = buf;
2927 u_int16_t len;
2928
2929 memset(binf, 0, sizeof(binf));
2930
2931 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2932 return -EINVAL;
2933 cur++;
2934
2935 len = ntohs(*(u_int16_t *)cur);
2936 cur += 2;
2937
2938 binf->info_type = ntohs(*(u_int16_t *)cur);
2939 cur += 2;
2940
2941 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2942 binf->freq_qual = *cur >> 2;
2943
2944 binf->arfcn = *cur++ & 3 << 8;
2945 binf->arfcn |= *cur++;
2946
2947 if (binf->info_type & IPAC_BINF_RXLEV)
2948 binf->rx_lev = *cur & 0x3f;
2949 cur++;
2950
2951 if (binf->info_type & IPAC_BINF_RXQUAL)
2952 binf->rx_qual = *cur & 0x7;
2953 cur++;
2954
2955 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2956 binf->freq_err = ntohs(*(u_int16_t *)cur);
2957 cur += 2;
2958
2959 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2960 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2961 cur += 2;
2962
2963 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2964 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2965 cur += 4;
2966
2967 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01002968 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002969 cur++;
2970
Harald Welteb40a38f2009-11-13 11:56:05 +01002971 ipac_parse_cgi(&binf->cgi, cur);
2972 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002973
2974 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2975 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2976 cur += sizeof(binf->ba_list_si2);
2977 }
2978
2979 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2980 memcpy(binf->ba_list_si2bis, cur,
2981 sizeof(binf->ba_list_si2bis));
2982 cur += sizeof(binf->ba_list_si2bis);
2983 }
2984
2985 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2986 memcpy(binf->ba_list_si2ter, cur,
2987 sizeof(binf->ba_list_si2ter));
2988 cur += sizeof(binf->ba_list_si2ter);
2989 }
2990
2991 return 0;
2992}
2993
2994