blob: bcfce681b0fb9e1e6ff7d61e5be39bf205a9c7e4 [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
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100602int nm_is_running(struct gsm_nm_state *s) {
603 return (s->operational == NM_OPSTATE_ENABLED) && (
604 (s->availability == NM_AVSTATE_OK) ||
605 (s->availability == 0xff)
606 );
607}
608
Harald Weltea8bd6d42009-10-20 09:56:18 +0200609static void debugp_foh(struct abis_om_fom_hdr *foh)
610{
611 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
612 obj_class_name(foh->obj_class), foh->obj_class,
613 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
614 foh->obj_inst.ts_nr);
615}
616
Harald Weltee0590df2009-02-15 03:34:15 +0000617/* obtain the gsm_nm_state data structure for a given object instance */
618static struct gsm_nm_state *
619objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
620 struct abis_om_obj_inst *obj_inst)
621{
622 struct gsm_bts_trx *trx;
623 struct gsm_nm_state *nm_state = NULL;
624
625 switch (obj_class) {
626 case NM_OC_BTS:
627 nm_state = &bts->nm_state;
628 break;
629 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100630 if (obj_inst->trx_nr >= bts->num_trx) {
631 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000632 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100633 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200634 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000635 nm_state = &trx->nm_state;
636 break;
637 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100638 if (obj_inst->trx_nr >= bts->num_trx) {
639 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000640 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100641 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200642 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000643 nm_state = &trx->bb_transc.nm_state;
644 break;
645 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100646 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100647 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000648 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100649 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200650 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000651 if (obj_inst->ts_nr >= TRX_NR_TS)
652 return NULL;
653 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
654 break;
655 case NM_OC_SITE_MANAGER:
656 nm_state = &bts->site_mgr.nm_state;
657 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000658 case NM_OC_BS11:
659 switch (obj_inst->bts_nr) {
660 case BS11_OBJ_CCLK:
661 nm_state = &bts->bs11.cclk.nm_state;
662 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000663 case BS11_OBJ_BBSIG:
664 if (obj_inst->ts_nr > bts->num_trx)
665 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200666 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000667 nm_state = &trx->bs11.bbsig.nm_state;
668 break;
669 case BS11_OBJ_PA:
670 if (obj_inst->ts_nr > bts->num_trx)
671 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200672 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000673 nm_state = &trx->bs11.pa.nm_state;
674 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000675 default:
676 return NULL;
677 }
678 case NM_OC_BS11_RACK:
679 nm_state = &bts->bs11.rack.nm_state;
680 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000681 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100682 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000683 return NULL;
684 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
685 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200686 case NM_OC_GPRS_NSE:
687 nm_state = &bts->gprs.nse.nm_state;
688 break;
689 case NM_OC_GPRS_CELL:
690 nm_state = &bts->gprs.cell.nm_state;
691 break;
692 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100693 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200694 return NULL;
695 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
696 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000697 }
698 return nm_state;
699}
700
701/* obtain the in-memory data structure of a given object instance */
702static void *
703objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
704 struct abis_om_obj_inst *obj_inst)
705{
706 struct gsm_bts_trx *trx;
707 void *obj = NULL;
708
709 switch (obj_class) {
710 case NM_OC_BTS:
711 obj = bts;
712 break;
713 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100714 if (obj_inst->trx_nr >= bts->num_trx) {
715 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000716 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100717 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200718 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000719 obj = trx;
720 break;
721 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100722 if (obj_inst->trx_nr >= bts->num_trx) {
723 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000724 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100725 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200726 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000727 obj = &trx->bb_transc;
728 break;
729 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100730 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100731 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000732 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100733 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200734 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000735 if (obj_inst->ts_nr >= TRX_NR_TS)
736 return NULL;
737 obj = &trx->ts[obj_inst->ts_nr];
738 break;
739 case NM_OC_SITE_MANAGER:
740 obj = &bts->site_mgr;
741 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200742 case NM_OC_GPRS_NSE:
743 obj = &bts->gprs.nse;
744 break;
745 case NM_OC_GPRS_CELL:
746 obj = &bts->gprs.cell;
747 break;
748 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100749 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200750 return NULL;
751 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
752 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000753 }
754 return obj;
755}
756
757/* Update the administrative state of a given object in our in-memory data
758 * structures and send an event to the higher layer */
759static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
760 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
761{
Harald Welteaeedeb42009-05-01 13:08:14 +0000762 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000763 void *obj;
764 int rc;
765
Harald Weltee0590df2009-02-15 03:34:15 +0000766 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100767 if (!obj)
768 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000769 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
770 if (!nm_state)
771 return -1;
772
773 new_state = *nm_state;
774 new_state.administrative = adm_state;
775
776 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
777
778 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000779
780 return rc;
781}
782
Harald Welte97ed1e72009-02-06 13:38:02 +0000783static int abis_nm_rx_statechg_rep(struct msgb *mb)
784{
Harald Weltee0590df2009-02-15 03:34:15 +0000785 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000786 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000787 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000788 struct tlv_parsed tp;
789 struct gsm_nm_state *nm_state, new_state;
790 int rc;
791
Harald Welte23897662009-05-01 14:52:51 +0000792 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000793
Harald Welte8b697c72009-06-05 19:18:45 +0000794 memset(&new_state, 0, sizeof(new_state));
795
Harald Weltee0590df2009-02-15 03:34:15 +0000796 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
797 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100798 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000799 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000800 }
Harald Weltee0590df2009-02-15 03:34:15 +0000801
802 new_state = *nm_state;
803
Harald Welte03133942009-02-18 19:51:53 +0000804 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000805 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
806 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000807 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000808 }
809 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000810 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
811 new_state.availability = 0xff;
812 else
813 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000814 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000815 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100816 } else
817 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000818 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
819 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200820 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000821 }
822 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000823
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100824 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
825 new_state.operational != nm_state->operational ||
826 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000827 /* Update the operational state of a given object in our in-memory data
828 * structures and send an event to the higher layer */
829 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
830 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100831 nm_state->operational = new_state.operational;
832 nm_state->availability = new_state.availability;
833 if (nm_state->administrative == 0)
834 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000835 }
836#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000837 if (op_state == 1) {
838 /* try to enable objects that are disabled */
839 abis_nm_opstart(bts, foh->obj_class,
840 foh->obj_inst.bts_nr,
841 foh->obj_inst.trx_nr,
842 foh->obj_inst.ts_nr);
843 }
Harald Weltee0590df2009-02-15 03:34:15 +0000844#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000845 return 0;
846}
847
Harald Welte0db97b22009-05-01 17:22:47 +0000848static int rx_fail_evt_rep(struct msgb *mb)
849{
850 struct abis_om_hdr *oh = msgb_l2(mb);
851 struct abis_om_fom_hdr *foh = msgb_l3(mb);
852 struct tlv_parsed tp;
853
854 DEBUGPC(DNM, "Failure Event Report ");
855
856 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
857
858 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
859 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
860 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
861 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
862
863 DEBUGPC(DNM, "\n");
864
865 return 0;
866}
867
Harald Welte97ed1e72009-02-06 13:38:02 +0000868static int abis_nm_rcvmsg_report(struct msgb *mb)
869{
870 struct abis_om_fom_hdr *foh = msgb_l3(mb);
871 u_int8_t mt = foh->msg_type;
872
Harald Weltea8bd6d42009-10-20 09:56:18 +0200873 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000874
Harald Welte97ed1e72009-02-06 13:38:02 +0000875 //nmh->cfg->report_cb(mb, foh);
876
877 switch (mt) {
878 case NM_MT_STATECHG_EVENT_REP:
879 return abis_nm_rx_statechg_rep(mb);
880 break;
Harald Welte34a99682009-02-13 02:41:40 +0000881 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000882 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000883 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000884 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000885 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000886 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000887 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000888 break;
Harald Weltec7310382009-08-08 00:02:36 +0200889 case NM_MT_TEST_REP:
890 DEBUGPC(DNM, "Test Report\n");
891 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
892 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000893 default:
Harald Welte23897662009-05-01 14:52:51 +0000894 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000895 break;
896
Harald Welte97ed1e72009-02-06 13:38:02 +0000897 };
898
Harald Welte97ed1e72009-02-06 13:38:02 +0000899 return 0;
900}
901
Harald Welte34a99682009-02-13 02:41:40 +0000902/* Activate the specified software into the BTS */
903static 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 +0200904 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000905{
906 struct abis_om_hdr *oh;
907 struct msgb *msg = nm_msgb_alloc();
908 u_int8_t len = swdesc_len;
909 u_int8_t *trailer;
910
911 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
912 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
913
914 trailer = msgb_put(msg, swdesc_len);
915 memcpy(trailer, sw_desc, swdesc_len);
916
917 return abis_nm_sendmsg(bts, msg);
918}
919
920static int abis_nm_rx_sw_act_req(struct msgb *mb)
921{
922 struct abis_om_hdr *oh = msgb_l2(mb);
923 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200924 struct tlv_parsed tp;
925 const u_int8_t *sw_config;
926 int sw_config_len;
927 int file_id_len;
Harald Welte5c1e4582009-02-15 11:57:29 +0000928 int nack = 0;
Harald Welte34a99682009-02-13 02:41:40 +0000929 int ret;
930
Harald Weltea8bd6d42009-10-20 09:56:18 +0200931 debugp_foh(foh);
932
933 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000934
Harald Welte5c1e4582009-02-15 11:57:29 +0000935 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
936 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
937 nack = 1;
938 } else
939 DEBUGPC(DNM, "ACKing and Activating\n");
940
941 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000942 foh->obj_inst.bts_nr,
943 foh->obj_inst.trx_nr,
Harald Welte5c1e4582009-02-15 11:57:29 +0000944 foh->obj_inst.ts_nr, nack,
Harald Welte34a99682009-02-13 02:41:40 +0000945 foh->data, oh->length-sizeof(*foh));
946
Harald Welte5c1e4582009-02-15 11:57:29 +0000947 if (nack)
948 return ret;
949
Mike Habena03f9772009-10-01 14:56:13 +0200950 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
951 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
952 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
953 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
954 DEBUGP(DNM, "SW config not found! Can't continue.\n");
955 return -EINVAL;
956 } else {
957 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
958 }
959
960 if (sw_config[0] != NM_ATT_SW_DESCR)
961 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
962 if (sw_config[1] != NM_ATT_FILE_ID)
963 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
964 file_id_len = sw_config[2] * 256 + sw_config[3];
965
966 /* Assumes first SW file in list is the one to be activated */
967 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000968 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
969 foh->obj_inst.bts_nr,
970 foh->obj_inst.trx_nr,
971 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200972 sw_config + 4,
973 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000974}
975
Harald Weltee0590df2009-02-15 03:34:15 +0000976/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
977static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
978{
979 struct abis_om_hdr *oh = msgb_l2(mb);
980 struct abis_om_fom_hdr *foh = msgb_l3(mb);
981 struct tlv_parsed tp;
982 u_int8_t adm_state;
983
Harald Welte03133942009-02-18 19:51:53 +0000984 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000985 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
986 return -EINVAL;
987
988 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
989
990 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
991}
992
Harald Welteee670472009-02-22 21:58:49 +0000993static int abis_nm_rx_lmt_event(struct msgb *mb)
994{
995 struct abis_om_hdr *oh = msgb_l2(mb);
996 struct abis_om_fom_hdr *foh = msgb_l3(mb);
997 struct tlv_parsed tp;
998
999 DEBUGP(DNM, "LMT Event ");
1000 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1001 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
1002 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
1003 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
1004 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
1005 }
1006 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
1007 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
1008 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
1009 DEBUGPC(DNM, "Level=%u ", level);
1010 }
1011 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
1012 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
1013 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1014 DEBUGPC(DNM, "Username=%s ", name);
1015 }
1016 DEBUGPC(DNM, "\n");
1017 /* FIXME: parse LMT LOGON TIME */
1018 return 0;
1019}
1020
Harald Welte52b1f982008-12-23 20:25:15 +00001021/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001022static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001023{
Harald Welte6c96ba52009-05-01 13:03:40 +00001024 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001025 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1026 u_int8_t mt = foh->msg_type;
1027
1028 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001029 if (is_report(mt))
1030 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001031
Harald Welte4724f992009-01-18 18:01:49 +00001032 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1033 return abis_nm_rcvmsg_sw(mb);
1034
Harald Welte78fc0d42009-02-19 02:50:57 +00001035 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +00001036 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001037
Harald Weltea8bd6d42009-10-20 09:56:18 +02001038 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001039
Harald Welte78fc0d42009-02-19 02:50:57 +00001040 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +02001041 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +00001042 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +00001043 else
Harald Welte4bd0a982009-10-08 20:18:59 +02001044 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +00001045
1046 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1047 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1048 DEBUGPC(DNM, "CAUSE=%s\n",
1049 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1050 else
1051 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001052
Harald Welted8cfc902009-11-17 06:09:56 +01001053 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001054 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001055 }
Harald Weltead384642008-12-26 10:20:07 +00001056#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001057 /* check if last message is to be acked */
1058 if (is_ack_nack(nmh->last_msgtype)) {
1059 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001060 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001061 /* we got our ACK, continue sending the next msg */
1062 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1063 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001064 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001065 /* FIXME: somehow signal this to the caller */
1066 } else {
1067 /* really strange things happen */
1068 return -EINVAL;
1069 }
1070 }
Harald Weltead384642008-12-26 10:20:07 +00001071#endif
1072
Harald Welte97ed1e72009-02-06 13:38:02 +00001073 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001074 case NM_MT_CHG_ADM_STATE_ACK:
1075 return abis_nm_rx_chg_adm_state_ack(mb);
1076 break;
Harald Welte34a99682009-02-13 02:41:40 +00001077 case NM_MT_SW_ACT_REQ:
1078 return abis_nm_rx_sw_act_req(mb);
1079 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001080 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001081 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001082 break;
Harald Welte1989c082009-08-06 17:58:31 +02001083 case NM_MT_CONN_MDROP_LINK_ACK:
1084 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1085 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001086 case NM_MT_IPACC_RESTART_ACK:
1087 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1088 break;
1089 case NM_MT_IPACC_RESTART_NACK:
1090 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1091 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001092 }
1093
Harald Weltead384642008-12-26 10:20:07 +00001094 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001095}
1096
Harald Welte677c21f2009-02-17 13:22:23 +00001097static int abis_nm_rx_ipacc(struct msgb *mb);
1098
1099static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1100{
1101 int rc;
1102 int bts_type = mb->trx->bts->type;
1103
1104 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001105 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001106 rc = abis_nm_rx_ipacc(mb);
1107 break;
1108 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001109 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1110 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001111 rc = 0;
1112 break;
1113 }
1114
1115 return rc;
1116}
1117
Harald Welte52b1f982008-12-23 20:25:15 +00001118/* High-Level API */
1119/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001120int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001121{
Harald Welte52b1f982008-12-23 20:25:15 +00001122 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001123 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001124
1125 /* Various consistency checks */
1126 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001127 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001128 oh->placement);
1129 return -EINVAL;
1130 }
1131 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001132 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001133 oh->sequence);
1134 return -EINVAL;
1135 }
Harald Welte702d8702008-12-26 20:25:35 +00001136#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001137 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1138 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001139 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001140 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001141 oh->length + sizeof(*oh), l2_len);
1142 return -EINVAL;
1143 }
Harald Welte702d8702008-12-26 20:25:35 +00001144 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001145 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 +00001146#endif
Harald Weltead384642008-12-26 10:20:07 +00001147 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001148
1149 switch (oh->mdisc) {
1150 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001151 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001152 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001153 case ABIS_OM_MDISC_MANUF:
1154 rc = abis_nm_rcvmsg_manuf(msg);
1155 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001156 case ABIS_OM_MDISC_MMI:
1157 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001158 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001159 oh->mdisc);
1160 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001161 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001162 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001163 oh->mdisc);
1164 return -EINVAL;
1165 }
1166
Harald Weltead384642008-12-26 10:20:07 +00001167 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001168 return rc;
1169}
1170
1171#if 0
1172/* initialized all resources */
1173struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1174{
1175 struct abis_nm_h *nmh;
1176
1177 nmh = malloc(sizeof(*nmh));
1178 if (!nmh)
1179 return NULL;
1180
1181 nmh->cfg = cfg;
1182
1183 return nmh;
1184}
1185
1186/* free all resources */
1187void abis_nm_fini(struct abis_nm_h *nmh)
1188{
1189 free(nmh);
1190}
1191#endif
1192
1193/* Here we are trying to define a high-level API that can be used by
1194 * the actual BSC implementation. However, the architecture is currently
1195 * still under design. Ideally the calls to this API would be synchronous,
1196 * while the underlying stack behind the APi runs in a traditional select
1197 * based state machine.
1198 */
1199
Harald Welte4724f992009-01-18 18:01:49 +00001200/* 6.2 Software Load: */
1201enum sw_state {
1202 SW_STATE_NONE,
1203 SW_STATE_WAIT_INITACK,
1204 SW_STATE_WAIT_SEGACK,
1205 SW_STATE_WAIT_ENDACK,
1206 SW_STATE_WAIT_ACTACK,
1207 SW_STATE_ERROR,
1208};
Harald Welte52b1f982008-12-23 20:25:15 +00001209
Harald Welte52b1f982008-12-23 20:25:15 +00001210struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001211 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001212 gsm_cbfn *cbfn;
1213 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001214 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001215
Harald Welte52b1f982008-12-23 20:25:15 +00001216 /* this will become part of the SW LOAD INITIATE */
1217 u_int8_t obj_class;
1218 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001219
1220 u_int8_t file_id[255];
1221 u_int8_t file_id_len;
1222
1223 u_int8_t file_version[255];
1224 u_int8_t file_version_len;
1225
1226 u_int8_t window_size;
1227 u_int8_t seg_in_window;
1228
1229 int fd;
1230 FILE *stream;
1231 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001232 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001233};
1234
Harald Welte4724f992009-01-18 18:01:49 +00001235static struct abis_nm_sw g_sw;
1236
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001237static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1238{
1239 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1240 msgb_v_put(msg, NM_ATT_SW_DESCR);
1241 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1242 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1243 sw->file_version);
1244 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1245 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1246 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1247 sw->file_version);
1248 } else {
1249 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1250 }
1251}
1252
Harald Welte4724f992009-01-18 18:01:49 +00001253/* 6.2.1 / 8.3.1: Load Data Initiate */
1254static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001255{
Harald Welte4724f992009-01-18 18:01:49 +00001256 struct abis_om_hdr *oh;
1257 struct msgb *msg = nm_msgb_alloc();
1258 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1259
1260 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1261 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1262 sw->obj_instance[0], sw->obj_instance[1],
1263 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001264
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001265 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001266 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1267
1268 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001269}
1270
Harald Welte1602ade2009-01-29 21:12:39 +00001271static int is_last_line(FILE *stream)
1272{
1273 char next_seg_buf[256];
1274 long pos;
1275
1276 /* check if we're sending the last line */
1277 pos = ftell(stream);
1278 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1279 fseek(stream, pos, SEEK_SET);
1280 return 1;
1281 }
1282
1283 fseek(stream, pos, SEEK_SET);
1284 return 0;
1285}
1286
Harald Welte4724f992009-01-18 18:01:49 +00001287/* 6.2.2 / 8.3.2 Load Data Segment */
1288static int sw_load_segment(struct abis_nm_sw *sw)
1289{
1290 struct abis_om_hdr *oh;
1291 struct msgb *msg = nm_msgb_alloc();
1292 char seg_buf[256];
1293 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001294 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001295 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001296
1297 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001298
1299 switch (sw->bts->type) {
1300 case GSM_BTS_TYPE_BS11:
1301 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1302 perror("fgets reading segment");
1303 return -EINVAL;
1304 }
1305 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001306
1307 /* check if we're sending the last line */
1308 sw->last_seg = is_last_line(sw->stream);
1309 if (sw->last_seg)
1310 seg_buf[1] = 0;
1311 else
1312 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001313
1314 len = strlen(line_buf) + 2;
1315 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1316 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1317 /* BS11 wants CR + LF in excess of the TLV length !?! */
1318 tlv[1] -= 2;
1319
1320 /* we only now know the exact length for the OM hdr */
1321 len = strlen(line_buf)+2;
1322 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001323 case GSM_BTS_TYPE_NANOBTS: {
1324 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1325 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1326 if (len < 0) {
1327 perror("read failed");
1328 return -EINVAL;
1329 }
1330
1331 if (len != IPACC_SEGMENT_SIZE)
1332 sw->last_seg = 1;
1333
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001334 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001335 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1336 len += 3;
1337 break;
1338 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001339 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001340 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001341 /* FIXME: Other BTS types */
1342 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001343 }
Harald Welte4724f992009-01-18 18:01:49 +00001344
Harald Welte4724f992009-01-18 18:01:49 +00001345 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1346 sw->obj_instance[0], sw->obj_instance[1],
1347 sw->obj_instance[2]);
1348
1349 return abis_nm_sendmsg(sw->bts, msg);
1350}
1351
1352/* 6.2.4 / 8.3.4 Load Data End */
1353static int sw_load_end(struct abis_nm_sw *sw)
1354{
1355 struct abis_om_hdr *oh;
1356 struct msgb *msg = nm_msgb_alloc();
1357 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1358
1359 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1360 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1361 sw->obj_instance[0], sw->obj_instance[1],
1362 sw->obj_instance[2]);
1363
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001364 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001365 return abis_nm_sendmsg(sw->bts, msg);
1366}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001367
Harald Welte52b1f982008-12-23 20:25:15 +00001368/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001369static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001370{
Harald Welte4724f992009-01-18 18:01:49 +00001371 struct abis_om_hdr *oh;
1372 struct msgb *msg = nm_msgb_alloc();
1373 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001374
Harald Welte4724f992009-01-18 18:01:49 +00001375 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1376 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1377 sw->obj_instance[0], sw->obj_instance[1],
1378 sw->obj_instance[2]);
1379
1380 /* FIXME: this is BS11 specific format */
1381 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1382 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1383 sw->file_version);
1384
1385 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001386}
Harald Welte4724f992009-01-18 18:01:49 +00001387
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001388struct sdp_firmware {
1389 char magic[4];
1390 char more_magic[4];
1391 unsigned int header_length;
1392 unsigned int file_length;
1393} __attribute__ ((packed));
1394
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001395static int parse_sdp_header(struct abis_nm_sw *sw)
1396{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001397 struct sdp_firmware firmware_header;
1398 int rc;
1399 struct stat stat;
1400
1401 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1402 if (rc != sizeof(firmware_header)) {
1403 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1404 return -1;
1405 }
1406
1407 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1408 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1409 return -1;
1410 }
1411
1412 if (firmware_header.more_magic[0] != 0x10 ||
1413 firmware_header.more_magic[1] != 0x02 ||
1414 firmware_header.more_magic[2] != 0x00 ||
1415 firmware_header.more_magic[3] != 0x00) {
1416 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1417 return -1;
1418 }
1419
1420
1421 if (fstat(sw->fd, &stat) == -1) {
1422 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1423 return -1;
1424 }
1425
1426 if (ntohl(firmware_header.file_length) != stat.st_size) {
1427 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1428 return -1;
1429 }
1430
1431 /* go back to the start as we checked the whole filesize.. */
1432 lseek(sw->fd, 0l, SEEK_SET);
1433 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1434 "There might be checksums in the file that are not\n"
1435 "verified and incomplete firmware might be flashed.\n"
1436 "There is absolutely no WARRANTY that flashing will\n"
1437 "work.\n");
1438 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001439}
1440
Harald Welte4724f992009-01-18 18:01:49 +00001441static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1442{
1443 char file_id[12+1];
1444 char file_version[80+1];
1445 int rc;
1446
1447 sw->fd = open(fname, O_RDONLY);
1448 if (sw->fd < 0)
1449 return sw->fd;
1450
1451 switch (sw->bts->type) {
1452 case GSM_BTS_TYPE_BS11:
1453 sw->stream = fdopen(sw->fd, "r");
1454 if (!sw->stream) {
1455 perror("fdopen");
1456 return -1;
1457 }
1458 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001459 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001460 file_id, file_version);
1461 if (rc != 2) {
1462 perror("parsing header line of software file");
1463 return -1;
1464 }
1465 strcpy((char *)sw->file_id, file_id);
1466 sw->file_id_len = strlen(file_id);
1467 strcpy((char *)sw->file_version, file_version);
1468 sw->file_version_len = strlen(file_version);
1469 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001470 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001471 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001472 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001473 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001474 rc = parse_sdp_header(sw);
1475 if (rc < 0) {
1476 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1477 return -1;
1478 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001479
1480 strcpy((char *)sw->file_id, "id");
1481 sw->file_id_len = 3;
1482 strcpy((char *)sw->file_version, "version");
1483 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001484 break;
Harald Welte4724f992009-01-18 18:01:49 +00001485 default:
1486 /* We don't know how to treat them yet */
1487 close(sw->fd);
1488 return -EINVAL;
1489 }
1490
1491 return 0;
1492}
1493
1494static void sw_close_file(struct abis_nm_sw *sw)
1495{
1496 switch (sw->bts->type) {
1497 case GSM_BTS_TYPE_BS11:
1498 fclose(sw->stream);
1499 break;
1500 default:
1501 close(sw->fd);
1502 break;
1503 }
1504}
1505
1506/* Fill the window */
1507static int sw_fill_window(struct abis_nm_sw *sw)
1508{
1509 int rc;
1510
1511 while (sw->seg_in_window < sw->window_size) {
1512 rc = sw_load_segment(sw);
1513 if (rc < 0)
1514 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001515 if (sw->last_seg)
1516 break;
Harald Welte4724f992009-01-18 18:01:49 +00001517 }
1518 return 0;
1519}
1520
1521/* callback function from abis_nm_rcvmsg() handler */
1522static int abis_nm_rcvmsg_sw(struct msgb *mb)
1523{
1524 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1525 int rc = -1;
1526 struct abis_nm_sw *sw = &g_sw;
1527 enum sw_state old_state = sw->state;
1528
Harald Welte3ffd1372009-02-01 22:15:49 +00001529 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001530
1531 switch (sw->state) {
1532 case SW_STATE_WAIT_INITACK:
1533 switch (foh->msg_type) {
1534 case NM_MT_LOAD_INIT_ACK:
1535 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001536 if (sw->cbfn)
1537 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1538 NM_MT_LOAD_INIT_ACK, mb,
1539 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001540 rc = sw_fill_window(sw);
1541 sw->state = SW_STATE_WAIT_SEGACK;
1542 break;
1543 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001544 if (sw->forced) {
1545 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1546 "Init NACK\n");
1547 if (sw->cbfn)
1548 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1549 NM_MT_LOAD_INIT_ACK, mb,
1550 sw->cb_data, NULL);
1551 rc = sw_fill_window(sw);
1552 sw->state = SW_STATE_WAIT_SEGACK;
1553 } else {
1554 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001555 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001556 if (sw->cbfn)
1557 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1558 NM_MT_LOAD_INIT_NACK, mb,
1559 sw->cb_data, NULL);
1560 sw->state = SW_STATE_ERROR;
1561 }
Harald Welte4724f992009-01-18 18:01:49 +00001562 break;
1563 }
1564 break;
1565 case SW_STATE_WAIT_SEGACK:
1566 switch (foh->msg_type) {
1567 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001568 if (sw->cbfn)
1569 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1570 NM_MT_LOAD_SEG_ACK, mb,
1571 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001572 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001573 if (!sw->last_seg) {
1574 /* fill window with more segments */
1575 rc = sw_fill_window(sw);
1576 sw->state = SW_STATE_WAIT_SEGACK;
1577 } else {
1578 /* end the transfer */
1579 sw->state = SW_STATE_WAIT_ENDACK;
1580 rc = sw_load_end(sw);
1581 }
Harald Welte4724f992009-01-18 18:01:49 +00001582 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001583 case NM_MT_LOAD_ABORT:
1584 if (sw->cbfn)
1585 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1586 NM_MT_LOAD_ABORT, mb,
1587 sw->cb_data, NULL);
1588 break;
Harald Welte4724f992009-01-18 18:01:49 +00001589 }
1590 break;
1591 case SW_STATE_WAIT_ENDACK:
1592 switch (foh->msg_type) {
1593 case NM_MT_LOAD_END_ACK:
1594 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001595 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1596 sw->bts->nr);
1597 sw->state = SW_STATE_NONE;
1598 if (sw->cbfn)
1599 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1600 NM_MT_LOAD_END_ACK, mb,
1601 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001602 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001603 break;
1604 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001605 if (sw->forced) {
1606 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1607 "End NACK\n");
1608 sw->state = SW_STATE_NONE;
1609 if (sw->cbfn)
1610 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1611 NM_MT_LOAD_END_ACK, mb,
1612 sw->cb_data, NULL);
1613 } else {
1614 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001615 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001616 sw->state = SW_STATE_ERROR;
1617 if (sw->cbfn)
1618 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1619 NM_MT_LOAD_END_NACK, mb,
1620 sw->cb_data, NULL);
1621 }
Harald Welte4724f992009-01-18 18:01:49 +00001622 break;
1623 }
1624 case SW_STATE_WAIT_ACTACK:
1625 switch (foh->msg_type) {
1626 case NM_MT_ACTIVATE_SW_ACK:
1627 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001628 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001629 sw->state = SW_STATE_NONE;
1630 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001631 if (sw->cbfn)
1632 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1633 NM_MT_ACTIVATE_SW_ACK, mb,
1634 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001635 break;
1636 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001637 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001638 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001639 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001640 if (sw->cbfn)
1641 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1642 NM_MT_ACTIVATE_SW_NACK, mb,
1643 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001644 break;
1645 }
1646 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001647 switch (foh->msg_type) {
1648 case NM_MT_ACTIVATE_SW_ACK:
1649 rc = 0;
1650 break;
1651 }
1652 break;
Harald Welte4724f992009-01-18 18:01:49 +00001653 case SW_STATE_ERROR:
1654 break;
1655 }
1656
1657 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001658 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001659 foh->msg_type, old_state, sw->state);
1660
1661 return rc;
1662}
1663
1664/* Load the specified software into the BTS */
1665int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001666 u_int8_t win_size, int forced,
1667 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001668{
1669 struct abis_nm_sw *sw = &g_sw;
1670 int rc;
1671
Harald Welte5e4d1b32009-02-01 13:36:56 +00001672 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1673 bts->nr, fname);
1674
Harald Welte4724f992009-01-18 18:01:49 +00001675 if (sw->state != SW_STATE_NONE)
1676 return -EBUSY;
1677
1678 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001679
1680 switch (bts->type) {
1681 case GSM_BTS_TYPE_BS11:
1682 sw->obj_class = NM_OC_SITE_MANAGER;
1683 sw->obj_instance[0] = 0xff;
1684 sw->obj_instance[1] = 0xff;
1685 sw->obj_instance[2] = 0xff;
1686 break;
1687 case GSM_BTS_TYPE_NANOBTS:
1688 sw->obj_class = NM_OC_BASEB_TRANSC;
1689 sw->obj_instance[0] = 0x00;
1690 sw->obj_instance[1] = 0x00;
1691 sw->obj_instance[2] = 0xff;
1692 break;
1693 case GSM_BTS_TYPE_UNKNOWN:
1694 default:
1695 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1696 return -1;
1697 break;
1698 }
Harald Welte4724f992009-01-18 18:01:49 +00001699 sw->window_size = win_size;
1700 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001701 sw->cbfn = cbfn;
1702 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001703 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001704
1705 rc = sw_open_file(sw, fname);
1706 if (rc < 0) {
1707 sw->state = SW_STATE_NONE;
1708 return rc;
1709 }
1710
1711 return sw_load_init(sw);
1712}
Harald Welte52b1f982008-12-23 20:25:15 +00001713
Harald Welte1602ade2009-01-29 21:12:39 +00001714int abis_nm_software_load_status(struct gsm_bts *bts)
1715{
1716 struct abis_nm_sw *sw = &g_sw;
1717 struct stat st;
1718 int rc, percent;
1719
1720 rc = fstat(sw->fd, &st);
1721 if (rc < 0) {
1722 perror("ERROR during stat");
1723 return rc;
1724 }
1725
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001726 if (sw->stream)
1727 percent = (ftell(sw->stream) * 100) / st.st_size;
1728 else
1729 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001730 return percent;
1731}
1732
Harald Welte5e4d1b32009-02-01 13:36:56 +00001733/* Activate the specified software into the BTS */
1734int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1735 gsm_cbfn *cbfn, void *cb_data)
1736{
1737 struct abis_nm_sw *sw = &g_sw;
1738 int rc;
1739
1740 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1741 bts->nr, fname);
1742
1743 if (sw->state != SW_STATE_NONE)
1744 return -EBUSY;
1745
1746 sw->bts = bts;
1747 sw->obj_class = NM_OC_SITE_MANAGER;
1748 sw->obj_instance[0] = 0xff;
1749 sw->obj_instance[1] = 0xff;
1750 sw->obj_instance[2] = 0xff;
1751 sw->state = SW_STATE_WAIT_ACTACK;
1752 sw->cbfn = cbfn;
1753 sw->cb_data = cb_data;
1754
1755 /* Open the file in order to fill some sw struct members */
1756 rc = sw_open_file(sw, fname);
1757 if (rc < 0) {
1758 sw->state = SW_STATE_NONE;
1759 return rc;
1760 }
1761 sw_close_file(sw);
1762
1763 return sw_activate(sw);
1764}
1765
Harald Welte8470bf22008-12-25 23:28:35 +00001766static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001767 u_int8_t ts_nr, u_int8_t subslot_nr)
1768{
Harald Welteadaf08b2009-01-18 11:08:10 +00001769 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001770 ch->bts_port = bts_port;
1771 ch->timeslot = ts_nr;
1772 ch->subslot = subslot_nr;
1773}
1774
1775int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1776 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1777 u_int8_t tei)
1778{
1779 struct abis_om_hdr *oh;
1780 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001781 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001782 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001783
1784 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1785 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1786 bts->bts_nr, trx_nr, 0xff);
1787
Harald Welte8470bf22008-12-25 23:28:35 +00001788 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001789
1790 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1791 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1792
1793 return abis_nm_sendmsg(bts, msg);
1794}
1795
1796/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1797int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1798 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1799{
Harald Welte8470bf22008-12-25 23:28:35 +00001800 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001801 struct abis_om_hdr *oh;
1802 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001803 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001804
1805 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001806 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001807 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1808
1809 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1810 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1811
1812 return abis_nm_sendmsg(bts, msg);
1813}
1814
1815#if 0
1816int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1817 struct abis_nm_abis_channel *chan)
1818{
1819}
1820#endif
1821
1822int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1823 u_int8_t e1_port, u_int8_t e1_timeslot,
1824 u_int8_t e1_subslot)
1825{
1826 struct gsm_bts *bts = ts->trx->bts;
1827 struct abis_om_hdr *oh;
1828 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001829 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001830
1831 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1832 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001833 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001834
1835 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1836 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1837
Harald Weltef325eb42009-02-19 17:07:39 +00001838 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1839 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001840 e1_port, e1_timeslot, e1_subslot);
1841
Harald Welte52b1f982008-12-23 20:25:15 +00001842 return abis_nm_sendmsg(bts, msg);
1843}
1844
1845#if 0
1846int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1847 struct abis_nm_abis_channel *chan,
1848 u_int8_t subchan)
1849{
1850}
1851#endif
1852
Harald Welte22af0db2009-02-14 15:41:08 +00001853/* Chapter 8.6.1 */
1854int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1855{
1856 struct abis_om_hdr *oh;
1857 struct msgb *msg = nm_msgb_alloc();
1858 u_int8_t *cur;
1859
1860 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1861
1862 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001863 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 +00001864 cur = msgb_put(msg, attr_len);
1865 memcpy(cur, attr, attr_len);
1866
1867 return abis_nm_sendmsg(bts, msg);
1868}
1869
1870/* Chapter 8.6.2 */
1871int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1872{
1873 struct abis_om_hdr *oh;
1874 struct msgb *msg = nm_msgb_alloc();
1875 u_int8_t *cur;
1876
1877 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1878
1879 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1880 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001881 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001882 cur = msgb_put(msg, attr_len);
1883 memcpy(cur, attr, attr_len);
1884
1885 return abis_nm_sendmsg(trx->bts, msg);
1886}
1887
Harald Welte39c7deb2009-08-09 21:49:48 +02001888static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1889{
1890 int i;
1891
1892 /* As it turns out, the BS-11 has some very peculiar restrictions
1893 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301894 switch (ts->trx->bts->type) {
1895 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001896 switch (chan_comb) {
1897 case NM_CHANC_TCHHalf:
1898 case NM_CHANC_TCHHalf2:
1899 /* not supported */
1900 return -EINVAL;
1901 case NM_CHANC_SDCCH:
1902 /* only one SDCCH/8 per TRX */
1903 for (i = 0; i < TRX_NR_TS; i++) {
1904 if (i == ts->nr)
1905 continue;
1906 if (ts->trx->ts[i].nm_chan_comb ==
1907 NM_CHANC_SDCCH)
1908 return -EINVAL;
1909 }
1910 /* not allowed for TS0 of BCCH-TRX */
1911 if (ts->trx == ts->trx->bts->c0 &&
1912 ts->nr == 0)
1913 return -EINVAL;
1914 /* not on the same TRX that has a BCCH+SDCCH4
1915 * combination */
1916 if (ts->trx == ts->trx->bts->c0 &&
1917 (ts->trx->ts[0].nm_chan_comb == 5 ||
1918 ts->trx->ts[0].nm_chan_comb == 8))
1919 return -EINVAL;
1920 break;
1921 case NM_CHANC_mainBCCH:
1922 case NM_CHANC_BCCHComb:
1923 /* allowed only for TS0 of C0 */
1924 if (ts->trx != ts->trx->bts->c0 ||
1925 ts->nr != 0)
1926 return -EINVAL;
1927 break;
1928 case NM_CHANC_BCCH:
1929 /* allowed only for TS 2/4/6 of C0 */
1930 if (ts->trx != ts->trx->bts->c0)
1931 return -EINVAL;
1932 if (ts->nr != 2 && ts->nr != 4 &&
1933 ts->nr != 6)
1934 return -EINVAL;
1935 break;
1936 case 8: /* this is not like 08.58, but in fact
1937 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1938 /* FIXME: only one CBCH allowed per cell */
1939 break;
1940 }
Harald Welted6575f92009-12-02 02:45:23 +05301941 break;
1942 case GSM_BTS_TYPE_NANOBTS:
1943 switch (ts->nr) {
1944 case 0:
1945 if (ts->trx->nr == 0) {
1946 /* only on TRX0 */
1947 switch (chan_comb) {
1948 case NM_CHANC_BCCH:
1949 case NM_CHANC_mainBCCH:
1950 case NM_CHANC_BCCHComb:
1951 return 0;
1952 break;
1953 default:
1954 return -EINVAL;
1955 }
1956 } else {
1957 switch (chan_comb) {
1958 case NM_CHANC_TCHFull:
1959 case NM_CHANC_TCHHalf:
1960 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1961 return 0;
1962 default:
1963 return -EINVAL;
1964 }
1965 }
1966 break;
1967 case 1:
1968 if (ts->trx->nr == 0) {
1969 switch (chan_comb) {
1970 case NM_CHANC_SDCCH_CBCH:
1971 if (ts->trx->ts[0].nm_chan_comb ==
1972 NM_CHANC_mainBCCH)
1973 return 0;
1974 return -EINVAL;
1975 case NM_CHANC_SDCCH:
1976 case NM_CHANC_TCHFull:
1977 case NM_CHANC_TCHHalf:
1978 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1979 case NM_CHANC_IPAC_TCHFull_PDCH:
1980 return 0;
1981 }
1982 } else {
1983 switch (chan_comb) {
1984 case NM_CHANC_SDCCH:
1985 case NM_CHANC_TCHFull:
1986 case NM_CHANC_TCHHalf:
1987 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1988 return 0;
1989 default:
1990 return -EINVAL;
1991 }
1992 }
1993 break;
1994 case 2:
1995 case 3:
1996 case 4:
1997 case 5:
1998 case 6:
1999 case 7:
2000 switch (chan_comb) {
2001 case NM_CHANC_TCHFull:
2002 case NM_CHANC_TCHHalf:
2003 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2004 return 0;
2005 case NM_CHANC_IPAC_PDCH:
2006 case NM_CHANC_IPAC_TCHFull_PDCH:
2007 if (ts->trx->nr == 0)
2008 return 0;
2009 else
2010 return -EINVAL;
2011 }
2012 break;
2013 }
2014 return -EINVAL;
2015 default:
2016 /* unknown BTS type */
2017 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002018 }
2019 return 0;
2020}
2021
Harald Welte22af0db2009-02-14 15:41:08 +00002022/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002023int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2024{
2025 struct gsm_bts *bts = ts->trx->bts;
2026 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002027 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002028 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002029 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002030 u_int8_t len = 2 + 2;
2031
2032 if (bts->type == GSM_BTS_TYPE_BS11)
2033 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002034
Harald Weltef325eb42009-02-19 17:07:39 +00002035 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002036 if (verify_chan_comb(ts, chan_comb) < 0) {
2037 msgb_free(msg);
2038 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2039 return -EINVAL;
2040 }
2041 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002042
Harald Welte52b1f982008-12-23 20:25:15 +00002043 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002044 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002045 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002046 ts->trx->nr, ts->nr);
2047 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00002048 if (bts->type == GSM_BTS_TYPE_BS11)
2049 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002050 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00002051 if (bts->type == GSM_BTS_TYPE_BS11) {
2052 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2053 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2054 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002055 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002056 if (bts->type == GSM_BTS_TYPE_BS11)
2057 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002058
2059 return abis_nm_sendmsg(bts, msg);
2060}
2061
Harald Welte34a99682009-02-13 02:41:40 +00002062int 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 +00002063 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002064{
2065 struct abis_om_hdr *oh;
2066 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002067 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2068 u_int8_t len = att_len;
2069
2070 if (nack) {
2071 len += 2;
2072 msgtype = NM_MT_SW_ACT_REQ_NACK;
2073 }
Harald Welte34a99682009-02-13 02:41:40 +00002074
2075 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002076 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2077
Harald Welte34a99682009-02-13 02:41:40 +00002078 if (attr) {
2079 u_int8_t *ptr = msgb_put(msg, att_len);
2080 memcpy(ptr, attr, att_len);
2081 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002082 if (nack)
2083 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002084
2085 return abis_nm_sendmsg(bts, msg);
2086}
2087
Harald Welte8470bf22008-12-25 23:28:35 +00002088int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002089{
Harald Welte8470bf22008-12-25 23:28:35 +00002090 struct msgb *msg = nm_msgb_alloc();
2091 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002092 u_int8_t *data;
2093
2094 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2095 fill_om_hdr(oh, len);
2096 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002097 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002098
2099 return abis_nm_sendmsg(bts, msg);
2100}
2101
2102/* Siemens specific commands */
2103static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2104{
2105 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002106 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002107
2108 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002109 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002110 0xff, 0xff, 0xff);
2111
2112 return abis_nm_sendmsg(bts, msg);
2113}
2114
Harald Welte34a99682009-02-13 02:41:40 +00002115/* Chapter 8.9.2 */
2116int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2117{
2118 struct abis_om_hdr *oh;
2119 struct msgb *msg = nm_msgb_alloc();
2120
2121 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2122 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2123
Harald Weltea8bd6d42009-10-20 09:56:18 +02002124 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2125 DEBUGPC(DNM, "Sending OPSTART\n");
2126
Harald Welte34a99682009-02-13 02:41:40 +00002127 return abis_nm_sendmsg(bts, msg);
2128}
2129
2130/* Chapter 8.8.5 */
2131int 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 +02002132 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002133{
2134 struct abis_om_hdr *oh;
2135 struct msgb *msg = nm_msgb_alloc();
2136
2137 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2138 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2139 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2140
2141 return abis_nm_sendmsg(bts, msg);
2142}
2143
Harald Welte1989c082009-08-06 17:58:31 +02002144int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2145 u_int8_t e1_port1, u_int8_t ts1)
2146{
2147 struct abis_om_hdr *oh;
2148 struct msgb *msg = nm_msgb_alloc();
2149 u_int8_t *attr;
2150
2151 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2152 e1_port0, ts0, e1_port1, ts1);
2153
2154 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2155 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2156 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2157
2158 attr = msgb_put(msg, 3);
2159 attr[0] = NM_ATT_MDROP_LINK;
2160 attr[1] = e1_port0;
2161 attr[2] = ts0;
2162
2163 attr = msgb_put(msg, 3);
2164 attr[0] = NM_ATT_MDROP_NEXT;
2165 attr[1] = e1_port1;
2166 attr[2] = ts1;
2167
2168 return abis_nm_sendmsg(bts, msg);
2169}
Harald Welte34a99682009-02-13 02:41:40 +00002170
Harald Weltec7310382009-08-08 00:02:36 +02002171/* Chapter 8.7.1 */
2172int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2173 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2174 u_int8_t test_nr, u_int8_t auton_report,
2175 u_int8_t *phys_config, u_int16_t phys_config_len)
2176{
2177 struct abis_om_hdr *oh;
2178 struct msgb *msg = nm_msgb_alloc();
2179 int len = 4; /* 2 TV attributes */
2180
2181 DEBUGP(DNM, "PEFORM TEST\n");
2182
2183 if (phys_config_len)
2184 len += 3 + phys_config_len;
2185
2186 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2187 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2188 obj_class, bts_nr, trx_nr, ts_nr);
2189 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2190 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2191 if (phys_config_len)
2192 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2193 phys_config);
2194
2195 return abis_nm_sendmsg(bts, msg);
2196}
2197
Harald Welte52b1f982008-12-23 20:25:15 +00002198int abis_nm_event_reports(struct gsm_bts *bts, int on)
2199{
2200 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002201 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002202 else
Harald Welte227d4072009-01-03 08:16:25 +00002203 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002204}
2205
Harald Welte47d88ae2009-01-04 12:02:08 +00002206/* Siemens (or BS-11) specific commands */
2207
Harald Welte3ffd1372009-02-01 22:15:49 +00002208int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2209{
2210 if (reconnect == 0)
2211 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2212 else
2213 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2214}
2215
Harald Welteb8427972009-02-05 19:27:17 +00002216int abis_nm_bs11_restart(struct gsm_bts *bts)
2217{
2218 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2219}
2220
2221
Harald Welte268bb402009-02-01 19:11:56 +00002222struct bs11_date_time {
2223 u_int16_t year;
2224 u_int8_t month;
2225 u_int8_t day;
2226 u_int8_t hour;
2227 u_int8_t min;
2228 u_int8_t sec;
2229} __attribute__((packed));
2230
2231
2232void get_bs11_date_time(struct bs11_date_time *aet)
2233{
2234 time_t t;
2235 struct tm *tm;
2236
2237 t = time(NULL);
2238 tm = localtime(&t);
2239 aet->sec = tm->tm_sec;
2240 aet->min = tm->tm_min;
2241 aet->hour = tm->tm_hour;
2242 aet->day = tm->tm_mday;
2243 aet->month = tm->tm_mon;
2244 aet->year = htons(1900 + tm->tm_year);
2245}
2246
Harald Welte05188ee2009-01-18 11:39:08 +00002247int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002248{
Harald Welte4668fda2009-01-03 08:19:29 +00002249 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002250}
2251
Harald Welte05188ee2009-01-18 11:39:08 +00002252int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002253{
2254 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002255 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002256 else
Harald Welte4668fda2009-01-03 08:19:29 +00002257 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002258}
Harald Welte47d88ae2009-01-04 12:02:08 +00002259
Harald Welte05188ee2009-01-18 11:39:08 +00002260int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002261 enum abis_bs11_objtype type, u_int8_t idx,
2262 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002263{
2264 struct abis_om_hdr *oh;
2265 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002266 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002267
2268 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002269 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002270 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002271 cur = msgb_put(msg, attr_len);
2272 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002273
2274 return abis_nm_sendmsg(bts, msg);
2275}
2276
Harald Welte78fc0d42009-02-19 02:50:57 +00002277int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2278 enum abis_bs11_objtype type, u_int8_t idx)
2279{
2280 struct abis_om_hdr *oh;
2281 struct msgb *msg = nm_msgb_alloc();
2282
2283 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2284 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2285 NM_OC_BS11, type, 0, idx);
2286
2287 return abis_nm_sendmsg(bts, msg);
2288}
2289
Harald Welte05188ee2009-01-18 11:39:08 +00002290int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002291{
2292 struct abis_om_hdr *oh;
2293 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002294 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002295
2296 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002297 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002298 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2299 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002300
2301 return abis_nm_sendmsg(bts, msg);
2302}
2303
Harald Welte05188ee2009-01-18 11:39:08 +00002304int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002305{
2306 struct abis_om_hdr *oh;
2307 struct msgb *msg = nm_msgb_alloc();
2308
2309 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2310 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002311 idx, 0xff, 0xff);
2312
2313 return abis_nm_sendmsg(bts, msg);
2314}
2315
2316int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2317{
2318 struct abis_om_hdr *oh;
2319 struct msgb *msg = nm_msgb_alloc();
2320
2321 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2322 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2323 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002324
2325 return abis_nm_sendmsg(bts, msg);
2326}
Harald Welte05188ee2009-01-18 11:39:08 +00002327
Harald Welte78fc0d42009-02-19 02:50:57 +00002328static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2329int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2330{
2331 struct abis_om_hdr *oh;
2332 struct msgb *msg = nm_msgb_alloc();
2333
2334 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2335 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2336 0xff, 0xff, 0xff);
2337 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2338
2339 return abis_nm_sendmsg(bts, msg);
2340}
2341
Harald Welteb6c92ae2009-02-21 20:15:32 +00002342/* like abis_nm_conn_terr_traf + set_tei */
2343int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2344 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2345 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002346{
2347 struct abis_om_hdr *oh;
2348 struct abis_nm_channel *ch;
2349 struct msgb *msg = nm_msgb_alloc();
2350
2351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002352 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002353 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2354
2355 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2356 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002357 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002358
2359 return abis_nm_sendmsg(bts, msg);
2360}
2361
2362int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2363{
2364 struct abis_om_hdr *oh;
2365 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002366
2367 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002368 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002369 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2370 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2371
2372 return abis_nm_sendmsg(trx->bts, msg);
2373}
2374
Harald Welte78fc0d42009-02-19 02:50:57 +00002375int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2376{
2377 struct abis_om_hdr *oh;
2378 struct msgb *msg = nm_msgb_alloc();
2379 u_int8_t attr = NM_ATT_BS11_TXPWR;
2380
2381 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2382 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2383 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2384 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2385
2386 return abis_nm_sendmsg(trx->bts, msg);
2387}
2388
Harald Welteaaf02d92009-04-29 13:25:57 +00002389int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2390{
2391 struct abis_om_hdr *oh;
2392 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002393 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002394
2395 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2396 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2397 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002398 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002399
2400 return abis_nm_sendmsg(bts, msg);
2401}
2402
Harald Welteef061952009-05-17 12:43:42 +00002403int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2404{
2405 struct abis_om_hdr *oh;
2406 struct msgb *msg = nm_msgb_alloc();
2407 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2408 NM_ATT_BS11_CCLK_TYPE };
2409
2410 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2411 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2412 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2413 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2414
2415 return abis_nm_sendmsg(bts, msg);
2416
2417}
Harald Welteaaf02d92009-04-29 13:25:57 +00002418
Harald Welte268bb402009-02-01 19:11:56 +00002419//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002420
Harald Welte1bc09062009-01-18 14:17:52 +00002421int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002422{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002423 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2424}
2425
Daniel Willmann4b054c82010-01-07 00:46:26 +01002426int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2427{
2428 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2429}
2430
Daniel Willmann493db4e2010-01-07 00:43:11 +01002431int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2432{
Harald Welte05188ee2009-01-18 11:39:08 +00002433 struct abis_om_hdr *oh;
2434 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002435 struct bs11_date_time bdt;
2436
2437 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002438
2439 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002440 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002441 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002442 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002443 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002444 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002445 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002446 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002447 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002448 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002449 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002450 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002451 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002452 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002453 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002454 }
Harald Welte05188ee2009-01-18 11:39:08 +00002455
2456 return abis_nm_sendmsg(bts, msg);
2457}
Harald Welte1bc09062009-01-18 14:17:52 +00002458
2459int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2460{
2461 struct abis_om_hdr *oh;
2462 struct msgb *msg;
2463
2464 if (strlen(password) != 10)
2465 return -EINVAL;
2466
2467 msg = nm_msgb_alloc();
2468 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002469 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002470 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2471 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2472
2473 return abis_nm_sendmsg(bts, msg);
2474}
2475
Harald Weltee69f5fb2009-04-28 16:31:38 +00002476/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2477int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2478{
2479 struct abis_om_hdr *oh;
2480 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002481 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002482
2483 msg = nm_msgb_alloc();
2484 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2485 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2486 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002487
2488 if (locked)
2489 tlv_value = BS11_LI_PLL_LOCKED;
2490 else
2491 tlv_value = BS11_LI_PLL_STANDALONE;
2492
2493 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002494
2495 return abis_nm_sendmsg(bts, msg);
2496}
2497
Harald Welte1bc09062009-01-18 14:17:52 +00002498int abis_nm_bs11_get_state(struct gsm_bts *bts)
2499{
2500 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2501}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002502
2503/* BS11 SWL */
2504
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002505void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002506
Harald Welte5e4d1b32009-02-01 13:36:56 +00002507struct abis_nm_bs11_sw {
2508 struct gsm_bts *bts;
2509 char swl_fname[PATH_MAX];
2510 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002511 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002512 struct llist_head file_list;
2513 gsm_cbfn *user_cb; /* specified by the user */
2514};
2515static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2516
2517struct file_list_entry {
2518 struct llist_head list;
2519 char fname[PATH_MAX];
2520};
2521
2522struct file_list_entry *fl_dequeue(struct llist_head *queue)
2523{
2524 struct llist_head *lh;
2525
2526 if (llist_empty(queue))
2527 return NULL;
2528
2529 lh = queue->next;
2530 llist_del(lh);
2531
2532 return llist_entry(lh, struct file_list_entry, list);
2533}
2534
2535static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2536{
2537 char linebuf[255];
2538 struct llist_head *lh, *lh2;
2539 FILE *swl;
2540 int rc = 0;
2541
2542 swl = fopen(bs11_sw->swl_fname, "r");
2543 if (!swl)
2544 return -ENODEV;
2545
2546 /* zero the stale file list, if any */
2547 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2548 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002549 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002550 }
2551
2552 while (fgets(linebuf, sizeof(linebuf), swl)) {
2553 char file_id[12+1];
2554 char file_version[80+1];
2555 struct file_list_entry *fle;
2556 static char dir[PATH_MAX];
2557
2558 if (strlen(linebuf) < 4)
2559 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002560
Harald Welte5e4d1b32009-02-01 13:36:56 +00002561 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2562 if (rc < 0) {
2563 perror("ERR parsing SWL file");
2564 rc = -EINVAL;
2565 goto out;
2566 }
2567 if (rc < 2)
2568 continue;
2569
Harald Welte470ec292009-06-26 20:25:23 +02002570 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002571 if (!fle) {
2572 rc = -ENOMEM;
2573 goto out;
2574 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002575
2576 /* construct new filename */
2577 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2578 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2579 strcat(fle->fname, "/");
2580 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002581
2582 llist_add_tail(&fle->list, &bs11_sw->file_list);
2583 }
2584
2585out:
2586 fclose(swl);
2587 return rc;
2588}
2589
2590/* bs11 swload specific callback, passed to abis_nm core swload */
2591static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2592 struct msgb *msg, void *data, void *param)
2593{
2594 struct abis_nm_bs11_sw *bs11_sw = data;
2595 struct file_list_entry *fle;
2596 int rc = 0;
2597
Harald Welte5e4d1b32009-02-01 13:36:56 +00002598 switch (event) {
2599 case NM_MT_LOAD_END_ACK:
2600 fle = fl_dequeue(&bs11_sw->file_list);
2601 if (fle) {
2602 /* start download the next file of our file list */
2603 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2604 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002605 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002606 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002607 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002608 } else {
2609 /* activate the SWL */
2610 rc = abis_nm_software_activate(bs11_sw->bts,
2611 bs11_sw->swl_fname,
2612 bs11_swload_cbfn,
2613 bs11_sw);
2614 }
2615 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002616 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002617 case NM_MT_LOAD_END_NACK:
2618 case NM_MT_LOAD_INIT_ACK:
2619 case NM_MT_LOAD_INIT_NACK:
2620 case NM_MT_ACTIVATE_SW_NACK:
2621 case NM_MT_ACTIVATE_SW_ACK:
2622 default:
2623 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002624 if (bs11_sw->user_cb)
2625 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002626 break;
2627 }
2628
2629 return rc;
2630}
2631
2632/* Siemens provides a SWL file that is a mere listing of all the other
2633 * files that are part of a software release. We need to upload first
2634 * the list file, and then each file that is listed in the list file */
2635int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002636 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002637{
2638 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2639 struct file_list_entry *fle;
2640 int rc = 0;
2641
2642 INIT_LLIST_HEAD(&bs11_sw->file_list);
2643 bs11_sw->bts = bts;
2644 bs11_sw->win_size = win_size;
2645 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002646 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002647
2648 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2649 rc = bs11_read_swl_file(bs11_sw);
2650 if (rc < 0)
2651 return rc;
2652
2653 /* dequeue next item in file list */
2654 fle = fl_dequeue(&bs11_sw->file_list);
2655 if (!fle)
2656 return -EINVAL;
2657
2658 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002659 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002660 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002661 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002662 return rc;
2663}
2664
Harald Welte5083b0b2009-02-02 19:20:52 +00002665#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002666static u_int8_t req_attr_btse[] = {
2667 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2668 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2669 NM_ATT_BS11_LMT_USER_NAME,
2670
2671 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2672
2673 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2674
2675 NM_ATT_BS11_SW_LOAD_STORED };
2676
2677static u_int8_t req_attr_btsm[] = {
2678 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2679 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2680 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2681 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002682#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002683
2684static u_int8_t req_attr[] = {
2685 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2686 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002687 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002688
2689int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2690{
2691 struct abis_om_hdr *oh;
2692 struct msgb *msg = nm_msgb_alloc();
2693
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(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2697 0x03, 0x00, 0x00);
2698 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2699
2700 return abis_nm_sendmsg(bts, msg);
2701}
Harald Welte268bb402009-02-01 19:11:56 +00002702
2703int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
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 /* SiemensHW CCTRL object */
2712 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2713 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002714 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002715
2716 return abis_nm_sendmsg(bts, msg);
2717}
Harald Welte5c1e4582009-02-15 11:57:29 +00002718
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002719int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2720{
2721 struct abis_om_hdr *oh;
2722 struct msgb *msg = nm_msgb_alloc();
2723 struct bs11_date_time aet;
2724
2725 get_bs11_date_time(&aet);
2726 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2727 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2728 bport, 0xff, 0x02);
2729 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2730
2731 return abis_nm_sendmsg(bts, msg);
2732}
2733
Harald Welte5c1e4582009-02-15 11:57:29 +00002734/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002735static const char ipaccess_magic[] = "com.ipaccess";
2736
Harald Welte677c21f2009-02-17 13:22:23 +00002737
2738static int abis_nm_rx_ipacc(struct msgb *msg)
2739{
2740 struct abis_om_hdr *oh = msgb_l2(msg);
2741 struct abis_om_fom_hdr *foh;
2742 u_int8_t idstrlen = oh->data[0];
2743 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002744 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002745
2746 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002747 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002748 return -EINVAL;
2749 }
2750
Harald Welte193fefc2009-04-30 15:16:27 +00002751 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002752 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002753
Harald Weltea8bd6d42009-10-20 09:56:18 +02002754 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002755
Harald Welte746d6092009-10-19 22:11:11 +02002756 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002757
Harald Welte677c21f2009-02-17 13:22:23 +00002758 switch (foh->msg_type) {
2759 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002760 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002761 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002762 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002763 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002764 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2765 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002766 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002767 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002768 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002769 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2770 DEBUGPC(DNM, "STREAM=0x%02x ",
2771 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002772 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002773 break;
2774 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002775 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002776 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002777 DEBUGPC(DNM, " CAUSE=%s\n",
2778 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002779 else
2780 DEBUGPC(DNM, "\n");
2781 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002782 case NM_MT_IPACC_SET_NVATTR_ACK:
2783 DEBUGPC(DNM, "SET NVATTR ACK\n");
2784 /* FIXME: decode and show the actual attributes */
2785 break;
2786 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002787 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002788 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002789 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002790 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2791 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002792 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002793 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002794 case NM_MT_IPACC_GET_NVATTR_ACK:
2795 DEBUGPC(DNM, "GET NVATTR ACK\n");
2796 /* FIXME: decode and show the actual attributes */
2797 break;
2798 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002799 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002800 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002801 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002802 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2803 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002804 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002805 break;
Harald Welte15c44172009-10-08 20:15:24 +02002806 case NM_MT_IPACC_SET_ATTR_ACK:
2807 DEBUGPC(DNM, "SET ATTR ACK\n");
2808 break;
2809 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002810 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002811 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002812 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002813 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2814 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002815 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002816 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002817 default:
2818 DEBUGPC(DNM, "unknown\n");
2819 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002820 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002821
2822 /* signal handling */
2823 switch (foh->msg_type) {
2824 case NM_MT_IPACC_RSL_CONNECT_NACK:
2825 case NM_MT_IPACC_SET_NVATTR_NACK:
2826 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002827 signal.bts = msg->trx->bts;
2828 signal.msg_type = foh->msg_type;
2829 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002830 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002831 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002832 signal.bts = msg->trx->bts;
2833 signal.msg_type = foh->msg_type;
2834 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002835 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002836 default:
2837 break;
2838 }
2839
Harald Welte677c21f2009-02-17 13:22:23 +00002840 return 0;
2841}
2842
Harald Welte193fefc2009-04-30 15:16:27 +00002843/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002844int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2845 u_int8_t obj_class, u_int8_t bts_nr,
2846 u_int8_t trx_nr, u_int8_t ts_nr,
2847 u_int8_t *attr, int attr_len)
2848{
2849 struct msgb *msg = nm_msgb_alloc();
2850 struct abis_om_hdr *oh;
2851 struct abis_om_fom_hdr *foh;
2852 u_int8_t *data;
2853
2854 /* construct the 12.21 OM header, observe the erroneous length */
2855 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2856 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2857 oh->mdisc = ABIS_OM_MDISC_MANUF;
2858
2859 /* add the ip.access magic */
2860 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2861 *data++ = sizeof(ipaccess_magic);
2862 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2863
2864 /* fill the 12.21 FOM header */
2865 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2866 foh->msg_type = msg_type;
2867 foh->obj_class = obj_class;
2868 foh->obj_inst.bts_nr = bts_nr;
2869 foh->obj_inst.trx_nr = trx_nr;
2870 foh->obj_inst.ts_nr = ts_nr;
2871
2872 if (attr && attr_len) {
2873 data = msgb_put(msg, attr_len);
2874 memcpy(data, attr, attr_len);
2875 }
2876
2877 return abis_nm_sendmsg(bts, msg);
2878}
Harald Welte677c21f2009-02-17 13:22:23 +00002879
Harald Welte193fefc2009-04-30 15:16:27 +00002880/* set some attributes in NVRAM */
2881int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2882 int attr_len)
2883{
2884 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2885 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2886 attr_len);
2887}
2888
Harald Welte746d6092009-10-19 22:11:11 +02002889int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2890 u_int32_t ip, u_int16_t port, u_int8_t stream)
2891{
2892 struct in_addr ia;
2893 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2894 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2895 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2896
2897 int attr_len = sizeof(attr);
2898
2899 ia.s_addr = htonl(ip);
2900 attr[1] = stream;
2901 attr[3] = port >> 8;
2902 attr[4] = port & 0xff;
2903 *(u_int32_t *)(attr+6) = ia.s_addr;
2904
2905 /* if ip == 0, we use the default IP */
2906 if (ip == 0)
2907 attr_len -= 5;
2908
2909 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002910 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002911
2912 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2913 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2914 trx->nr, 0xff, attr, attr_len);
2915}
2916
Harald Welte193fefc2009-04-30 15:16:27 +00002917/* restart / reboot an ip.access nanoBTS */
2918int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2919{
2920 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2921}
Harald Weltedaef5212009-10-24 10:20:41 +02002922
2923int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2924 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2925 u_int8_t *attr, u_int8_t attr_len)
2926{
2927 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2928 obj_class, bts_nr, trx_nr, ts_nr,
2929 attr, attr_len);
2930}
Harald Welte0f255852009-11-12 14:48:42 +01002931
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002932void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2933{
2934 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2935
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002936 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002937 if (!trx->bts || !trx->bts->oml_link)
2938 return;
2939
2940 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2941 trx->bts->bts_nr, trx->nr, 0xff,
2942 new_state);
2943}
2944
Harald Welte0f255852009-11-12 14:48:42 +01002945static const char *ipacc_testres_names[] = {
2946 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2947 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2948 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2949 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2950 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2951};
2952
2953const char *ipacc_testres_name(u_int8_t res)
2954{
2955 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2956 ipacc_testres_names[res])
2957 return ipacc_testres_names[res];
2958
2959 return "unknown";
2960}
2961
Harald Welteb40a38f2009-11-13 11:56:05 +01002962void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2963{
2964 cid->mcc = (buf[0] & 0xf) * 100;
2965 cid->mcc += (buf[0] >> 4) * 10;
2966 cid->mcc += (buf[1] & 0xf) * 1;
2967
2968 if (buf[1] >> 4 == 0xf) {
2969 cid->mnc = (buf[2] & 0xf) * 10;
2970 cid->mnc += (buf[2] >> 4) * 1;
2971 } else {
2972 cid->mnc = (buf[2] & 0xf) * 100;
2973 cid->mnc += (buf[2] >> 4) * 10;
2974 cid->mnc += (buf[1] >> 4) * 1;
2975 }
2976
Harald Welteaff237d2009-11-13 14:41:52 +01002977 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2978 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002979}
2980
Harald Welte0f255852009-11-12 14:48:42 +01002981/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2982int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2983{
2984 u_int8_t *cur = buf;
2985 u_int16_t len;
2986
2987 memset(binf, 0, sizeof(binf));
2988
2989 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2990 return -EINVAL;
2991 cur++;
2992
2993 len = ntohs(*(u_int16_t *)cur);
2994 cur += 2;
2995
2996 binf->info_type = ntohs(*(u_int16_t *)cur);
2997 cur += 2;
2998
2999 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3000 binf->freq_qual = *cur >> 2;
3001
3002 binf->arfcn = *cur++ & 3 << 8;
3003 binf->arfcn |= *cur++;
3004
3005 if (binf->info_type & IPAC_BINF_RXLEV)
3006 binf->rx_lev = *cur & 0x3f;
3007 cur++;
3008
3009 if (binf->info_type & IPAC_BINF_RXQUAL)
3010 binf->rx_qual = *cur & 0x7;
3011 cur++;
3012
3013 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3014 binf->freq_err = ntohs(*(u_int16_t *)cur);
3015 cur += 2;
3016
3017 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3018 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3019 cur += 2;
3020
3021 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3022 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3023 cur += 4;
3024
3025 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01003026 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003027 cur++;
3028
Harald Welteb40a38f2009-11-13 11:56:05 +01003029 ipac_parse_cgi(&binf->cgi, cur);
3030 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003031
3032 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3033 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3034 cur += sizeof(binf->ba_list_si2);
3035 }
3036
3037 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3038 memcpy(binf->ba_list_si2bis, cur,
3039 sizeof(binf->ba_list_si2bis));
3040 cur += sizeof(binf->ba_list_si2bis);
3041 }
3042
3043 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3044 memcpy(binf->ba_list_si2ter, cur,
3045 sizeof(binf->ba_list_si2ter));
3046 cur += sizeof(binf->ba_list_si2ter);
3047 }
3048
3049 return 0;
3050}
3051
3052