blob: 38c8c2bf5066f0e62a740e89089a1414ca69c57f [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
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100816 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
817 new_state.operational != nm_state->operational ||
818 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000819 /* Update the operational state of a given object in our in-memory data
820 * structures and send an event to the higher layer */
821 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
822 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100823 nm_state->operational = new_state.operational;
824 nm_state->availability = new_state.availability;
825 if (nm_state->administrative == 0)
826 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000827 }
828#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000829 if (op_state == 1) {
830 /* try to enable objects that are disabled */
831 abis_nm_opstart(bts, foh->obj_class,
832 foh->obj_inst.bts_nr,
833 foh->obj_inst.trx_nr,
834 foh->obj_inst.ts_nr);
835 }
Harald Weltee0590df2009-02-15 03:34:15 +0000836#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000837 return 0;
838}
839
Harald Welte0db97b22009-05-01 17:22:47 +0000840static int rx_fail_evt_rep(struct msgb *mb)
841{
842 struct abis_om_hdr *oh = msgb_l2(mb);
843 struct abis_om_fom_hdr *foh = msgb_l3(mb);
844 struct tlv_parsed tp;
845
846 DEBUGPC(DNM, "Failure Event Report ");
847
848 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
849
850 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
851 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
852 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
853 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
854
855 DEBUGPC(DNM, "\n");
856
857 return 0;
858}
859
Harald Welte97ed1e72009-02-06 13:38:02 +0000860static int abis_nm_rcvmsg_report(struct msgb *mb)
861{
862 struct abis_om_fom_hdr *foh = msgb_l3(mb);
863 u_int8_t mt = foh->msg_type;
864
Harald Weltea8bd6d42009-10-20 09:56:18 +0200865 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000866
Harald Welte97ed1e72009-02-06 13:38:02 +0000867 //nmh->cfg->report_cb(mb, foh);
868
869 switch (mt) {
870 case NM_MT_STATECHG_EVENT_REP:
871 return abis_nm_rx_statechg_rep(mb);
872 break;
Harald Welte34a99682009-02-13 02:41:40 +0000873 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000874 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000875 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000876 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000877 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000878 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000879 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000880 break;
Harald Weltec7310382009-08-08 00:02:36 +0200881 case NM_MT_TEST_REP:
882 DEBUGPC(DNM, "Test Report\n");
883 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
884 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000885 default:
Harald Welte23897662009-05-01 14:52:51 +0000886 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000887 break;
888
Harald Welte97ed1e72009-02-06 13:38:02 +0000889 };
890
Harald Welte97ed1e72009-02-06 13:38:02 +0000891 return 0;
892}
893
Harald Welte34a99682009-02-13 02:41:40 +0000894/* Activate the specified software into the BTS */
895static 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 +0200896 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000897{
898 struct abis_om_hdr *oh;
899 struct msgb *msg = nm_msgb_alloc();
900 u_int8_t len = swdesc_len;
901 u_int8_t *trailer;
902
903 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
904 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
905
906 trailer = msgb_put(msg, swdesc_len);
907 memcpy(trailer, sw_desc, swdesc_len);
908
909 return abis_nm_sendmsg(bts, msg);
910}
911
912static int abis_nm_rx_sw_act_req(struct msgb *mb)
913{
914 struct abis_om_hdr *oh = msgb_l2(mb);
915 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200916 struct tlv_parsed tp;
917 const u_int8_t *sw_config;
918 int sw_config_len;
919 int file_id_len;
Harald Welte5c1e4582009-02-15 11:57:29 +0000920 int nack = 0;
Harald Welte34a99682009-02-13 02:41:40 +0000921 int ret;
922
Harald Weltea8bd6d42009-10-20 09:56:18 +0200923 debugp_foh(foh);
924
925 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000926
Harald Welte5c1e4582009-02-15 11:57:29 +0000927 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
928 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
929 nack = 1;
930 } else
931 DEBUGPC(DNM, "ACKing and Activating\n");
932
933 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000934 foh->obj_inst.bts_nr,
935 foh->obj_inst.trx_nr,
Harald Welte5c1e4582009-02-15 11:57:29 +0000936 foh->obj_inst.ts_nr, nack,
Harald Welte34a99682009-02-13 02:41:40 +0000937 foh->data, oh->length-sizeof(*foh));
938
Harald Welte5c1e4582009-02-15 11:57:29 +0000939 if (nack)
940 return ret;
941
Mike Habena03f9772009-10-01 14:56:13 +0200942 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
943 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
944 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
945 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
946 DEBUGP(DNM, "SW config not found! Can't continue.\n");
947 return -EINVAL;
948 } else {
949 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
950 }
951
952 if (sw_config[0] != NM_ATT_SW_DESCR)
953 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
954 if (sw_config[1] != NM_ATT_FILE_ID)
955 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
956 file_id_len = sw_config[2] * 256 + sw_config[3];
957
958 /* Assumes first SW file in list is the one to be activated */
959 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000960 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
961 foh->obj_inst.bts_nr,
962 foh->obj_inst.trx_nr,
963 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200964 sw_config + 4,
965 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000966}
967
Harald Weltee0590df2009-02-15 03:34:15 +0000968/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
969static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
970{
971 struct abis_om_hdr *oh = msgb_l2(mb);
972 struct abis_om_fom_hdr *foh = msgb_l3(mb);
973 struct tlv_parsed tp;
974 u_int8_t adm_state;
975
Harald Welte03133942009-02-18 19:51:53 +0000976 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000977 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
978 return -EINVAL;
979
980 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
981
982 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
983}
984
Harald Welteee670472009-02-22 21:58:49 +0000985static int abis_nm_rx_lmt_event(struct msgb *mb)
986{
987 struct abis_om_hdr *oh = msgb_l2(mb);
988 struct abis_om_fom_hdr *foh = msgb_l3(mb);
989 struct tlv_parsed tp;
990
991 DEBUGP(DNM, "LMT Event ");
992 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
993 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
994 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
995 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
996 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
997 }
998 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
999 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
1000 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
1001 DEBUGPC(DNM, "Level=%u ", level);
1002 }
1003 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
1004 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
1005 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1006 DEBUGPC(DNM, "Username=%s ", name);
1007 }
1008 DEBUGPC(DNM, "\n");
1009 /* FIXME: parse LMT LOGON TIME */
1010 return 0;
1011}
1012
Harald Welte52b1f982008-12-23 20:25:15 +00001013/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001014static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001015{
Harald Welte6c96ba52009-05-01 13:03:40 +00001016 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001017 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1018 u_int8_t mt = foh->msg_type;
1019
1020 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001021 if (is_report(mt))
1022 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001023
Harald Welte4724f992009-01-18 18:01:49 +00001024 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1025 return abis_nm_rcvmsg_sw(mb);
1026
Harald Welte78fc0d42009-02-19 02:50:57 +00001027 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +00001028 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001029
Harald Weltea8bd6d42009-10-20 09:56:18 +02001030 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001031
Harald Welte78fc0d42009-02-19 02:50:57 +00001032 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +02001033 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +00001034 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +00001035 else
Harald Welte4bd0a982009-10-08 20:18:59 +02001036 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +00001037
1038 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1039 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1040 DEBUGPC(DNM, "CAUSE=%s\n",
1041 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1042 else
1043 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001044
Harald Welted8cfc902009-11-17 06:09:56 +01001045 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001046 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001047 }
Harald Weltead384642008-12-26 10:20:07 +00001048#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001049 /* check if last message is to be acked */
1050 if (is_ack_nack(nmh->last_msgtype)) {
1051 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001052 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001053 /* we got our ACK, continue sending the next msg */
1054 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1055 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001056 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001057 /* FIXME: somehow signal this to the caller */
1058 } else {
1059 /* really strange things happen */
1060 return -EINVAL;
1061 }
1062 }
Harald Weltead384642008-12-26 10:20:07 +00001063#endif
1064
Harald Welte97ed1e72009-02-06 13:38:02 +00001065 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001066 case NM_MT_CHG_ADM_STATE_ACK:
1067 return abis_nm_rx_chg_adm_state_ack(mb);
1068 break;
Harald Welte34a99682009-02-13 02:41:40 +00001069 case NM_MT_SW_ACT_REQ:
1070 return abis_nm_rx_sw_act_req(mb);
1071 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001072 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001073 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001074 break;
Harald Welte1989c082009-08-06 17:58:31 +02001075 case NM_MT_CONN_MDROP_LINK_ACK:
1076 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1077 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001078 case NM_MT_IPACC_RESTART_ACK:
1079 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1080 break;
1081 case NM_MT_IPACC_RESTART_NACK:
1082 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1083 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001084 }
1085
Harald Weltead384642008-12-26 10:20:07 +00001086 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001087}
1088
Harald Welte677c21f2009-02-17 13:22:23 +00001089static int abis_nm_rx_ipacc(struct msgb *mb);
1090
1091static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1092{
1093 int rc;
1094 int bts_type = mb->trx->bts->type;
1095
1096 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001097 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001098 rc = abis_nm_rx_ipacc(mb);
1099 break;
1100 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001101 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1102 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001103 rc = 0;
1104 break;
1105 }
1106
1107 return rc;
1108}
1109
Harald Welte52b1f982008-12-23 20:25:15 +00001110/* High-Level API */
1111/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001112int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001113{
Harald Welte52b1f982008-12-23 20:25:15 +00001114 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001115 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001116
1117 /* Various consistency checks */
1118 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001119 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001120 oh->placement);
1121 return -EINVAL;
1122 }
1123 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001124 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001125 oh->sequence);
1126 return -EINVAL;
1127 }
Harald Welte702d8702008-12-26 20:25:35 +00001128#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001129 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1130 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001131 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001132 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001133 oh->length + sizeof(*oh), l2_len);
1134 return -EINVAL;
1135 }
Harald Welte702d8702008-12-26 20:25:35 +00001136 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001137 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 +00001138#endif
Harald Weltead384642008-12-26 10:20:07 +00001139 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001140
1141 switch (oh->mdisc) {
1142 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001143 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001144 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001145 case ABIS_OM_MDISC_MANUF:
1146 rc = abis_nm_rcvmsg_manuf(msg);
1147 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001148 case ABIS_OM_MDISC_MMI:
1149 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001150 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001151 oh->mdisc);
1152 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001153 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001154 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001155 oh->mdisc);
1156 return -EINVAL;
1157 }
1158
Harald Weltead384642008-12-26 10:20:07 +00001159 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001160 return rc;
1161}
1162
1163#if 0
1164/* initialized all resources */
1165struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1166{
1167 struct abis_nm_h *nmh;
1168
1169 nmh = malloc(sizeof(*nmh));
1170 if (!nmh)
1171 return NULL;
1172
1173 nmh->cfg = cfg;
1174
1175 return nmh;
1176}
1177
1178/* free all resources */
1179void abis_nm_fini(struct abis_nm_h *nmh)
1180{
1181 free(nmh);
1182}
1183#endif
1184
1185/* Here we are trying to define a high-level API that can be used by
1186 * the actual BSC implementation. However, the architecture is currently
1187 * still under design. Ideally the calls to this API would be synchronous,
1188 * while the underlying stack behind the APi runs in a traditional select
1189 * based state machine.
1190 */
1191
Harald Welte4724f992009-01-18 18:01:49 +00001192/* 6.2 Software Load: */
1193enum sw_state {
1194 SW_STATE_NONE,
1195 SW_STATE_WAIT_INITACK,
1196 SW_STATE_WAIT_SEGACK,
1197 SW_STATE_WAIT_ENDACK,
1198 SW_STATE_WAIT_ACTACK,
1199 SW_STATE_ERROR,
1200};
Harald Welte52b1f982008-12-23 20:25:15 +00001201
Harald Welte52b1f982008-12-23 20:25:15 +00001202struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001203 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001204 gsm_cbfn *cbfn;
1205 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001206 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001207
Harald Welte52b1f982008-12-23 20:25:15 +00001208 /* this will become part of the SW LOAD INITIATE */
1209 u_int8_t obj_class;
1210 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001211
1212 u_int8_t file_id[255];
1213 u_int8_t file_id_len;
1214
1215 u_int8_t file_version[255];
1216 u_int8_t file_version_len;
1217
1218 u_int8_t window_size;
1219 u_int8_t seg_in_window;
1220
1221 int fd;
1222 FILE *stream;
1223 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001224 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001225};
1226
Harald Welte4724f992009-01-18 18:01:49 +00001227static struct abis_nm_sw g_sw;
1228
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001229static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1230{
1231 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1232 msgb_v_put(msg, NM_ATT_SW_DESCR);
1233 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1234 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1235 sw->file_version);
1236 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1237 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1238 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1239 sw->file_version);
1240 } else {
1241 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1242 }
1243}
1244
Harald Welte4724f992009-01-18 18:01:49 +00001245/* 6.2.1 / 8.3.1: Load Data Initiate */
1246static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001247{
Harald Welte4724f992009-01-18 18:01:49 +00001248 struct abis_om_hdr *oh;
1249 struct msgb *msg = nm_msgb_alloc();
1250 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1251
1252 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1253 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1254 sw->obj_instance[0], sw->obj_instance[1],
1255 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001256
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001257 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001258 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1259
1260 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001261}
1262
Harald Welte1602ade2009-01-29 21:12:39 +00001263static int is_last_line(FILE *stream)
1264{
1265 char next_seg_buf[256];
1266 long pos;
1267
1268 /* check if we're sending the last line */
1269 pos = ftell(stream);
1270 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1271 fseek(stream, pos, SEEK_SET);
1272 return 1;
1273 }
1274
1275 fseek(stream, pos, SEEK_SET);
1276 return 0;
1277}
1278
Harald Welte4724f992009-01-18 18:01:49 +00001279/* 6.2.2 / 8.3.2 Load Data Segment */
1280static int sw_load_segment(struct abis_nm_sw *sw)
1281{
1282 struct abis_om_hdr *oh;
1283 struct msgb *msg = nm_msgb_alloc();
1284 char seg_buf[256];
1285 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001286 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001287 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001288
1289 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001290
1291 switch (sw->bts->type) {
1292 case GSM_BTS_TYPE_BS11:
1293 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1294 perror("fgets reading segment");
1295 return -EINVAL;
1296 }
1297 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001298
1299 /* check if we're sending the last line */
1300 sw->last_seg = is_last_line(sw->stream);
1301 if (sw->last_seg)
1302 seg_buf[1] = 0;
1303 else
1304 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001305
1306 len = strlen(line_buf) + 2;
1307 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1308 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1309 /* BS11 wants CR + LF in excess of the TLV length !?! */
1310 tlv[1] -= 2;
1311
1312 /* we only now know the exact length for the OM hdr */
1313 len = strlen(line_buf)+2;
1314 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001315 case GSM_BTS_TYPE_NANOBTS: {
1316 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1317 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1318 if (len < 0) {
1319 perror("read failed");
1320 return -EINVAL;
1321 }
1322
1323 if (len != IPACC_SEGMENT_SIZE)
1324 sw->last_seg = 1;
1325
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001326 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001327 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1328 len += 3;
1329 break;
1330 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001331 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001332 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001333 /* FIXME: Other BTS types */
1334 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001335 }
Harald Welte4724f992009-01-18 18:01:49 +00001336
Harald Welte4724f992009-01-18 18:01:49 +00001337 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1338 sw->obj_instance[0], sw->obj_instance[1],
1339 sw->obj_instance[2]);
1340
1341 return abis_nm_sendmsg(sw->bts, msg);
1342}
1343
1344/* 6.2.4 / 8.3.4 Load Data End */
1345static int sw_load_end(struct abis_nm_sw *sw)
1346{
1347 struct abis_om_hdr *oh;
1348 struct msgb *msg = nm_msgb_alloc();
1349 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1350
1351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1352 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1353 sw->obj_instance[0], sw->obj_instance[1],
1354 sw->obj_instance[2]);
1355
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001356 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001357 return abis_nm_sendmsg(sw->bts, msg);
1358}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001359
Harald Welte52b1f982008-12-23 20:25:15 +00001360/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001361static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001362{
Harald Welte4724f992009-01-18 18:01:49 +00001363 struct abis_om_hdr *oh;
1364 struct msgb *msg = nm_msgb_alloc();
1365 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001366
Harald Welte4724f992009-01-18 18:01:49 +00001367 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1368 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1369 sw->obj_instance[0], sw->obj_instance[1],
1370 sw->obj_instance[2]);
1371
1372 /* FIXME: this is BS11 specific format */
1373 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1374 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1375 sw->file_version);
1376
1377 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001378}
Harald Welte4724f992009-01-18 18:01:49 +00001379
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001380struct sdp_firmware {
1381 char magic[4];
1382 char more_magic[4];
1383 unsigned int header_length;
1384 unsigned int file_length;
1385} __attribute__ ((packed));
1386
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001387static int parse_sdp_header(struct abis_nm_sw *sw)
1388{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001389 struct sdp_firmware firmware_header;
1390 int rc;
1391 struct stat stat;
1392
1393 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1394 if (rc != sizeof(firmware_header)) {
1395 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1396 return -1;
1397 }
1398
1399 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1400 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1401 return -1;
1402 }
1403
1404 if (firmware_header.more_magic[0] != 0x10 ||
1405 firmware_header.more_magic[1] != 0x02 ||
1406 firmware_header.more_magic[2] != 0x00 ||
1407 firmware_header.more_magic[3] != 0x00) {
1408 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1409 return -1;
1410 }
1411
1412
1413 if (fstat(sw->fd, &stat) == -1) {
1414 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1415 return -1;
1416 }
1417
1418 if (ntohl(firmware_header.file_length) != stat.st_size) {
1419 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1420 return -1;
1421 }
1422
1423 /* go back to the start as we checked the whole filesize.. */
1424 lseek(sw->fd, 0l, SEEK_SET);
1425 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1426 "There might be checksums in the file that are not\n"
1427 "verified and incomplete firmware might be flashed.\n"
1428 "There is absolutely no WARRANTY that flashing will\n"
1429 "work.\n");
1430 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001431}
1432
Harald Welte4724f992009-01-18 18:01:49 +00001433static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1434{
1435 char file_id[12+1];
1436 char file_version[80+1];
1437 int rc;
1438
1439 sw->fd = open(fname, O_RDONLY);
1440 if (sw->fd < 0)
1441 return sw->fd;
1442
1443 switch (sw->bts->type) {
1444 case GSM_BTS_TYPE_BS11:
1445 sw->stream = fdopen(sw->fd, "r");
1446 if (!sw->stream) {
1447 perror("fdopen");
1448 return -1;
1449 }
1450 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001451 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001452 file_id, file_version);
1453 if (rc != 2) {
1454 perror("parsing header line of software file");
1455 return -1;
1456 }
1457 strcpy((char *)sw->file_id, file_id);
1458 sw->file_id_len = strlen(file_id);
1459 strcpy((char *)sw->file_version, file_version);
1460 sw->file_version_len = strlen(file_version);
1461 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001462 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001463 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001464 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001465 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001466 rc = parse_sdp_header(sw);
1467 if (rc < 0) {
1468 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1469 return -1;
1470 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001471
1472 strcpy((char *)sw->file_id, "id");
1473 sw->file_id_len = 3;
1474 strcpy((char *)sw->file_version, "version");
1475 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001476 break;
Harald Welte4724f992009-01-18 18:01:49 +00001477 default:
1478 /* We don't know how to treat them yet */
1479 close(sw->fd);
1480 return -EINVAL;
1481 }
1482
1483 return 0;
1484}
1485
1486static void sw_close_file(struct abis_nm_sw *sw)
1487{
1488 switch (sw->bts->type) {
1489 case GSM_BTS_TYPE_BS11:
1490 fclose(sw->stream);
1491 break;
1492 default:
1493 close(sw->fd);
1494 break;
1495 }
1496}
1497
1498/* Fill the window */
1499static int sw_fill_window(struct abis_nm_sw *sw)
1500{
1501 int rc;
1502
1503 while (sw->seg_in_window < sw->window_size) {
1504 rc = sw_load_segment(sw);
1505 if (rc < 0)
1506 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001507 if (sw->last_seg)
1508 break;
Harald Welte4724f992009-01-18 18:01:49 +00001509 }
1510 return 0;
1511}
1512
1513/* callback function from abis_nm_rcvmsg() handler */
1514static int abis_nm_rcvmsg_sw(struct msgb *mb)
1515{
1516 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1517 int rc = -1;
1518 struct abis_nm_sw *sw = &g_sw;
1519 enum sw_state old_state = sw->state;
1520
Harald Welte3ffd1372009-02-01 22:15:49 +00001521 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001522
1523 switch (sw->state) {
1524 case SW_STATE_WAIT_INITACK:
1525 switch (foh->msg_type) {
1526 case NM_MT_LOAD_INIT_ACK:
1527 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001528 if (sw->cbfn)
1529 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1530 NM_MT_LOAD_INIT_ACK, mb,
1531 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001532 rc = sw_fill_window(sw);
1533 sw->state = SW_STATE_WAIT_SEGACK;
1534 break;
1535 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001536 if (sw->forced) {
1537 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1538 "Init NACK\n");
1539 if (sw->cbfn)
1540 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1541 NM_MT_LOAD_INIT_ACK, mb,
1542 sw->cb_data, NULL);
1543 rc = sw_fill_window(sw);
1544 sw->state = SW_STATE_WAIT_SEGACK;
1545 } else {
1546 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001547 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001548 if (sw->cbfn)
1549 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1550 NM_MT_LOAD_INIT_NACK, mb,
1551 sw->cb_data, NULL);
1552 sw->state = SW_STATE_ERROR;
1553 }
Harald Welte4724f992009-01-18 18:01:49 +00001554 break;
1555 }
1556 break;
1557 case SW_STATE_WAIT_SEGACK:
1558 switch (foh->msg_type) {
1559 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001560 if (sw->cbfn)
1561 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1562 NM_MT_LOAD_SEG_ACK, mb,
1563 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001564 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001565 if (!sw->last_seg) {
1566 /* fill window with more segments */
1567 rc = sw_fill_window(sw);
1568 sw->state = SW_STATE_WAIT_SEGACK;
1569 } else {
1570 /* end the transfer */
1571 sw->state = SW_STATE_WAIT_ENDACK;
1572 rc = sw_load_end(sw);
1573 }
Harald Welte4724f992009-01-18 18:01:49 +00001574 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001575 case NM_MT_LOAD_ABORT:
1576 if (sw->cbfn)
1577 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1578 NM_MT_LOAD_ABORT, mb,
1579 sw->cb_data, NULL);
1580 break;
Harald Welte4724f992009-01-18 18:01:49 +00001581 }
1582 break;
1583 case SW_STATE_WAIT_ENDACK:
1584 switch (foh->msg_type) {
1585 case NM_MT_LOAD_END_ACK:
1586 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001587 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1588 sw->bts->nr);
1589 sw->state = SW_STATE_NONE;
1590 if (sw->cbfn)
1591 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1592 NM_MT_LOAD_END_ACK, mb,
1593 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001594 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001595 break;
1596 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001597 if (sw->forced) {
1598 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1599 "End NACK\n");
1600 sw->state = SW_STATE_NONE;
1601 if (sw->cbfn)
1602 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1603 NM_MT_LOAD_END_ACK, mb,
1604 sw->cb_data, NULL);
1605 } else {
1606 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001607 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001608 sw->state = SW_STATE_ERROR;
1609 if (sw->cbfn)
1610 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1611 NM_MT_LOAD_END_NACK, mb,
1612 sw->cb_data, NULL);
1613 }
Harald Welte4724f992009-01-18 18:01:49 +00001614 break;
1615 }
1616 case SW_STATE_WAIT_ACTACK:
1617 switch (foh->msg_type) {
1618 case NM_MT_ACTIVATE_SW_ACK:
1619 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001620 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001621 sw->state = SW_STATE_NONE;
1622 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001623 if (sw->cbfn)
1624 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1625 NM_MT_ACTIVATE_SW_ACK, mb,
1626 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001627 break;
1628 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001629 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001630 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001631 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001632 if (sw->cbfn)
1633 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1634 NM_MT_ACTIVATE_SW_NACK, mb,
1635 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001636 break;
1637 }
1638 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001639 switch (foh->msg_type) {
1640 case NM_MT_ACTIVATE_SW_ACK:
1641 rc = 0;
1642 break;
1643 }
1644 break;
Harald Welte4724f992009-01-18 18:01:49 +00001645 case SW_STATE_ERROR:
1646 break;
1647 }
1648
1649 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001650 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001651 foh->msg_type, old_state, sw->state);
1652
1653 return rc;
1654}
1655
1656/* Load the specified software into the BTS */
1657int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001658 u_int8_t win_size, int forced,
1659 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001660{
1661 struct abis_nm_sw *sw = &g_sw;
1662 int rc;
1663
Harald Welte5e4d1b32009-02-01 13:36:56 +00001664 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1665 bts->nr, fname);
1666
Harald Welte4724f992009-01-18 18:01:49 +00001667 if (sw->state != SW_STATE_NONE)
1668 return -EBUSY;
1669
1670 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001671
1672 switch (bts->type) {
1673 case GSM_BTS_TYPE_BS11:
1674 sw->obj_class = NM_OC_SITE_MANAGER;
1675 sw->obj_instance[0] = 0xff;
1676 sw->obj_instance[1] = 0xff;
1677 sw->obj_instance[2] = 0xff;
1678 break;
1679 case GSM_BTS_TYPE_NANOBTS:
1680 sw->obj_class = NM_OC_BASEB_TRANSC;
1681 sw->obj_instance[0] = 0x00;
1682 sw->obj_instance[1] = 0x00;
1683 sw->obj_instance[2] = 0xff;
1684 break;
1685 case GSM_BTS_TYPE_UNKNOWN:
1686 default:
1687 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1688 return -1;
1689 break;
1690 }
Harald Welte4724f992009-01-18 18:01:49 +00001691 sw->window_size = win_size;
1692 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001693 sw->cbfn = cbfn;
1694 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001695 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001696
1697 rc = sw_open_file(sw, fname);
1698 if (rc < 0) {
1699 sw->state = SW_STATE_NONE;
1700 return rc;
1701 }
1702
1703 return sw_load_init(sw);
1704}
Harald Welte52b1f982008-12-23 20:25:15 +00001705
Harald Welte1602ade2009-01-29 21:12:39 +00001706int abis_nm_software_load_status(struct gsm_bts *bts)
1707{
1708 struct abis_nm_sw *sw = &g_sw;
1709 struct stat st;
1710 int rc, percent;
1711
1712 rc = fstat(sw->fd, &st);
1713 if (rc < 0) {
1714 perror("ERROR during stat");
1715 return rc;
1716 }
1717
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001718 if (sw->stream)
1719 percent = (ftell(sw->stream) * 100) / st.st_size;
1720 else
1721 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001722 return percent;
1723}
1724
Harald Welte5e4d1b32009-02-01 13:36:56 +00001725/* Activate the specified software into the BTS */
1726int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1727 gsm_cbfn *cbfn, void *cb_data)
1728{
1729 struct abis_nm_sw *sw = &g_sw;
1730 int rc;
1731
1732 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1733 bts->nr, fname);
1734
1735 if (sw->state != SW_STATE_NONE)
1736 return -EBUSY;
1737
1738 sw->bts = bts;
1739 sw->obj_class = NM_OC_SITE_MANAGER;
1740 sw->obj_instance[0] = 0xff;
1741 sw->obj_instance[1] = 0xff;
1742 sw->obj_instance[2] = 0xff;
1743 sw->state = SW_STATE_WAIT_ACTACK;
1744 sw->cbfn = cbfn;
1745 sw->cb_data = cb_data;
1746
1747 /* Open the file in order to fill some sw struct members */
1748 rc = sw_open_file(sw, fname);
1749 if (rc < 0) {
1750 sw->state = SW_STATE_NONE;
1751 return rc;
1752 }
1753 sw_close_file(sw);
1754
1755 return sw_activate(sw);
1756}
1757
Harald Welte8470bf22008-12-25 23:28:35 +00001758static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001759 u_int8_t ts_nr, u_int8_t subslot_nr)
1760{
Harald Welteadaf08b2009-01-18 11:08:10 +00001761 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001762 ch->bts_port = bts_port;
1763 ch->timeslot = ts_nr;
1764 ch->subslot = subslot_nr;
1765}
1766
1767int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1768 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1769 u_int8_t tei)
1770{
1771 struct abis_om_hdr *oh;
1772 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001773 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001774 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001775
1776 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1777 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1778 bts->bts_nr, trx_nr, 0xff);
1779
Harald Welte8470bf22008-12-25 23:28:35 +00001780 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001781
1782 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1783 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1784
1785 return abis_nm_sendmsg(bts, msg);
1786}
1787
1788/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1789int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1790 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1791{
Harald Welte8470bf22008-12-25 23:28:35 +00001792 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001793 struct abis_om_hdr *oh;
1794 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001795 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001796
1797 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001798 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001799 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1800
1801 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1802 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1803
1804 return abis_nm_sendmsg(bts, msg);
1805}
1806
1807#if 0
1808int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1809 struct abis_nm_abis_channel *chan)
1810{
1811}
1812#endif
1813
1814int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1815 u_int8_t e1_port, u_int8_t e1_timeslot,
1816 u_int8_t e1_subslot)
1817{
1818 struct gsm_bts *bts = ts->trx->bts;
1819 struct abis_om_hdr *oh;
1820 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001821 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001822
1823 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1824 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001825 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001826
1827 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1828 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1829
Harald Weltef325eb42009-02-19 17:07:39 +00001830 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1831 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001832 e1_port, e1_timeslot, e1_subslot);
1833
Harald Welte52b1f982008-12-23 20:25:15 +00001834 return abis_nm_sendmsg(bts, msg);
1835}
1836
1837#if 0
1838int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1839 struct abis_nm_abis_channel *chan,
1840 u_int8_t subchan)
1841{
1842}
1843#endif
1844
Harald Welte22af0db2009-02-14 15:41:08 +00001845/* Chapter 8.6.1 */
1846int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1847{
1848 struct abis_om_hdr *oh;
1849 struct msgb *msg = nm_msgb_alloc();
1850 u_int8_t *cur;
1851
1852 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1853
1854 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001855 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 +00001856 cur = msgb_put(msg, attr_len);
1857 memcpy(cur, attr, attr_len);
1858
1859 return abis_nm_sendmsg(bts, msg);
1860}
1861
1862/* Chapter 8.6.2 */
1863int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1864{
1865 struct abis_om_hdr *oh;
1866 struct msgb *msg = nm_msgb_alloc();
1867 u_int8_t *cur;
1868
1869 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1870
1871 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1872 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001873 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001874 cur = msgb_put(msg, attr_len);
1875 memcpy(cur, attr, attr_len);
1876
1877 return abis_nm_sendmsg(trx->bts, msg);
1878}
1879
Harald Welte39c7deb2009-08-09 21:49:48 +02001880static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1881{
1882 int i;
1883
1884 /* As it turns out, the BS-11 has some very peculiar restrictions
1885 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301886 switch (ts->trx->bts->type) {
1887 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001888 switch (chan_comb) {
1889 case NM_CHANC_TCHHalf:
1890 case NM_CHANC_TCHHalf2:
1891 /* not supported */
1892 return -EINVAL;
1893 case NM_CHANC_SDCCH:
1894 /* only one SDCCH/8 per TRX */
1895 for (i = 0; i < TRX_NR_TS; i++) {
1896 if (i == ts->nr)
1897 continue;
1898 if (ts->trx->ts[i].nm_chan_comb ==
1899 NM_CHANC_SDCCH)
1900 return -EINVAL;
1901 }
1902 /* not allowed for TS0 of BCCH-TRX */
1903 if (ts->trx == ts->trx->bts->c0 &&
1904 ts->nr == 0)
1905 return -EINVAL;
1906 /* not on the same TRX that has a BCCH+SDCCH4
1907 * combination */
1908 if (ts->trx == ts->trx->bts->c0 &&
1909 (ts->trx->ts[0].nm_chan_comb == 5 ||
1910 ts->trx->ts[0].nm_chan_comb == 8))
1911 return -EINVAL;
1912 break;
1913 case NM_CHANC_mainBCCH:
1914 case NM_CHANC_BCCHComb:
1915 /* allowed only for TS0 of C0 */
1916 if (ts->trx != ts->trx->bts->c0 ||
1917 ts->nr != 0)
1918 return -EINVAL;
1919 break;
1920 case NM_CHANC_BCCH:
1921 /* allowed only for TS 2/4/6 of C0 */
1922 if (ts->trx != ts->trx->bts->c0)
1923 return -EINVAL;
1924 if (ts->nr != 2 && ts->nr != 4 &&
1925 ts->nr != 6)
1926 return -EINVAL;
1927 break;
1928 case 8: /* this is not like 08.58, but in fact
1929 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1930 /* FIXME: only one CBCH allowed per cell */
1931 break;
1932 }
Harald Welted6575f92009-12-02 02:45:23 +05301933 break;
1934 case GSM_BTS_TYPE_NANOBTS:
1935 switch (ts->nr) {
1936 case 0:
1937 if (ts->trx->nr == 0) {
1938 /* only on TRX0 */
1939 switch (chan_comb) {
1940 case NM_CHANC_BCCH:
1941 case NM_CHANC_mainBCCH:
1942 case NM_CHANC_BCCHComb:
1943 return 0;
1944 break;
1945 default:
1946 return -EINVAL;
1947 }
1948 } else {
1949 switch (chan_comb) {
1950 case NM_CHANC_TCHFull:
1951 case NM_CHANC_TCHHalf:
1952 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1953 return 0;
1954 default:
1955 return -EINVAL;
1956 }
1957 }
1958 break;
1959 case 1:
1960 if (ts->trx->nr == 0) {
1961 switch (chan_comb) {
1962 case NM_CHANC_SDCCH_CBCH:
1963 if (ts->trx->ts[0].nm_chan_comb ==
1964 NM_CHANC_mainBCCH)
1965 return 0;
1966 return -EINVAL;
1967 case NM_CHANC_SDCCH:
1968 case NM_CHANC_TCHFull:
1969 case NM_CHANC_TCHHalf:
1970 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1971 case NM_CHANC_IPAC_TCHFull_PDCH:
1972 return 0;
1973 }
1974 } else {
1975 switch (chan_comb) {
1976 case NM_CHANC_SDCCH:
1977 case NM_CHANC_TCHFull:
1978 case NM_CHANC_TCHHalf:
1979 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1980 return 0;
1981 default:
1982 return -EINVAL;
1983 }
1984 }
1985 break;
1986 case 2:
1987 case 3:
1988 case 4:
1989 case 5:
1990 case 6:
1991 case 7:
1992 switch (chan_comb) {
1993 case NM_CHANC_TCHFull:
1994 case NM_CHANC_TCHHalf:
1995 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1996 return 0;
1997 case NM_CHANC_IPAC_PDCH:
1998 case NM_CHANC_IPAC_TCHFull_PDCH:
1999 if (ts->trx->nr == 0)
2000 return 0;
2001 else
2002 return -EINVAL;
2003 }
2004 break;
2005 }
2006 return -EINVAL;
2007 default:
2008 /* unknown BTS type */
2009 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002010 }
2011 return 0;
2012}
2013
Harald Welte22af0db2009-02-14 15:41:08 +00002014/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002015int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2016{
2017 struct gsm_bts *bts = ts->trx->bts;
2018 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002019 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002020 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002021 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002022 u_int8_t len = 2 + 2;
2023
2024 if (bts->type == GSM_BTS_TYPE_BS11)
2025 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002026
Harald Weltef325eb42009-02-19 17:07:39 +00002027 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002028 if (verify_chan_comb(ts, chan_comb) < 0) {
2029 msgb_free(msg);
2030 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2031 return -EINVAL;
2032 }
2033 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002034
Harald Welte52b1f982008-12-23 20:25:15 +00002035 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002036 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002037 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002038 ts->trx->nr, ts->nr);
2039 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00002040 if (bts->type == GSM_BTS_TYPE_BS11)
2041 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002042 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00002043 if (bts->type == GSM_BTS_TYPE_BS11) {
2044 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2045 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2046 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002047 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002048 if (bts->type == GSM_BTS_TYPE_BS11)
2049 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002050
2051 return abis_nm_sendmsg(bts, msg);
2052}
2053
Harald Welte34a99682009-02-13 02:41:40 +00002054int 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 +00002055 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002056{
2057 struct abis_om_hdr *oh;
2058 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002059 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2060 u_int8_t len = att_len;
2061
2062 if (nack) {
2063 len += 2;
2064 msgtype = NM_MT_SW_ACT_REQ_NACK;
2065 }
Harald Welte34a99682009-02-13 02:41:40 +00002066
2067 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002068 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2069
Harald Welte34a99682009-02-13 02:41:40 +00002070 if (attr) {
2071 u_int8_t *ptr = msgb_put(msg, att_len);
2072 memcpy(ptr, attr, att_len);
2073 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002074 if (nack)
2075 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002076
2077 return abis_nm_sendmsg(bts, msg);
2078}
2079
Harald Welte8470bf22008-12-25 23:28:35 +00002080int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002081{
Harald Welte8470bf22008-12-25 23:28:35 +00002082 struct msgb *msg = nm_msgb_alloc();
2083 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002084 u_int8_t *data;
2085
2086 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2087 fill_om_hdr(oh, len);
2088 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002089 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002090
2091 return abis_nm_sendmsg(bts, msg);
2092}
2093
2094/* Siemens specific commands */
2095static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2096{
2097 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002098 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002099
2100 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002101 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002102 0xff, 0xff, 0xff);
2103
2104 return abis_nm_sendmsg(bts, msg);
2105}
2106
Harald Welte34a99682009-02-13 02:41:40 +00002107/* Chapter 8.9.2 */
2108int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2109{
2110 struct abis_om_hdr *oh;
2111 struct msgb *msg = nm_msgb_alloc();
2112
2113 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2114 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2115
Harald Weltea8bd6d42009-10-20 09:56:18 +02002116 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2117 DEBUGPC(DNM, "Sending OPSTART\n");
2118
Harald Welte34a99682009-02-13 02:41:40 +00002119 return abis_nm_sendmsg(bts, msg);
2120}
2121
2122/* Chapter 8.8.5 */
2123int 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 +02002124 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002125{
2126 struct abis_om_hdr *oh;
2127 struct msgb *msg = nm_msgb_alloc();
2128
2129 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2130 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2131 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2132
2133 return abis_nm_sendmsg(bts, msg);
2134}
2135
Harald Welte1989c082009-08-06 17:58:31 +02002136int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2137 u_int8_t e1_port1, u_int8_t ts1)
2138{
2139 struct abis_om_hdr *oh;
2140 struct msgb *msg = nm_msgb_alloc();
2141 u_int8_t *attr;
2142
2143 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2144 e1_port0, ts0, e1_port1, ts1);
2145
2146 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2147 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2148 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2149
2150 attr = msgb_put(msg, 3);
2151 attr[0] = NM_ATT_MDROP_LINK;
2152 attr[1] = e1_port0;
2153 attr[2] = ts0;
2154
2155 attr = msgb_put(msg, 3);
2156 attr[0] = NM_ATT_MDROP_NEXT;
2157 attr[1] = e1_port1;
2158 attr[2] = ts1;
2159
2160 return abis_nm_sendmsg(bts, msg);
2161}
Harald Welte34a99682009-02-13 02:41:40 +00002162
Harald Weltec7310382009-08-08 00:02:36 +02002163/* Chapter 8.7.1 */
2164int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2165 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2166 u_int8_t test_nr, u_int8_t auton_report,
2167 u_int8_t *phys_config, u_int16_t phys_config_len)
2168{
2169 struct abis_om_hdr *oh;
2170 struct msgb *msg = nm_msgb_alloc();
2171 int len = 4; /* 2 TV attributes */
2172
2173 DEBUGP(DNM, "PEFORM TEST\n");
2174
2175 if (phys_config_len)
2176 len += 3 + phys_config_len;
2177
2178 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2179 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2180 obj_class, bts_nr, trx_nr, ts_nr);
2181 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2182 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2183 if (phys_config_len)
2184 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2185 phys_config);
2186
2187 return abis_nm_sendmsg(bts, msg);
2188}
2189
Harald Welte52b1f982008-12-23 20:25:15 +00002190int abis_nm_event_reports(struct gsm_bts *bts, int on)
2191{
2192 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002193 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002194 else
Harald Welte227d4072009-01-03 08:16:25 +00002195 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002196}
2197
Harald Welte47d88ae2009-01-04 12:02:08 +00002198/* Siemens (or BS-11) specific commands */
2199
Harald Welte3ffd1372009-02-01 22:15:49 +00002200int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2201{
2202 if (reconnect == 0)
2203 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2204 else
2205 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2206}
2207
Harald Welteb8427972009-02-05 19:27:17 +00002208int abis_nm_bs11_restart(struct gsm_bts *bts)
2209{
2210 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2211}
2212
2213
Harald Welte268bb402009-02-01 19:11:56 +00002214struct bs11_date_time {
2215 u_int16_t year;
2216 u_int8_t month;
2217 u_int8_t day;
2218 u_int8_t hour;
2219 u_int8_t min;
2220 u_int8_t sec;
2221} __attribute__((packed));
2222
2223
2224void get_bs11_date_time(struct bs11_date_time *aet)
2225{
2226 time_t t;
2227 struct tm *tm;
2228
2229 t = time(NULL);
2230 tm = localtime(&t);
2231 aet->sec = tm->tm_sec;
2232 aet->min = tm->tm_min;
2233 aet->hour = tm->tm_hour;
2234 aet->day = tm->tm_mday;
2235 aet->month = tm->tm_mon;
2236 aet->year = htons(1900 + tm->tm_year);
2237}
2238
Harald Welte05188ee2009-01-18 11:39:08 +00002239int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002240{
Harald Welte4668fda2009-01-03 08:19:29 +00002241 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002242}
2243
Harald Welte05188ee2009-01-18 11:39:08 +00002244int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002245{
2246 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002247 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002248 else
Harald Welte4668fda2009-01-03 08:19:29 +00002249 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002250}
Harald Welte47d88ae2009-01-04 12:02:08 +00002251
Harald Welte05188ee2009-01-18 11:39:08 +00002252int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002253 enum abis_bs11_objtype type, u_int8_t idx,
2254 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002255{
2256 struct abis_om_hdr *oh;
2257 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002258 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002259
2260 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002261 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002262 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002263 cur = msgb_put(msg, attr_len);
2264 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002265
2266 return abis_nm_sendmsg(bts, msg);
2267}
2268
Harald Welte78fc0d42009-02-19 02:50:57 +00002269int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2270 enum abis_bs11_objtype type, u_int8_t idx)
2271{
2272 struct abis_om_hdr *oh;
2273 struct msgb *msg = nm_msgb_alloc();
2274
2275 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2276 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2277 NM_OC_BS11, type, 0, idx);
2278
2279 return abis_nm_sendmsg(bts, msg);
2280}
2281
Harald Welte05188ee2009-01-18 11:39:08 +00002282int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002283{
2284 struct abis_om_hdr *oh;
2285 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002286 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002287
2288 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002289 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002290 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2291 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002292
2293 return abis_nm_sendmsg(bts, msg);
2294}
2295
Harald Welte05188ee2009-01-18 11:39:08 +00002296int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002297{
2298 struct abis_om_hdr *oh;
2299 struct msgb *msg = nm_msgb_alloc();
2300
2301 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2302 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002303 idx, 0xff, 0xff);
2304
2305 return abis_nm_sendmsg(bts, msg);
2306}
2307
2308int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2309{
2310 struct abis_om_hdr *oh;
2311 struct msgb *msg = nm_msgb_alloc();
2312
2313 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2314 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2315 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002316
2317 return abis_nm_sendmsg(bts, msg);
2318}
Harald Welte05188ee2009-01-18 11:39:08 +00002319
Harald Welte78fc0d42009-02-19 02:50:57 +00002320static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2321int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2322{
2323 struct abis_om_hdr *oh;
2324 struct msgb *msg = nm_msgb_alloc();
2325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2327 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2328 0xff, 0xff, 0xff);
2329 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2330
2331 return abis_nm_sendmsg(bts, msg);
2332}
2333
Harald Welteb6c92ae2009-02-21 20:15:32 +00002334/* like abis_nm_conn_terr_traf + set_tei */
2335int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2336 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2337 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002338{
2339 struct abis_om_hdr *oh;
2340 struct abis_nm_channel *ch;
2341 struct msgb *msg = nm_msgb_alloc();
2342
2343 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002344 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002345 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2346
2347 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2348 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002349 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002350
2351 return abis_nm_sendmsg(bts, msg);
2352}
2353
2354int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2355{
2356 struct abis_om_hdr *oh;
2357 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002358
2359 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002360 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002361 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2362 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2363
2364 return abis_nm_sendmsg(trx->bts, msg);
2365}
2366
Harald Welte78fc0d42009-02-19 02:50:57 +00002367int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2368{
2369 struct abis_om_hdr *oh;
2370 struct msgb *msg = nm_msgb_alloc();
2371 u_int8_t attr = NM_ATT_BS11_TXPWR;
2372
2373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2374 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2375 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2376 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2377
2378 return abis_nm_sendmsg(trx->bts, msg);
2379}
2380
Harald Welteaaf02d92009-04-29 13:25:57 +00002381int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2382{
2383 struct abis_om_hdr *oh;
2384 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002385 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002386
2387 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2388 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2389 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002390 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002391
2392 return abis_nm_sendmsg(bts, msg);
2393}
2394
Harald Welteef061952009-05-17 12:43:42 +00002395int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2396{
2397 struct abis_om_hdr *oh;
2398 struct msgb *msg = nm_msgb_alloc();
2399 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2400 NM_ATT_BS11_CCLK_TYPE };
2401
2402 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2403 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2404 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2405 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2406
2407 return abis_nm_sendmsg(bts, msg);
2408
2409}
Harald Welteaaf02d92009-04-29 13:25:57 +00002410
Harald Welte268bb402009-02-01 19:11:56 +00002411//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +00002412static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +00002413static const u_int8_t bs11_logon_c9[] = "FACTORY";
2414
Harald Welte1bc09062009-01-18 14:17:52 +00002415int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002416{
2417 struct abis_om_hdr *oh;
2418 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002419 struct bs11_date_time bdt;
2420
2421 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002422
2423 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002424 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002425 u_int8_t len = 3*2 + sizeof(bdt)
Harald Welte6f676a32009-01-18 14:27:48 +00002426 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +00002427 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002428 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002429 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002430 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002431 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2432 sizeof(bs11_logon_c8), bs11_logon_c8);
2433 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2434 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +00002435 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002436 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002437 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002438 }
Harald Welte05188ee2009-01-18 11:39:08 +00002439
2440 return abis_nm_sendmsg(bts, msg);
2441}
Harald Welte1bc09062009-01-18 14:17:52 +00002442
2443int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2444{
2445 struct abis_om_hdr *oh;
2446 struct msgb *msg;
2447
2448 if (strlen(password) != 10)
2449 return -EINVAL;
2450
2451 msg = nm_msgb_alloc();
2452 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002453 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002454 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2455 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2456
2457 return abis_nm_sendmsg(bts, msg);
2458}
2459
Harald Weltee69f5fb2009-04-28 16:31:38 +00002460/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2461int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2462{
2463 struct abis_om_hdr *oh;
2464 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002465 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002466
2467 msg = nm_msgb_alloc();
2468 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2469 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2470 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002471
2472 if (locked)
2473 tlv_value = BS11_LI_PLL_LOCKED;
2474 else
2475 tlv_value = BS11_LI_PLL_STANDALONE;
2476
2477 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002478
2479 return abis_nm_sendmsg(bts, msg);
2480}
2481
Harald Welte1bc09062009-01-18 14:17:52 +00002482int abis_nm_bs11_get_state(struct gsm_bts *bts)
2483{
2484 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2485}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002486
2487/* BS11 SWL */
2488
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002489void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002490
Harald Welte5e4d1b32009-02-01 13:36:56 +00002491struct abis_nm_bs11_sw {
2492 struct gsm_bts *bts;
2493 char swl_fname[PATH_MAX];
2494 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002495 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002496 struct llist_head file_list;
2497 gsm_cbfn *user_cb; /* specified by the user */
2498};
2499static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2500
2501struct file_list_entry {
2502 struct llist_head list;
2503 char fname[PATH_MAX];
2504};
2505
2506struct file_list_entry *fl_dequeue(struct llist_head *queue)
2507{
2508 struct llist_head *lh;
2509
2510 if (llist_empty(queue))
2511 return NULL;
2512
2513 lh = queue->next;
2514 llist_del(lh);
2515
2516 return llist_entry(lh, struct file_list_entry, list);
2517}
2518
2519static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2520{
2521 char linebuf[255];
2522 struct llist_head *lh, *lh2;
2523 FILE *swl;
2524 int rc = 0;
2525
2526 swl = fopen(bs11_sw->swl_fname, "r");
2527 if (!swl)
2528 return -ENODEV;
2529
2530 /* zero the stale file list, if any */
2531 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2532 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002533 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002534 }
2535
2536 while (fgets(linebuf, sizeof(linebuf), swl)) {
2537 char file_id[12+1];
2538 char file_version[80+1];
2539 struct file_list_entry *fle;
2540 static char dir[PATH_MAX];
2541
2542 if (strlen(linebuf) < 4)
2543 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002544
Harald Welte5e4d1b32009-02-01 13:36:56 +00002545 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2546 if (rc < 0) {
2547 perror("ERR parsing SWL file");
2548 rc = -EINVAL;
2549 goto out;
2550 }
2551 if (rc < 2)
2552 continue;
2553
Harald Welte470ec292009-06-26 20:25:23 +02002554 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002555 if (!fle) {
2556 rc = -ENOMEM;
2557 goto out;
2558 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002559
2560 /* construct new filename */
2561 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2562 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2563 strcat(fle->fname, "/");
2564 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002565
2566 llist_add_tail(&fle->list, &bs11_sw->file_list);
2567 }
2568
2569out:
2570 fclose(swl);
2571 return rc;
2572}
2573
2574/* bs11 swload specific callback, passed to abis_nm core swload */
2575static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2576 struct msgb *msg, void *data, void *param)
2577{
2578 struct abis_nm_bs11_sw *bs11_sw = data;
2579 struct file_list_entry *fle;
2580 int rc = 0;
2581
Harald Welte5e4d1b32009-02-01 13:36:56 +00002582 switch (event) {
2583 case NM_MT_LOAD_END_ACK:
2584 fle = fl_dequeue(&bs11_sw->file_list);
2585 if (fle) {
2586 /* start download the next file of our file list */
2587 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2588 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002589 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002590 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002591 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002592 } else {
2593 /* activate the SWL */
2594 rc = abis_nm_software_activate(bs11_sw->bts,
2595 bs11_sw->swl_fname,
2596 bs11_swload_cbfn,
2597 bs11_sw);
2598 }
2599 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002600 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002601 case NM_MT_LOAD_END_NACK:
2602 case NM_MT_LOAD_INIT_ACK:
2603 case NM_MT_LOAD_INIT_NACK:
2604 case NM_MT_ACTIVATE_SW_NACK:
2605 case NM_MT_ACTIVATE_SW_ACK:
2606 default:
2607 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002608 if (bs11_sw->user_cb)
2609 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002610 break;
2611 }
2612
2613 return rc;
2614}
2615
2616/* Siemens provides a SWL file that is a mere listing of all the other
2617 * files that are part of a software release. We need to upload first
2618 * the list file, and then each file that is listed in the list file */
2619int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002620 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002621{
2622 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2623 struct file_list_entry *fle;
2624 int rc = 0;
2625
2626 INIT_LLIST_HEAD(&bs11_sw->file_list);
2627 bs11_sw->bts = bts;
2628 bs11_sw->win_size = win_size;
2629 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002630 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002631
2632 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2633 rc = bs11_read_swl_file(bs11_sw);
2634 if (rc < 0)
2635 return rc;
2636
2637 /* dequeue next item in file list */
2638 fle = fl_dequeue(&bs11_sw->file_list);
2639 if (!fle)
2640 return -EINVAL;
2641
2642 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002643 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002644 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002645 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002646 return rc;
2647}
2648
Harald Welte5083b0b2009-02-02 19:20:52 +00002649#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002650static u_int8_t req_attr_btse[] = {
2651 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2652 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2653 NM_ATT_BS11_LMT_USER_NAME,
2654
2655 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2656
2657 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2658
2659 NM_ATT_BS11_SW_LOAD_STORED };
2660
2661static u_int8_t req_attr_btsm[] = {
2662 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2663 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2664 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2665 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002666#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002667
2668static u_int8_t req_attr[] = {
2669 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2670 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002671 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002672
2673int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2674{
2675 struct abis_om_hdr *oh;
2676 struct msgb *msg = nm_msgb_alloc();
2677
2678 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2679 /* SiemensHW CCTRL object */
2680 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2681 0x03, 0x00, 0x00);
2682 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2683
2684 return abis_nm_sendmsg(bts, msg);
2685}
Harald Welte268bb402009-02-01 19:11:56 +00002686
2687int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2688{
2689 struct abis_om_hdr *oh;
2690 struct msgb *msg = nm_msgb_alloc();
2691 struct bs11_date_time aet;
2692
2693 get_bs11_date_time(&aet);
2694 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2695 /* SiemensHW CCTRL object */
2696 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2697 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002698 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002699
2700 return abis_nm_sendmsg(bts, msg);
2701}
Harald Welte5c1e4582009-02-15 11:57:29 +00002702
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002703int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2704{
2705 struct abis_om_hdr *oh;
2706 struct msgb *msg = nm_msgb_alloc();
2707 struct bs11_date_time aet;
2708
2709 get_bs11_date_time(&aet);
2710 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2711 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2712 bport, 0xff, 0x02);
2713 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2714
2715 return abis_nm_sendmsg(bts, msg);
2716}
2717
Harald Welte5c1e4582009-02-15 11:57:29 +00002718/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002719static const char ipaccess_magic[] = "com.ipaccess";
2720
Harald Welte677c21f2009-02-17 13:22:23 +00002721
2722static int abis_nm_rx_ipacc(struct msgb *msg)
2723{
2724 struct abis_om_hdr *oh = msgb_l2(msg);
2725 struct abis_om_fom_hdr *foh;
2726 u_int8_t idstrlen = oh->data[0];
2727 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002728 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002729
2730 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002731 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002732 return -EINVAL;
2733 }
2734
Harald Welte193fefc2009-04-30 15:16:27 +00002735 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002736 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002737
Harald Weltea8bd6d42009-10-20 09:56:18 +02002738 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002739
Harald Welte746d6092009-10-19 22:11:11 +02002740 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002741
Harald Welte677c21f2009-02-17 13:22:23 +00002742 switch (foh->msg_type) {
2743 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002744 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002745 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002746 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002747 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002748 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2749 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002750 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002751 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002752 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002753 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2754 DEBUGPC(DNM, "STREAM=0x%02x ",
2755 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002756 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002757 break;
2758 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002759 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002760 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002761 DEBUGPC(DNM, " CAUSE=%s\n",
2762 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002763 else
2764 DEBUGPC(DNM, "\n");
2765 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002766 case NM_MT_IPACC_SET_NVATTR_ACK:
2767 DEBUGPC(DNM, "SET NVATTR ACK\n");
2768 /* FIXME: decode and show the actual attributes */
2769 break;
2770 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002771 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002772 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002773 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002774 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2775 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002776 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002777 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002778 case NM_MT_IPACC_GET_NVATTR_ACK:
2779 DEBUGPC(DNM, "GET NVATTR ACK\n");
2780 /* FIXME: decode and show the actual attributes */
2781 break;
2782 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002783 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +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 Welte684b1a82009-07-03 11:26:45 +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 Welte684b1a82009-07-03 11:26:45 +02002789 break;
Harald Welte15c44172009-10-08 20:15:24 +02002790 case NM_MT_IPACC_SET_ATTR_ACK:
2791 DEBUGPC(DNM, "SET ATTR ACK\n");
2792 break;
2793 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002794 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002795 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002796 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002797 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2798 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002799 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002800 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002801 default:
2802 DEBUGPC(DNM, "unknown\n");
2803 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002804 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002805
2806 /* signal handling */
2807 switch (foh->msg_type) {
2808 case NM_MT_IPACC_RSL_CONNECT_NACK:
2809 case NM_MT_IPACC_SET_NVATTR_NACK:
2810 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002811 signal.bts = msg->trx->bts;
2812 signal.msg_type = foh->msg_type;
2813 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002814 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002815 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002816 signal.bts = msg->trx->bts;
2817 signal.msg_type = foh->msg_type;
2818 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002819 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002820 default:
2821 break;
2822 }
2823
Harald Welte677c21f2009-02-17 13:22:23 +00002824 return 0;
2825}
2826
Harald Welte193fefc2009-04-30 15:16:27 +00002827/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002828int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2829 u_int8_t obj_class, u_int8_t bts_nr,
2830 u_int8_t trx_nr, u_int8_t ts_nr,
2831 u_int8_t *attr, int attr_len)
2832{
2833 struct msgb *msg = nm_msgb_alloc();
2834 struct abis_om_hdr *oh;
2835 struct abis_om_fom_hdr *foh;
2836 u_int8_t *data;
2837
2838 /* construct the 12.21 OM header, observe the erroneous length */
2839 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2840 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2841 oh->mdisc = ABIS_OM_MDISC_MANUF;
2842
2843 /* add the ip.access magic */
2844 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2845 *data++ = sizeof(ipaccess_magic);
2846 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2847
2848 /* fill the 12.21 FOM header */
2849 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2850 foh->msg_type = msg_type;
2851 foh->obj_class = obj_class;
2852 foh->obj_inst.bts_nr = bts_nr;
2853 foh->obj_inst.trx_nr = trx_nr;
2854 foh->obj_inst.ts_nr = ts_nr;
2855
2856 if (attr && attr_len) {
2857 data = msgb_put(msg, attr_len);
2858 memcpy(data, attr, attr_len);
2859 }
2860
2861 return abis_nm_sendmsg(bts, msg);
2862}
Harald Welte677c21f2009-02-17 13:22:23 +00002863
Harald Welte193fefc2009-04-30 15:16:27 +00002864/* set some attributes in NVRAM */
2865int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2866 int attr_len)
2867{
2868 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2869 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2870 attr_len);
2871}
2872
Harald Welte746d6092009-10-19 22:11:11 +02002873int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2874 u_int32_t ip, u_int16_t port, u_int8_t stream)
2875{
2876 struct in_addr ia;
2877 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2878 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2879 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2880
2881 int attr_len = sizeof(attr);
2882
2883 ia.s_addr = htonl(ip);
2884 attr[1] = stream;
2885 attr[3] = port >> 8;
2886 attr[4] = port & 0xff;
2887 *(u_int32_t *)(attr+6) = ia.s_addr;
2888
2889 /* if ip == 0, we use the default IP */
2890 if (ip == 0)
2891 attr_len -= 5;
2892
2893 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002894 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002895
2896 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2897 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2898 trx->nr, 0xff, attr, attr_len);
2899}
2900
Harald Welte193fefc2009-04-30 15:16:27 +00002901/* restart / reboot an ip.access nanoBTS */
2902int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2903{
2904 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2905}
Harald Weltedaef5212009-10-24 10:20:41 +02002906
2907int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2908 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2909 u_int8_t *attr, u_int8_t attr_len)
2910{
2911 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2912 obj_class, bts_nr, trx_nr, ts_nr,
2913 attr, attr_len);
2914}
Harald Welte0f255852009-11-12 14:48:42 +01002915
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002916void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2917{
2918 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2919
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002920 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002921 if (!trx->bts || !trx->bts->oml_link)
2922 return;
2923
2924 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2925 trx->bts->bts_nr, trx->nr, 0xff,
2926 new_state);
2927}
2928
Harald Welte0f255852009-11-12 14:48:42 +01002929static const char *ipacc_testres_names[] = {
2930 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2931 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2932 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2933 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2934 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2935};
2936
2937const char *ipacc_testres_name(u_int8_t res)
2938{
2939 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2940 ipacc_testres_names[res])
2941 return ipacc_testres_names[res];
2942
2943 return "unknown";
2944}
2945
Harald Welteb40a38f2009-11-13 11:56:05 +01002946void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2947{
2948 cid->mcc = (buf[0] & 0xf) * 100;
2949 cid->mcc += (buf[0] >> 4) * 10;
2950 cid->mcc += (buf[1] & 0xf) * 1;
2951
2952 if (buf[1] >> 4 == 0xf) {
2953 cid->mnc = (buf[2] & 0xf) * 10;
2954 cid->mnc += (buf[2] >> 4) * 1;
2955 } else {
2956 cid->mnc = (buf[2] & 0xf) * 100;
2957 cid->mnc += (buf[2] >> 4) * 10;
2958 cid->mnc += (buf[1] >> 4) * 1;
2959 }
2960
Harald Welteaff237d2009-11-13 14:41:52 +01002961 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2962 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002963}
2964
Harald Welte0f255852009-11-12 14:48:42 +01002965/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2966int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2967{
2968 u_int8_t *cur = buf;
2969 u_int16_t len;
2970
2971 memset(binf, 0, sizeof(binf));
2972
2973 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2974 return -EINVAL;
2975 cur++;
2976
2977 len = ntohs(*(u_int16_t *)cur);
2978 cur += 2;
2979
2980 binf->info_type = ntohs(*(u_int16_t *)cur);
2981 cur += 2;
2982
2983 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2984 binf->freq_qual = *cur >> 2;
2985
2986 binf->arfcn = *cur++ & 3 << 8;
2987 binf->arfcn |= *cur++;
2988
2989 if (binf->info_type & IPAC_BINF_RXLEV)
2990 binf->rx_lev = *cur & 0x3f;
2991 cur++;
2992
2993 if (binf->info_type & IPAC_BINF_RXQUAL)
2994 binf->rx_qual = *cur & 0x7;
2995 cur++;
2996
2997 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2998 binf->freq_err = ntohs(*(u_int16_t *)cur);
2999 cur += 2;
3000
3001 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3002 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3003 cur += 2;
3004
3005 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3006 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3007 cur += 4;
3008
3009 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01003010 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003011 cur++;
3012
Harald Welteb40a38f2009-11-13 11:56:05 +01003013 ipac_parse_cgi(&binf->cgi, cur);
3014 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003015
3016 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3017 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3018 cur += sizeof(binf->ba_list_si2);
3019 }
3020
3021 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3022 memcpy(binf->ba_list_si2bis, cur,
3023 sizeof(binf->ba_list_si2bis));
3024 cur += sizeof(binf->ba_list_si2bis);
3025 }
3026
3027 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3028 memcpy(binf->ba_list_si2ter, cur,
3029 sizeof(binf->ba_list_si2ter));
3030 cur += sizeof(binf->ba_list_si2ter);
3031 }
3032
3033 return 0;
3034}
3035
3036