blob: f82dc6f39089da56a36be443cc035580725eddc5 [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
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000051
52/* unidirectional messages from BTS to BSC */
53static const enum abis_nm_msgtype reports[] = {
54 NM_MT_SW_ACTIVATED_REP,
55 NM_MT_TEST_REP,
56 NM_MT_STATECHG_EVENT_REP,
57 NM_MT_FAILURE_EVENT_REP,
58};
59
60/* messages without ACK/NACK */
61static const enum abis_nm_msgtype no_ack_nack[] = {
62 NM_MT_MEAS_RES_REQ,
63 NM_MT_STOP_MEAS,
64 NM_MT_START_MEAS,
65};
66
Harald Welte4724f992009-01-18 18:01:49 +000067/* Messages related to software load */
68static const enum abis_nm_msgtype sw_load_msgs[] = {
69 NM_MT_LOAD_INIT_ACK,
70 NM_MT_LOAD_INIT_NACK,
71 NM_MT_LOAD_SEG_ACK,
72 NM_MT_LOAD_ABORT,
73 NM_MT_LOAD_END_ACK,
74 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000075 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000076 NM_MT_ACTIVATE_SW_ACK,
77 NM_MT_ACTIVATE_SW_NACK,
78 NM_MT_SW_ACTIVATED_REP,
79};
80
Harald Weltee0590df2009-02-15 03:34:15 +000081static const enum abis_nm_msgtype nacks[] = {
82 NM_MT_LOAD_INIT_NACK,
83 NM_MT_LOAD_END_NACK,
84 NM_MT_SW_ACT_REQ_NACK,
85 NM_MT_ACTIVATE_SW_NACK,
86 NM_MT_ESTABLISH_TEI_NACK,
87 NM_MT_CONN_TERR_SIGN_NACK,
88 NM_MT_DISC_TERR_SIGN_NACK,
89 NM_MT_CONN_TERR_TRAF_NACK,
90 NM_MT_DISC_TERR_TRAF_NACK,
91 NM_MT_CONN_MDROP_LINK_NACK,
92 NM_MT_DISC_MDROP_LINK_NACK,
93 NM_MT_SET_BTS_ATTR_NACK,
94 NM_MT_SET_RADIO_ATTR_NACK,
95 NM_MT_SET_CHAN_ATTR_NACK,
96 NM_MT_PERF_TEST_NACK,
97 NM_MT_SEND_TEST_REP_NACK,
98 NM_MT_STOP_TEST_NACK,
99 NM_MT_STOP_EVENT_REP_NACK,
100 NM_MT_REST_EVENT_REP_NACK,
101 NM_MT_CHG_ADM_STATE_NACK,
102 NM_MT_CHG_ADM_STATE_REQ_NACK,
103 NM_MT_REP_OUTST_ALARMS_NACK,
104 NM_MT_CHANGEOVER_NACK,
105 NM_MT_OPSTART_NACK,
106 NM_MT_REINIT_NACK,
107 NM_MT_SET_SITE_OUT_NACK,
108 NM_MT_CHG_HW_CONF_NACK,
109 NM_MT_GET_ATTR_NACK,
110 NM_MT_SET_ALARM_THRES_NACK,
111 NM_MT_BS11_BEGIN_DB_TX_NACK,
112 NM_MT_BS11_END_DB_TX_NACK,
113 NM_MT_BS11_CREATE_OBJ_NACK,
114 NM_MT_BS11_DELETE_OBJ_NACK,
115};
Harald Welte78fc0d42009-02-19 02:50:57 +0000116
117static const char *nack_names[0xff] = {
118 [NM_MT_LOAD_INIT_NACK] = "SOFTWARE LOAD INIT",
119 [NM_MT_LOAD_END_NACK] = "SOFTWARE LOAD END",
120 [NM_MT_SW_ACT_REQ_NACK] = "SOFTWARE ACTIVATE REQUEST",
121 [NM_MT_ACTIVATE_SW_NACK] = "ACTIVATE SOFTWARE",
122 [NM_MT_ESTABLISH_TEI_NACK] = "ESTABLISH TEI",
123 [NM_MT_CONN_TERR_SIGN_NACK] = "CONNECT TERRESTRIAL SIGNALLING",
124 [NM_MT_DISC_TERR_SIGN_NACK] = "DISCONNECT TERRESTRIAL SIGNALLING",
125 [NM_MT_CONN_TERR_TRAF_NACK] = "CONNECT TERRESTRIAL TRAFFIC",
126 [NM_MT_DISC_TERR_TRAF_NACK] = "DISCONNECT TERRESTRIAL TRAFFIC",
127 [NM_MT_CONN_MDROP_LINK_NACK] = "CONNECT MULTI-DROP LINK",
128 [NM_MT_DISC_MDROP_LINK_NACK] = "DISCONNECT MULTI-DROP LINK",
129 [NM_MT_SET_BTS_ATTR_NACK] = "SET BTS ATTRIBUTE",
130 [NM_MT_SET_RADIO_ATTR_NACK] = "SET RADIO ATTRIBUTE",
131 [NM_MT_SET_CHAN_ATTR_NACK] = "SET CHANNEL ATTRIBUTE",
132 [NM_MT_PERF_TEST_NACK] = "PERFORM TEST",
133 [NM_MT_SEND_TEST_REP_NACK] = "SEND TEST REPORT",
134 [NM_MT_STOP_TEST_NACK] = "STOP TEST",
135 [NM_MT_STOP_EVENT_REP_NACK] = "STOP EVENT REPORT",
136 [NM_MT_REST_EVENT_REP_NACK] = "RESET EVENT REPORT",
137 [NM_MT_CHG_ADM_STATE_NACK] = "CHANGE ADMINISTRATIVE STATE",
138 [NM_MT_CHG_ADM_STATE_REQ_NACK] = "CHANGE ADMINISTRATIVE STATE REQUEST",
139 [NM_MT_REP_OUTST_ALARMS_NACK] = "REPORT OUTSTANDING ALARMS",
140 [NM_MT_CHANGEOVER_NACK] = "CHANGEOVER",
141 [NM_MT_OPSTART_NACK] = "OPSTART",
142 [NM_MT_REINIT_NACK] = "REINIT",
143 [NM_MT_SET_SITE_OUT_NACK] = "SET SITE OUTPUT",
144 [NM_MT_CHG_HW_CONF_NACK] = "CHANGE HARDWARE CONFIGURATION",
145 [NM_MT_GET_ATTR_NACK] = "GET ATTRIBUTE",
146 [NM_MT_SET_ALARM_THRES_NACK] = "SET ALARM THRESHOLD",
147 [NM_MT_BS11_BEGIN_DB_TX_NACK] = "BS11 BEGIN DATABASE TRANSMISSION",
148 [NM_MT_BS11_END_DB_TX_NACK] = "BS11 END DATABASE TRANSMISSION",
149 [NM_MT_BS11_CREATE_OBJ_NACK] = "BS11 CREATE OBJECT",
150 [NM_MT_BS11_DELETE_OBJ_NACK] = "BS11 DELETE OBJECT",
151};
152
Harald Welte6c96ba52009-05-01 13:03:40 +0000153/* Chapter 9.4.36 */
154static const char *nack_cause_names[] = {
155 /* General Nack Causes */
156 [NM_NACK_INCORR_STRUCT] = "Incorrect message structure",
157 [NM_NACK_MSGTYPE_INVAL] = "Invalid message type value",
158 [NM_NACK_OBJCLASS_INVAL] = "Invalid Object class value",
159 [NM_NACK_OBJCLASS_NOTSUPP] = "Object class not supported",
160 [NM_NACK_BTSNR_UNKN] = "BTS no. unknown",
161 [NM_NACK_TRXNR_UNKN] = "Baseband Transceiver no. unknown",
162 [NM_NACK_OBJINST_UNKN] = "Object Instance unknown",
163 [NM_NACK_ATTRID_INVAL] = "Invalid attribute identifier value",
164 [NM_NACK_ATTRID_NOTSUPP] = "Attribute identifier not supported",
165 [NM_NACK_PARAM_RANGE] = "Parameter value outside permitted range",
166 [NM_NACK_ATTRLIST_INCONSISTENT] = "Inconsistency in attribute list",
167 [NM_NACK_SPEC_IMPL_NOTSUPP] = "Specified implementation not supported",
168 [NM_NACK_CANT_PERFORM] = "Message cannot be performed",
169 /* Specific Nack Causes */
170 [NM_NACK_RES_NOTIMPL] = "Resource not implemented",
171 [NM_NACK_RES_NOTAVAIL] = "Resource not available",
172 [NM_NACK_FREQ_NOTAVAIL] = "Frequency not available",
173 [NM_NACK_TEST_NOTSUPP] = "Test not supported",
174 [NM_NACK_CAPACITY_RESTR] = "Capacity restrictions",
175 [NM_NACK_PHYSCFG_NOTPERFORM] = "Physical configuration cannot be performed",
176 [NM_NACK_TEST_NOTINIT] = "Test not initiated",
177 [NM_NACK_PHYSCFG_NOTRESTORE] = "Physical configuration cannot be restored",
178 [NM_NACK_TEST_NOSUCH] = "No such test",
179 [NM_NACK_TEST_NOSTOP] = "Test cannot be stopped",
180 [NM_NACK_MSGINCONSIST_PHYSCFG] = "Message inconsistent with physical configuration",
181 [NM_NACK_FILE_INCOMPLETE] = "Complete file notreceived",
182 [NM_NACK_FILE_NOTAVAIL] = "File not available at destination",
Harald Welte560982b2009-06-26 13:21:57 +0200183 [NM_NACK_FILE_NOTACTIVATE] = "File cannot be activate",
Harald Welte6c96ba52009-05-01 13:03:40 +0000184 [NM_NACK_REQ_NOT_GRANT] = "Request not granted",
185 [NM_NACK_WAIT] = "Wait",
186 [NM_NACK_NOTH_REPORT_EXIST] = "Nothing reportable existing",
187 [NM_NACK_MEAS_NOTSUPP] = "Measurement not supported",
188 [NM_NACK_MEAS_NOTSTART] = "Measurement not started",
189};
190
191static char namebuf[255];
192static const char *nack_cause_name(u_int8_t cause)
193{
194 if (cause < ARRAY_SIZE(nack_cause_names) && nack_cause_names[cause])
195 return nack_cause_names[cause];
196
197 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
198 return namebuf;
199}
200
Harald Welte0db97b22009-05-01 17:22:47 +0000201/* Chapter 9.4.16: Event Type */
202static const char *event_type_names[] = {
203 [NM_EVT_COMM_FAIL] = "communication failure",
204 [NM_EVT_QOS_FAIL] = "quality of service failure",
205 [NM_EVT_PROC_FAIL] = "processing failure",
206 [NM_EVT_EQUIP_FAIL] = "equipment failure",
207 [NM_EVT_ENV_FAIL] = "environment failure",
208};
209
210static const char *event_type_name(u_int8_t cause)
211{
212 if (cause < ARRAY_SIZE(event_type_names) && event_type_names[cause])
213 return event_type_names[cause];
214
215 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
216 return namebuf;
217}
218
219/* Chapter 9.4.63: Perceived Severity */
220static const char *severity_names[] = {
221 [NM_SEVER_CEASED] = "failure ceased",
222 [NM_SEVER_CRITICAL] = "critical failure",
223 [NM_SEVER_MAJOR] = "major failure",
224 [NM_SEVER_MINOR] = "minor failure",
225 [NM_SEVER_WARNING] = "warning level failure",
226 [NM_SEVER_INDETERMINATE] = "indeterminate failure",
227};
228
229static const char *severity_name(u_int8_t cause)
230{
231 if (cause < ARRAY_SIZE(severity_names) && severity_names[cause])
232 return severity_names[cause];
233
234 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
235 return namebuf;
236}
237
Harald Welte52b1f982008-12-23 20:25:15 +0000238/* Attributes that the BSC can set, not only get, according to Section 9.4 */
239static const enum abis_nm_attr nm_att_settable[] = {
240 NM_ATT_ADD_INFO,
241 NM_ATT_ADD_TEXT,
242 NM_ATT_DEST,
243 NM_ATT_EVENT_TYPE,
244 NM_ATT_FILE_DATA,
245 NM_ATT_GET_ARI,
246 NM_ATT_HW_CONF_CHG,
247 NM_ATT_LIST_REQ_ATTR,
248 NM_ATT_MDROP_LINK,
249 NM_ATT_MDROP_NEXT,
250 NM_ATT_NACK_CAUSES,
251 NM_ATT_OUTST_ALARM,
252 NM_ATT_PHYS_CONF,
253 NM_ATT_PROB_CAUSE,
254 NM_ATT_RAD_SUBC,
255 NM_ATT_SOURCE,
256 NM_ATT_SPEC_PROB,
257 NM_ATT_START_TIME,
258 NM_ATT_TEST_DUR,
259 NM_ATT_TEST_NO,
260 NM_ATT_TEST_REPORT,
261 NM_ATT_WINDOW_SIZE,
262 NM_ATT_SEVERITY,
263 NM_ATT_MEAS_RES,
264 NM_ATT_MEAS_TYPE,
265};
266
Harald Weltee0590df2009-02-15 03:34:15 +0000267static const struct tlv_definition nm_att_tlvdef = {
268 .def = {
269 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
270 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
271 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
272 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
273 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
274 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
275 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
276 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
277 [NM_ATT_BSIC] = { TLV_TYPE_TV },
278 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
279 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
280 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
281 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
282 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
283 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
284 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
285 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
286 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
287 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
288 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
289 [NM_ATT_HSN] = { TLV_TYPE_TV },
290 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
291 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
292 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
293 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
294 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
295 [NM_ATT_MAIO] = { TLV_TYPE_TV },
296 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
297 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
298 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
299 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
300 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
301 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
302 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
303 [NM_ATT_NY1] = { TLV_TYPE_TV },
304 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
305 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
306 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
307 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
308 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
309 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
310 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
311 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
312 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
313 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
314 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
315 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
316 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
317 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
318 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
319 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
320 [NM_ATT_TEI] = { TLV_TYPE_TV },
321 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
322 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
323 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
324 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
325 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
326 [NM_ATT_TSC] = { TLV_TYPE_TV },
327 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
328 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
329 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
330 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
331 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000332 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
333 /* BS11 specifics */
Harald Welte78fc0d42009-02-19 02:50:57 +0000334 [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV },
335 [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV },
336 [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV },
337 [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV },
338 [0xd5] = { TLV_TYPE_TLV },
339 [0xa8] = { TLV_TYPE_TLV },
Harald Weltee0590df2009-02-15 03:34:15 +0000340 [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV },
341 [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV },
342 [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV },
343 [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV },
344 [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV },
345 [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 },
346 [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV },
Harald Welteee670472009-02-22 21:58:49 +0000347 [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },
Harald Weltee0590df2009-02-15 03:34:15 +0000348 [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV },
349 [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
350 [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV },
Harald Welte03133942009-02-18 19:51:53 +0000351 [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV },
352 [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV },
Harald Welteaaf02d92009-04-29 13:25:57 +0000353 [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV },
Harald Weltea7cfa032009-04-29 22:33:02 +0000354 [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV },
Harald Welteef061952009-05-17 12:43:42 +0000355 [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV },
356 [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV },
Harald Welte677c21f2009-02-17 13:22:23 +0000357 /* ip.access specifics */
Harald Welte0efe9b72009-07-12 09:33:54 +0200358 [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
359 [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200360 [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
361 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, },
362 [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
363 [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
364 [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
365 [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
366 [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
367 [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
368 [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
369 [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
370 [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
Harald Welte0efe9b72009-07-12 09:33:54 +0200371 [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200372 [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
373 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
Harald Welte0efe9b72009-07-12 09:33:54 +0200374 [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200375 [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
376 [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
377 [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
378 [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
379 [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
380 [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
381 [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
382 [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
383 [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
384 [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
385 [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
386 [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
387 [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200388 [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200389 [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
390 [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
391 [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
392 [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
393 [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
394 [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
395 [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
396 [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
397 [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
398 [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
399 [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
400 [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200401 //[0x95] = { TLV_TYPE_FIXED, 2 },
Harald Welte677c21f2009-02-17 13:22:23 +0000402 [0x85] = { TLV_TYPE_TV },
403
Harald Weltee0590df2009-02-15 03:34:15 +0000404 },
405};
Harald Welte03133942009-02-18 19:51:53 +0000406
Harald Welte21bd3a52009-08-10 12:21:22 +0200407static const enum abis_nm_chan_comb chcomb4pchan[] = {
408 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
409 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
410 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
411 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
412 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200413 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
414 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200415 /* FIXME: bounds check */
416};
417
418int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
419{
420 if (pchan < ARRAY_SIZE(chcomb4pchan))
421 return chcomb4pchan[pchan];
422
423 return -EINVAL;
424}
425
Harald Welte03133942009-02-18 19:51:53 +0000426int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
427{
Harald Weltea4d49e92009-05-23 06:39:58 +0000428 return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000429}
Harald Weltee0590df2009-02-15 03:34:15 +0000430
Harald Welte52b1f982008-12-23 20:25:15 +0000431static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
432{
433 int i;
434
435 for (i = 0; i < size; i++) {
436 if (arr[i] == mt)
437 return 1;
438 }
439
440 return 0;
441}
442
Holger Freytherca362a62009-01-04 21:05:01 +0000443#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000444/* is this msgtype the usual ACK/NACK type ? */
445static int is_ack_nack(enum abis_nm_msgtype mt)
446{
447 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
448}
Holger Freytherca362a62009-01-04 21:05:01 +0000449#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000450
451/* is this msgtype a report ? */
452static int is_report(enum abis_nm_msgtype mt)
453{
Harald Welte8470bf22008-12-25 23:28:35 +0000454 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000455}
456
457#define MT_ACK(x) (x+1)
458#define MT_NACK(x) (x+2)
459
460static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
461{
462 oh->mdisc = ABIS_OM_MDISC_FOM;
463 oh->placement = ABIS_OM_PLACEMENT_ONLY;
464 oh->sequence = 0;
465 oh->length = len;
466}
467
468static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
469 u_int8_t msg_type, u_int8_t obj_class,
470 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
471{
472 struct abis_om_fom_hdr *foh =
473 (struct abis_om_fom_hdr *) oh->data;
474
Harald Welte702d8702008-12-26 20:25:35 +0000475 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000476 foh->msg_type = msg_type;
477 foh->obj_class = obj_class;
478 foh->obj_inst.bts_nr = bts_nr;
479 foh->obj_inst.trx_nr = trx_nr;
480 foh->obj_inst.ts_nr = ts_nr;
481}
482
Harald Welte8470bf22008-12-25 23:28:35 +0000483static struct msgb *nm_msgb_alloc(void)
484{
Harald Welte966636f2009-06-26 19:39:35 +0200485 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
486 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000487}
488
Harald Welte52b1f982008-12-23 20:25:15 +0000489/* Send a OML NM Message from BSC to BTS */
490int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
491{
Holger Freyther59639e82009-02-09 23:09:55 +0000492 msg->trx = bts->c0;
493
Harald Weltead384642008-12-26 10:20:07 +0000494 return _abis_nm_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000495}
496
Harald Welte4724f992009-01-18 18:01:49 +0000497static int abis_nm_rcvmsg_sw(struct msgb *mb);
498
Harald Welte34a99682009-02-13 02:41:40 +0000499static const char *obj_class_name(u_int8_t oc)
500{
Harald Welte7b26bcb2009-05-28 11:39:21 +0000501 switch (oc) {
502 case NM_OC_SITE_MANAGER:
503 return "SITE MANAGER";
504 case NM_OC_BTS:
505 return "BTS";
506 case NM_OC_RADIO_CARRIER:
507 return "RADIO CARRIER";
508 case NM_OC_BASEB_TRANSC:
509 return "BASEBAND TRANSCEIVER";
510 case NM_OC_CHANNEL:
Harald Weltebd8f7e32009-06-09 20:17:12 +0000511 return "CHANNEL";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000512 case NM_OC_BS11_ADJC:
513 return "ADJC";
514 case NM_OC_BS11_HANDOVER:
515 return "HANDOVER";
516 case NM_OC_BS11_PWR_CTRL:
517 return "POWER CONTROL";
518 case NM_OC_BS11_BTSE:
519 return "BTSE";
520 case NM_OC_BS11_RACK:
521 return "RACK";
522 case NM_OC_BS11_TEST:
523 return "TEST";
524 case NM_OC_BS11_ENVABTSE:
525 return "ENVABTSE";
526 case NM_OC_BS11_BPORT:
527 return "BPORT";
528 case NM_OC_GPRS_NSE:
529 return "GPRS NSE";
530 case NM_OC_GPRS_CELL:
531 return "GPRS CELL";
Harald Welted83a1272009-07-12 10:56:06 +0200532 case NM_OC_GPRS_NSVC:
533 return "GPRS NSVC";
Harald Welte8b697c72009-06-05 19:18:45 +0000534 case NM_OC_BS11:
535 return "SIEMENSHW";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000536 }
537
538 return "UNKNOWN";
Harald Welte34a99682009-02-13 02:41:40 +0000539}
540
Harald Welte4d87f242009-03-10 19:43:44 +0000541const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000542{
543 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100544 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000545 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100546 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000547 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100548 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000549 return "NULL";
550 default:
551 return "RFU";
552 }
553}
554
Harald Weltee0590df2009-02-15 03:34:15 +0000555/* Chapter 9.4.7 */
Harald Welte4d87f242009-03-10 19:43:44 +0000556static const char *avail_names[] = {
Harald Weltee0590df2009-02-15 03:34:15 +0000557 "In test",
558 "Failed",
559 "Power off",
560 "Off line",
561 "<not used>",
562 "Dependency",
563 "Degraded",
564 "Not installed",
565};
566
Harald Welte4d87f242009-03-10 19:43:44 +0000567const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000568{
Harald Welte0b8348d2009-02-18 03:43:01 +0000569 if (avail == 0xff)
570 return "OK";
Harald Weltee0590df2009-02-15 03:34:15 +0000571 if (avail >= ARRAY_SIZE(avail_names))
572 return "UNKNOWN";
573 return avail_names[avail];
574}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000575
Harald Welte0f255852009-11-12 14:48:42 +0100576static struct value_string test_names[] = {
577 /* FIXME: standard test names */
578 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
579 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
580 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
581 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
582 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
583 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
584 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
585 { 0, NULL }
586};
587
Harald Welte7b26bcb2009-05-28 11:39:21 +0000588const char *nm_adm_name(u_int8_t adm)
589{
590 switch (adm) {
591 case 1:
592 return "Locked";
593 case 2:
594 return "Unlocked";
595 case 3:
596 return "Shutdown";
597 default:
598 return "<not used>";
599 }
600}
Harald Weltee0590df2009-02-15 03:34:15 +0000601
Harald Weltea8bd6d42009-10-20 09:56:18 +0200602static void debugp_foh(struct abis_om_fom_hdr *foh)
603{
604 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
605 obj_class_name(foh->obj_class), foh->obj_class,
606 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
607 foh->obj_inst.ts_nr);
608}
609
Harald Weltee0590df2009-02-15 03:34:15 +0000610/* obtain the gsm_nm_state data structure for a given object instance */
611static struct gsm_nm_state *
612objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
613 struct abis_om_obj_inst *obj_inst)
614{
615 struct gsm_bts_trx *trx;
616 struct gsm_nm_state *nm_state = NULL;
617
618 switch (obj_class) {
619 case NM_OC_BTS:
620 nm_state = &bts->nm_state;
621 break;
622 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100623 if (obj_inst->trx_nr >= bts->num_trx) {
624 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000625 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100626 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200627 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000628 nm_state = &trx->nm_state;
629 break;
630 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100631 if (obj_inst->trx_nr >= bts->num_trx) {
632 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000633 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100634 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200635 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000636 nm_state = &trx->bb_transc.nm_state;
637 break;
638 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100639 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100640 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000641 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100642 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200643 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000644 if (obj_inst->ts_nr >= TRX_NR_TS)
645 return NULL;
646 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
647 break;
648 case NM_OC_SITE_MANAGER:
649 nm_state = &bts->site_mgr.nm_state;
650 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000651 case NM_OC_BS11:
652 switch (obj_inst->bts_nr) {
653 case BS11_OBJ_CCLK:
654 nm_state = &bts->bs11.cclk.nm_state;
655 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000656 case BS11_OBJ_BBSIG:
657 if (obj_inst->ts_nr > bts->num_trx)
658 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200659 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000660 nm_state = &trx->bs11.bbsig.nm_state;
661 break;
662 case BS11_OBJ_PA:
663 if (obj_inst->ts_nr > bts->num_trx)
664 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200665 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000666 nm_state = &trx->bs11.pa.nm_state;
667 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000668 default:
669 return NULL;
670 }
671 case NM_OC_BS11_RACK:
672 nm_state = &bts->bs11.rack.nm_state;
673 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000674 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100675 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000676 return NULL;
677 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
678 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200679 case NM_OC_GPRS_NSE:
680 nm_state = &bts->gprs.nse.nm_state;
681 break;
682 case NM_OC_GPRS_CELL:
683 nm_state = &bts->gprs.cell.nm_state;
684 break;
685 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100686 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200687 return NULL;
688 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
689 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000690 }
691 return nm_state;
692}
693
694/* obtain the in-memory data structure of a given object instance */
695static void *
696objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
697 struct abis_om_obj_inst *obj_inst)
698{
699 struct gsm_bts_trx *trx;
700 void *obj = NULL;
701
702 switch (obj_class) {
703 case NM_OC_BTS:
704 obj = bts;
705 break;
706 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100707 if (obj_inst->trx_nr >= bts->num_trx) {
708 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000709 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100710 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200711 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000712 obj = trx;
713 break;
714 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100715 if (obj_inst->trx_nr >= bts->num_trx) {
716 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000717 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100718 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200719 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000720 obj = &trx->bb_transc;
721 break;
722 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100723 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100724 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000725 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100726 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200727 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000728 if (obj_inst->ts_nr >= TRX_NR_TS)
729 return NULL;
730 obj = &trx->ts[obj_inst->ts_nr];
731 break;
732 case NM_OC_SITE_MANAGER:
733 obj = &bts->site_mgr;
734 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200735 case NM_OC_GPRS_NSE:
736 obj = &bts->gprs.nse;
737 break;
738 case NM_OC_GPRS_CELL:
739 obj = &bts->gprs.cell;
740 break;
741 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100742 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200743 return NULL;
744 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
745 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000746 }
747 return obj;
748}
749
750/* Update the administrative state of a given object in our in-memory data
751 * structures and send an event to the higher layer */
752static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
753 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
754{
Harald Welteaeedeb42009-05-01 13:08:14 +0000755 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000756 void *obj;
757 int rc;
758
Harald Weltee0590df2009-02-15 03:34:15 +0000759 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100760 if (!obj)
761 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000762 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
763 if (!nm_state)
764 return -1;
765
766 new_state = *nm_state;
767 new_state.administrative = adm_state;
768
769 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
770
771 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000772
773 return rc;
774}
775
Harald Welte97ed1e72009-02-06 13:38:02 +0000776static int abis_nm_rx_statechg_rep(struct msgb *mb)
777{
Harald Weltee0590df2009-02-15 03:34:15 +0000778 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000779 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000780 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000781 struct tlv_parsed tp;
782 struct gsm_nm_state *nm_state, new_state;
783 int rc;
784
Harald Welte23897662009-05-01 14:52:51 +0000785 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000786
Harald Welte8b697c72009-06-05 19:18:45 +0000787 memset(&new_state, 0, sizeof(new_state));
788
Harald Weltee0590df2009-02-15 03:34:15 +0000789 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
790 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100791 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000792 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000793 }
Harald Weltee0590df2009-02-15 03:34:15 +0000794
795 new_state = *nm_state;
796
Harald Welte03133942009-02-18 19:51:53 +0000797 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000798 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
799 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000800 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000801 }
802 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000803 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
804 new_state.availability = 0xff;
805 else
806 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000807 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000808 new_state.availability);
809 }
810 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
811 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200812 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000813 }
814 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000815
816 if (memcmp(&new_state, nm_state, sizeof(new_state))) {
817 /* Update the operational state of a given object in our in-memory data
818 * structures and send an event to the higher layer */
819 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
820 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
821 *nm_state = new_state;
822 }
823#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000824 if (op_state == 1) {
825 /* try to enable objects that are disabled */
826 abis_nm_opstart(bts, foh->obj_class,
827 foh->obj_inst.bts_nr,
828 foh->obj_inst.trx_nr,
829 foh->obj_inst.ts_nr);
830 }
Harald Weltee0590df2009-02-15 03:34:15 +0000831#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000832 return 0;
833}
834
Harald Welte0db97b22009-05-01 17:22:47 +0000835static int rx_fail_evt_rep(struct msgb *mb)
836{
837 struct abis_om_hdr *oh = msgb_l2(mb);
838 struct abis_om_fom_hdr *foh = msgb_l3(mb);
839 struct tlv_parsed tp;
840
841 DEBUGPC(DNM, "Failure Event Report ");
842
843 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
844
845 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
846 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
847 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
848 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
849
850 DEBUGPC(DNM, "\n");
851
852 return 0;
853}
854
Harald Welte97ed1e72009-02-06 13:38:02 +0000855static int abis_nm_rcvmsg_report(struct msgb *mb)
856{
857 struct abis_om_fom_hdr *foh = msgb_l3(mb);
858 u_int8_t mt = foh->msg_type;
859
Harald Weltea8bd6d42009-10-20 09:56:18 +0200860 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000861
Harald Welte97ed1e72009-02-06 13:38:02 +0000862 //nmh->cfg->report_cb(mb, foh);
863
864 switch (mt) {
865 case NM_MT_STATECHG_EVENT_REP:
866 return abis_nm_rx_statechg_rep(mb);
867 break;
Harald Welte34a99682009-02-13 02:41:40 +0000868 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000869 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000870 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000871 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000872 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000873 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000874 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000875 break;
Harald Weltec7310382009-08-08 00:02:36 +0200876 case NM_MT_TEST_REP:
877 DEBUGPC(DNM, "Test Report\n");
878 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
879 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000880 default:
Harald Welte23897662009-05-01 14:52:51 +0000881 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000882 break;
883
Harald Welte97ed1e72009-02-06 13:38:02 +0000884 };
885
Harald Welte97ed1e72009-02-06 13:38:02 +0000886 return 0;
887}
888
Harald Welte34a99682009-02-13 02:41:40 +0000889/* Activate the specified software into the BTS */
890static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
Mike Habena03f9772009-10-01 14:56:13 +0200891 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000892{
893 struct abis_om_hdr *oh;
894 struct msgb *msg = nm_msgb_alloc();
895 u_int8_t len = swdesc_len;
896 u_int8_t *trailer;
897
898 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
899 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
900
901 trailer = msgb_put(msg, swdesc_len);
902 memcpy(trailer, sw_desc, swdesc_len);
903
904 return abis_nm_sendmsg(bts, msg);
905}
906
907static int abis_nm_rx_sw_act_req(struct msgb *mb)
908{
909 struct abis_om_hdr *oh = msgb_l2(mb);
910 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200911 struct tlv_parsed tp;
912 const u_int8_t *sw_config;
913 int sw_config_len;
914 int file_id_len;
Harald Welte5c1e4582009-02-15 11:57:29 +0000915 int nack = 0;
Harald Welte34a99682009-02-13 02:41:40 +0000916 int ret;
917
Harald Weltea8bd6d42009-10-20 09:56:18 +0200918 debugp_foh(foh);
919
920 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000921
Harald Welte5c1e4582009-02-15 11:57:29 +0000922 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
923 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
924 nack = 1;
925 } else
926 DEBUGPC(DNM, "ACKing and Activating\n");
927
928 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000929 foh->obj_inst.bts_nr,
930 foh->obj_inst.trx_nr,
Harald Welte5c1e4582009-02-15 11:57:29 +0000931 foh->obj_inst.ts_nr, nack,
Harald Welte34a99682009-02-13 02:41:40 +0000932 foh->data, oh->length-sizeof(*foh));
933
Harald Welte5c1e4582009-02-15 11:57:29 +0000934 if (nack)
935 return ret;
936
Mike Habena03f9772009-10-01 14:56:13 +0200937 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
938 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
939 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
940 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
941 DEBUGP(DNM, "SW config not found! Can't continue.\n");
942 return -EINVAL;
943 } else {
944 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
945 }
946
947 if (sw_config[0] != NM_ATT_SW_DESCR)
948 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
949 if (sw_config[1] != NM_ATT_FILE_ID)
950 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
951 file_id_len = sw_config[2] * 256 + sw_config[3];
952
953 /* Assumes first SW file in list is the one to be activated */
954 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000955 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
956 foh->obj_inst.bts_nr,
957 foh->obj_inst.trx_nr,
958 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200959 sw_config + 4,
960 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000961}
962
Harald Weltee0590df2009-02-15 03:34:15 +0000963/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
964static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
965{
966 struct abis_om_hdr *oh = msgb_l2(mb);
967 struct abis_om_fom_hdr *foh = msgb_l3(mb);
968 struct tlv_parsed tp;
969 u_int8_t adm_state;
970
Harald Welte03133942009-02-18 19:51:53 +0000971 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000972 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
973 return -EINVAL;
974
975 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
976
977 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
978}
979
Harald Welteee670472009-02-22 21:58:49 +0000980static int abis_nm_rx_lmt_event(struct msgb *mb)
981{
982 struct abis_om_hdr *oh = msgb_l2(mb);
983 struct abis_om_fom_hdr *foh = msgb_l3(mb);
984 struct tlv_parsed tp;
985
986 DEBUGP(DNM, "LMT Event ");
987 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
988 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
989 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
990 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
991 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
992 }
993 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
994 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
995 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
996 DEBUGPC(DNM, "Level=%u ", level);
997 }
998 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
999 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
1000 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1001 DEBUGPC(DNM, "Username=%s ", name);
1002 }
1003 DEBUGPC(DNM, "\n");
1004 /* FIXME: parse LMT LOGON TIME */
1005 return 0;
1006}
1007
Harald Welte52b1f982008-12-23 20:25:15 +00001008/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001009static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001010{
Harald Welte6c96ba52009-05-01 13:03:40 +00001011 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001012 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1013 u_int8_t mt = foh->msg_type;
1014
1015 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001016 if (is_report(mt))
1017 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001018
Harald Welte4724f992009-01-18 18:01:49 +00001019 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1020 return abis_nm_rcvmsg_sw(mb);
1021
Harald Welte78fc0d42009-02-19 02:50:57 +00001022 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +00001023 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001024
Harald Weltea8bd6d42009-10-20 09:56:18 +02001025 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001026
Harald Welte78fc0d42009-02-19 02:50:57 +00001027 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +02001028 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +00001029 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +00001030 else
Harald Welte4bd0a982009-10-08 20:18:59 +02001031 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +00001032
1033 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1034 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1035 DEBUGPC(DNM, "CAUSE=%s\n",
1036 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1037 else
1038 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001039
Harald Welted8cfc902009-11-17 06:09:56 +01001040 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001041 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001042 }
Harald Weltead384642008-12-26 10:20:07 +00001043#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001044 /* check if last message is to be acked */
1045 if (is_ack_nack(nmh->last_msgtype)) {
1046 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001047 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001048 /* we got our ACK, continue sending the next msg */
1049 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1050 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001051 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001052 /* FIXME: somehow signal this to the caller */
1053 } else {
1054 /* really strange things happen */
1055 return -EINVAL;
1056 }
1057 }
Harald Weltead384642008-12-26 10:20:07 +00001058#endif
1059
Harald Welte97ed1e72009-02-06 13:38:02 +00001060 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001061 case NM_MT_CHG_ADM_STATE_ACK:
1062 return abis_nm_rx_chg_adm_state_ack(mb);
1063 break;
Harald Welte34a99682009-02-13 02:41:40 +00001064 case NM_MT_SW_ACT_REQ:
1065 return abis_nm_rx_sw_act_req(mb);
1066 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001067 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001068 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001069 break;
Harald Welte1989c082009-08-06 17:58:31 +02001070 case NM_MT_CONN_MDROP_LINK_ACK:
1071 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1072 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001073 case NM_MT_IPACC_RESTART_ACK:
1074 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1075 break;
1076 case NM_MT_IPACC_RESTART_NACK:
1077 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1078 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001079 }
1080
Harald Weltead384642008-12-26 10:20:07 +00001081 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001082}
1083
Harald Welte677c21f2009-02-17 13:22:23 +00001084static int abis_nm_rx_ipacc(struct msgb *mb);
1085
1086static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1087{
1088 int rc;
1089 int bts_type = mb->trx->bts->type;
1090
1091 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001092 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001093 rc = abis_nm_rx_ipacc(mb);
1094 break;
1095 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001096 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1097 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001098 rc = 0;
1099 break;
1100 }
1101
1102 return rc;
1103}
1104
Harald Welte52b1f982008-12-23 20:25:15 +00001105/* High-Level API */
1106/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001107int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001108{
Harald Welte52b1f982008-12-23 20:25:15 +00001109 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001110 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001111
1112 /* Various consistency checks */
1113 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001114 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001115 oh->placement);
1116 return -EINVAL;
1117 }
1118 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001119 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001120 oh->sequence);
1121 return -EINVAL;
1122 }
Harald Welte702d8702008-12-26 20:25:35 +00001123#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001124 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1125 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001126 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001127 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001128 oh->length + sizeof(*oh), l2_len);
1129 return -EINVAL;
1130 }
Harald Welte702d8702008-12-26 20:25:35 +00001131 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001132 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 +00001133#endif
Harald Weltead384642008-12-26 10:20:07 +00001134 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001135
1136 switch (oh->mdisc) {
1137 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001138 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001139 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001140 case ABIS_OM_MDISC_MANUF:
1141 rc = abis_nm_rcvmsg_manuf(msg);
1142 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001143 case ABIS_OM_MDISC_MMI:
1144 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001145 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001146 oh->mdisc);
1147 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001148 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001149 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001150 oh->mdisc);
1151 return -EINVAL;
1152 }
1153
Harald Weltead384642008-12-26 10:20:07 +00001154 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001155 return rc;
1156}
1157
1158#if 0
1159/* initialized all resources */
1160struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1161{
1162 struct abis_nm_h *nmh;
1163
1164 nmh = malloc(sizeof(*nmh));
1165 if (!nmh)
1166 return NULL;
1167
1168 nmh->cfg = cfg;
1169
1170 return nmh;
1171}
1172
1173/* free all resources */
1174void abis_nm_fini(struct abis_nm_h *nmh)
1175{
1176 free(nmh);
1177}
1178#endif
1179
1180/* Here we are trying to define a high-level API that can be used by
1181 * the actual BSC implementation. However, the architecture is currently
1182 * still under design. Ideally the calls to this API would be synchronous,
1183 * while the underlying stack behind the APi runs in a traditional select
1184 * based state machine.
1185 */
1186
Harald Welte4724f992009-01-18 18:01:49 +00001187/* 6.2 Software Load: */
1188enum sw_state {
1189 SW_STATE_NONE,
1190 SW_STATE_WAIT_INITACK,
1191 SW_STATE_WAIT_SEGACK,
1192 SW_STATE_WAIT_ENDACK,
1193 SW_STATE_WAIT_ACTACK,
1194 SW_STATE_ERROR,
1195};
Harald Welte52b1f982008-12-23 20:25:15 +00001196
Harald Welte52b1f982008-12-23 20:25:15 +00001197struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001198 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001199 gsm_cbfn *cbfn;
1200 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001201 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001202
Harald Welte52b1f982008-12-23 20:25:15 +00001203 /* this will become part of the SW LOAD INITIATE */
1204 u_int8_t obj_class;
1205 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001206
1207 u_int8_t file_id[255];
1208 u_int8_t file_id_len;
1209
1210 u_int8_t file_version[255];
1211 u_int8_t file_version_len;
1212
1213 u_int8_t window_size;
1214 u_int8_t seg_in_window;
1215
1216 int fd;
1217 FILE *stream;
1218 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001219 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001220};
1221
Harald Welte4724f992009-01-18 18:01:49 +00001222static struct abis_nm_sw g_sw;
1223
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001224static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1225{
1226 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1227 msgb_v_put(msg, NM_ATT_SW_DESCR);
1228 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1229 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1230 sw->file_version);
1231 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1232 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1233 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1234 sw->file_version);
1235 } else {
1236 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1237 }
1238}
1239
Harald Welte4724f992009-01-18 18:01:49 +00001240/* 6.2.1 / 8.3.1: Load Data Initiate */
1241static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001242{
Harald Welte4724f992009-01-18 18:01:49 +00001243 struct abis_om_hdr *oh;
1244 struct msgb *msg = nm_msgb_alloc();
1245 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1246
1247 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1248 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1249 sw->obj_instance[0], sw->obj_instance[1],
1250 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001251
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001252 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001253 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1254
1255 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001256}
1257
Harald Welte1602ade2009-01-29 21:12:39 +00001258static int is_last_line(FILE *stream)
1259{
1260 char next_seg_buf[256];
1261 long pos;
1262
1263 /* check if we're sending the last line */
1264 pos = ftell(stream);
1265 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1266 fseek(stream, pos, SEEK_SET);
1267 return 1;
1268 }
1269
1270 fseek(stream, pos, SEEK_SET);
1271 return 0;
1272}
1273
Harald Welte4724f992009-01-18 18:01:49 +00001274/* 6.2.2 / 8.3.2 Load Data Segment */
1275static int sw_load_segment(struct abis_nm_sw *sw)
1276{
1277 struct abis_om_hdr *oh;
1278 struct msgb *msg = nm_msgb_alloc();
1279 char seg_buf[256];
1280 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001281 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001282 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001283
1284 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001285
1286 switch (sw->bts->type) {
1287 case GSM_BTS_TYPE_BS11:
1288 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1289 perror("fgets reading segment");
1290 return -EINVAL;
1291 }
1292 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001293
1294 /* check if we're sending the last line */
1295 sw->last_seg = is_last_line(sw->stream);
1296 if (sw->last_seg)
1297 seg_buf[1] = 0;
1298 else
1299 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001300
1301 len = strlen(line_buf) + 2;
1302 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1303 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1304 /* BS11 wants CR + LF in excess of the TLV length !?! */
1305 tlv[1] -= 2;
1306
1307 /* we only now know the exact length for the OM hdr */
1308 len = strlen(line_buf)+2;
1309 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001310 case GSM_BTS_TYPE_NANOBTS: {
1311 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1312 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1313 if (len < 0) {
1314 perror("read failed");
1315 return -EINVAL;
1316 }
1317
1318 if (len != IPACC_SEGMENT_SIZE)
1319 sw->last_seg = 1;
1320
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001321 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001322 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1323 len += 3;
1324 break;
1325 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001326 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001327 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001328 /* FIXME: Other BTS types */
1329 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001330 }
Harald Welte4724f992009-01-18 18:01:49 +00001331
Harald Welte4724f992009-01-18 18:01:49 +00001332 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1333 sw->obj_instance[0], sw->obj_instance[1],
1334 sw->obj_instance[2]);
1335
1336 return abis_nm_sendmsg(sw->bts, msg);
1337}
1338
1339/* 6.2.4 / 8.3.4 Load Data End */
1340static int sw_load_end(struct abis_nm_sw *sw)
1341{
1342 struct abis_om_hdr *oh;
1343 struct msgb *msg = nm_msgb_alloc();
1344 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1345
1346 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1347 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1348 sw->obj_instance[0], sw->obj_instance[1],
1349 sw->obj_instance[2]);
1350
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001351 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001352 return abis_nm_sendmsg(sw->bts, msg);
1353}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001354
Harald Welte52b1f982008-12-23 20:25:15 +00001355/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001356static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001357{
Harald Welte4724f992009-01-18 18:01:49 +00001358 struct abis_om_hdr *oh;
1359 struct msgb *msg = nm_msgb_alloc();
1360 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001361
Harald Welte4724f992009-01-18 18:01:49 +00001362 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1363 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1364 sw->obj_instance[0], sw->obj_instance[1],
1365 sw->obj_instance[2]);
1366
1367 /* FIXME: this is BS11 specific format */
1368 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1369 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1370 sw->file_version);
1371
1372 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001373}
Harald Welte4724f992009-01-18 18:01:49 +00001374
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001375struct sdp_firmware {
1376 char magic[4];
1377 char more_magic[4];
1378 unsigned int header_length;
1379 unsigned int file_length;
1380} __attribute__ ((packed));
1381
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001382static int parse_sdp_header(struct abis_nm_sw *sw)
1383{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001384 struct sdp_firmware firmware_header;
1385 int rc;
1386 struct stat stat;
1387
1388 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1389 if (rc != sizeof(firmware_header)) {
1390 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1391 return -1;
1392 }
1393
1394 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1395 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1396 return -1;
1397 }
1398
1399 if (firmware_header.more_magic[0] != 0x10 ||
1400 firmware_header.more_magic[1] != 0x02 ||
1401 firmware_header.more_magic[2] != 0x00 ||
1402 firmware_header.more_magic[3] != 0x00) {
1403 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1404 return -1;
1405 }
1406
1407
1408 if (fstat(sw->fd, &stat) == -1) {
1409 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1410 return -1;
1411 }
1412
1413 if (ntohl(firmware_header.file_length) != stat.st_size) {
1414 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1415 return -1;
1416 }
1417
1418 /* go back to the start as we checked the whole filesize.. */
1419 lseek(sw->fd, 0l, SEEK_SET);
1420 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1421 "There might be checksums in the file that are not\n"
1422 "verified and incomplete firmware might be flashed.\n"
1423 "There is absolutely no WARRANTY that flashing will\n"
1424 "work.\n");
1425 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001426}
1427
Harald Welte4724f992009-01-18 18:01:49 +00001428static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1429{
1430 char file_id[12+1];
1431 char file_version[80+1];
1432 int rc;
1433
1434 sw->fd = open(fname, O_RDONLY);
1435 if (sw->fd < 0)
1436 return sw->fd;
1437
1438 switch (sw->bts->type) {
1439 case GSM_BTS_TYPE_BS11:
1440 sw->stream = fdopen(sw->fd, "r");
1441 if (!sw->stream) {
1442 perror("fdopen");
1443 return -1;
1444 }
1445 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001446 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001447 file_id, file_version);
1448 if (rc != 2) {
1449 perror("parsing header line of software file");
1450 return -1;
1451 }
1452 strcpy((char *)sw->file_id, file_id);
1453 sw->file_id_len = strlen(file_id);
1454 strcpy((char *)sw->file_version, file_version);
1455 sw->file_version_len = strlen(file_version);
1456 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001457 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001458 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001459 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001460 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001461 rc = parse_sdp_header(sw);
1462 if (rc < 0) {
1463 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1464 return -1;
1465 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001466
1467 strcpy((char *)sw->file_id, "id");
1468 sw->file_id_len = 3;
1469 strcpy((char *)sw->file_version, "version");
1470 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001471 break;
Harald Welte4724f992009-01-18 18:01:49 +00001472 default:
1473 /* We don't know how to treat them yet */
1474 close(sw->fd);
1475 return -EINVAL;
1476 }
1477
1478 return 0;
1479}
1480
1481static void sw_close_file(struct abis_nm_sw *sw)
1482{
1483 switch (sw->bts->type) {
1484 case GSM_BTS_TYPE_BS11:
1485 fclose(sw->stream);
1486 break;
1487 default:
1488 close(sw->fd);
1489 break;
1490 }
1491}
1492
1493/* Fill the window */
1494static int sw_fill_window(struct abis_nm_sw *sw)
1495{
1496 int rc;
1497
1498 while (sw->seg_in_window < sw->window_size) {
1499 rc = sw_load_segment(sw);
1500 if (rc < 0)
1501 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001502 if (sw->last_seg)
1503 break;
Harald Welte4724f992009-01-18 18:01:49 +00001504 }
1505 return 0;
1506}
1507
1508/* callback function from abis_nm_rcvmsg() handler */
1509static int abis_nm_rcvmsg_sw(struct msgb *mb)
1510{
1511 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1512 int rc = -1;
1513 struct abis_nm_sw *sw = &g_sw;
1514 enum sw_state old_state = sw->state;
1515
Harald Welte3ffd1372009-02-01 22:15:49 +00001516 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001517
1518 switch (sw->state) {
1519 case SW_STATE_WAIT_INITACK:
1520 switch (foh->msg_type) {
1521 case NM_MT_LOAD_INIT_ACK:
1522 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001523 if (sw->cbfn)
1524 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1525 NM_MT_LOAD_INIT_ACK, mb,
1526 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001527 rc = sw_fill_window(sw);
1528 sw->state = SW_STATE_WAIT_SEGACK;
1529 break;
1530 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001531 if (sw->forced) {
1532 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1533 "Init NACK\n");
1534 if (sw->cbfn)
1535 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1536 NM_MT_LOAD_INIT_ACK, mb,
1537 sw->cb_data, NULL);
1538 rc = sw_fill_window(sw);
1539 sw->state = SW_STATE_WAIT_SEGACK;
1540 } else {
1541 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001542 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001543 if (sw->cbfn)
1544 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1545 NM_MT_LOAD_INIT_NACK, mb,
1546 sw->cb_data, NULL);
1547 sw->state = SW_STATE_ERROR;
1548 }
Harald Welte4724f992009-01-18 18:01:49 +00001549 break;
1550 }
1551 break;
1552 case SW_STATE_WAIT_SEGACK:
1553 switch (foh->msg_type) {
1554 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001555 if (sw->cbfn)
1556 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1557 NM_MT_LOAD_SEG_ACK, mb,
1558 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001559 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001560 if (!sw->last_seg) {
1561 /* fill window with more segments */
1562 rc = sw_fill_window(sw);
1563 sw->state = SW_STATE_WAIT_SEGACK;
1564 } else {
1565 /* end the transfer */
1566 sw->state = SW_STATE_WAIT_ENDACK;
1567 rc = sw_load_end(sw);
1568 }
Harald Welte4724f992009-01-18 18:01:49 +00001569 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001570 case NM_MT_LOAD_ABORT:
1571 if (sw->cbfn)
1572 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1573 NM_MT_LOAD_ABORT, mb,
1574 sw->cb_data, NULL);
1575 break;
Harald Welte4724f992009-01-18 18:01:49 +00001576 }
1577 break;
1578 case SW_STATE_WAIT_ENDACK:
1579 switch (foh->msg_type) {
1580 case NM_MT_LOAD_END_ACK:
1581 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001582 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1583 sw->bts->nr);
1584 sw->state = SW_STATE_NONE;
1585 if (sw->cbfn)
1586 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1587 NM_MT_LOAD_END_ACK, mb,
1588 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001589 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001590 break;
1591 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001592 if (sw->forced) {
1593 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1594 "End NACK\n");
1595 sw->state = SW_STATE_NONE;
1596 if (sw->cbfn)
1597 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1598 NM_MT_LOAD_END_ACK, mb,
1599 sw->cb_data, NULL);
1600 } else {
1601 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001602 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001603 sw->state = SW_STATE_ERROR;
1604 if (sw->cbfn)
1605 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1606 NM_MT_LOAD_END_NACK, mb,
1607 sw->cb_data, NULL);
1608 }
Harald Welte4724f992009-01-18 18:01:49 +00001609 break;
1610 }
1611 case SW_STATE_WAIT_ACTACK:
1612 switch (foh->msg_type) {
1613 case NM_MT_ACTIVATE_SW_ACK:
1614 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001615 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001616 sw->state = SW_STATE_NONE;
1617 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001618 if (sw->cbfn)
1619 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1620 NM_MT_ACTIVATE_SW_ACK, mb,
1621 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001622 break;
1623 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001624 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001625 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001626 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001627 if (sw->cbfn)
1628 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1629 NM_MT_ACTIVATE_SW_NACK, mb,
1630 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001631 break;
1632 }
1633 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001634 switch (foh->msg_type) {
1635 case NM_MT_ACTIVATE_SW_ACK:
1636 rc = 0;
1637 break;
1638 }
1639 break;
Harald Welte4724f992009-01-18 18:01:49 +00001640 case SW_STATE_ERROR:
1641 break;
1642 }
1643
1644 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001645 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001646 foh->msg_type, old_state, sw->state);
1647
1648 return rc;
1649}
1650
1651/* Load the specified software into the BTS */
1652int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001653 u_int8_t win_size, int forced,
1654 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001655{
1656 struct abis_nm_sw *sw = &g_sw;
1657 int rc;
1658
Harald Welte5e4d1b32009-02-01 13:36:56 +00001659 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1660 bts->nr, fname);
1661
Harald Welte4724f992009-01-18 18:01:49 +00001662 if (sw->state != SW_STATE_NONE)
1663 return -EBUSY;
1664
1665 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001666
1667 switch (bts->type) {
1668 case GSM_BTS_TYPE_BS11:
1669 sw->obj_class = NM_OC_SITE_MANAGER;
1670 sw->obj_instance[0] = 0xff;
1671 sw->obj_instance[1] = 0xff;
1672 sw->obj_instance[2] = 0xff;
1673 break;
1674 case GSM_BTS_TYPE_NANOBTS:
1675 sw->obj_class = NM_OC_BASEB_TRANSC;
1676 sw->obj_instance[0] = 0x00;
1677 sw->obj_instance[1] = 0x00;
1678 sw->obj_instance[2] = 0xff;
1679 break;
1680 case GSM_BTS_TYPE_UNKNOWN:
1681 default:
1682 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1683 return -1;
1684 break;
1685 }
Harald Welte4724f992009-01-18 18:01:49 +00001686 sw->window_size = win_size;
1687 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001688 sw->cbfn = cbfn;
1689 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001690 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001691
1692 rc = sw_open_file(sw, fname);
1693 if (rc < 0) {
1694 sw->state = SW_STATE_NONE;
1695 return rc;
1696 }
1697
1698 return sw_load_init(sw);
1699}
Harald Welte52b1f982008-12-23 20:25:15 +00001700
Harald Welte1602ade2009-01-29 21:12:39 +00001701int abis_nm_software_load_status(struct gsm_bts *bts)
1702{
1703 struct abis_nm_sw *sw = &g_sw;
1704 struct stat st;
1705 int rc, percent;
1706
1707 rc = fstat(sw->fd, &st);
1708 if (rc < 0) {
1709 perror("ERROR during stat");
1710 return rc;
1711 }
1712
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001713 if (sw->stream)
1714 percent = (ftell(sw->stream) * 100) / st.st_size;
1715 else
1716 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001717 return percent;
1718}
1719
Harald Welte5e4d1b32009-02-01 13:36:56 +00001720/* Activate the specified software into the BTS */
1721int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1722 gsm_cbfn *cbfn, void *cb_data)
1723{
1724 struct abis_nm_sw *sw = &g_sw;
1725 int rc;
1726
1727 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1728 bts->nr, fname);
1729
1730 if (sw->state != SW_STATE_NONE)
1731 return -EBUSY;
1732
1733 sw->bts = bts;
1734 sw->obj_class = NM_OC_SITE_MANAGER;
1735 sw->obj_instance[0] = 0xff;
1736 sw->obj_instance[1] = 0xff;
1737 sw->obj_instance[2] = 0xff;
1738 sw->state = SW_STATE_WAIT_ACTACK;
1739 sw->cbfn = cbfn;
1740 sw->cb_data = cb_data;
1741
1742 /* Open the file in order to fill some sw struct members */
1743 rc = sw_open_file(sw, fname);
1744 if (rc < 0) {
1745 sw->state = SW_STATE_NONE;
1746 return rc;
1747 }
1748 sw_close_file(sw);
1749
1750 return sw_activate(sw);
1751}
1752
Harald Welte8470bf22008-12-25 23:28:35 +00001753static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001754 u_int8_t ts_nr, u_int8_t subslot_nr)
1755{
Harald Welteadaf08b2009-01-18 11:08:10 +00001756 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001757 ch->bts_port = bts_port;
1758 ch->timeslot = ts_nr;
1759 ch->subslot = subslot_nr;
1760}
1761
1762int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1763 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1764 u_int8_t tei)
1765{
1766 struct abis_om_hdr *oh;
1767 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001768 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001769 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001770
1771 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1772 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1773 bts->bts_nr, trx_nr, 0xff);
1774
Harald Welte8470bf22008-12-25 23:28:35 +00001775 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001776
1777 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1778 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1779
1780 return abis_nm_sendmsg(bts, msg);
1781}
1782
1783/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1784int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1785 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1786{
Harald Welte8470bf22008-12-25 23:28:35 +00001787 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001788 struct abis_om_hdr *oh;
1789 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001790 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001791
1792 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001793 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001794 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1795
1796 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1797 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1798
1799 return abis_nm_sendmsg(bts, msg);
1800}
1801
1802#if 0
1803int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1804 struct abis_nm_abis_channel *chan)
1805{
1806}
1807#endif
1808
1809int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1810 u_int8_t e1_port, u_int8_t e1_timeslot,
1811 u_int8_t e1_subslot)
1812{
1813 struct gsm_bts *bts = ts->trx->bts;
1814 struct abis_om_hdr *oh;
1815 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001816 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001817
1818 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1819 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001820 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001821
1822 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1823 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1824
Harald Weltef325eb42009-02-19 17:07:39 +00001825 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1826 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001827 e1_port, e1_timeslot, e1_subslot);
1828
Harald Welte52b1f982008-12-23 20:25:15 +00001829 return abis_nm_sendmsg(bts, msg);
1830}
1831
1832#if 0
1833int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1834 struct abis_nm_abis_channel *chan,
1835 u_int8_t subchan)
1836{
1837}
1838#endif
1839
Harald Welte22af0db2009-02-14 15:41:08 +00001840/* Chapter 8.6.1 */
1841int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1842{
1843 struct abis_om_hdr *oh;
1844 struct msgb *msg = nm_msgb_alloc();
1845 u_int8_t *cur;
1846
1847 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1848
1849 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001850 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 +00001851 cur = msgb_put(msg, attr_len);
1852 memcpy(cur, attr, attr_len);
1853
1854 return abis_nm_sendmsg(bts, msg);
1855}
1856
1857/* Chapter 8.6.2 */
1858int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1859{
1860 struct abis_om_hdr *oh;
1861 struct msgb *msg = nm_msgb_alloc();
1862 u_int8_t *cur;
1863
1864 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1865
1866 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1867 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001868 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001869 cur = msgb_put(msg, attr_len);
1870 memcpy(cur, attr, attr_len);
1871
1872 return abis_nm_sendmsg(trx->bts, msg);
1873}
1874
Harald Welte39c7deb2009-08-09 21:49:48 +02001875static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1876{
1877 int i;
1878
1879 /* As it turns out, the BS-11 has some very peculiar restrictions
1880 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301881 switch (ts->trx->bts->type) {
1882 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001883 switch (chan_comb) {
1884 case NM_CHANC_TCHHalf:
1885 case NM_CHANC_TCHHalf2:
1886 /* not supported */
1887 return -EINVAL;
1888 case NM_CHANC_SDCCH:
1889 /* only one SDCCH/8 per TRX */
1890 for (i = 0; i < TRX_NR_TS; i++) {
1891 if (i == ts->nr)
1892 continue;
1893 if (ts->trx->ts[i].nm_chan_comb ==
1894 NM_CHANC_SDCCH)
1895 return -EINVAL;
1896 }
1897 /* not allowed for TS0 of BCCH-TRX */
1898 if (ts->trx == ts->trx->bts->c0 &&
1899 ts->nr == 0)
1900 return -EINVAL;
1901 /* not on the same TRX that has a BCCH+SDCCH4
1902 * combination */
1903 if (ts->trx == ts->trx->bts->c0 &&
1904 (ts->trx->ts[0].nm_chan_comb == 5 ||
1905 ts->trx->ts[0].nm_chan_comb == 8))
1906 return -EINVAL;
1907 break;
1908 case NM_CHANC_mainBCCH:
1909 case NM_CHANC_BCCHComb:
1910 /* allowed only for TS0 of C0 */
1911 if (ts->trx != ts->trx->bts->c0 ||
1912 ts->nr != 0)
1913 return -EINVAL;
1914 break;
1915 case NM_CHANC_BCCH:
1916 /* allowed only for TS 2/4/6 of C0 */
1917 if (ts->trx != ts->trx->bts->c0)
1918 return -EINVAL;
1919 if (ts->nr != 2 && ts->nr != 4 &&
1920 ts->nr != 6)
1921 return -EINVAL;
1922 break;
1923 case 8: /* this is not like 08.58, but in fact
1924 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1925 /* FIXME: only one CBCH allowed per cell */
1926 break;
1927 }
Harald Welted6575f92009-12-02 02:45:23 +05301928 break;
1929 case GSM_BTS_TYPE_NANOBTS:
1930 switch (ts->nr) {
1931 case 0:
1932 if (ts->trx->nr == 0) {
1933 /* only on TRX0 */
1934 switch (chan_comb) {
1935 case NM_CHANC_BCCH:
1936 case NM_CHANC_mainBCCH:
1937 case NM_CHANC_BCCHComb:
1938 return 0;
1939 break;
1940 default:
1941 return -EINVAL;
1942 }
1943 } else {
1944 switch (chan_comb) {
1945 case NM_CHANC_TCHFull:
1946 case NM_CHANC_TCHHalf:
1947 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1948 return 0;
1949 default:
1950 return -EINVAL;
1951 }
1952 }
1953 break;
1954 case 1:
1955 if (ts->trx->nr == 0) {
1956 switch (chan_comb) {
1957 case NM_CHANC_SDCCH_CBCH:
1958 if (ts->trx->ts[0].nm_chan_comb ==
1959 NM_CHANC_mainBCCH)
1960 return 0;
1961 return -EINVAL;
1962 case NM_CHANC_SDCCH:
1963 case NM_CHANC_TCHFull:
1964 case NM_CHANC_TCHHalf:
1965 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1966 case NM_CHANC_IPAC_TCHFull_PDCH:
1967 return 0;
1968 }
1969 } else {
1970 switch (chan_comb) {
1971 case NM_CHANC_SDCCH:
1972 case NM_CHANC_TCHFull:
1973 case NM_CHANC_TCHHalf:
1974 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1975 return 0;
1976 default:
1977 return -EINVAL;
1978 }
1979 }
1980 break;
1981 case 2:
1982 case 3:
1983 case 4:
1984 case 5:
1985 case 6:
1986 case 7:
1987 switch (chan_comb) {
1988 case NM_CHANC_TCHFull:
1989 case NM_CHANC_TCHHalf:
1990 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1991 return 0;
1992 case NM_CHANC_IPAC_PDCH:
1993 case NM_CHANC_IPAC_TCHFull_PDCH:
1994 if (ts->trx->nr == 0)
1995 return 0;
1996 else
1997 return -EINVAL;
1998 }
1999 break;
2000 }
2001 return -EINVAL;
2002 default:
2003 /* unknown BTS type */
2004 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002005 }
2006 return 0;
2007}
2008
Harald Welte22af0db2009-02-14 15:41:08 +00002009/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002010int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2011{
2012 struct gsm_bts *bts = ts->trx->bts;
2013 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002014 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002015 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002016 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002017 u_int8_t len = 2 + 2;
2018
2019 if (bts->type == GSM_BTS_TYPE_BS11)
2020 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002021
Harald Weltef325eb42009-02-19 17:07:39 +00002022 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002023 if (verify_chan_comb(ts, chan_comb) < 0) {
2024 msgb_free(msg);
2025 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2026 return -EINVAL;
2027 }
2028 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002029
Harald Welte52b1f982008-12-23 20:25:15 +00002030 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002031 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002032 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002033 ts->trx->nr, ts->nr);
2034 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00002035 if (bts->type == GSM_BTS_TYPE_BS11)
2036 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002037 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00002038 if (bts->type == GSM_BTS_TYPE_BS11) {
2039 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2040 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2041 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002042 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002043 if (bts->type == GSM_BTS_TYPE_BS11)
2044 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002045
2046 return abis_nm_sendmsg(bts, msg);
2047}
2048
Harald Welte34a99682009-02-13 02:41:40 +00002049int 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 +00002050 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002051{
2052 struct abis_om_hdr *oh;
2053 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002054 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2055 u_int8_t len = att_len;
2056
2057 if (nack) {
2058 len += 2;
2059 msgtype = NM_MT_SW_ACT_REQ_NACK;
2060 }
Harald Welte34a99682009-02-13 02:41:40 +00002061
2062 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002063 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2064
Harald Welte34a99682009-02-13 02:41:40 +00002065 if (attr) {
2066 u_int8_t *ptr = msgb_put(msg, att_len);
2067 memcpy(ptr, attr, att_len);
2068 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002069 if (nack)
2070 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002071
2072 return abis_nm_sendmsg(bts, msg);
2073}
2074
Harald Welte8470bf22008-12-25 23:28:35 +00002075int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002076{
Harald Welte8470bf22008-12-25 23:28:35 +00002077 struct msgb *msg = nm_msgb_alloc();
2078 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002079 u_int8_t *data;
2080
2081 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2082 fill_om_hdr(oh, len);
2083 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002084 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002085
2086 return abis_nm_sendmsg(bts, msg);
2087}
2088
2089/* Siemens specific commands */
2090static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2091{
2092 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002093 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002094
2095 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002096 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002097 0xff, 0xff, 0xff);
2098
2099 return abis_nm_sendmsg(bts, msg);
2100}
2101
Harald Welte34a99682009-02-13 02:41:40 +00002102/* Chapter 8.9.2 */
2103int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2104{
2105 struct abis_om_hdr *oh;
2106 struct msgb *msg = nm_msgb_alloc();
2107
2108 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2109 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2110
Harald Weltea8bd6d42009-10-20 09:56:18 +02002111 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2112 DEBUGPC(DNM, "Sending OPSTART\n");
2113
Harald Welte34a99682009-02-13 02:41:40 +00002114 return abis_nm_sendmsg(bts, msg);
2115}
2116
2117/* Chapter 8.8.5 */
2118int 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 +02002119 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002120{
2121 struct abis_om_hdr *oh;
2122 struct msgb *msg = nm_msgb_alloc();
2123
2124 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2125 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2126 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2127
2128 return abis_nm_sendmsg(bts, msg);
2129}
2130
Harald Welte1989c082009-08-06 17:58:31 +02002131int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2132 u_int8_t e1_port1, u_int8_t ts1)
2133{
2134 struct abis_om_hdr *oh;
2135 struct msgb *msg = nm_msgb_alloc();
2136 u_int8_t *attr;
2137
2138 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2139 e1_port0, ts0, e1_port1, ts1);
2140
2141 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2142 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2143 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2144
2145 attr = msgb_put(msg, 3);
2146 attr[0] = NM_ATT_MDROP_LINK;
2147 attr[1] = e1_port0;
2148 attr[2] = ts0;
2149
2150 attr = msgb_put(msg, 3);
2151 attr[0] = NM_ATT_MDROP_NEXT;
2152 attr[1] = e1_port1;
2153 attr[2] = ts1;
2154
2155 return abis_nm_sendmsg(bts, msg);
2156}
Harald Welte34a99682009-02-13 02:41:40 +00002157
Harald Weltec7310382009-08-08 00:02:36 +02002158/* Chapter 8.7.1 */
2159int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2160 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2161 u_int8_t test_nr, u_int8_t auton_report,
2162 u_int8_t *phys_config, u_int16_t phys_config_len)
2163{
2164 struct abis_om_hdr *oh;
2165 struct msgb *msg = nm_msgb_alloc();
2166 int len = 4; /* 2 TV attributes */
2167
2168 DEBUGP(DNM, "PEFORM TEST\n");
2169
2170 if (phys_config_len)
2171 len += 3 + phys_config_len;
2172
2173 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2174 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2175 obj_class, bts_nr, trx_nr, ts_nr);
2176 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2177 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2178 if (phys_config_len)
2179 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2180 phys_config);
2181
2182 return abis_nm_sendmsg(bts, msg);
2183}
2184
Harald Welte52b1f982008-12-23 20:25:15 +00002185int abis_nm_event_reports(struct gsm_bts *bts, int on)
2186{
2187 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002188 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002189 else
Harald Welte227d4072009-01-03 08:16:25 +00002190 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002191}
2192
Harald Welte47d88ae2009-01-04 12:02:08 +00002193/* Siemens (or BS-11) specific commands */
2194
Harald Welte3ffd1372009-02-01 22:15:49 +00002195int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2196{
2197 if (reconnect == 0)
2198 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2199 else
2200 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2201}
2202
Harald Welteb8427972009-02-05 19:27:17 +00002203int abis_nm_bs11_restart(struct gsm_bts *bts)
2204{
2205 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2206}
2207
2208
Harald Welte268bb402009-02-01 19:11:56 +00002209struct bs11_date_time {
2210 u_int16_t year;
2211 u_int8_t month;
2212 u_int8_t day;
2213 u_int8_t hour;
2214 u_int8_t min;
2215 u_int8_t sec;
2216} __attribute__((packed));
2217
2218
2219void get_bs11_date_time(struct bs11_date_time *aet)
2220{
2221 time_t t;
2222 struct tm *tm;
2223
2224 t = time(NULL);
2225 tm = localtime(&t);
2226 aet->sec = tm->tm_sec;
2227 aet->min = tm->tm_min;
2228 aet->hour = tm->tm_hour;
2229 aet->day = tm->tm_mday;
2230 aet->month = tm->tm_mon;
2231 aet->year = htons(1900 + tm->tm_year);
2232}
2233
Harald Welte05188ee2009-01-18 11:39:08 +00002234int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002235{
Harald Welte4668fda2009-01-03 08:19:29 +00002236 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002237}
2238
Harald Welte05188ee2009-01-18 11:39:08 +00002239int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002240{
2241 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002242 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002243 else
Harald Welte4668fda2009-01-03 08:19:29 +00002244 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002245}
Harald Welte47d88ae2009-01-04 12:02:08 +00002246
Harald Welte05188ee2009-01-18 11:39:08 +00002247int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002248 enum abis_bs11_objtype type, u_int8_t idx,
2249 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002250{
2251 struct abis_om_hdr *oh;
2252 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002253 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002254
2255 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002256 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002257 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002258 cur = msgb_put(msg, attr_len);
2259 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002260
2261 return abis_nm_sendmsg(bts, msg);
2262}
2263
Harald Welte78fc0d42009-02-19 02:50:57 +00002264int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2265 enum abis_bs11_objtype type, u_int8_t idx)
2266{
2267 struct abis_om_hdr *oh;
2268 struct msgb *msg = nm_msgb_alloc();
2269
2270 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2271 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2272 NM_OC_BS11, type, 0, idx);
2273
2274 return abis_nm_sendmsg(bts, msg);
2275}
2276
Harald Welte05188ee2009-01-18 11:39:08 +00002277int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002278{
2279 struct abis_om_hdr *oh;
2280 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002281 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002282
2283 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002284 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002285 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2286 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002287
2288 return abis_nm_sendmsg(bts, msg);
2289}
2290
Harald Welte05188ee2009-01-18 11:39:08 +00002291int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002292{
2293 struct abis_om_hdr *oh;
2294 struct msgb *msg = nm_msgb_alloc();
2295
2296 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2297 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002298 idx, 0xff, 0xff);
2299
2300 return abis_nm_sendmsg(bts, msg);
2301}
2302
2303int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2304{
2305 struct abis_om_hdr *oh;
2306 struct msgb *msg = nm_msgb_alloc();
2307
2308 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2309 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2310 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002311
2312 return abis_nm_sendmsg(bts, msg);
2313}
Harald Welte05188ee2009-01-18 11:39:08 +00002314
Harald Welte78fc0d42009-02-19 02:50:57 +00002315static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2316int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2317{
2318 struct abis_om_hdr *oh;
2319 struct msgb *msg = nm_msgb_alloc();
2320
2321 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2322 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2323 0xff, 0xff, 0xff);
2324 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2325
2326 return abis_nm_sendmsg(bts, msg);
2327}
2328
Harald Welteb6c92ae2009-02-21 20:15:32 +00002329/* like abis_nm_conn_terr_traf + set_tei */
2330int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2331 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2332 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002333{
2334 struct abis_om_hdr *oh;
2335 struct abis_nm_channel *ch;
2336 struct msgb *msg = nm_msgb_alloc();
2337
2338 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002339 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002340 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2341
2342 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2343 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002344 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002345
2346 return abis_nm_sendmsg(bts, msg);
2347}
2348
2349int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2350{
2351 struct abis_om_hdr *oh;
2352 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002353
2354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002355 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002356 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2357 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2358
2359 return abis_nm_sendmsg(trx->bts, msg);
2360}
2361
Harald Welte78fc0d42009-02-19 02:50:57 +00002362int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2363{
2364 struct abis_om_hdr *oh;
2365 struct msgb *msg = nm_msgb_alloc();
2366 u_int8_t attr = NM_ATT_BS11_TXPWR;
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_PA, 0x00, trx->nr);
2371 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2372
2373 return abis_nm_sendmsg(trx->bts, msg);
2374}
2375
Harald Welteaaf02d92009-04-29 13:25:57 +00002376int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2377{
2378 struct abis_om_hdr *oh;
2379 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002380 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002381
2382 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2383 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2384 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002385 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002386
2387 return abis_nm_sendmsg(bts, msg);
2388}
2389
Harald Welteef061952009-05-17 12:43:42 +00002390int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2391{
2392 struct abis_om_hdr *oh;
2393 struct msgb *msg = nm_msgb_alloc();
2394 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2395 NM_ATT_BS11_CCLK_TYPE };
2396
2397 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2398 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2399 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2400 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2401
2402 return abis_nm_sendmsg(bts, msg);
2403
2404}
Harald Welteaaf02d92009-04-29 13:25:57 +00002405
Harald Welte268bb402009-02-01 19:11:56 +00002406//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +00002407static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +00002408static const u_int8_t bs11_logon_c9[] = "FACTORY";
2409
Harald Welte1bc09062009-01-18 14:17:52 +00002410int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002411{
2412 struct abis_om_hdr *oh;
2413 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002414 struct bs11_date_time bdt;
2415
2416 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002417
2418 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002419 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002420 u_int8_t len = 3*2 + sizeof(bdt)
Harald Welte6f676a32009-01-18 14:27:48 +00002421 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +00002422 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002423 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002424 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002425 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002426 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2427 sizeof(bs11_logon_c8), bs11_logon_c8);
2428 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2429 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +00002430 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002431 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002432 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002433 }
Harald Welte05188ee2009-01-18 11:39:08 +00002434
2435 return abis_nm_sendmsg(bts, msg);
2436}
Harald Welte1bc09062009-01-18 14:17:52 +00002437
2438int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2439{
2440 struct abis_om_hdr *oh;
2441 struct msgb *msg;
2442
2443 if (strlen(password) != 10)
2444 return -EINVAL;
2445
2446 msg = nm_msgb_alloc();
2447 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002448 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002449 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2450 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2451
2452 return abis_nm_sendmsg(bts, msg);
2453}
2454
Harald Weltee69f5fb2009-04-28 16:31:38 +00002455/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2456int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2457{
2458 struct abis_om_hdr *oh;
2459 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002460 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002461
2462 msg = nm_msgb_alloc();
2463 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2464 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2465 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002466
2467 if (locked)
2468 tlv_value = BS11_LI_PLL_LOCKED;
2469 else
2470 tlv_value = BS11_LI_PLL_STANDALONE;
2471
2472 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002473
2474 return abis_nm_sendmsg(bts, msg);
2475}
2476
Harald Welte1bc09062009-01-18 14:17:52 +00002477int abis_nm_bs11_get_state(struct gsm_bts *bts)
2478{
2479 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2480}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002481
2482/* BS11 SWL */
2483
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002484void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002485
Harald Welte5e4d1b32009-02-01 13:36:56 +00002486struct abis_nm_bs11_sw {
2487 struct gsm_bts *bts;
2488 char swl_fname[PATH_MAX];
2489 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002490 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002491 struct llist_head file_list;
2492 gsm_cbfn *user_cb; /* specified by the user */
2493};
2494static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2495
2496struct file_list_entry {
2497 struct llist_head list;
2498 char fname[PATH_MAX];
2499};
2500
2501struct file_list_entry *fl_dequeue(struct llist_head *queue)
2502{
2503 struct llist_head *lh;
2504
2505 if (llist_empty(queue))
2506 return NULL;
2507
2508 lh = queue->next;
2509 llist_del(lh);
2510
2511 return llist_entry(lh, struct file_list_entry, list);
2512}
2513
2514static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2515{
2516 char linebuf[255];
2517 struct llist_head *lh, *lh2;
2518 FILE *swl;
2519 int rc = 0;
2520
2521 swl = fopen(bs11_sw->swl_fname, "r");
2522 if (!swl)
2523 return -ENODEV;
2524
2525 /* zero the stale file list, if any */
2526 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2527 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002528 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002529 }
2530
2531 while (fgets(linebuf, sizeof(linebuf), swl)) {
2532 char file_id[12+1];
2533 char file_version[80+1];
2534 struct file_list_entry *fle;
2535 static char dir[PATH_MAX];
2536
2537 if (strlen(linebuf) < 4)
2538 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002539
Harald Welte5e4d1b32009-02-01 13:36:56 +00002540 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2541 if (rc < 0) {
2542 perror("ERR parsing SWL file");
2543 rc = -EINVAL;
2544 goto out;
2545 }
2546 if (rc < 2)
2547 continue;
2548
Harald Welte470ec292009-06-26 20:25:23 +02002549 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002550 if (!fle) {
2551 rc = -ENOMEM;
2552 goto out;
2553 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002554
2555 /* construct new filename */
2556 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2557 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2558 strcat(fle->fname, "/");
2559 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002560
2561 llist_add_tail(&fle->list, &bs11_sw->file_list);
2562 }
2563
2564out:
2565 fclose(swl);
2566 return rc;
2567}
2568
2569/* bs11 swload specific callback, passed to abis_nm core swload */
2570static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2571 struct msgb *msg, void *data, void *param)
2572{
2573 struct abis_nm_bs11_sw *bs11_sw = data;
2574 struct file_list_entry *fle;
2575 int rc = 0;
2576
Harald Welte5e4d1b32009-02-01 13:36:56 +00002577 switch (event) {
2578 case NM_MT_LOAD_END_ACK:
2579 fle = fl_dequeue(&bs11_sw->file_list);
2580 if (fle) {
2581 /* start download the next file of our file list */
2582 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2583 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002584 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002585 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002586 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002587 } else {
2588 /* activate the SWL */
2589 rc = abis_nm_software_activate(bs11_sw->bts,
2590 bs11_sw->swl_fname,
2591 bs11_swload_cbfn,
2592 bs11_sw);
2593 }
2594 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002595 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002596 case NM_MT_LOAD_END_NACK:
2597 case NM_MT_LOAD_INIT_ACK:
2598 case NM_MT_LOAD_INIT_NACK:
2599 case NM_MT_ACTIVATE_SW_NACK:
2600 case NM_MT_ACTIVATE_SW_ACK:
2601 default:
2602 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002603 if (bs11_sw->user_cb)
2604 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002605 break;
2606 }
2607
2608 return rc;
2609}
2610
2611/* Siemens provides a SWL file that is a mere listing of all the other
2612 * files that are part of a software release. We need to upload first
2613 * the list file, and then each file that is listed in the list file */
2614int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002615 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002616{
2617 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2618 struct file_list_entry *fle;
2619 int rc = 0;
2620
2621 INIT_LLIST_HEAD(&bs11_sw->file_list);
2622 bs11_sw->bts = bts;
2623 bs11_sw->win_size = win_size;
2624 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002625 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002626
2627 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2628 rc = bs11_read_swl_file(bs11_sw);
2629 if (rc < 0)
2630 return rc;
2631
2632 /* dequeue next item in file list */
2633 fle = fl_dequeue(&bs11_sw->file_list);
2634 if (!fle)
2635 return -EINVAL;
2636
2637 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002638 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002639 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002640 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002641 return rc;
2642}
2643
Harald Welte5083b0b2009-02-02 19:20:52 +00002644#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002645static u_int8_t req_attr_btse[] = {
2646 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2647 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2648 NM_ATT_BS11_LMT_USER_NAME,
2649
2650 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2651
2652 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2653
2654 NM_ATT_BS11_SW_LOAD_STORED };
2655
2656static u_int8_t req_attr_btsm[] = {
2657 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2658 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2659 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2660 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002661#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002662
2663static u_int8_t req_attr[] = {
2664 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2665 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002666 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002667
2668int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2669{
2670 struct abis_om_hdr *oh;
2671 struct msgb *msg = nm_msgb_alloc();
2672
2673 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2674 /* SiemensHW CCTRL object */
2675 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2676 0x03, 0x00, 0x00);
2677 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2678
2679 return abis_nm_sendmsg(bts, msg);
2680}
Harald Welte268bb402009-02-01 19:11:56 +00002681
2682int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2683{
2684 struct abis_om_hdr *oh;
2685 struct msgb *msg = nm_msgb_alloc();
2686 struct bs11_date_time aet;
2687
2688 get_bs11_date_time(&aet);
2689 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2690 /* SiemensHW CCTRL object */
2691 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2692 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002693 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002694
2695 return abis_nm_sendmsg(bts, msg);
2696}
Harald Welte5c1e4582009-02-15 11:57:29 +00002697
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002698int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2699{
2700 struct abis_om_hdr *oh;
2701 struct msgb *msg = nm_msgb_alloc();
2702 struct bs11_date_time aet;
2703
2704 get_bs11_date_time(&aet);
2705 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2706 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2707 bport, 0xff, 0x02);
2708 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2709
2710 return abis_nm_sendmsg(bts, msg);
2711}
2712
Harald Welte5c1e4582009-02-15 11:57:29 +00002713/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002714static const char ipaccess_magic[] = "com.ipaccess";
2715
Harald Welte677c21f2009-02-17 13:22:23 +00002716
2717static int abis_nm_rx_ipacc(struct msgb *msg)
2718{
2719 struct abis_om_hdr *oh = msgb_l2(msg);
2720 struct abis_om_fom_hdr *foh;
2721 u_int8_t idstrlen = oh->data[0];
2722 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002723 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002724
2725 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002726 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002727 return -EINVAL;
2728 }
2729
Harald Welte193fefc2009-04-30 15:16:27 +00002730 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002731 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002732
Harald Weltea8bd6d42009-10-20 09:56:18 +02002733 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002734
Harald Welte746d6092009-10-19 22:11:11 +02002735 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002736
Harald Welte677c21f2009-02-17 13:22:23 +00002737 switch (foh->msg_type) {
2738 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002739 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002740 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002741 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002742 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002743 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2744 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002745 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002746 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002747 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002748 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2749 DEBUGPC(DNM, "STREAM=0x%02x ",
2750 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002751 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002752 break;
2753 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002754 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002755 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002756 DEBUGPC(DNM, " CAUSE=%s\n",
2757 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002758 else
2759 DEBUGPC(DNM, "\n");
2760 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002761 case NM_MT_IPACC_SET_NVATTR_ACK:
2762 DEBUGPC(DNM, "SET NVATTR ACK\n");
2763 /* FIXME: decode and show the actual attributes */
2764 break;
2765 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002766 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002767 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002768 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002769 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2770 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002771 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002772 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002773 case NM_MT_IPACC_GET_NVATTR_ACK:
2774 DEBUGPC(DNM, "GET NVATTR ACK\n");
2775 /* FIXME: decode and show the actual attributes */
2776 break;
2777 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002778 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002779 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002780 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002781 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2782 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002783 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002784 break;
Harald Welte15c44172009-10-08 20:15:24 +02002785 case NM_MT_IPACC_SET_ATTR_ACK:
2786 DEBUGPC(DNM, "SET ATTR ACK\n");
2787 break;
2788 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002789 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002790 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002791 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002792 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2793 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002794 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002795 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002796 default:
2797 DEBUGPC(DNM, "unknown\n");
2798 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002799 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002800
2801 /* signal handling */
2802 switch (foh->msg_type) {
2803 case NM_MT_IPACC_RSL_CONNECT_NACK:
2804 case NM_MT_IPACC_SET_NVATTR_NACK:
2805 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002806 signal.bts = msg->trx->bts;
2807 signal.msg_type = foh->msg_type;
2808 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002809 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002810 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002811 signal.bts = msg->trx->bts;
2812 signal.msg_type = foh->msg_type;
2813 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002814 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002815 default:
2816 break;
2817 }
2818
Harald Welte677c21f2009-02-17 13:22:23 +00002819 return 0;
2820}
2821
Harald Welte193fefc2009-04-30 15:16:27 +00002822/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002823int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2824 u_int8_t obj_class, u_int8_t bts_nr,
2825 u_int8_t trx_nr, u_int8_t ts_nr,
2826 u_int8_t *attr, int attr_len)
2827{
2828 struct msgb *msg = nm_msgb_alloc();
2829 struct abis_om_hdr *oh;
2830 struct abis_om_fom_hdr *foh;
2831 u_int8_t *data;
2832
2833 /* construct the 12.21 OM header, observe the erroneous length */
2834 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2835 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2836 oh->mdisc = ABIS_OM_MDISC_MANUF;
2837
2838 /* add the ip.access magic */
2839 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2840 *data++ = sizeof(ipaccess_magic);
2841 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2842
2843 /* fill the 12.21 FOM header */
2844 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2845 foh->msg_type = msg_type;
2846 foh->obj_class = obj_class;
2847 foh->obj_inst.bts_nr = bts_nr;
2848 foh->obj_inst.trx_nr = trx_nr;
2849 foh->obj_inst.ts_nr = ts_nr;
2850
2851 if (attr && attr_len) {
2852 data = msgb_put(msg, attr_len);
2853 memcpy(data, attr, attr_len);
2854 }
2855
2856 return abis_nm_sendmsg(bts, msg);
2857}
Harald Welte677c21f2009-02-17 13:22:23 +00002858
Harald Welte193fefc2009-04-30 15:16:27 +00002859/* set some attributes in NVRAM */
2860int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2861 int attr_len)
2862{
2863 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2864 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2865 attr_len);
2866}
2867
Harald Welte746d6092009-10-19 22:11:11 +02002868int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2869 u_int32_t ip, u_int16_t port, u_int8_t stream)
2870{
2871 struct in_addr ia;
2872 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2873 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2874 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2875
2876 int attr_len = sizeof(attr);
2877
2878 ia.s_addr = htonl(ip);
2879 attr[1] = stream;
2880 attr[3] = port >> 8;
2881 attr[4] = port & 0xff;
2882 *(u_int32_t *)(attr+6) = ia.s_addr;
2883
2884 /* if ip == 0, we use the default IP */
2885 if (ip == 0)
2886 attr_len -= 5;
2887
2888 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002889 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002890
2891 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2892 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2893 trx->nr, 0xff, attr, attr_len);
2894}
2895
Harald Welte193fefc2009-04-30 15:16:27 +00002896/* restart / reboot an ip.access nanoBTS */
2897int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2898{
2899 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2900}
Harald Weltedaef5212009-10-24 10:20:41 +02002901
2902int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2903 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2904 u_int8_t *attr, u_int8_t attr_len)
2905{
2906 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2907 obj_class, bts_nr, trx_nr, ts_nr,
2908 attr, attr_len);
2909}
Harald Welte0f255852009-11-12 14:48:42 +01002910
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002911void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2912{
2913 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2914
2915 trx->rf_locked = locked;
2916 if (!trx->bts || !trx->bts->oml_link)
2917 return;
2918
2919 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2920 trx->bts->bts_nr, trx->nr, 0xff,
2921 new_state);
2922}
2923
Harald Welte0f255852009-11-12 14:48:42 +01002924static const char *ipacc_testres_names[] = {
2925 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2926 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2927 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2928 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2929 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2930};
2931
2932const char *ipacc_testres_name(u_int8_t res)
2933{
2934 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2935 ipacc_testres_names[res])
2936 return ipacc_testres_names[res];
2937
2938 return "unknown";
2939}
2940
Harald Welteb40a38f2009-11-13 11:56:05 +01002941void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2942{
2943 cid->mcc = (buf[0] & 0xf) * 100;
2944 cid->mcc += (buf[0] >> 4) * 10;
2945 cid->mcc += (buf[1] & 0xf) * 1;
2946
2947 if (buf[1] >> 4 == 0xf) {
2948 cid->mnc = (buf[2] & 0xf) * 10;
2949 cid->mnc += (buf[2] >> 4) * 1;
2950 } else {
2951 cid->mnc = (buf[2] & 0xf) * 100;
2952 cid->mnc += (buf[2] >> 4) * 10;
2953 cid->mnc += (buf[1] >> 4) * 1;
2954 }
2955
Harald Welteaff237d2009-11-13 14:41:52 +01002956 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2957 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002958}
2959
Harald Welte0f255852009-11-12 14:48:42 +01002960/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2961int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2962{
2963 u_int8_t *cur = buf;
2964 u_int16_t len;
2965
2966 memset(binf, 0, sizeof(binf));
2967
2968 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2969 return -EINVAL;
2970 cur++;
2971
2972 len = ntohs(*(u_int16_t *)cur);
2973 cur += 2;
2974
2975 binf->info_type = ntohs(*(u_int16_t *)cur);
2976 cur += 2;
2977
2978 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2979 binf->freq_qual = *cur >> 2;
2980
2981 binf->arfcn = *cur++ & 3 << 8;
2982 binf->arfcn |= *cur++;
2983
2984 if (binf->info_type & IPAC_BINF_RXLEV)
2985 binf->rx_lev = *cur & 0x3f;
2986 cur++;
2987
2988 if (binf->info_type & IPAC_BINF_RXQUAL)
2989 binf->rx_qual = *cur & 0x7;
2990 cur++;
2991
2992 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2993 binf->freq_err = ntohs(*(u_int16_t *)cur);
2994 cur += 2;
2995
2996 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2997 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2998 cur += 2;
2999
3000 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3001 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3002 cur += 4;
3003
3004 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01003005 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003006 cur++;
3007
Harald Welteb40a38f2009-11-13 11:56:05 +01003008 ipac_parse_cgi(&binf->cgi, cur);
3009 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003010
3011 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3012 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3013 cur += sizeof(binf->ba_list_si2);
3014 }
3015
3016 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3017 memcpy(binf->ba_list_si2bis, cur,
3018 sizeof(binf->ba_list_si2bis));
3019 cur += sizeof(binf->ba_list_si2bis);
3020 }
3021
3022 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3023 memcpy(binf->ba_list_si2ter, cur,
3024 sizeof(binf->ba_list_si2ter));
3025 cur += sizeof(binf->ba_list_si2ter);
3026 }
3027
3028 return 0;
3029}
3030
3031