blob: 8b3ac9c622ea84e9cc0271bcf2a615dc936dadb6 [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;
Harald Welte97ed1e72009-02-06 13:38:02 +00001073 }
1074
Harald Weltead384642008-12-26 10:20:07 +00001075 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001076}
1077
Harald Welte677c21f2009-02-17 13:22:23 +00001078static int abis_nm_rx_ipacc(struct msgb *mb);
1079
1080static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1081{
1082 int rc;
1083 int bts_type = mb->trx->bts->type;
1084
1085 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001086 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001087 rc = abis_nm_rx_ipacc(mb);
1088 break;
1089 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001090 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1091 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001092 rc = 0;
1093 break;
1094 }
1095
1096 return rc;
1097}
1098
Harald Welte52b1f982008-12-23 20:25:15 +00001099/* High-Level API */
1100/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001101int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001102{
Harald Welte52b1f982008-12-23 20:25:15 +00001103 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001104 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001105
1106 /* Various consistency checks */
1107 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001108 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001109 oh->placement);
1110 return -EINVAL;
1111 }
1112 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001113 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001114 oh->sequence);
1115 return -EINVAL;
1116 }
Harald Welte702d8702008-12-26 20:25:35 +00001117#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001118 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1119 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001120 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001121 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001122 oh->length + sizeof(*oh), l2_len);
1123 return -EINVAL;
1124 }
Harald Welte702d8702008-12-26 20:25:35 +00001125 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001126 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte702d8702008-12-26 20:25:35 +00001127#endif
Harald Weltead384642008-12-26 10:20:07 +00001128 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001129
1130 switch (oh->mdisc) {
1131 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001132 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001133 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001134 case ABIS_OM_MDISC_MANUF:
1135 rc = abis_nm_rcvmsg_manuf(msg);
1136 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001137 case ABIS_OM_MDISC_MMI:
1138 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001139 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001140 oh->mdisc);
1141 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001142 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001143 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001144 oh->mdisc);
1145 return -EINVAL;
1146 }
1147
Harald Weltead384642008-12-26 10:20:07 +00001148 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001149 return rc;
1150}
1151
1152#if 0
1153/* initialized all resources */
1154struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1155{
1156 struct abis_nm_h *nmh;
1157
1158 nmh = malloc(sizeof(*nmh));
1159 if (!nmh)
1160 return NULL;
1161
1162 nmh->cfg = cfg;
1163
1164 return nmh;
1165}
1166
1167/* free all resources */
1168void abis_nm_fini(struct abis_nm_h *nmh)
1169{
1170 free(nmh);
1171}
1172#endif
1173
1174/* Here we are trying to define a high-level API that can be used by
1175 * the actual BSC implementation. However, the architecture is currently
1176 * still under design. Ideally the calls to this API would be synchronous,
1177 * while the underlying stack behind the APi runs in a traditional select
1178 * based state machine.
1179 */
1180
Harald Welte4724f992009-01-18 18:01:49 +00001181/* 6.2 Software Load: */
1182enum sw_state {
1183 SW_STATE_NONE,
1184 SW_STATE_WAIT_INITACK,
1185 SW_STATE_WAIT_SEGACK,
1186 SW_STATE_WAIT_ENDACK,
1187 SW_STATE_WAIT_ACTACK,
1188 SW_STATE_ERROR,
1189};
Harald Welte52b1f982008-12-23 20:25:15 +00001190
Harald Welte52b1f982008-12-23 20:25:15 +00001191struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001192 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001193 gsm_cbfn *cbfn;
1194 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001195 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001196
Harald Welte52b1f982008-12-23 20:25:15 +00001197 /* this will become part of the SW LOAD INITIATE */
1198 u_int8_t obj_class;
1199 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001200
1201 u_int8_t file_id[255];
1202 u_int8_t file_id_len;
1203
1204 u_int8_t file_version[255];
1205 u_int8_t file_version_len;
1206
1207 u_int8_t window_size;
1208 u_int8_t seg_in_window;
1209
1210 int fd;
1211 FILE *stream;
1212 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001213 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001214};
1215
Harald Welte4724f992009-01-18 18:01:49 +00001216static struct abis_nm_sw g_sw;
1217
1218/* 6.2.1 / 8.3.1: Load Data Initiate */
1219static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001220{
Harald Welte4724f992009-01-18 18:01:49 +00001221 struct abis_om_hdr *oh;
1222 struct msgb *msg = nm_msgb_alloc();
1223 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1224
1225 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1226 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1227 sw->obj_instance[0], sw->obj_instance[1],
1228 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001229
1230 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1231 msgb_v_put(msg, NM_ATT_SW_DESCR);
1232 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1233 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1234 sw->file_version);
1235 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1236 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1237 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1238 sw->file_version);
1239 } else {
1240 return -1;
1241 }
Harald Welte4724f992009-01-18 18:01:49 +00001242 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1243
1244 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001245}
1246
Harald Welte1602ade2009-01-29 21:12:39 +00001247static int is_last_line(FILE *stream)
1248{
1249 char next_seg_buf[256];
1250 long pos;
1251
1252 /* check if we're sending the last line */
1253 pos = ftell(stream);
1254 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1255 fseek(stream, pos, SEEK_SET);
1256 return 1;
1257 }
1258
1259 fseek(stream, pos, SEEK_SET);
1260 return 0;
1261}
1262
Harald Welte4724f992009-01-18 18:01:49 +00001263/* 6.2.2 / 8.3.2 Load Data Segment */
1264static int sw_load_segment(struct abis_nm_sw *sw)
1265{
1266 struct abis_om_hdr *oh;
1267 struct msgb *msg = nm_msgb_alloc();
1268 char seg_buf[256];
1269 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001270 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001271 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001272
1273 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001274
1275 switch (sw->bts->type) {
1276 case GSM_BTS_TYPE_BS11:
1277 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1278 perror("fgets reading segment");
1279 return -EINVAL;
1280 }
1281 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001282
1283 /* check if we're sending the last line */
1284 sw->last_seg = is_last_line(sw->stream);
1285 if (sw->last_seg)
1286 seg_buf[1] = 0;
1287 else
1288 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001289
1290 len = strlen(line_buf) + 2;
1291 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1292 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1293 /* BS11 wants CR + LF in excess of the TLV length !?! */
1294 tlv[1] -= 2;
1295
1296 /* we only now know the exact length for the OM hdr */
1297 len = strlen(line_buf)+2;
1298 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001299 case GSM_BTS_TYPE_NANOBTS: {
1300 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1301 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1302 if (len < 0) {
1303 perror("read failed");
1304 return -EINVAL;
1305 }
1306
1307 if (len != IPACC_SEGMENT_SIZE)
1308 sw->last_seg = 1;
1309
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001310 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001311 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1312 len += 3;
1313 break;
1314 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001315 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001316 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001317 /* FIXME: Other BTS types */
1318 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001319 }
Harald Welte4724f992009-01-18 18:01:49 +00001320
Harald Welte4724f992009-01-18 18:01:49 +00001321 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1322 sw->obj_instance[0], sw->obj_instance[1],
1323 sw->obj_instance[2]);
1324
1325 return abis_nm_sendmsg(sw->bts, msg);
1326}
1327
1328/* 6.2.4 / 8.3.4 Load Data End */
1329static int sw_load_end(struct abis_nm_sw *sw)
1330{
1331 struct abis_om_hdr *oh;
1332 struct msgb *msg = nm_msgb_alloc();
1333 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1334
1335 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1336 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1337 sw->obj_instance[0], sw->obj_instance[1],
1338 sw->obj_instance[2]);
1339
Holger Hans Peter Freyther326a6322009-12-28 11:45:43 +01001340 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1341 msgb_v_put(msg, NM_ATT_SW_DESCR);
1342 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1343 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1344 sw->file_version);
1345 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1346 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1347 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1348 sw->file_version);
1349 } else {
1350 return -1;
1351 }
Harald Welte4724f992009-01-18 18:01:49 +00001352
1353 return abis_nm_sendmsg(sw->bts, msg);
1354}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001355
Harald Welte52b1f982008-12-23 20:25:15 +00001356/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001357static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001358{
Harald Welte4724f992009-01-18 18:01:49 +00001359 struct abis_om_hdr *oh;
1360 struct msgb *msg = nm_msgb_alloc();
1361 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001362
Harald Welte4724f992009-01-18 18:01:49 +00001363 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1364 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1365 sw->obj_instance[0], sw->obj_instance[1],
1366 sw->obj_instance[2]);
1367
1368 /* FIXME: this is BS11 specific format */
1369 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1370 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1371 sw->file_version);
1372
1373 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001374}
Harald Welte4724f992009-01-18 18:01:49 +00001375
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001376struct sdp_firmware {
1377 char magic[4];
1378 char more_magic[4];
1379 unsigned int header_length;
1380 unsigned int file_length;
1381} __attribute__ ((packed));
1382
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001383static int parse_sdp_header(struct abis_nm_sw *sw)
1384{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001385 struct sdp_firmware firmware_header;
1386 int rc;
1387 struct stat stat;
1388
1389 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1390 if (rc != sizeof(firmware_header)) {
1391 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1392 return -1;
1393 }
1394
1395 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1396 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1397 return -1;
1398 }
1399
1400 if (firmware_header.more_magic[0] != 0x10 ||
1401 firmware_header.more_magic[1] != 0x02 ||
1402 firmware_header.more_magic[2] != 0x00 ||
1403 firmware_header.more_magic[3] != 0x00) {
1404 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1405 return -1;
1406 }
1407
1408
1409 if (fstat(sw->fd, &stat) == -1) {
1410 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1411 return -1;
1412 }
1413
1414 if (ntohl(firmware_header.file_length) != stat.st_size) {
1415 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1416 return -1;
1417 }
1418
1419 /* go back to the start as we checked the whole filesize.. */
1420 lseek(sw->fd, 0l, SEEK_SET);
1421 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1422 "There might be checksums in the file that are not\n"
1423 "verified and incomplete firmware might be flashed.\n"
1424 "There is absolutely no WARRANTY that flashing will\n"
1425 "work.\n");
1426 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001427}
1428
Harald Welte4724f992009-01-18 18:01:49 +00001429static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1430{
1431 char file_id[12+1];
1432 char file_version[80+1];
1433 int rc;
1434
1435 sw->fd = open(fname, O_RDONLY);
1436 if (sw->fd < 0)
1437 return sw->fd;
1438
1439 switch (sw->bts->type) {
1440 case GSM_BTS_TYPE_BS11:
1441 sw->stream = fdopen(sw->fd, "r");
1442 if (!sw->stream) {
1443 perror("fdopen");
1444 return -1;
1445 }
1446 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001447 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001448 file_id, file_version);
1449 if (rc != 2) {
1450 perror("parsing header line of software file");
1451 return -1;
1452 }
1453 strcpy((char *)sw->file_id, file_id);
1454 sw->file_id_len = strlen(file_id);
1455 strcpy((char *)sw->file_version, file_version);
1456 sw->file_version_len = strlen(file_version);
1457 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001458 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001459 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001460 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001461 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001462 rc = parse_sdp_header(sw);
1463 if (rc < 0) {
1464 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1465 return -1;
1466 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001467
1468 strcpy((char *)sw->file_id, "id");
1469 sw->file_id_len = 3;
1470 strcpy((char *)sw->file_version, "version");
1471 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001472 break;
Harald Welte4724f992009-01-18 18:01:49 +00001473 default:
1474 /* We don't know how to treat them yet */
1475 close(sw->fd);
1476 return -EINVAL;
1477 }
1478
1479 return 0;
1480}
1481
1482static void sw_close_file(struct abis_nm_sw *sw)
1483{
1484 switch (sw->bts->type) {
1485 case GSM_BTS_TYPE_BS11:
1486 fclose(sw->stream);
1487 break;
1488 default:
1489 close(sw->fd);
1490 break;
1491 }
1492}
1493
1494/* Fill the window */
1495static int sw_fill_window(struct abis_nm_sw *sw)
1496{
1497 int rc;
1498
1499 while (sw->seg_in_window < sw->window_size) {
1500 rc = sw_load_segment(sw);
1501 if (rc < 0)
1502 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001503 if (sw->last_seg)
1504 break;
Harald Welte4724f992009-01-18 18:01:49 +00001505 }
1506 return 0;
1507}
1508
1509/* callback function from abis_nm_rcvmsg() handler */
1510static int abis_nm_rcvmsg_sw(struct msgb *mb)
1511{
1512 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1513 int rc = -1;
1514 struct abis_nm_sw *sw = &g_sw;
1515 enum sw_state old_state = sw->state;
1516
Harald Welte3ffd1372009-02-01 22:15:49 +00001517 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001518
1519 switch (sw->state) {
1520 case SW_STATE_WAIT_INITACK:
1521 switch (foh->msg_type) {
1522 case NM_MT_LOAD_INIT_ACK:
1523 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001524 if (sw->cbfn)
1525 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1526 NM_MT_LOAD_INIT_ACK, mb,
1527 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001528 rc = sw_fill_window(sw);
1529 sw->state = SW_STATE_WAIT_SEGACK;
1530 break;
1531 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001532 if (sw->forced) {
1533 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1534 "Init NACK\n");
1535 if (sw->cbfn)
1536 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1537 NM_MT_LOAD_INIT_ACK, mb,
1538 sw->cb_data, NULL);
1539 rc = sw_fill_window(sw);
1540 sw->state = SW_STATE_WAIT_SEGACK;
1541 } else {
1542 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001543 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001544 if (sw->cbfn)
1545 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1546 NM_MT_LOAD_INIT_NACK, mb,
1547 sw->cb_data, NULL);
1548 sw->state = SW_STATE_ERROR;
1549 }
Harald Welte4724f992009-01-18 18:01:49 +00001550 break;
1551 }
1552 break;
1553 case SW_STATE_WAIT_SEGACK:
1554 switch (foh->msg_type) {
1555 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001556 if (sw->cbfn)
1557 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1558 NM_MT_LOAD_SEG_ACK, mb,
1559 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001560 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001561 if (!sw->last_seg) {
1562 /* fill window with more segments */
1563 rc = sw_fill_window(sw);
1564 sw->state = SW_STATE_WAIT_SEGACK;
1565 } else {
1566 /* end the transfer */
1567 sw->state = SW_STATE_WAIT_ENDACK;
1568 rc = sw_load_end(sw);
1569 }
Harald Welte4724f992009-01-18 18:01:49 +00001570 break;
1571 }
1572 break;
1573 case SW_STATE_WAIT_ENDACK:
1574 switch (foh->msg_type) {
1575 case NM_MT_LOAD_END_ACK:
1576 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001577 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1578 sw->bts->nr);
1579 sw->state = SW_STATE_NONE;
1580 if (sw->cbfn)
1581 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1582 NM_MT_LOAD_END_ACK, mb,
1583 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001584 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001585 break;
1586 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001587 if (sw->forced) {
1588 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1589 "End NACK\n");
1590 sw->state = SW_STATE_NONE;
1591 if (sw->cbfn)
1592 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1593 NM_MT_LOAD_END_ACK, mb,
1594 sw->cb_data, NULL);
1595 } else {
1596 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001597 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001598 sw->state = SW_STATE_ERROR;
1599 if (sw->cbfn)
1600 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1601 NM_MT_LOAD_END_NACK, mb,
1602 sw->cb_data, NULL);
1603 }
Harald Welte4724f992009-01-18 18:01:49 +00001604 break;
1605 }
1606 case SW_STATE_WAIT_ACTACK:
1607 switch (foh->msg_type) {
1608 case NM_MT_ACTIVATE_SW_ACK:
1609 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001610 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001611 sw->state = SW_STATE_NONE;
1612 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001613 if (sw->cbfn)
1614 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1615 NM_MT_ACTIVATE_SW_ACK, mb,
1616 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001617 break;
1618 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001619 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001620 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001621 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001622 if (sw->cbfn)
1623 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1624 NM_MT_ACTIVATE_SW_NACK, mb,
1625 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001626 break;
1627 }
1628 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001629 switch (foh->msg_type) {
1630 case NM_MT_ACTIVATE_SW_ACK:
1631 rc = 0;
1632 break;
1633 }
1634 break;
Harald Welte4724f992009-01-18 18:01:49 +00001635 case SW_STATE_ERROR:
1636 break;
1637 }
1638
1639 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001640 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001641 foh->msg_type, old_state, sw->state);
1642
1643 return rc;
1644}
1645
1646/* Load the specified software into the BTS */
1647int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001648 u_int8_t win_size, int forced,
1649 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001650{
1651 struct abis_nm_sw *sw = &g_sw;
1652 int rc;
1653
Harald Welte5e4d1b32009-02-01 13:36:56 +00001654 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1655 bts->nr, fname);
1656
Harald Welte4724f992009-01-18 18:01:49 +00001657 if (sw->state != SW_STATE_NONE)
1658 return -EBUSY;
1659
1660 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001661
1662 switch (bts->type) {
1663 case GSM_BTS_TYPE_BS11:
1664 sw->obj_class = NM_OC_SITE_MANAGER;
1665 sw->obj_instance[0] = 0xff;
1666 sw->obj_instance[1] = 0xff;
1667 sw->obj_instance[2] = 0xff;
1668 break;
1669 case GSM_BTS_TYPE_NANOBTS:
1670 sw->obj_class = NM_OC_BASEB_TRANSC;
1671 sw->obj_instance[0] = 0x00;
1672 sw->obj_instance[1] = 0x00;
1673 sw->obj_instance[2] = 0xff;
1674 break;
1675 case GSM_BTS_TYPE_UNKNOWN:
1676 default:
1677 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1678 return -1;
1679 break;
1680 }
Harald Welte4724f992009-01-18 18:01:49 +00001681 sw->window_size = win_size;
1682 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001683 sw->cbfn = cbfn;
1684 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001685 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001686
1687 rc = sw_open_file(sw, fname);
1688 if (rc < 0) {
1689 sw->state = SW_STATE_NONE;
1690 return rc;
1691 }
1692
1693 return sw_load_init(sw);
1694}
Harald Welte52b1f982008-12-23 20:25:15 +00001695
Harald Welte1602ade2009-01-29 21:12:39 +00001696int abis_nm_software_load_status(struct gsm_bts *bts)
1697{
1698 struct abis_nm_sw *sw = &g_sw;
1699 struct stat st;
1700 int rc, percent;
1701
1702 rc = fstat(sw->fd, &st);
1703 if (rc < 0) {
1704 perror("ERROR during stat");
1705 return rc;
1706 }
1707
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001708 if (sw->stream)
1709 percent = (ftell(sw->stream) * 100) / st.st_size;
1710 else
1711 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001712 return percent;
1713}
1714
Harald Welte5e4d1b32009-02-01 13:36:56 +00001715/* Activate the specified software into the BTS */
1716int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1717 gsm_cbfn *cbfn, void *cb_data)
1718{
1719 struct abis_nm_sw *sw = &g_sw;
1720 int rc;
1721
1722 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1723 bts->nr, fname);
1724
1725 if (sw->state != SW_STATE_NONE)
1726 return -EBUSY;
1727
1728 sw->bts = bts;
1729 sw->obj_class = NM_OC_SITE_MANAGER;
1730 sw->obj_instance[0] = 0xff;
1731 sw->obj_instance[1] = 0xff;
1732 sw->obj_instance[2] = 0xff;
1733 sw->state = SW_STATE_WAIT_ACTACK;
1734 sw->cbfn = cbfn;
1735 sw->cb_data = cb_data;
1736
1737 /* Open the file in order to fill some sw struct members */
1738 rc = sw_open_file(sw, fname);
1739 if (rc < 0) {
1740 sw->state = SW_STATE_NONE;
1741 return rc;
1742 }
1743 sw_close_file(sw);
1744
1745 return sw_activate(sw);
1746}
1747
Harald Welte8470bf22008-12-25 23:28:35 +00001748static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001749 u_int8_t ts_nr, u_int8_t subslot_nr)
1750{
Harald Welteadaf08b2009-01-18 11:08:10 +00001751 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001752 ch->bts_port = bts_port;
1753 ch->timeslot = ts_nr;
1754 ch->subslot = subslot_nr;
1755}
1756
1757int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1758 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1759 u_int8_t tei)
1760{
1761 struct abis_om_hdr *oh;
1762 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001763 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001764 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001765
1766 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1767 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1768 bts->bts_nr, trx_nr, 0xff);
1769
Harald Welte8470bf22008-12-25 23:28:35 +00001770 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001771
1772 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1773 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1774
1775 return abis_nm_sendmsg(bts, msg);
1776}
1777
1778/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1779int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1780 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1781{
Harald Welte8470bf22008-12-25 23:28:35 +00001782 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001783 struct abis_om_hdr *oh;
1784 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001785 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001786
1787 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001788 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001789 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1790
1791 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1792 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1793
1794 return abis_nm_sendmsg(bts, msg);
1795}
1796
1797#if 0
1798int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1799 struct abis_nm_abis_channel *chan)
1800{
1801}
1802#endif
1803
1804int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1805 u_int8_t e1_port, u_int8_t e1_timeslot,
1806 u_int8_t e1_subslot)
1807{
1808 struct gsm_bts *bts = ts->trx->bts;
1809 struct abis_om_hdr *oh;
1810 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001811 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001812
1813 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1814 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001815 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001816
1817 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1818 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1819
Harald Weltef325eb42009-02-19 17:07:39 +00001820 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1821 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001822 e1_port, e1_timeslot, e1_subslot);
1823
Harald Welte52b1f982008-12-23 20:25:15 +00001824 return abis_nm_sendmsg(bts, msg);
1825}
1826
1827#if 0
1828int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1829 struct abis_nm_abis_channel *chan,
1830 u_int8_t subchan)
1831{
1832}
1833#endif
1834
Harald Welte22af0db2009-02-14 15:41:08 +00001835/* Chapter 8.6.1 */
1836int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1837{
1838 struct abis_om_hdr *oh;
1839 struct msgb *msg = nm_msgb_alloc();
1840 u_int8_t *cur;
1841
1842 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1843
1844 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001845 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 +00001846 cur = msgb_put(msg, attr_len);
1847 memcpy(cur, attr, attr_len);
1848
1849 return abis_nm_sendmsg(bts, msg);
1850}
1851
1852/* Chapter 8.6.2 */
1853int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1854{
1855 struct abis_om_hdr *oh;
1856 struct msgb *msg = nm_msgb_alloc();
1857 u_int8_t *cur;
1858
1859 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1860
1861 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1862 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001863 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001864 cur = msgb_put(msg, attr_len);
1865 memcpy(cur, attr, attr_len);
1866
1867 return abis_nm_sendmsg(trx->bts, msg);
1868}
1869
Harald Welte39c7deb2009-08-09 21:49:48 +02001870static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1871{
1872 int i;
1873
1874 /* As it turns out, the BS-11 has some very peculiar restrictions
1875 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301876 switch (ts->trx->bts->type) {
1877 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001878 switch (chan_comb) {
1879 case NM_CHANC_TCHHalf:
1880 case NM_CHANC_TCHHalf2:
1881 /* not supported */
1882 return -EINVAL;
1883 case NM_CHANC_SDCCH:
1884 /* only one SDCCH/8 per TRX */
1885 for (i = 0; i < TRX_NR_TS; i++) {
1886 if (i == ts->nr)
1887 continue;
1888 if (ts->trx->ts[i].nm_chan_comb ==
1889 NM_CHANC_SDCCH)
1890 return -EINVAL;
1891 }
1892 /* not allowed for TS0 of BCCH-TRX */
1893 if (ts->trx == ts->trx->bts->c0 &&
1894 ts->nr == 0)
1895 return -EINVAL;
1896 /* not on the same TRX that has a BCCH+SDCCH4
1897 * combination */
1898 if (ts->trx == ts->trx->bts->c0 &&
1899 (ts->trx->ts[0].nm_chan_comb == 5 ||
1900 ts->trx->ts[0].nm_chan_comb == 8))
1901 return -EINVAL;
1902 break;
1903 case NM_CHANC_mainBCCH:
1904 case NM_CHANC_BCCHComb:
1905 /* allowed only for TS0 of C0 */
1906 if (ts->trx != ts->trx->bts->c0 ||
1907 ts->nr != 0)
1908 return -EINVAL;
1909 break;
1910 case NM_CHANC_BCCH:
1911 /* allowed only for TS 2/4/6 of C0 */
1912 if (ts->trx != ts->trx->bts->c0)
1913 return -EINVAL;
1914 if (ts->nr != 2 && ts->nr != 4 &&
1915 ts->nr != 6)
1916 return -EINVAL;
1917 break;
1918 case 8: /* this is not like 08.58, but in fact
1919 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1920 /* FIXME: only one CBCH allowed per cell */
1921 break;
1922 }
Harald Welted6575f92009-12-02 02:45:23 +05301923 break;
1924 case GSM_BTS_TYPE_NANOBTS:
1925 switch (ts->nr) {
1926 case 0:
1927 if (ts->trx->nr == 0) {
1928 /* only on TRX0 */
1929 switch (chan_comb) {
1930 case NM_CHANC_BCCH:
1931 case NM_CHANC_mainBCCH:
1932 case NM_CHANC_BCCHComb:
1933 return 0;
1934 break;
1935 default:
1936 return -EINVAL;
1937 }
1938 } else {
1939 switch (chan_comb) {
1940 case NM_CHANC_TCHFull:
1941 case NM_CHANC_TCHHalf:
1942 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1943 return 0;
1944 default:
1945 return -EINVAL;
1946 }
1947 }
1948 break;
1949 case 1:
1950 if (ts->trx->nr == 0) {
1951 switch (chan_comb) {
1952 case NM_CHANC_SDCCH_CBCH:
1953 if (ts->trx->ts[0].nm_chan_comb ==
1954 NM_CHANC_mainBCCH)
1955 return 0;
1956 return -EINVAL;
1957 case NM_CHANC_SDCCH:
1958 case NM_CHANC_TCHFull:
1959 case NM_CHANC_TCHHalf:
1960 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1961 case NM_CHANC_IPAC_TCHFull_PDCH:
1962 return 0;
1963 }
1964 } else {
1965 switch (chan_comb) {
1966 case NM_CHANC_SDCCH:
1967 case NM_CHANC_TCHFull:
1968 case NM_CHANC_TCHHalf:
1969 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1970 return 0;
1971 default:
1972 return -EINVAL;
1973 }
1974 }
1975 break;
1976 case 2:
1977 case 3:
1978 case 4:
1979 case 5:
1980 case 6:
1981 case 7:
1982 switch (chan_comb) {
1983 case NM_CHANC_TCHFull:
1984 case NM_CHANC_TCHHalf:
1985 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1986 return 0;
1987 case NM_CHANC_IPAC_PDCH:
1988 case NM_CHANC_IPAC_TCHFull_PDCH:
1989 if (ts->trx->nr == 0)
1990 return 0;
1991 else
1992 return -EINVAL;
1993 }
1994 break;
1995 }
1996 return -EINVAL;
1997 default:
1998 /* unknown BTS type */
1999 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002000 }
2001 return 0;
2002}
2003
Harald Welte22af0db2009-02-14 15:41:08 +00002004/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002005int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2006{
2007 struct gsm_bts *bts = ts->trx->bts;
2008 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002009 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002010 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002011 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002012 u_int8_t len = 2 + 2;
2013
2014 if (bts->type == GSM_BTS_TYPE_BS11)
2015 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002016
Harald Weltef325eb42009-02-19 17:07:39 +00002017 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002018 if (verify_chan_comb(ts, chan_comb) < 0) {
2019 msgb_free(msg);
2020 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2021 return -EINVAL;
2022 }
2023 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002024
Harald Welte52b1f982008-12-23 20:25:15 +00002025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002026 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002027 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002028 ts->trx->nr, ts->nr);
2029 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00002030 if (bts->type == GSM_BTS_TYPE_BS11)
2031 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002032 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00002033 if (bts->type == GSM_BTS_TYPE_BS11) {
2034 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2035 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2036 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002037 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002038 if (bts->type == GSM_BTS_TYPE_BS11)
2039 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002040
2041 return abis_nm_sendmsg(bts, msg);
2042}
2043
Harald Welte34a99682009-02-13 02:41:40 +00002044int 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 +00002045 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002046{
2047 struct abis_om_hdr *oh;
2048 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002049 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2050 u_int8_t len = att_len;
2051
2052 if (nack) {
2053 len += 2;
2054 msgtype = NM_MT_SW_ACT_REQ_NACK;
2055 }
Harald Welte34a99682009-02-13 02:41:40 +00002056
2057 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002058 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2059
Harald Welte34a99682009-02-13 02:41:40 +00002060 if (attr) {
2061 u_int8_t *ptr = msgb_put(msg, att_len);
2062 memcpy(ptr, attr, att_len);
2063 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002064 if (nack)
2065 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002066
2067 return abis_nm_sendmsg(bts, msg);
2068}
2069
Harald Welte8470bf22008-12-25 23:28:35 +00002070int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002071{
Harald Welte8470bf22008-12-25 23:28:35 +00002072 struct msgb *msg = nm_msgb_alloc();
2073 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002074 u_int8_t *data;
2075
2076 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2077 fill_om_hdr(oh, len);
2078 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002079 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002080
2081 return abis_nm_sendmsg(bts, msg);
2082}
2083
2084/* Siemens specific commands */
2085static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2086{
2087 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002088 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002089
2090 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002091 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002092 0xff, 0xff, 0xff);
2093
2094 return abis_nm_sendmsg(bts, msg);
2095}
2096
Harald Welte34a99682009-02-13 02:41:40 +00002097/* Chapter 8.9.2 */
2098int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2099{
2100 struct abis_om_hdr *oh;
2101 struct msgb *msg = nm_msgb_alloc();
2102
2103 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2104 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2105
Harald Weltea8bd6d42009-10-20 09:56:18 +02002106 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2107 DEBUGPC(DNM, "Sending OPSTART\n");
2108
Harald Welte34a99682009-02-13 02:41:40 +00002109 return abis_nm_sendmsg(bts, msg);
2110}
2111
2112/* Chapter 8.8.5 */
2113int 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 +02002114 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002115{
2116 struct abis_om_hdr *oh;
2117 struct msgb *msg = nm_msgb_alloc();
2118
2119 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2120 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2121 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2122
2123 return abis_nm_sendmsg(bts, msg);
2124}
2125
Harald Welte1989c082009-08-06 17:58:31 +02002126int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2127 u_int8_t e1_port1, u_int8_t ts1)
2128{
2129 struct abis_om_hdr *oh;
2130 struct msgb *msg = nm_msgb_alloc();
2131 u_int8_t *attr;
2132
2133 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2134 e1_port0, ts0, e1_port1, ts1);
2135
2136 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2137 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2138 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2139
2140 attr = msgb_put(msg, 3);
2141 attr[0] = NM_ATT_MDROP_LINK;
2142 attr[1] = e1_port0;
2143 attr[2] = ts0;
2144
2145 attr = msgb_put(msg, 3);
2146 attr[0] = NM_ATT_MDROP_NEXT;
2147 attr[1] = e1_port1;
2148 attr[2] = ts1;
2149
2150 return abis_nm_sendmsg(bts, msg);
2151}
Harald Welte34a99682009-02-13 02:41:40 +00002152
Harald Weltec7310382009-08-08 00:02:36 +02002153/* Chapter 8.7.1 */
2154int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2155 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2156 u_int8_t test_nr, u_int8_t auton_report,
2157 u_int8_t *phys_config, u_int16_t phys_config_len)
2158{
2159 struct abis_om_hdr *oh;
2160 struct msgb *msg = nm_msgb_alloc();
2161 int len = 4; /* 2 TV attributes */
2162
2163 DEBUGP(DNM, "PEFORM TEST\n");
2164
2165 if (phys_config_len)
2166 len += 3 + phys_config_len;
2167
2168 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2169 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2170 obj_class, bts_nr, trx_nr, ts_nr);
2171 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2172 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2173 if (phys_config_len)
2174 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2175 phys_config);
2176
2177 return abis_nm_sendmsg(bts, msg);
2178}
2179
Harald Welte52b1f982008-12-23 20:25:15 +00002180int abis_nm_event_reports(struct gsm_bts *bts, int on)
2181{
2182 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002183 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002184 else
Harald Welte227d4072009-01-03 08:16:25 +00002185 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002186}
2187
Harald Welte47d88ae2009-01-04 12:02:08 +00002188/* Siemens (or BS-11) specific commands */
2189
Harald Welte3ffd1372009-02-01 22:15:49 +00002190int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2191{
2192 if (reconnect == 0)
2193 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2194 else
2195 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2196}
2197
Harald Welteb8427972009-02-05 19:27:17 +00002198int abis_nm_bs11_restart(struct gsm_bts *bts)
2199{
2200 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2201}
2202
2203
Harald Welte268bb402009-02-01 19:11:56 +00002204struct bs11_date_time {
2205 u_int16_t year;
2206 u_int8_t month;
2207 u_int8_t day;
2208 u_int8_t hour;
2209 u_int8_t min;
2210 u_int8_t sec;
2211} __attribute__((packed));
2212
2213
2214void get_bs11_date_time(struct bs11_date_time *aet)
2215{
2216 time_t t;
2217 struct tm *tm;
2218
2219 t = time(NULL);
2220 tm = localtime(&t);
2221 aet->sec = tm->tm_sec;
2222 aet->min = tm->tm_min;
2223 aet->hour = tm->tm_hour;
2224 aet->day = tm->tm_mday;
2225 aet->month = tm->tm_mon;
2226 aet->year = htons(1900 + tm->tm_year);
2227}
2228
Harald Welte05188ee2009-01-18 11:39:08 +00002229int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002230{
Harald Welte4668fda2009-01-03 08:19:29 +00002231 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002232}
2233
Harald Welte05188ee2009-01-18 11:39:08 +00002234int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002235{
2236 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002237 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002238 else
Harald Welte4668fda2009-01-03 08:19:29 +00002239 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002240}
Harald Welte47d88ae2009-01-04 12:02:08 +00002241
Harald Welte05188ee2009-01-18 11:39:08 +00002242int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002243 enum abis_bs11_objtype type, u_int8_t idx,
2244 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002245{
2246 struct abis_om_hdr *oh;
2247 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002248 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002249
2250 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002251 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002252 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002253 cur = msgb_put(msg, attr_len);
2254 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002255
2256 return abis_nm_sendmsg(bts, msg);
2257}
2258
Harald Welte78fc0d42009-02-19 02:50:57 +00002259int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2260 enum abis_bs11_objtype type, u_int8_t idx)
2261{
2262 struct abis_om_hdr *oh;
2263 struct msgb *msg = nm_msgb_alloc();
2264
2265 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2266 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2267 NM_OC_BS11, type, 0, idx);
2268
2269 return abis_nm_sendmsg(bts, msg);
2270}
2271
Harald Welte05188ee2009-01-18 11:39:08 +00002272int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002273{
2274 struct abis_om_hdr *oh;
2275 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002276 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002277
2278 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002279 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002280 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2281 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002282
2283 return abis_nm_sendmsg(bts, msg);
2284}
2285
Harald Welte05188ee2009-01-18 11:39:08 +00002286int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002287{
2288 struct abis_om_hdr *oh;
2289 struct msgb *msg = nm_msgb_alloc();
2290
2291 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2292 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002293 idx, 0xff, 0xff);
2294
2295 return abis_nm_sendmsg(bts, msg);
2296}
2297
2298int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2299{
2300 struct abis_om_hdr *oh;
2301 struct msgb *msg = nm_msgb_alloc();
2302
2303 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2304 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2305 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002306
2307 return abis_nm_sendmsg(bts, msg);
2308}
Harald Welte05188ee2009-01-18 11:39:08 +00002309
Harald Welte78fc0d42009-02-19 02:50:57 +00002310static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2311int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2312{
2313 struct abis_om_hdr *oh;
2314 struct msgb *msg = nm_msgb_alloc();
2315
2316 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2317 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2318 0xff, 0xff, 0xff);
2319 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2320
2321 return abis_nm_sendmsg(bts, msg);
2322}
2323
Harald Welteb6c92ae2009-02-21 20:15:32 +00002324/* like abis_nm_conn_terr_traf + set_tei */
2325int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2326 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2327 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002328{
2329 struct abis_om_hdr *oh;
2330 struct abis_nm_channel *ch;
2331 struct msgb *msg = nm_msgb_alloc();
2332
2333 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002334 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002335 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2336
2337 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2338 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002339 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002340
2341 return abis_nm_sendmsg(bts, msg);
2342}
2343
2344int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2345{
2346 struct abis_om_hdr *oh;
2347 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002348
2349 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002350 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002351 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2352 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2353
2354 return abis_nm_sendmsg(trx->bts, msg);
2355}
2356
Harald Welte78fc0d42009-02-19 02:50:57 +00002357int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2358{
2359 struct abis_om_hdr *oh;
2360 struct msgb *msg = nm_msgb_alloc();
2361 u_int8_t attr = NM_ATT_BS11_TXPWR;
2362
2363 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2364 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2365 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2366 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2367
2368 return abis_nm_sendmsg(trx->bts, msg);
2369}
2370
Harald Welteaaf02d92009-04-29 13:25:57 +00002371int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2372{
2373 struct abis_om_hdr *oh;
2374 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002375 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002376
2377 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2378 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2379 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002380 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002381
2382 return abis_nm_sendmsg(bts, msg);
2383}
2384
Harald Welteef061952009-05-17 12:43:42 +00002385int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2386{
2387 struct abis_om_hdr *oh;
2388 struct msgb *msg = nm_msgb_alloc();
2389 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2390 NM_ATT_BS11_CCLK_TYPE };
2391
2392 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2393 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2394 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2395 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2396
2397 return abis_nm_sendmsg(bts, msg);
2398
2399}
Harald Welteaaf02d92009-04-29 13:25:57 +00002400
Harald Welte268bb402009-02-01 19:11:56 +00002401//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +00002402static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +00002403static const u_int8_t bs11_logon_c9[] = "FACTORY";
2404
Harald Welte1bc09062009-01-18 14:17:52 +00002405int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002406{
2407 struct abis_om_hdr *oh;
2408 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002409 struct bs11_date_time bdt;
2410
2411 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002412
2413 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002414 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002415 u_int8_t len = 3*2 + sizeof(bdt)
Harald Welte6f676a32009-01-18 14:27:48 +00002416 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +00002417 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002418 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002419 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002420 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002421 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2422 sizeof(bs11_logon_c8), bs11_logon_c8);
2423 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2424 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +00002425 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002426 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002427 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002428 }
Harald Welte05188ee2009-01-18 11:39:08 +00002429
2430 return abis_nm_sendmsg(bts, msg);
2431}
Harald Welte1bc09062009-01-18 14:17:52 +00002432
2433int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2434{
2435 struct abis_om_hdr *oh;
2436 struct msgb *msg;
2437
2438 if (strlen(password) != 10)
2439 return -EINVAL;
2440
2441 msg = nm_msgb_alloc();
2442 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002443 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002444 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2445 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2446
2447 return abis_nm_sendmsg(bts, msg);
2448}
2449
Harald Weltee69f5fb2009-04-28 16:31:38 +00002450/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2451int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2452{
2453 struct abis_om_hdr *oh;
2454 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002455 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002456
2457 msg = nm_msgb_alloc();
2458 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2459 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2460 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002461
2462 if (locked)
2463 tlv_value = BS11_LI_PLL_LOCKED;
2464 else
2465 tlv_value = BS11_LI_PLL_STANDALONE;
2466
2467 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002468
2469 return abis_nm_sendmsg(bts, msg);
2470}
2471
Harald Welte1bc09062009-01-18 14:17:52 +00002472int abis_nm_bs11_get_state(struct gsm_bts *bts)
2473{
2474 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2475}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002476
2477/* BS11 SWL */
2478
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002479void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002480
Harald Welte5e4d1b32009-02-01 13:36:56 +00002481struct abis_nm_bs11_sw {
2482 struct gsm_bts *bts;
2483 char swl_fname[PATH_MAX];
2484 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002485 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002486 struct llist_head file_list;
2487 gsm_cbfn *user_cb; /* specified by the user */
2488};
2489static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2490
2491struct file_list_entry {
2492 struct llist_head list;
2493 char fname[PATH_MAX];
2494};
2495
2496struct file_list_entry *fl_dequeue(struct llist_head *queue)
2497{
2498 struct llist_head *lh;
2499
2500 if (llist_empty(queue))
2501 return NULL;
2502
2503 lh = queue->next;
2504 llist_del(lh);
2505
2506 return llist_entry(lh, struct file_list_entry, list);
2507}
2508
2509static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2510{
2511 char linebuf[255];
2512 struct llist_head *lh, *lh2;
2513 FILE *swl;
2514 int rc = 0;
2515
2516 swl = fopen(bs11_sw->swl_fname, "r");
2517 if (!swl)
2518 return -ENODEV;
2519
2520 /* zero the stale file list, if any */
2521 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2522 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002523 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002524 }
2525
2526 while (fgets(linebuf, sizeof(linebuf), swl)) {
2527 char file_id[12+1];
2528 char file_version[80+1];
2529 struct file_list_entry *fle;
2530 static char dir[PATH_MAX];
2531
2532 if (strlen(linebuf) < 4)
2533 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002534
Harald Welte5e4d1b32009-02-01 13:36:56 +00002535 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2536 if (rc < 0) {
2537 perror("ERR parsing SWL file");
2538 rc = -EINVAL;
2539 goto out;
2540 }
2541 if (rc < 2)
2542 continue;
2543
Harald Welte470ec292009-06-26 20:25:23 +02002544 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002545 if (!fle) {
2546 rc = -ENOMEM;
2547 goto out;
2548 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002549
2550 /* construct new filename */
2551 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2552 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2553 strcat(fle->fname, "/");
2554 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002555
2556 llist_add_tail(&fle->list, &bs11_sw->file_list);
2557 }
2558
2559out:
2560 fclose(swl);
2561 return rc;
2562}
2563
2564/* bs11 swload specific callback, passed to abis_nm core swload */
2565static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2566 struct msgb *msg, void *data, void *param)
2567{
2568 struct abis_nm_bs11_sw *bs11_sw = data;
2569 struct file_list_entry *fle;
2570 int rc = 0;
2571
Harald Welte5e4d1b32009-02-01 13:36:56 +00002572 switch (event) {
2573 case NM_MT_LOAD_END_ACK:
2574 fle = fl_dequeue(&bs11_sw->file_list);
2575 if (fle) {
2576 /* start download the next file of our file list */
2577 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2578 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002579 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002580 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002581 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002582 } else {
2583 /* activate the SWL */
2584 rc = abis_nm_software_activate(bs11_sw->bts,
2585 bs11_sw->swl_fname,
2586 bs11_swload_cbfn,
2587 bs11_sw);
2588 }
2589 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002590 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002591 case NM_MT_LOAD_END_NACK:
2592 case NM_MT_LOAD_INIT_ACK:
2593 case NM_MT_LOAD_INIT_NACK:
2594 case NM_MT_ACTIVATE_SW_NACK:
2595 case NM_MT_ACTIVATE_SW_ACK:
2596 default:
2597 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002598 if (bs11_sw->user_cb)
2599 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002600 break;
2601 }
2602
2603 return rc;
2604}
2605
2606/* Siemens provides a SWL file that is a mere listing of all the other
2607 * files that are part of a software release. We need to upload first
2608 * the list file, and then each file that is listed in the list file */
2609int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002610 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002611{
2612 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2613 struct file_list_entry *fle;
2614 int rc = 0;
2615
2616 INIT_LLIST_HEAD(&bs11_sw->file_list);
2617 bs11_sw->bts = bts;
2618 bs11_sw->win_size = win_size;
2619 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002620 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002621
2622 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2623 rc = bs11_read_swl_file(bs11_sw);
2624 if (rc < 0)
2625 return rc;
2626
2627 /* dequeue next item in file list */
2628 fle = fl_dequeue(&bs11_sw->file_list);
2629 if (!fle)
2630 return -EINVAL;
2631
2632 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002633 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002634 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002635 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002636 return rc;
2637}
2638
Harald Welte5083b0b2009-02-02 19:20:52 +00002639#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002640static u_int8_t req_attr_btse[] = {
2641 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2642 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2643 NM_ATT_BS11_LMT_USER_NAME,
2644
2645 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2646
2647 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2648
2649 NM_ATT_BS11_SW_LOAD_STORED };
2650
2651static u_int8_t req_attr_btsm[] = {
2652 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2653 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2654 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2655 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002656#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002657
2658static u_int8_t req_attr[] = {
2659 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2660 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002661 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002662
2663int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2664{
2665 struct abis_om_hdr *oh;
2666 struct msgb *msg = nm_msgb_alloc();
2667
2668 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2669 /* SiemensHW CCTRL object */
2670 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2671 0x03, 0x00, 0x00);
2672 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2673
2674 return abis_nm_sendmsg(bts, msg);
2675}
Harald Welte268bb402009-02-01 19:11:56 +00002676
2677int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2678{
2679 struct abis_om_hdr *oh;
2680 struct msgb *msg = nm_msgb_alloc();
2681 struct bs11_date_time aet;
2682
2683 get_bs11_date_time(&aet);
2684 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2685 /* SiemensHW CCTRL object */
2686 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2687 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002688 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002689
2690 return abis_nm_sendmsg(bts, msg);
2691}
Harald Welte5c1e4582009-02-15 11:57:29 +00002692
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002693int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2694{
2695 struct abis_om_hdr *oh;
2696 struct msgb *msg = nm_msgb_alloc();
2697 struct bs11_date_time aet;
2698
2699 get_bs11_date_time(&aet);
2700 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2701 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2702 bport, 0xff, 0x02);
2703 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2704
2705 return abis_nm_sendmsg(bts, msg);
2706}
2707
Harald Welte5c1e4582009-02-15 11:57:29 +00002708/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002709static const char ipaccess_magic[] = "com.ipaccess";
2710
Harald Welte677c21f2009-02-17 13:22:23 +00002711
2712static int abis_nm_rx_ipacc(struct msgb *msg)
2713{
2714 struct abis_om_hdr *oh = msgb_l2(msg);
2715 struct abis_om_fom_hdr *foh;
2716 u_int8_t idstrlen = oh->data[0];
2717 struct tlv_parsed tp;
2718
2719 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002720 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002721 return -EINVAL;
2722 }
2723
Harald Welte193fefc2009-04-30 15:16:27 +00002724 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002725 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002726
Harald Weltea8bd6d42009-10-20 09:56:18 +02002727 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002728
Harald Welte746d6092009-10-19 22:11:11 +02002729 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002730
Harald Welte677c21f2009-02-17 13:22:23 +00002731 switch (foh->msg_type) {
2732 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002733 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002734 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002735 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002736 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002737 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2738 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002739 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002740 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002741 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002742 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2743 DEBUGPC(DNM, "STREAM=0x%02x ",
2744 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002745 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002746 break;
2747 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002748 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002749 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002750 DEBUGPC(DNM, " CAUSE=%s\n",
2751 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002752 else
2753 DEBUGPC(DNM, "\n");
2754 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002755 case NM_MT_IPACC_SET_NVATTR_ACK:
2756 DEBUGPC(DNM, "SET NVATTR ACK\n");
2757 /* FIXME: decode and show the actual attributes */
2758 break;
2759 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002760 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002761 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002762 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002763 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2764 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002765 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002766 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002767 case NM_MT_IPACC_GET_NVATTR_ACK:
2768 DEBUGPC(DNM, "GET NVATTR ACK\n");
2769 /* FIXME: decode and show the actual attributes */
2770 break;
2771 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002772 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002773 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002774 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002775 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2776 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002777 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002778 break;
Harald Welte15c44172009-10-08 20:15:24 +02002779 case NM_MT_IPACC_SET_ATTR_ACK:
2780 DEBUGPC(DNM, "SET ATTR ACK\n");
2781 break;
2782 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002783 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002784 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002785 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002786 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2787 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002788 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002789 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002790 default:
2791 DEBUGPC(DNM, "unknown\n");
2792 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002793 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002794
2795 /* signal handling */
2796 switch (foh->msg_type) {
2797 case NM_MT_IPACC_RSL_CONNECT_NACK:
2798 case NM_MT_IPACC_SET_NVATTR_NACK:
2799 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welted8cfc902009-11-17 06:09:56 +01002800 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002801 break;
2802 default:
2803 break;
2804 }
2805
Harald Welte677c21f2009-02-17 13:22:23 +00002806 return 0;
2807}
2808
Harald Welte193fefc2009-04-30 15:16:27 +00002809/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002810int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2811 u_int8_t obj_class, u_int8_t bts_nr,
2812 u_int8_t trx_nr, u_int8_t ts_nr,
2813 u_int8_t *attr, int attr_len)
2814{
2815 struct msgb *msg = nm_msgb_alloc();
2816 struct abis_om_hdr *oh;
2817 struct abis_om_fom_hdr *foh;
2818 u_int8_t *data;
2819
2820 /* construct the 12.21 OM header, observe the erroneous length */
2821 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2822 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2823 oh->mdisc = ABIS_OM_MDISC_MANUF;
2824
2825 /* add the ip.access magic */
2826 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2827 *data++ = sizeof(ipaccess_magic);
2828 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2829
2830 /* fill the 12.21 FOM header */
2831 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2832 foh->msg_type = msg_type;
2833 foh->obj_class = obj_class;
2834 foh->obj_inst.bts_nr = bts_nr;
2835 foh->obj_inst.trx_nr = trx_nr;
2836 foh->obj_inst.ts_nr = ts_nr;
2837
2838 if (attr && attr_len) {
2839 data = msgb_put(msg, attr_len);
2840 memcpy(data, attr, attr_len);
2841 }
2842
2843 return abis_nm_sendmsg(bts, msg);
2844}
Harald Welte677c21f2009-02-17 13:22:23 +00002845
Harald Welte193fefc2009-04-30 15:16:27 +00002846/* set some attributes in NVRAM */
2847int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2848 int attr_len)
2849{
2850 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2851 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2852 attr_len);
2853}
2854
Harald Welte746d6092009-10-19 22:11:11 +02002855int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2856 u_int32_t ip, u_int16_t port, u_int8_t stream)
2857{
2858 struct in_addr ia;
2859 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2860 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2861 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2862
2863 int attr_len = sizeof(attr);
2864
2865 ia.s_addr = htonl(ip);
2866 attr[1] = stream;
2867 attr[3] = port >> 8;
2868 attr[4] = port & 0xff;
2869 *(u_int32_t *)(attr+6) = ia.s_addr;
2870
2871 /* if ip == 0, we use the default IP */
2872 if (ip == 0)
2873 attr_len -= 5;
2874
2875 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002876 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002877
2878 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2879 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2880 trx->nr, 0xff, attr, attr_len);
2881}
2882
Harald Welte193fefc2009-04-30 15:16:27 +00002883/* restart / reboot an ip.access nanoBTS */
2884int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2885{
2886 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2887}
Harald Weltedaef5212009-10-24 10:20:41 +02002888
2889int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2890 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2891 u_int8_t *attr, u_int8_t attr_len)
2892{
2893 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2894 obj_class, bts_nr, trx_nr, ts_nr,
2895 attr, attr_len);
2896}
Harald Welte0f255852009-11-12 14:48:42 +01002897
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002898void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2899{
2900 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2901
2902 trx->rf_locked = locked;
2903 if (!trx->bts || !trx->bts->oml_link)
2904 return;
2905
2906 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2907 trx->bts->bts_nr, trx->nr, 0xff,
2908 new_state);
2909}
2910
Harald Welte0f255852009-11-12 14:48:42 +01002911static const char *ipacc_testres_names[] = {
2912 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2913 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2914 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2915 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2916 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2917};
2918
2919const char *ipacc_testres_name(u_int8_t res)
2920{
2921 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2922 ipacc_testres_names[res])
2923 return ipacc_testres_names[res];
2924
2925 return "unknown";
2926}
2927
Harald Welteb40a38f2009-11-13 11:56:05 +01002928void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2929{
2930 cid->mcc = (buf[0] & 0xf) * 100;
2931 cid->mcc += (buf[0] >> 4) * 10;
2932 cid->mcc += (buf[1] & 0xf) * 1;
2933
2934 if (buf[1] >> 4 == 0xf) {
2935 cid->mnc = (buf[2] & 0xf) * 10;
2936 cid->mnc += (buf[2] >> 4) * 1;
2937 } else {
2938 cid->mnc = (buf[2] & 0xf) * 100;
2939 cid->mnc += (buf[2] >> 4) * 10;
2940 cid->mnc += (buf[1] >> 4) * 1;
2941 }
2942
Harald Welteaff237d2009-11-13 14:41:52 +01002943 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2944 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002945}
2946
Harald Welte0f255852009-11-12 14:48:42 +01002947/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2948int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2949{
2950 u_int8_t *cur = buf;
2951 u_int16_t len;
2952
2953 memset(binf, 0, sizeof(binf));
2954
2955 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2956 return -EINVAL;
2957 cur++;
2958
2959 len = ntohs(*(u_int16_t *)cur);
2960 cur += 2;
2961
2962 binf->info_type = ntohs(*(u_int16_t *)cur);
2963 cur += 2;
2964
2965 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2966 binf->freq_qual = *cur >> 2;
2967
2968 binf->arfcn = *cur++ & 3 << 8;
2969 binf->arfcn |= *cur++;
2970
2971 if (binf->info_type & IPAC_BINF_RXLEV)
2972 binf->rx_lev = *cur & 0x3f;
2973 cur++;
2974
2975 if (binf->info_type & IPAC_BINF_RXQUAL)
2976 binf->rx_qual = *cur & 0x7;
2977 cur++;
2978
2979 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2980 binf->freq_err = ntohs(*(u_int16_t *)cur);
2981 cur += 2;
2982
2983 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2984 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2985 cur += 2;
2986
2987 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2988 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2989 cur += 4;
2990
2991 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01002992 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002993 cur++;
2994
Harald Welteb40a38f2009-11-13 11:56:05 +01002995 ipac_parse_cgi(&binf->cgi, cur);
2996 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002997
2998 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2999 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3000 cur += sizeof(binf->ba_list_si2);
3001 }
3002
3003 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3004 memcpy(binf->ba_list_si2bis, cur,
3005 sizeof(binf->ba_list_si2bis));
3006 cur += sizeof(binf->ba_list_si2bis);
3007 }
3008
3009 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3010 memcpy(binf->ba_list_si2ter, cur,
3011 sizeof(binf->ba_list_si2ter));
3012 cur += sizeof(binf->ba_list_si2ter);
3013 }
3014
3015 return 0;
3016}
3017
3018