blob: 1e5e1c87c6f559c2718390e7a4bc9d9cd5948d58 [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>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010041#include <osmocore/msgb.h>
42#include <osmocore/tlv.h>
43#include <osmocore/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000044#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000045#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000046#include <openbsc/signal.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 Welte39315c42010-01-10 18:01:52 +0100267const struct tlv_definition nm_att_tlvdef = {
Harald Weltee0590df2009-02-15 03:34:15 +0000268 .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 },
Harald Weltee0590df2009-02-15 03:34:15 +0000333 },
334};
Harald Welte03133942009-02-18 19:51:53 +0000335
Harald Welte21bd3a52009-08-10 12:21:22 +0200336static const enum abis_nm_chan_comb chcomb4pchan[] = {
337 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
338 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
339 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
340 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
341 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200342 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
343 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200344 /* FIXME: bounds check */
345};
346
347int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
348{
349 if (pchan < ARRAY_SIZE(chcomb4pchan))
350 return chcomb4pchan[pchan];
351
352 return -EINVAL;
353}
354
Harald Welte39315c42010-01-10 18:01:52 +0100355int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +0000356{
Harald Welte39315c42010-01-10 18:01:52 +0100357 if (!bts->model)
358 return -EIO;
359 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000360}
Harald Weltee0590df2009-02-15 03:34:15 +0000361
Harald Welte52b1f982008-12-23 20:25:15 +0000362static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
363{
364 int i;
365
366 for (i = 0; i < size; i++) {
367 if (arr[i] == mt)
368 return 1;
369 }
370
371 return 0;
372}
373
Holger Freytherca362a62009-01-04 21:05:01 +0000374#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000375/* is this msgtype the usual ACK/NACK type ? */
376static int is_ack_nack(enum abis_nm_msgtype mt)
377{
378 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
379}
Holger Freytherca362a62009-01-04 21:05:01 +0000380#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000381
382/* is this msgtype a report ? */
383static int is_report(enum abis_nm_msgtype mt)
384{
Harald Welte8470bf22008-12-25 23:28:35 +0000385 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000386}
387
388#define MT_ACK(x) (x+1)
389#define MT_NACK(x) (x+2)
390
391static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
392{
393 oh->mdisc = ABIS_OM_MDISC_FOM;
394 oh->placement = ABIS_OM_PLACEMENT_ONLY;
395 oh->sequence = 0;
396 oh->length = len;
397}
398
399static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
400 u_int8_t msg_type, u_int8_t obj_class,
401 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
402{
403 struct abis_om_fom_hdr *foh =
404 (struct abis_om_fom_hdr *) oh->data;
405
Harald Welte702d8702008-12-26 20:25:35 +0000406 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000407 foh->msg_type = msg_type;
408 foh->obj_class = obj_class;
409 foh->obj_inst.bts_nr = bts_nr;
410 foh->obj_inst.trx_nr = trx_nr;
411 foh->obj_inst.ts_nr = ts_nr;
412}
413
Harald Welte8470bf22008-12-25 23:28:35 +0000414static struct msgb *nm_msgb_alloc(void)
415{
Harald Welte966636f2009-06-26 19:39:35 +0200416 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
417 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000418}
419
Harald Welte52b1f982008-12-23 20:25:15 +0000420/* Send a OML NM Message from BSC to BTS */
421int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
422{
Holger Freyther59639e82009-02-09 23:09:55 +0000423 msg->trx = bts->c0;
424
Harald Weltead384642008-12-26 10:20:07 +0000425 return _abis_nm_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000426}
427
Harald Welte4724f992009-01-18 18:01:49 +0000428static int abis_nm_rcvmsg_sw(struct msgb *mb);
429
Harald Welte34a99682009-02-13 02:41:40 +0000430static const char *obj_class_name(u_int8_t oc)
431{
Harald Welte7b26bcb2009-05-28 11:39:21 +0000432 switch (oc) {
433 case NM_OC_SITE_MANAGER:
434 return "SITE MANAGER";
435 case NM_OC_BTS:
436 return "BTS";
437 case NM_OC_RADIO_CARRIER:
438 return "RADIO CARRIER";
439 case NM_OC_BASEB_TRANSC:
440 return "BASEBAND TRANSCEIVER";
441 case NM_OC_CHANNEL:
Harald Weltebd8f7e32009-06-09 20:17:12 +0000442 return "CHANNEL";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000443 case NM_OC_BS11_ADJC:
444 return "ADJC";
445 case NM_OC_BS11_HANDOVER:
446 return "HANDOVER";
447 case NM_OC_BS11_PWR_CTRL:
448 return "POWER CONTROL";
449 case NM_OC_BS11_BTSE:
450 return "BTSE";
451 case NM_OC_BS11_RACK:
452 return "RACK";
453 case NM_OC_BS11_TEST:
454 return "TEST";
455 case NM_OC_BS11_ENVABTSE:
456 return "ENVABTSE";
457 case NM_OC_BS11_BPORT:
458 return "BPORT";
459 case NM_OC_GPRS_NSE:
460 return "GPRS NSE";
461 case NM_OC_GPRS_CELL:
462 return "GPRS CELL";
Harald Welted83a1272009-07-12 10:56:06 +0200463 case NM_OC_GPRS_NSVC:
464 return "GPRS NSVC";
Harald Welte8b697c72009-06-05 19:18:45 +0000465 case NM_OC_BS11:
466 return "SIEMENSHW";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000467 }
468
469 return "UNKNOWN";
Harald Welte34a99682009-02-13 02:41:40 +0000470}
471
Harald Welte4d87f242009-03-10 19:43:44 +0000472const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000473{
474 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100475 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000476 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100477 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000478 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100479 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000480 return "NULL";
481 default:
482 return "RFU";
483 }
484}
485
Harald Weltee0590df2009-02-15 03:34:15 +0000486/* Chapter 9.4.7 */
Harald Welte4d87f242009-03-10 19:43:44 +0000487static const char *avail_names[] = {
Harald Weltee0590df2009-02-15 03:34:15 +0000488 "In test",
489 "Failed",
490 "Power off",
491 "Off line",
492 "<not used>",
493 "Dependency",
494 "Degraded",
495 "Not installed",
496};
497
Harald Welte4d87f242009-03-10 19:43:44 +0000498const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000499{
Harald Welte0b8348d2009-02-18 03:43:01 +0000500 if (avail == 0xff)
501 return "OK";
Harald Weltee0590df2009-02-15 03:34:15 +0000502 if (avail >= ARRAY_SIZE(avail_names))
503 return "UNKNOWN";
504 return avail_names[avail];
505}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000506
Harald Welte0f255852009-11-12 14:48:42 +0100507static struct value_string test_names[] = {
508 /* FIXME: standard test names */
509 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
510 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
511 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
512 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
513 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
514 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
515 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
516 { 0, NULL }
517};
518
Harald Welte7b26bcb2009-05-28 11:39:21 +0000519const char *nm_adm_name(u_int8_t adm)
520{
521 switch (adm) {
522 case 1:
523 return "Locked";
524 case 2:
525 return "Unlocked";
526 case 3:
527 return "Shutdown";
528 default:
529 return "<not used>";
530 }
531}
Harald Weltee0590df2009-02-15 03:34:15 +0000532
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100533int nm_is_running(struct gsm_nm_state *s) {
534 return (s->operational == NM_OPSTATE_ENABLED) && (
535 (s->availability == NM_AVSTATE_OK) ||
536 (s->availability == 0xff)
537 );
538}
539
Harald Weltea8bd6d42009-10-20 09:56:18 +0200540static void debugp_foh(struct abis_om_fom_hdr *foh)
541{
542 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
543 obj_class_name(foh->obj_class), foh->obj_class,
544 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
545 foh->obj_inst.ts_nr);
546}
547
Harald Weltee0590df2009-02-15 03:34:15 +0000548/* obtain the gsm_nm_state data structure for a given object instance */
549static struct gsm_nm_state *
550objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
551 struct abis_om_obj_inst *obj_inst)
552{
553 struct gsm_bts_trx *trx;
554 struct gsm_nm_state *nm_state = NULL;
555
556 switch (obj_class) {
557 case NM_OC_BTS:
558 nm_state = &bts->nm_state;
559 break;
560 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100561 if (obj_inst->trx_nr >= bts->num_trx) {
562 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000563 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100564 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200565 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000566 nm_state = &trx->nm_state;
567 break;
568 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100569 if (obj_inst->trx_nr >= bts->num_trx) {
570 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000571 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100572 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200573 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000574 nm_state = &trx->bb_transc.nm_state;
575 break;
576 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100577 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100578 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000579 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100580 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200581 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000582 if (obj_inst->ts_nr >= TRX_NR_TS)
583 return NULL;
584 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
585 break;
586 case NM_OC_SITE_MANAGER:
587 nm_state = &bts->site_mgr.nm_state;
588 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000589 case NM_OC_BS11:
590 switch (obj_inst->bts_nr) {
591 case BS11_OBJ_CCLK:
592 nm_state = &bts->bs11.cclk.nm_state;
593 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000594 case BS11_OBJ_BBSIG:
595 if (obj_inst->ts_nr > bts->num_trx)
596 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200597 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000598 nm_state = &trx->bs11.bbsig.nm_state;
599 break;
600 case BS11_OBJ_PA:
601 if (obj_inst->ts_nr > bts->num_trx)
602 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200603 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000604 nm_state = &trx->bs11.pa.nm_state;
605 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000606 default:
607 return NULL;
608 }
609 case NM_OC_BS11_RACK:
610 nm_state = &bts->bs11.rack.nm_state;
611 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000612 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100613 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000614 return NULL;
615 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
616 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200617 case NM_OC_GPRS_NSE:
618 nm_state = &bts->gprs.nse.nm_state;
619 break;
620 case NM_OC_GPRS_CELL:
621 nm_state = &bts->gprs.cell.nm_state;
622 break;
623 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100624 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200625 return NULL;
626 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
627 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000628 }
629 return nm_state;
630}
631
632/* obtain the in-memory data structure of a given object instance */
633static void *
634objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
635 struct abis_om_obj_inst *obj_inst)
636{
637 struct gsm_bts_trx *trx;
638 void *obj = NULL;
639
640 switch (obj_class) {
641 case NM_OC_BTS:
642 obj = bts;
643 break;
644 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100645 if (obj_inst->trx_nr >= bts->num_trx) {
646 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000647 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100648 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200649 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000650 obj = trx;
651 break;
652 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100653 if (obj_inst->trx_nr >= bts->num_trx) {
654 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000655 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100656 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200657 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000658 obj = &trx->bb_transc;
659 break;
660 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100661 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100662 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000663 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100664 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200665 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000666 if (obj_inst->ts_nr >= TRX_NR_TS)
667 return NULL;
668 obj = &trx->ts[obj_inst->ts_nr];
669 break;
670 case NM_OC_SITE_MANAGER:
671 obj = &bts->site_mgr;
672 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200673 case NM_OC_GPRS_NSE:
674 obj = &bts->gprs.nse;
675 break;
676 case NM_OC_GPRS_CELL:
677 obj = &bts->gprs.cell;
678 break;
679 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100680 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200681 return NULL;
682 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
683 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000684 }
685 return obj;
686}
687
688/* Update the administrative state of a given object in our in-memory data
689 * structures and send an event to the higher layer */
690static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
691 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
692{
Harald Welteaeedeb42009-05-01 13:08:14 +0000693 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000694 void *obj;
695 int rc;
696
Harald Weltee0590df2009-02-15 03:34:15 +0000697 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100698 if (!obj)
699 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000700 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
701 if (!nm_state)
702 return -1;
703
704 new_state = *nm_state;
705 new_state.administrative = adm_state;
706
707 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
708
709 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000710
711 return rc;
712}
713
Harald Welte97ed1e72009-02-06 13:38:02 +0000714static int abis_nm_rx_statechg_rep(struct msgb *mb)
715{
Harald Weltee0590df2009-02-15 03:34:15 +0000716 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000717 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000718 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000719 struct tlv_parsed tp;
720 struct gsm_nm_state *nm_state, new_state;
721 int rc;
722
Harald Welte23897662009-05-01 14:52:51 +0000723 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000724
Harald Welte8b697c72009-06-05 19:18:45 +0000725 memset(&new_state, 0, sizeof(new_state));
726
Harald Weltee0590df2009-02-15 03:34:15 +0000727 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
728 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100729 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000730 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000731 }
Harald Weltee0590df2009-02-15 03:34:15 +0000732
733 new_state = *nm_state;
734
Harald Welte39315c42010-01-10 18:01:52 +0100735 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000736 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
737 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000738 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000739 }
740 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000741 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
742 new_state.availability = 0xff;
743 else
744 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000745 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000746 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100747 } else
748 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000749 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
750 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200751 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000752 }
753 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000754
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100755 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
756 new_state.operational != nm_state->operational ||
757 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000758 /* Update the operational state of a given object in our in-memory data
759 * structures and send an event to the higher layer */
760 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
761 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100762 nm_state->operational = new_state.operational;
763 nm_state->availability = new_state.availability;
764 if (nm_state->administrative == 0)
765 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000766 }
767#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000768 if (op_state == 1) {
769 /* try to enable objects that are disabled */
770 abis_nm_opstart(bts, foh->obj_class,
771 foh->obj_inst.bts_nr,
772 foh->obj_inst.trx_nr,
773 foh->obj_inst.ts_nr);
774 }
Harald Weltee0590df2009-02-15 03:34:15 +0000775#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000776 return 0;
777}
778
Harald Welte0db97b22009-05-01 17:22:47 +0000779static int rx_fail_evt_rep(struct msgb *mb)
780{
781 struct abis_om_hdr *oh = msgb_l2(mb);
782 struct abis_om_fom_hdr *foh = msgb_l3(mb);
783 struct tlv_parsed tp;
784
785 DEBUGPC(DNM, "Failure Event Report ");
786
Harald Welte39315c42010-01-10 18:01:52 +0100787 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000788
789 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
790 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
791 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
792 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
793
794 DEBUGPC(DNM, "\n");
795
796 return 0;
797}
798
Harald Welte97ed1e72009-02-06 13:38:02 +0000799static int abis_nm_rcvmsg_report(struct msgb *mb)
800{
801 struct abis_om_fom_hdr *foh = msgb_l3(mb);
802 u_int8_t mt = foh->msg_type;
803
Harald Weltea8bd6d42009-10-20 09:56:18 +0200804 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000805
Harald Welte97ed1e72009-02-06 13:38:02 +0000806 //nmh->cfg->report_cb(mb, foh);
807
808 switch (mt) {
809 case NM_MT_STATECHG_EVENT_REP:
810 return abis_nm_rx_statechg_rep(mb);
811 break;
Harald Welte34a99682009-02-13 02:41:40 +0000812 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000813 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000814 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000815 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000816 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000817 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000818 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000819 break;
Harald Weltec7310382009-08-08 00:02:36 +0200820 case NM_MT_TEST_REP:
821 DEBUGPC(DNM, "Test Report\n");
822 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
823 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000824 default:
Harald Welte23897662009-05-01 14:52:51 +0000825 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000826 break;
827
Harald Welte97ed1e72009-02-06 13:38:02 +0000828 };
829
Harald Welte97ed1e72009-02-06 13:38:02 +0000830 return 0;
831}
832
Harald Welte34a99682009-02-13 02:41:40 +0000833/* Activate the specified software into the BTS */
834static 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 +0200835 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000836{
837 struct abis_om_hdr *oh;
838 struct msgb *msg = nm_msgb_alloc();
839 u_int8_t len = swdesc_len;
840 u_int8_t *trailer;
841
842 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
843 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
844
845 trailer = msgb_put(msg, swdesc_len);
846 memcpy(trailer, sw_desc, swdesc_len);
847
848 return abis_nm_sendmsg(bts, msg);
849}
850
851static int abis_nm_rx_sw_act_req(struct msgb *mb)
852{
853 struct abis_om_hdr *oh = msgb_l2(mb);
854 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200855 struct tlv_parsed tp;
856 const u_int8_t *sw_config;
857 int sw_config_len;
858 int file_id_len;
Harald Welte34a99682009-02-13 02:41:40 +0000859 int ret;
860
Harald Weltea8bd6d42009-10-20 09:56:18 +0200861 debugp_foh(foh);
862
863 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000864
Harald Welte97a282b2010-03-14 15:37:43 +0800865 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000866
867 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000868 foh->obj_inst.bts_nr,
869 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800870 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000871 foh->data, oh->length-sizeof(*foh));
872
Harald Welte39315c42010-01-10 18:01:52 +0100873 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200874 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
875 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
876 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
877 DEBUGP(DNM, "SW config not found! Can't continue.\n");
878 return -EINVAL;
879 } else {
880 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
881 }
882
883 if (sw_config[0] != NM_ATT_SW_DESCR)
884 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
885 if (sw_config[1] != NM_ATT_FILE_ID)
886 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
887 file_id_len = sw_config[2] * 256 + sw_config[3];
888
889 /* Assumes first SW file in list is the one to be activated */
890 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000891 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
892 foh->obj_inst.bts_nr,
893 foh->obj_inst.trx_nr,
894 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200895 sw_config + 4,
896 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000897}
898
Harald Weltee0590df2009-02-15 03:34:15 +0000899/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
900static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
901{
902 struct abis_om_hdr *oh = msgb_l2(mb);
903 struct abis_om_fom_hdr *foh = msgb_l3(mb);
904 struct tlv_parsed tp;
905 u_int8_t adm_state;
906
Harald Welte39315c42010-01-10 18:01:52 +0100907 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000908 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
909 return -EINVAL;
910
911 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
912
913 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
914}
915
Harald Welteee670472009-02-22 21:58:49 +0000916static int abis_nm_rx_lmt_event(struct msgb *mb)
917{
918 struct abis_om_hdr *oh = msgb_l2(mb);
919 struct abis_om_fom_hdr *foh = msgb_l3(mb);
920 struct tlv_parsed tp;
921
922 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100923 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000924 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
925 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
926 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
927 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
928 }
929 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
930 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
931 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
932 DEBUGPC(DNM, "Level=%u ", level);
933 }
934 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
935 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
936 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
937 DEBUGPC(DNM, "Username=%s ", name);
938 }
939 DEBUGPC(DNM, "\n");
940 /* FIXME: parse LMT LOGON TIME */
941 return 0;
942}
943
Harald Welte52b1f982008-12-23 20:25:15 +0000944/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000945static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000946{
Harald Welte6c96ba52009-05-01 13:03:40 +0000947 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000948 struct abis_om_fom_hdr *foh = msgb_l3(mb);
949 u_int8_t mt = foh->msg_type;
950
951 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000952 if (is_report(mt))
953 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000954
Harald Welte4724f992009-01-18 18:01:49 +0000955 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
956 return abis_nm_rcvmsg_sw(mb);
957
Harald Welte78fc0d42009-02-19 02:50:57 +0000958 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +0000959 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200960
Harald Weltea8bd6d42009-10-20 09:56:18 +0200961 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200962
Harald Welte78fc0d42009-02-19 02:50:57 +0000963 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +0200964 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +0000965 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +0000966 else
Harald Welte4bd0a982009-10-08 20:18:59 +0200967 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +0000968
Harald Welte39315c42010-01-10 18:01:52 +0100969 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000970 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
971 DEBUGPC(DNM, "CAUSE=%s\n",
972 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
973 else
974 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200975
Harald Welted8cfc902009-11-17 06:09:56 +0100976 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200977 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000978 }
Harald Weltead384642008-12-26 10:20:07 +0000979#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000980 /* check if last message is to be acked */
981 if (is_ack_nack(nmh->last_msgtype)) {
982 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100983 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000984 /* we got our ACK, continue sending the next msg */
985 } else if (mt == MT_NACK(nmh->last_msgtype)) {
986 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100987 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000988 /* FIXME: somehow signal this to the caller */
989 } else {
990 /* really strange things happen */
991 return -EINVAL;
992 }
993 }
Harald Weltead384642008-12-26 10:20:07 +0000994#endif
995
Harald Welte97ed1e72009-02-06 13:38:02 +0000996 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000997 case NM_MT_CHG_ADM_STATE_ACK:
998 return abis_nm_rx_chg_adm_state_ack(mb);
999 break;
Harald Welte34a99682009-02-13 02:41:40 +00001000 case NM_MT_SW_ACT_REQ:
1001 return abis_nm_rx_sw_act_req(mb);
1002 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001003 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001004 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001005 break;
Harald Welte1989c082009-08-06 17:58:31 +02001006 case NM_MT_CONN_MDROP_LINK_ACK:
1007 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1008 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001009 case NM_MT_IPACC_RESTART_ACK:
1010 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1011 break;
1012 case NM_MT_IPACC_RESTART_NACK:
1013 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1014 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001015 }
1016
Harald Weltead384642008-12-26 10:20:07 +00001017 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001018}
1019
Harald Welte677c21f2009-02-17 13:22:23 +00001020static int abis_nm_rx_ipacc(struct msgb *mb);
1021
1022static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1023{
1024 int rc;
1025 int bts_type = mb->trx->bts->type;
1026
1027 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001028 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001029 rc = abis_nm_rx_ipacc(mb);
1030 break;
1031 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001032 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1033 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001034 rc = 0;
1035 break;
1036 }
1037
1038 return rc;
1039}
1040
Harald Welte52b1f982008-12-23 20:25:15 +00001041/* High-Level API */
1042/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001043int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001044{
Harald Welte52b1f982008-12-23 20:25:15 +00001045 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001046 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001047
1048 /* Various consistency checks */
1049 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001050 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001051 oh->placement);
1052 return -EINVAL;
1053 }
1054 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001055 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001056 oh->sequence);
1057 return -EINVAL;
1058 }
Harald Welte702d8702008-12-26 20:25:35 +00001059#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001060 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1061 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001062 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001063 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001064 oh->length + sizeof(*oh), l2_len);
1065 return -EINVAL;
1066 }
Harald Welte702d8702008-12-26 20:25:35 +00001067 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001068 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 +00001069#endif
Harald Weltead384642008-12-26 10:20:07 +00001070 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001071
1072 switch (oh->mdisc) {
1073 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001074 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001075 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001076 case ABIS_OM_MDISC_MANUF:
1077 rc = abis_nm_rcvmsg_manuf(msg);
1078 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001079 case ABIS_OM_MDISC_MMI:
1080 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001081 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001082 oh->mdisc);
1083 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001084 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001085 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001086 oh->mdisc);
1087 return -EINVAL;
1088 }
1089
Harald Weltead384642008-12-26 10:20:07 +00001090 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001091 return rc;
1092}
1093
1094#if 0
1095/* initialized all resources */
1096struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1097{
1098 struct abis_nm_h *nmh;
1099
1100 nmh = malloc(sizeof(*nmh));
1101 if (!nmh)
1102 return NULL;
1103
1104 nmh->cfg = cfg;
1105
1106 return nmh;
1107}
1108
1109/* free all resources */
1110void abis_nm_fini(struct abis_nm_h *nmh)
1111{
1112 free(nmh);
1113}
1114#endif
1115
1116/* Here we are trying to define a high-level API that can be used by
1117 * the actual BSC implementation. However, the architecture is currently
1118 * still under design. Ideally the calls to this API would be synchronous,
1119 * while the underlying stack behind the APi runs in a traditional select
1120 * based state machine.
1121 */
1122
Harald Welte4724f992009-01-18 18:01:49 +00001123/* 6.2 Software Load: */
1124enum sw_state {
1125 SW_STATE_NONE,
1126 SW_STATE_WAIT_INITACK,
1127 SW_STATE_WAIT_SEGACK,
1128 SW_STATE_WAIT_ENDACK,
1129 SW_STATE_WAIT_ACTACK,
1130 SW_STATE_ERROR,
1131};
Harald Welte52b1f982008-12-23 20:25:15 +00001132
Harald Welte52b1f982008-12-23 20:25:15 +00001133struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001134 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001135 gsm_cbfn *cbfn;
1136 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001137 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001138
Harald Welte52b1f982008-12-23 20:25:15 +00001139 /* this will become part of the SW LOAD INITIATE */
1140 u_int8_t obj_class;
1141 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001142
1143 u_int8_t file_id[255];
1144 u_int8_t file_id_len;
1145
1146 u_int8_t file_version[255];
1147 u_int8_t file_version_len;
1148
1149 u_int8_t window_size;
1150 u_int8_t seg_in_window;
1151
1152 int fd;
1153 FILE *stream;
1154 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001155 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001156};
1157
Harald Welte4724f992009-01-18 18:01:49 +00001158static struct abis_nm_sw g_sw;
1159
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001160static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1161{
1162 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1163 msgb_v_put(msg, NM_ATT_SW_DESCR);
1164 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1165 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1166 sw->file_version);
1167 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1168 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1169 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1170 sw->file_version);
1171 } else {
1172 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1173 }
1174}
1175
Harald Welte4724f992009-01-18 18:01:49 +00001176/* 6.2.1 / 8.3.1: Load Data Initiate */
1177static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001178{
Harald Welte4724f992009-01-18 18:01:49 +00001179 struct abis_om_hdr *oh;
1180 struct msgb *msg = nm_msgb_alloc();
1181 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1182
1183 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1184 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1185 sw->obj_instance[0], sw->obj_instance[1],
1186 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001187
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001188 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001189 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1190
1191 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001192}
1193
Harald Welte1602ade2009-01-29 21:12:39 +00001194static int is_last_line(FILE *stream)
1195{
1196 char next_seg_buf[256];
1197 long pos;
1198
1199 /* check if we're sending the last line */
1200 pos = ftell(stream);
1201 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1202 fseek(stream, pos, SEEK_SET);
1203 return 1;
1204 }
1205
1206 fseek(stream, pos, SEEK_SET);
1207 return 0;
1208}
1209
Harald Welte4724f992009-01-18 18:01:49 +00001210/* 6.2.2 / 8.3.2 Load Data Segment */
1211static int sw_load_segment(struct abis_nm_sw *sw)
1212{
1213 struct abis_om_hdr *oh;
1214 struct msgb *msg = nm_msgb_alloc();
1215 char seg_buf[256];
1216 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001217 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001218 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001219
1220 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001221
1222 switch (sw->bts->type) {
1223 case GSM_BTS_TYPE_BS11:
1224 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1225 perror("fgets reading segment");
1226 return -EINVAL;
1227 }
1228 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001229
1230 /* check if we're sending the last line */
1231 sw->last_seg = is_last_line(sw->stream);
1232 if (sw->last_seg)
1233 seg_buf[1] = 0;
1234 else
1235 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001236
1237 len = strlen(line_buf) + 2;
1238 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1239 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1240 /* BS11 wants CR + LF in excess of the TLV length !?! */
1241 tlv[1] -= 2;
1242
1243 /* we only now know the exact length for the OM hdr */
1244 len = strlen(line_buf)+2;
1245 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001246 case GSM_BTS_TYPE_NANOBTS: {
1247 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1248 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1249 if (len < 0) {
1250 perror("read failed");
1251 return -EINVAL;
1252 }
1253
1254 if (len != IPACC_SEGMENT_SIZE)
1255 sw->last_seg = 1;
1256
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001257 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001258 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1259 len += 3;
1260 break;
1261 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001262 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001263 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001264 /* FIXME: Other BTS types */
1265 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001266 }
Harald Welte4724f992009-01-18 18:01:49 +00001267
Harald Welte4724f992009-01-18 18:01:49 +00001268 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1269 sw->obj_instance[0], sw->obj_instance[1],
1270 sw->obj_instance[2]);
1271
1272 return abis_nm_sendmsg(sw->bts, msg);
1273}
1274
1275/* 6.2.4 / 8.3.4 Load Data End */
1276static int sw_load_end(struct abis_nm_sw *sw)
1277{
1278 struct abis_om_hdr *oh;
1279 struct msgb *msg = nm_msgb_alloc();
1280 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1281
1282 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1283 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1284 sw->obj_instance[0], sw->obj_instance[1],
1285 sw->obj_instance[2]);
1286
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001287 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001288 return abis_nm_sendmsg(sw->bts, msg);
1289}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001290
Harald Welte52b1f982008-12-23 20:25:15 +00001291/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001292static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001293{
Harald Welte4724f992009-01-18 18:01:49 +00001294 struct abis_om_hdr *oh;
1295 struct msgb *msg = nm_msgb_alloc();
1296 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001297
Harald Welte4724f992009-01-18 18:01:49 +00001298 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1299 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1300 sw->obj_instance[0], sw->obj_instance[1],
1301 sw->obj_instance[2]);
1302
1303 /* FIXME: this is BS11 specific format */
1304 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1305 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1306 sw->file_version);
1307
1308 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001309}
Harald Welte4724f992009-01-18 18:01:49 +00001310
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001311struct sdp_firmware {
1312 char magic[4];
1313 char more_magic[4];
1314 unsigned int header_length;
1315 unsigned int file_length;
1316} __attribute__ ((packed));
1317
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001318static int parse_sdp_header(struct abis_nm_sw *sw)
1319{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001320 struct sdp_firmware firmware_header;
1321 int rc;
1322 struct stat stat;
1323
1324 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1325 if (rc != sizeof(firmware_header)) {
1326 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1327 return -1;
1328 }
1329
1330 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1331 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1332 return -1;
1333 }
1334
1335 if (firmware_header.more_magic[0] != 0x10 ||
1336 firmware_header.more_magic[1] != 0x02 ||
1337 firmware_header.more_magic[2] != 0x00 ||
1338 firmware_header.more_magic[3] != 0x00) {
1339 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1340 return -1;
1341 }
1342
1343
1344 if (fstat(sw->fd, &stat) == -1) {
1345 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1346 return -1;
1347 }
1348
1349 if (ntohl(firmware_header.file_length) != stat.st_size) {
1350 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1351 return -1;
1352 }
1353
1354 /* go back to the start as we checked the whole filesize.. */
1355 lseek(sw->fd, 0l, SEEK_SET);
1356 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1357 "There might be checksums in the file that are not\n"
1358 "verified and incomplete firmware might be flashed.\n"
1359 "There is absolutely no WARRANTY that flashing will\n"
1360 "work.\n");
1361 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001362}
1363
Harald Welte4724f992009-01-18 18:01:49 +00001364static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1365{
1366 char file_id[12+1];
1367 char file_version[80+1];
1368 int rc;
1369
1370 sw->fd = open(fname, O_RDONLY);
1371 if (sw->fd < 0)
1372 return sw->fd;
1373
1374 switch (sw->bts->type) {
1375 case GSM_BTS_TYPE_BS11:
1376 sw->stream = fdopen(sw->fd, "r");
1377 if (!sw->stream) {
1378 perror("fdopen");
1379 return -1;
1380 }
1381 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001382 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001383 file_id, file_version);
1384 if (rc != 2) {
1385 perror("parsing header line of software file");
1386 return -1;
1387 }
1388 strcpy((char *)sw->file_id, file_id);
1389 sw->file_id_len = strlen(file_id);
1390 strcpy((char *)sw->file_version, file_version);
1391 sw->file_version_len = strlen(file_version);
1392 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001393 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001394 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001395 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001396 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001397 rc = parse_sdp_header(sw);
1398 if (rc < 0) {
1399 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1400 return -1;
1401 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001402
1403 strcpy((char *)sw->file_id, "id");
1404 sw->file_id_len = 3;
1405 strcpy((char *)sw->file_version, "version");
1406 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001407 break;
Harald Welte4724f992009-01-18 18:01:49 +00001408 default:
1409 /* We don't know how to treat them yet */
1410 close(sw->fd);
1411 return -EINVAL;
1412 }
1413
1414 return 0;
1415}
1416
1417static void sw_close_file(struct abis_nm_sw *sw)
1418{
1419 switch (sw->bts->type) {
1420 case GSM_BTS_TYPE_BS11:
1421 fclose(sw->stream);
1422 break;
1423 default:
1424 close(sw->fd);
1425 break;
1426 }
1427}
1428
1429/* Fill the window */
1430static int sw_fill_window(struct abis_nm_sw *sw)
1431{
1432 int rc;
1433
1434 while (sw->seg_in_window < sw->window_size) {
1435 rc = sw_load_segment(sw);
1436 if (rc < 0)
1437 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001438 if (sw->last_seg)
1439 break;
Harald Welte4724f992009-01-18 18:01:49 +00001440 }
1441 return 0;
1442}
1443
1444/* callback function from abis_nm_rcvmsg() handler */
1445static int abis_nm_rcvmsg_sw(struct msgb *mb)
1446{
1447 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1448 int rc = -1;
1449 struct abis_nm_sw *sw = &g_sw;
1450 enum sw_state old_state = sw->state;
1451
Harald Welte3ffd1372009-02-01 22:15:49 +00001452 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001453
1454 switch (sw->state) {
1455 case SW_STATE_WAIT_INITACK:
1456 switch (foh->msg_type) {
1457 case NM_MT_LOAD_INIT_ACK:
1458 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001459 if (sw->cbfn)
1460 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1461 NM_MT_LOAD_INIT_ACK, mb,
1462 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001463 rc = sw_fill_window(sw);
1464 sw->state = SW_STATE_WAIT_SEGACK;
1465 break;
1466 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001467 if (sw->forced) {
1468 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1469 "Init NACK\n");
1470 if (sw->cbfn)
1471 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1472 NM_MT_LOAD_INIT_ACK, mb,
1473 sw->cb_data, NULL);
1474 rc = sw_fill_window(sw);
1475 sw->state = SW_STATE_WAIT_SEGACK;
1476 } else {
1477 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001478 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001479 if (sw->cbfn)
1480 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1481 NM_MT_LOAD_INIT_NACK, mb,
1482 sw->cb_data, NULL);
1483 sw->state = SW_STATE_ERROR;
1484 }
Harald Welte4724f992009-01-18 18:01:49 +00001485 break;
1486 }
1487 break;
1488 case SW_STATE_WAIT_SEGACK:
1489 switch (foh->msg_type) {
1490 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001491 if (sw->cbfn)
1492 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1493 NM_MT_LOAD_SEG_ACK, mb,
1494 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001495 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001496 if (!sw->last_seg) {
1497 /* fill window with more segments */
1498 rc = sw_fill_window(sw);
1499 sw->state = SW_STATE_WAIT_SEGACK;
1500 } else {
1501 /* end the transfer */
1502 sw->state = SW_STATE_WAIT_ENDACK;
1503 rc = sw_load_end(sw);
1504 }
Harald Welte4724f992009-01-18 18:01:49 +00001505 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001506 case NM_MT_LOAD_ABORT:
1507 if (sw->cbfn)
1508 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1509 NM_MT_LOAD_ABORT, mb,
1510 sw->cb_data, NULL);
1511 break;
Harald Welte4724f992009-01-18 18:01:49 +00001512 }
1513 break;
1514 case SW_STATE_WAIT_ENDACK:
1515 switch (foh->msg_type) {
1516 case NM_MT_LOAD_END_ACK:
1517 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001518 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1519 sw->bts->nr);
1520 sw->state = SW_STATE_NONE;
1521 if (sw->cbfn)
1522 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1523 NM_MT_LOAD_END_ACK, mb,
1524 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001525 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001526 break;
1527 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001528 if (sw->forced) {
1529 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1530 "End NACK\n");
1531 sw->state = SW_STATE_NONE;
1532 if (sw->cbfn)
1533 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1534 NM_MT_LOAD_END_ACK, mb,
1535 sw->cb_data, NULL);
1536 } else {
1537 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001538 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001539 sw->state = SW_STATE_ERROR;
1540 if (sw->cbfn)
1541 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1542 NM_MT_LOAD_END_NACK, mb,
1543 sw->cb_data, NULL);
1544 }
Harald Welte4724f992009-01-18 18:01:49 +00001545 break;
1546 }
1547 case SW_STATE_WAIT_ACTACK:
1548 switch (foh->msg_type) {
1549 case NM_MT_ACTIVATE_SW_ACK:
1550 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001551 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001552 sw->state = SW_STATE_NONE;
1553 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001554 if (sw->cbfn)
1555 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1556 NM_MT_ACTIVATE_SW_ACK, mb,
1557 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001558 break;
1559 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001560 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001561 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001562 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001563 if (sw->cbfn)
1564 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1565 NM_MT_ACTIVATE_SW_NACK, mb,
1566 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001567 break;
1568 }
1569 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001570 switch (foh->msg_type) {
1571 case NM_MT_ACTIVATE_SW_ACK:
1572 rc = 0;
1573 break;
1574 }
1575 break;
Harald Welte4724f992009-01-18 18:01:49 +00001576 case SW_STATE_ERROR:
1577 break;
1578 }
1579
1580 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001581 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001582 foh->msg_type, old_state, sw->state);
1583
1584 return rc;
1585}
1586
1587/* Load the specified software into the BTS */
1588int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001589 u_int8_t win_size, int forced,
1590 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001591{
1592 struct abis_nm_sw *sw = &g_sw;
1593 int rc;
1594
Harald Welte5e4d1b32009-02-01 13:36:56 +00001595 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1596 bts->nr, fname);
1597
Harald Welte4724f992009-01-18 18:01:49 +00001598 if (sw->state != SW_STATE_NONE)
1599 return -EBUSY;
1600
1601 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001602
1603 switch (bts->type) {
1604 case GSM_BTS_TYPE_BS11:
1605 sw->obj_class = NM_OC_SITE_MANAGER;
1606 sw->obj_instance[0] = 0xff;
1607 sw->obj_instance[1] = 0xff;
1608 sw->obj_instance[2] = 0xff;
1609 break;
1610 case GSM_BTS_TYPE_NANOBTS:
1611 sw->obj_class = NM_OC_BASEB_TRANSC;
1612 sw->obj_instance[0] = 0x00;
1613 sw->obj_instance[1] = 0x00;
1614 sw->obj_instance[2] = 0xff;
1615 break;
1616 case GSM_BTS_TYPE_UNKNOWN:
1617 default:
1618 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1619 return -1;
1620 break;
1621 }
Harald Welte4724f992009-01-18 18:01:49 +00001622 sw->window_size = win_size;
1623 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001624 sw->cbfn = cbfn;
1625 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001626 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001627
1628 rc = sw_open_file(sw, fname);
1629 if (rc < 0) {
1630 sw->state = SW_STATE_NONE;
1631 return rc;
1632 }
1633
1634 return sw_load_init(sw);
1635}
Harald Welte52b1f982008-12-23 20:25:15 +00001636
Harald Welte1602ade2009-01-29 21:12:39 +00001637int abis_nm_software_load_status(struct gsm_bts *bts)
1638{
1639 struct abis_nm_sw *sw = &g_sw;
1640 struct stat st;
1641 int rc, percent;
1642
1643 rc = fstat(sw->fd, &st);
1644 if (rc < 0) {
1645 perror("ERROR during stat");
1646 return rc;
1647 }
1648
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001649 if (sw->stream)
1650 percent = (ftell(sw->stream) * 100) / st.st_size;
1651 else
1652 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001653 return percent;
1654}
1655
Harald Welte5e4d1b32009-02-01 13:36:56 +00001656/* Activate the specified software into the BTS */
1657int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1658 gsm_cbfn *cbfn, void *cb_data)
1659{
1660 struct abis_nm_sw *sw = &g_sw;
1661 int rc;
1662
1663 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1664 bts->nr, fname);
1665
1666 if (sw->state != SW_STATE_NONE)
1667 return -EBUSY;
1668
1669 sw->bts = bts;
1670 sw->obj_class = NM_OC_SITE_MANAGER;
1671 sw->obj_instance[0] = 0xff;
1672 sw->obj_instance[1] = 0xff;
1673 sw->obj_instance[2] = 0xff;
1674 sw->state = SW_STATE_WAIT_ACTACK;
1675 sw->cbfn = cbfn;
1676 sw->cb_data = cb_data;
1677
1678 /* Open the file in order to fill some sw struct members */
1679 rc = sw_open_file(sw, fname);
1680 if (rc < 0) {
1681 sw->state = SW_STATE_NONE;
1682 return rc;
1683 }
1684 sw_close_file(sw);
1685
1686 return sw_activate(sw);
1687}
1688
Harald Welte8470bf22008-12-25 23:28:35 +00001689static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001690 u_int8_t ts_nr, u_int8_t subslot_nr)
1691{
Harald Welteadaf08b2009-01-18 11:08:10 +00001692 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001693 ch->bts_port = bts_port;
1694 ch->timeslot = ts_nr;
1695 ch->subslot = subslot_nr;
1696}
1697
1698int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1699 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1700 u_int8_t tei)
1701{
1702 struct abis_om_hdr *oh;
1703 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001704 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001705 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001706
1707 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1708 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1709 bts->bts_nr, trx_nr, 0xff);
1710
Harald Welte8470bf22008-12-25 23:28:35 +00001711 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001712
1713 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1714 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1715
1716 return abis_nm_sendmsg(bts, msg);
1717}
1718
1719/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1720int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1721 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1722{
Harald Welte8470bf22008-12-25 23:28:35 +00001723 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001724 struct abis_om_hdr *oh;
1725 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001726 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001727
1728 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001729 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001730 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1731
1732 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1733 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1734
1735 return abis_nm_sendmsg(bts, msg);
1736}
1737
1738#if 0
1739int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1740 struct abis_nm_abis_channel *chan)
1741{
1742}
1743#endif
1744
1745int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1746 u_int8_t e1_port, u_int8_t e1_timeslot,
1747 u_int8_t e1_subslot)
1748{
1749 struct gsm_bts *bts = ts->trx->bts;
1750 struct abis_om_hdr *oh;
1751 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001752 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001753
1754 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1755 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001756 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001757
1758 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1759 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1760
Harald Weltef325eb42009-02-19 17:07:39 +00001761 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1762 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001763 e1_port, e1_timeslot, e1_subslot);
1764
Harald Welte52b1f982008-12-23 20:25:15 +00001765 return abis_nm_sendmsg(bts, msg);
1766}
1767
1768#if 0
1769int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1770 struct abis_nm_abis_channel *chan,
1771 u_int8_t subchan)
1772{
1773}
1774#endif
1775
Harald Welte22af0db2009-02-14 15:41:08 +00001776/* Chapter 8.6.1 */
1777int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1778{
1779 struct abis_om_hdr *oh;
1780 struct msgb *msg = nm_msgb_alloc();
1781 u_int8_t *cur;
1782
1783 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1784
1785 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001786 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 +00001787 cur = msgb_put(msg, attr_len);
1788 memcpy(cur, attr, attr_len);
1789
1790 return abis_nm_sendmsg(bts, msg);
1791}
1792
1793/* Chapter 8.6.2 */
1794int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1795{
1796 struct abis_om_hdr *oh;
1797 struct msgb *msg = nm_msgb_alloc();
1798 u_int8_t *cur;
1799
1800 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1801
1802 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1803 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001804 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001805 cur = msgb_put(msg, attr_len);
1806 memcpy(cur, attr, attr_len);
1807
1808 return abis_nm_sendmsg(trx->bts, msg);
1809}
1810
Harald Welte39c7deb2009-08-09 21:49:48 +02001811static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1812{
1813 int i;
1814
1815 /* As it turns out, the BS-11 has some very peculiar restrictions
1816 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301817 switch (ts->trx->bts->type) {
1818 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001819 switch (chan_comb) {
1820 case NM_CHANC_TCHHalf:
1821 case NM_CHANC_TCHHalf2:
1822 /* not supported */
1823 return -EINVAL;
1824 case NM_CHANC_SDCCH:
1825 /* only one SDCCH/8 per TRX */
1826 for (i = 0; i < TRX_NR_TS; i++) {
1827 if (i == ts->nr)
1828 continue;
1829 if (ts->trx->ts[i].nm_chan_comb ==
1830 NM_CHANC_SDCCH)
1831 return -EINVAL;
1832 }
1833 /* not allowed for TS0 of BCCH-TRX */
1834 if (ts->trx == ts->trx->bts->c0 &&
1835 ts->nr == 0)
1836 return -EINVAL;
1837 /* not on the same TRX that has a BCCH+SDCCH4
1838 * combination */
1839 if (ts->trx == ts->trx->bts->c0 &&
1840 (ts->trx->ts[0].nm_chan_comb == 5 ||
1841 ts->trx->ts[0].nm_chan_comb == 8))
1842 return -EINVAL;
1843 break;
1844 case NM_CHANC_mainBCCH:
1845 case NM_CHANC_BCCHComb:
1846 /* allowed only for TS0 of C0 */
1847 if (ts->trx != ts->trx->bts->c0 ||
1848 ts->nr != 0)
1849 return -EINVAL;
1850 break;
1851 case NM_CHANC_BCCH:
1852 /* allowed only for TS 2/4/6 of C0 */
1853 if (ts->trx != ts->trx->bts->c0)
1854 return -EINVAL;
1855 if (ts->nr != 2 && ts->nr != 4 &&
1856 ts->nr != 6)
1857 return -EINVAL;
1858 break;
1859 case 8: /* this is not like 08.58, but in fact
1860 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1861 /* FIXME: only one CBCH allowed per cell */
1862 break;
1863 }
Harald Welted6575f92009-12-02 02:45:23 +05301864 break;
1865 case GSM_BTS_TYPE_NANOBTS:
1866 switch (ts->nr) {
1867 case 0:
1868 if (ts->trx->nr == 0) {
1869 /* only on TRX0 */
1870 switch (chan_comb) {
1871 case NM_CHANC_BCCH:
1872 case NM_CHANC_mainBCCH:
1873 case NM_CHANC_BCCHComb:
1874 return 0;
1875 break;
1876 default:
1877 return -EINVAL;
1878 }
1879 } else {
1880 switch (chan_comb) {
1881 case NM_CHANC_TCHFull:
1882 case NM_CHANC_TCHHalf:
1883 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1884 return 0;
1885 default:
1886 return -EINVAL;
1887 }
1888 }
1889 break;
1890 case 1:
1891 if (ts->trx->nr == 0) {
1892 switch (chan_comb) {
1893 case NM_CHANC_SDCCH_CBCH:
1894 if (ts->trx->ts[0].nm_chan_comb ==
1895 NM_CHANC_mainBCCH)
1896 return 0;
1897 return -EINVAL;
1898 case NM_CHANC_SDCCH:
1899 case NM_CHANC_TCHFull:
1900 case NM_CHANC_TCHHalf:
1901 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1902 case NM_CHANC_IPAC_TCHFull_PDCH:
1903 return 0;
1904 }
1905 } else {
1906 switch (chan_comb) {
1907 case NM_CHANC_SDCCH:
1908 case NM_CHANC_TCHFull:
1909 case NM_CHANC_TCHHalf:
1910 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1911 return 0;
1912 default:
1913 return -EINVAL;
1914 }
1915 }
1916 break;
1917 case 2:
1918 case 3:
1919 case 4:
1920 case 5:
1921 case 6:
1922 case 7:
1923 switch (chan_comb) {
1924 case NM_CHANC_TCHFull:
1925 case NM_CHANC_TCHHalf:
1926 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1927 return 0;
1928 case NM_CHANC_IPAC_PDCH:
1929 case NM_CHANC_IPAC_TCHFull_PDCH:
1930 if (ts->trx->nr == 0)
1931 return 0;
1932 else
1933 return -EINVAL;
1934 }
1935 break;
1936 }
1937 return -EINVAL;
1938 default:
1939 /* unknown BTS type */
1940 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001941 }
1942 return 0;
1943}
1944
Harald Welte22af0db2009-02-14 15:41:08 +00001945/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001946int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1947{
1948 struct gsm_bts *bts = ts->trx->bts;
1949 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001950 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001951 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001952 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001953 u_int8_t len = 2 + 2;
1954
1955 if (bts->type == GSM_BTS_TYPE_BS11)
1956 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001957
Harald Weltef325eb42009-02-19 17:07:39 +00001958 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001959 if (verify_chan_comb(ts, chan_comb) < 0) {
1960 msgb_free(msg);
1961 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1962 return -EINVAL;
1963 }
1964 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001965
Harald Welte52b1f982008-12-23 20:25:15 +00001966 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001967 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001968 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001969 ts->trx->nr, ts->nr);
1970 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00001971 if (bts->type == GSM_BTS_TYPE_BS11)
1972 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001973 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00001974 if (bts->type == GSM_BTS_TYPE_BS11) {
1975 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1976 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1977 }
Harald Weltee6c22d92009-07-21 20:40:05 +02001978 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001979 if (bts->type == GSM_BTS_TYPE_BS11)
1980 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001981
1982 return abis_nm_sendmsg(bts, msg);
1983}
1984
Harald Welte34a99682009-02-13 02:41:40 +00001985int 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 +00001986 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001987{
1988 struct abis_om_hdr *oh;
1989 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00001990 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1991 u_int8_t len = att_len;
1992
1993 if (nack) {
1994 len += 2;
1995 msgtype = NM_MT_SW_ACT_REQ_NACK;
1996 }
Harald Welte34a99682009-02-13 02:41:40 +00001997
1998 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001999 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2000
Harald Welte34a99682009-02-13 02:41:40 +00002001 if (attr) {
2002 u_int8_t *ptr = msgb_put(msg, att_len);
2003 memcpy(ptr, attr, att_len);
2004 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002005 if (nack)
2006 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002007
2008 return abis_nm_sendmsg(bts, msg);
2009}
2010
Harald Welte8470bf22008-12-25 23:28:35 +00002011int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002012{
Harald Welte8470bf22008-12-25 23:28:35 +00002013 struct msgb *msg = nm_msgb_alloc();
2014 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002015 u_int8_t *data;
2016
2017 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2018 fill_om_hdr(oh, len);
2019 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002020 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002021
2022 return abis_nm_sendmsg(bts, msg);
2023}
2024
2025/* Siemens specific commands */
2026static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2027{
2028 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002029 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002030
2031 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002032 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002033 0xff, 0xff, 0xff);
2034
2035 return abis_nm_sendmsg(bts, msg);
2036}
2037
Harald Welte34a99682009-02-13 02:41:40 +00002038/* Chapter 8.9.2 */
2039int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2040{
2041 struct abis_om_hdr *oh;
2042 struct msgb *msg = nm_msgb_alloc();
2043
2044 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2045 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2046
Harald Weltea8bd6d42009-10-20 09:56:18 +02002047 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2048 DEBUGPC(DNM, "Sending OPSTART\n");
2049
Harald Welte34a99682009-02-13 02:41:40 +00002050 return abis_nm_sendmsg(bts, msg);
2051}
2052
2053/* Chapter 8.8.5 */
2054int 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 +02002055 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002056{
2057 struct abis_om_hdr *oh;
2058 struct msgb *msg = nm_msgb_alloc();
2059
2060 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2061 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2062 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2063
2064 return abis_nm_sendmsg(bts, msg);
2065}
2066
Harald Welte1989c082009-08-06 17:58:31 +02002067int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2068 u_int8_t e1_port1, u_int8_t ts1)
2069{
2070 struct abis_om_hdr *oh;
2071 struct msgb *msg = nm_msgb_alloc();
2072 u_int8_t *attr;
2073
2074 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2075 e1_port0, ts0, e1_port1, ts1);
2076
2077 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2078 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2079 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2080
2081 attr = msgb_put(msg, 3);
2082 attr[0] = NM_ATT_MDROP_LINK;
2083 attr[1] = e1_port0;
2084 attr[2] = ts0;
2085
2086 attr = msgb_put(msg, 3);
2087 attr[0] = NM_ATT_MDROP_NEXT;
2088 attr[1] = e1_port1;
2089 attr[2] = ts1;
2090
2091 return abis_nm_sendmsg(bts, msg);
2092}
Harald Welte34a99682009-02-13 02:41:40 +00002093
Harald Weltec7310382009-08-08 00:02:36 +02002094/* Chapter 8.7.1 */
2095int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2096 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2097 u_int8_t test_nr, u_int8_t auton_report,
2098 u_int8_t *phys_config, u_int16_t phys_config_len)
2099{
2100 struct abis_om_hdr *oh;
2101 struct msgb *msg = nm_msgb_alloc();
2102 int len = 4; /* 2 TV attributes */
2103
2104 DEBUGP(DNM, "PEFORM TEST\n");
2105
2106 if (phys_config_len)
2107 len += 3 + phys_config_len;
2108
2109 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2110 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2111 obj_class, bts_nr, trx_nr, ts_nr);
2112 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2113 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2114 if (phys_config_len)
2115 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2116 phys_config);
2117
2118 return abis_nm_sendmsg(bts, msg);
2119}
2120
Harald Welte52b1f982008-12-23 20:25:15 +00002121int abis_nm_event_reports(struct gsm_bts *bts, int on)
2122{
2123 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002124 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002125 else
Harald Welte227d4072009-01-03 08:16:25 +00002126 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002127}
2128
Harald Welte47d88ae2009-01-04 12:02:08 +00002129/* Siemens (or BS-11) specific commands */
2130
Harald Welte3ffd1372009-02-01 22:15:49 +00002131int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2132{
2133 if (reconnect == 0)
2134 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2135 else
2136 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2137}
2138
Harald Welteb8427972009-02-05 19:27:17 +00002139int abis_nm_bs11_restart(struct gsm_bts *bts)
2140{
2141 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2142}
2143
2144
Harald Welte268bb402009-02-01 19:11:56 +00002145struct bs11_date_time {
2146 u_int16_t year;
2147 u_int8_t month;
2148 u_int8_t day;
2149 u_int8_t hour;
2150 u_int8_t min;
2151 u_int8_t sec;
2152} __attribute__((packed));
2153
2154
2155void get_bs11_date_time(struct bs11_date_time *aet)
2156{
2157 time_t t;
2158 struct tm *tm;
2159
2160 t = time(NULL);
2161 tm = localtime(&t);
2162 aet->sec = tm->tm_sec;
2163 aet->min = tm->tm_min;
2164 aet->hour = tm->tm_hour;
2165 aet->day = tm->tm_mday;
2166 aet->month = tm->tm_mon;
2167 aet->year = htons(1900 + tm->tm_year);
2168}
2169
Harald Welte05188ee2009-01-18 11:39:08 +00002170int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002171{
Harald Welte4668fda2009-01-03 08:19:29 +00002172 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002173}
2174
Harald Welte05188ee2009-01-18 11:39:08 +00002175int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002176{
2177 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002178 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002179 else
Harald Welte4668fda2009-01-03 08:19:29 +00002180 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002181}
Harald Welte47d88ae2009-01-04 12:02:08 +00002182
Harald Welte05188ee2009-01-18 11:39:08 +00002183int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002184 enum abis_bs11_objtype type, u_int8_t idx,
2185 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002186{
2187 struct abis_om_hdr *oh;
2188 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002189 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002190
2191 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002192 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002193 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002194 cur = msgb_put(msg, attr_len);
2195 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002196
2197 return abis_nm_sendmsg(bts, msg);
2198}
2199
Harald Welte78fc0d42009-02-19 02:50:57 +00002200int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2201 enum abis_bs11_objtype type, u_int8_t idx)
2202{
2203 struct abis_om_hdr *oh;
2204 struct msgb *msg = nm_msgb_alloc();
2205
2206 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2207 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2208 NM_OC_BS11, type, 0, idx);
2209
2210 return abis_nm_sendmsg(bts, msg);
2211}
2212
Harald Welte05188ee2009-01-18 11:39:08 +00002213int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002214{
2215 struct abis_om_hdr *oh;
2216 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002217 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002218
2219 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002220 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002221 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2222 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002223
2224 return abis_nm_sendmsg(bts, msg);
2225}
2226
Harald Welte05188ee2009-01-18 11:39:08 +00002227int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002228{
2229 struct abis_om_hdr *oh;
2230 struct msgb *msg = nm_msgb_alloc();
2231
2232 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2233 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002234 idx, 0xff, 0xff);
2235
2236 return abis_nm_sendmsg(bts, msg);
2237}
2238
2239int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2240{
2241 struct abis_om_hdr *oh;
2242 struct msgb *msg = nm_msgb_alloc();
2243
2244 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2245 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2246 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002247
2248 return abis_nm_sendmsg(bts, msg);
2249}
Harald Welte05188ee2009-01-18 11:39:08 +00002250
Harald Welte78fc0d42009-02-19 02:50:57 +00002251static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2252int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2253{
2254 struct abis_om_hdr *oh;
2255 struct msgb *msg = nm_msgb_alloc();
2256
2257 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2258 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2259 0xff, 0xff, 0xff);
2260 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2261
2262 return abis_nm_sendmsg(bts, msg);
2263}
2264
Harald Welteb6c92ae2009-02-21 20:15:32 +00002265/* like abis_nm_conn_terr_traf + set_tei */
2266int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2267 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2268 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002269{
2270 struct abis_om_hdr *oh;
2271 struct abis_nm_channel *ch;
2272 struct msgb *msg = nm_msgb_alloc();
2273
2274 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002275 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002276 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2277
2278 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2279 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002280 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002281
2282 return abis_nm_sendmsg(bts, msg);
2283}
2284
2285int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2286{
2287 struct abis_om_hdr *oh;
2288 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002289
2290 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002291 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002292 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2293 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2294
2295 return abis_nm_sendmsg(trx->bts, msg);
2296}
2297
Harald Welte78fc0d42009-02-19 02:50:57 +00002298int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2299{
2300 struct abis_om_hdr *oh;
2301 struct msgb *msg = nm_msgb_alloc();
2302 u_int8_t attr = NM_ATT_BS11_TXPWR;
2303
2304 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2305 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2306 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2307 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2308
2309 return abis_nm_sendmsg(trx->bts, msg);
2310}
2311
Harald Welteaaf02d92009-04-29 13:25:57 +00002312int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2313{
2314 struct abis_om_hdr *oh;
2315 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002316 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002317
2318 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2319 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2320 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002321 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002322
2323 return abis_nm_sendmsg(bts, msg);
2324}
2325
Harald Welteef061952009-05-17 12:43:42 +00002326int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2327{
2328 struct abis_om_hdr *oh;
2329 struct msgb *msg = nm_msgb_alloc();
2330 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2331 NM_ATT_BS11_CCLK_TYPE };
2332
2333 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2334 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2335 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2336 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2337
2338 return abis_nm_sendmsg(bts, msg);
2339
2340}
Harald Welteaaf02d92009-04-29 13:25:57 +00002341
Harald Welte268bb402009-02-01 19:11:56 +00002342//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002343
Harald Welte1bc09062009-01-18 14:17:52 +00002344int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002345{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002346 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2347}
2348
Daniel Willmann4b054c82010-01-07 00:46:26 +01002349int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2350{
2351 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2352}
2353
Daniel Willmann493db4e2010-01-07 00:43:11 +01002354int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2355{
Harald Welte05188ee2009-01-18 11:39:08 +00002356 struct abis_om_hdr *oh;
2357 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002358 struct bs11_date_time bdt;
2359
2360 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002361
2362 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002363 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002364 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002365 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002366 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002367 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002368 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002369 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002370 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002371 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002372 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002373 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002374 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002375 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002376 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002377 }
Harald Welte05188ee2009-01-18 11:39:08 +00002378
2379 return abis_nm_sendmsg(bts, msg);
2380}
Harald Welte1bc09062009-01-18 14:17:52 +00002381
2382int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2383{
2384 struct abis_om_hdr *oh;
2385 struct msgb *msg;
2386
2387 if (strlen(password) != 10)
2388 return -EINVAL;
2389
2390 msg = nm_msgb_alloc();
2391 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002392 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002393 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2394 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2395
2396 return abis_nm_sendmsg(bts, msg);
2397}
2398
Harald Weltee69f5fb2009-04-28 16:31:38 +00002399/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2400int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2401{
2402 struct abis_om_hdr *oh;
2403 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002404 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002405
2406 msg = nm_msgb_alloc();
2407 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2408 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2409 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002410
2411 if (locked)
2412 tlv_value = BS11_LI_PLL_LOCKED;
2413 else
2414 tlv_value = BS11_LI_PLL_STANDALONE;
2415
2416 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002417
2418 return abis_nm_sendmsg(bts, msg);
2419}
2420
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002421/* Set the calibration value of the PLL (work value/set value)
2422 * It depends on the login which one is changed */
2423int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2424{
2425 struct abis_om_hdr *oh;
2426 struct msgb *msg;
2427 u_int8_t tlv_value[2];
2428
2429 msg = nm_msgb_alloc();
2430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2431 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2432 BS11_OBJ_TRX1, 0x00, 0x00);
2433
2434 tlv_value[0] = value>>8;
2435 tlv_value[1] = value&0xff;
2436
2437 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2438
2439 return abis_nm_sendmsg(bts, msg);
2440}
2441
Harald Welte1bc09062009-01-18 14:17:52 +00002442int abis_nm_bs11_get_state(struct gsm_bts *bts)
2443{
2444 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2445}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002446
2447/* BS11 SWL */
2448
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002449void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002450
Harald Welte5e4d1b32009-02-01 13:36:56 +00002451struct abis_nm_bs11_sw {
2452 struct gsm_bts *bts;
2453 char swl_fname[PATH_MAX];
2454 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002455 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002456 struct llist_head file_list;
2457 gsm_cbfn *user_cb; /* specified by the user */
2458};
2459static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2460
2461struct file_list_entry {
2462 struct llist_head list;
2463 char fname[PATH_MAX];
2464};
2465
2466struct file_list_entry *fl_dequeue(struct llist_head *queue)
2467{
2468 struct llist_head *lh;
2469
2470 if (llist_empty(queue))
2471 return NULL;
2472
2473 lh = queue->next;
2474 llist_del(lh);
2475
2476 return llist_entry(lh, struct file_list_entry, list);
2477}
2478
2479static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2480{
2481 char linebuf[255];
2482 struct llist_head *lh, *lh2;
2483 FILE *swl;
2484 int rc = 0;
2485
2486 swl = fopen(bs11_sw->swl_fname, "r");
2487 if (!swl)
2488 return -ENODEV;
2489
2490 /* zero the stale file list, if any */
2491 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2492 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002493 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002494 }
2495
2496 while (fgets(linebuf, sizeof(linebuf), swl)) {
2497 char file_id[12+1];
2498 char file_version[80+1];
2499 struct file_list_entry *fle;
2500 static char dir[PATH_MAX];
2501
2502 if (strlen(linebuf) < 4)
2503 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002504
Harald Welte5e4d1b32009-02-01 13:36:56 +00002505 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2506 if (rc < 0) {
2507 perror("ERR parsing SWL file");
2508 rc = -EINVAL;
2509 goto out;
2510 }
2511 if (rc < 2)
2512 continue;
2513
Harald Welte470ec292009-06-26 20:25:23 +02002514 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002515 if (!fle) {
2516 rc = -ENOMEM;
2517 goto out;
2518 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002519
2520 /* construct new filename */
2521 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2522 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2523 strcat(fle->fname, "/");
2524 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002525
2526 llist_add_tail(&fle->list, &bs11_sw->file_list);
2527 }
2528
2529out:
2530 fclose(swl);
2531 return rc;
2532}
2533
2534/* bs11 swload specific callback, passed to abis_nm core swload */
2535static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2536 struct msgb *msg, void *data, void *param)
2537{
2538 struct abis_nm_bs11_sw *bs11_sw = data;
2539 struct file_list_entry *fle;
2540 int rc = 0;
2541
Harald Welte5e4d1b32009-02-01 13:36:56 +00002542 switch (event) {
2543 case NM_MT_LOAD_END_ACK:
2544 fle = fl_dequeue(&bs11_sw->file_list);
2545 if (fle) {
2546 /* start download the next file of our file list */
2547 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2548 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002549 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002550 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002551 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002552 } else {
2553 /* activate the SWL */
2554 rc = abis_nm_software_activate(bs11_sw->bts,
2555 bs11_sw->swl_fname,
2556 bs11_swload_cbfn,
2557 bs11_sw);
2558 }
2559 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002560 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002561 case NM_MT_LOAD_END_NACK:
2562 case NM_MT_LOAD_INIT_ACK:
2563 case NM_MT_LOAD_INIT_NACK:
2564 case NM_MT_ACTIVATE_SW_NACK:
2565 case NM_MT_ACTIVATE_SW_ACK:
2566 default:
2567 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002568 if (bs11_sw->user_cb)
2569 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002570 break;
2571 }
2572
2573 return rc;
2574}
2575
2576/* Siemens provides a SWL file that is a mere listing of all the other
2577 * files that are part of a software release. We need to upload first
2578 * the list file, and then each file that is listed in the list file */
2579int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002580 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002581{
2582 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2583 struct file_list_entry *fle;
2584 int rc = 0;
2585
2586 INIT_LLIST_HEAD(&bs11_sw->file_list);
2587 bs11_sw->bts = bts;
2588 bs11_sw->win_size = win_size;
2589 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002590 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002591
2592 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2593 rc = bs11_read_swl_file(bs11_sw);
2594 if (rc < 0)
2595 return rc;
2596
2597 /* dequeue next item in file list */
2598 fle = fl_dequeue(&bs11_sw->file_list);
2599 if (!fle)
2600 return -EINVAL;
2601
2602 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002603 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002604 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002605 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002606 return rc;
2607}
2608
Harald Welte5083b0b2009-02-02 19:20:52 +00002609#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002610static u_int8_t req_attr_btse[] = {
2611 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2612 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2613 NM_ATT_BS11_LMT_USER_NAME,
2614
2615 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2616
2617 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2618
2619 NM_ATT_BS11_SW_LOAD_STORED };
2620
2621static u_int8_t req_attr_btsm[] = {
2622 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2623 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2624 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2625 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002626#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002627
2628static u_int8_t req_attr[] = {
2629 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2630 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002631 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002632
2633int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2634{
2635 struct abis_om_hdr *oh;
2636 struct msgb *msg = nm_msgb_alloc();
2637
2638 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2639 /* SiemensHW CCTRL object */
2640 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2641 0x03, 0x00, 0x00);
2642 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2643
2644 return abis_nm_sendmsg(bts, msg);
2645}
Harald Welte268bb402009-02-01 19:11:56 +00002646
2647int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2648{
2649 struct abis_om_hdr *oh;
2650 struct msgb *msg = nm_msgb_alloc();
2651 struct bs11_date_time aet;
2652
2653 get_bs11_date_time(&aet);
2654 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2655 /* SiemensHW CCTRL object */
2656 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2657 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002658 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002659
2660 return abis_nm_sendmsg(bts, msg);
2661}
Harald Welte5c1e4582009-02-15 11:57:29 +00002662
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002663int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2664{
2665 struct abis_om_hdr *oh;
2666 struct msgb *msg = nm_msgb_alloc();
2667 struct bs11_date_time aet;
2668
2669 get_bs11_date_time(&aet);
2670 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2671 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2672 bport, 0xff, 0x02);
2673 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2674
2675 return abis_nm_sendmsg(bts, msg);
2676}
2677
Harald Welte5c1e4582009-02-15 11:57:29 +00002678/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002679static const char ipaccess_magic[] = "com.ipaccess";
2680
Harald Welte677c21f2009-02-17 13:22:23 +00002681
2682static int abis_nm_rx_ipacc(struct msgb *msg)
2683{
2684 struct abis_om_hdr *oh = msgb_l2(msg);
2685 struct abis_om_fom_hdr *foh;
2686 u_int8_t idstrlen = oh->data[0];
2687 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002688 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002689
2690 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002691 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002692 return -EINVAL;
2693 }
2694
Harald Welte193fefc2009-04-30 15:16:27 +00002695 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002696 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002697
Harald Weltea8bd6d42009-10-20 09:56:18 +02002698 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002699
Harald Welte746d6092009-10-19 22:11:11 +02002700 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002701
Harald Welte677c21f2009-02-17 13:22:23 +00002702 switch (foh->msg_type) {
2703 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002704 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002705 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002706 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002707 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002708 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2709 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002710 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002711 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002712 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002713 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2714 DEBUGPC(DNM, "STREAM=0x%02x ",
2715 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002716 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002717 break;
2718 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002719 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002720 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002721 DEBUGPC(DNM, " CAUSE=%s\n",
2722 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002723 else
2724 DEBUGPC(DNM, "\n");
2725 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002726 case NM_MT_IPACC_SET_NVATTR_ACK:
2727 DEBUGPC(DNM, "SET NVATTR ACK\n");
2728 /* FIXME: decode and show the actual attributes */
2729 break;
2730 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002731 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002732 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002733 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002734 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2735 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002736 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002737 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002738 case NM_MT_IPACC_GET_NVATTR_ACK:
2739 DEBUGPC(DNM, "GET NVATTR ACK\n");
2740 /* FIXME: decode and show the actual attributes */
2741 break;
2742 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002743 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002744 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002745 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002746 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2747 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002748 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002749 break;
Harald Welte15c44172009-10-08 20:15:24 +02002750 case NM_MT_IPACC_SET_ATTR_ACK:
2751 DEBUGPC(DNM, "SET ATTR ACK\n");
2752 break;
2753 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002754 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002755 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002756 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002757 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2758 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002759 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002760 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002761 default:
2762 DEBUGPC(DNM, "unknown\n");
2763 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002764 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002765
2766 /* signal handling */
2767 switch (foh->msg_type) {
2768 case NM_MT_IPACC_RSL_CONNECT_NACK:
2769 case NM_MT_IPACC_SET_NVATTR_NACK:
2770 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002771 signal.bts = msg->trx->bts;
2772 signal.msg_type = foh->msg_type;
2773 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002774 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002775 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002776 signal.bts = msg->trx->bts;
2777 signal.msg_type = foh->msg_type;
2778 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002779 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002780 default:
2781 break;
2782 }
2783
Harald Welte677c21f2009-02-17 13:22:23 +00002784 return 0;
2785}
2786
Harald Welte193fefc2009-04-30 15:16:27 +00002787/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002788int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2789 u_int8_t obj_class, u_int8_t bts_nr,
2790 u_int8_t trx_nr, u_int8_t ts_nr,
2791 u_int8_t *attr, int attr_len)
2792{
2793 struct msgb *msg = nm_msgb_alloc();
2794 struct abis_om_hdr *oh;
2795 struct abis_om_fom_hdr *foh;
2796 u_int8_t *data;
2797
2798 /* construct the 12.21 OM header, observe the erroneous length */
2799 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2800 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2801 oh->mdisc = ABIS_OM_MDISC_MANUF;
2802
2803 /* add the ip.access magic */
2804 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2805 *data++ = sizeof(ipaccess_magic);
2806 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2807
2808 /* fill the 12.21 FOM header */
2809 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2810 foh->msg_type = msg_type;
2811 foh->obj_class = obj_class;
2812 foh->obj_inst.bts_nr = bts_nr;
2813 foh->obj_inst.trx_nr = trx_nr;
2814 foh->obj_inst.ts_nr = ts_nr;
2815
2816 if (attr && attr_len) {
2817 data = msgb_put(msg, attr_len);
2818 memcpy(data, attr, attr_len);
2819 }
2820
2821 return abis_nm_sendmsg(bts, msg);
2822}
Harald Welte677c21f2009-02-17 13:22:23 +00002823
Harald Welte193fefc2009-04-30 15:16:27 +00002824/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002825int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002826 int attr_len)
2827{
Harald Welte2ef156d2010-01-07 20:39:42 +01002828 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2829 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002830 attr_len);
2831}
2832
Harald Welte746d6092009-10-19 22:11:11 +02002833int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2834 u_int32_t ip, u_int16_t port, u_int8_t stream)
2835{
2836 struct in_addr ia;
2837 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2838 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2839 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2840
2841 int attr_len = sizeof(attr);
2842
2843 ia.s_addr = htonl(ip);
2844 attr[1] = stream;
2845 attr[3] = port >> 8;
2846 attr[4] = port & 0xff;
2847 *(u_int32_t *)(attr+6) = ia.s_addr;
2848
2849 /* if ip == 0, we use the default IP */
2850 if (ip == 0)
2851 attr_len -= 5;
2852
2853 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002854 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002855
2856 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2857 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2858 trx->nr, 0xff, attr, attr_len);
2859}
2860
Harald Welte193fefc2009-04-30 15:16:27 +00002861/* restart / reboot an ip.access nanoBTS */
2862int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2863{
2864 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2865}
Harald Weltedaef5212009-10-24 10:20:41 +02002866
2867int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2868 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2869 u_int8_t *attr, u_int8_t attr_len)
2870{
2871 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2872 obj_class, bts_nr, trx_nr, ts_nr,
2873 attr, attr_len);
2874}
Harald Welte0f255852009-11-12 14:48:42 +01002875
Harald Welte97a282b2010-03-14 15:37:43 +08002876void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2877{
2878 /* we simply reuse the GSM48 function and overwrite the RAC
2879 * with the Cell ID */
2880 gsm48_ra_id_by_bts(buf, bts);
2881 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2882}
2883
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002884void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2885{
2886 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2887
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002888 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002889 if (!trx->bts || !trx->bts->oml_link)
2890 return;
2891
2892 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2893 trx->bts->bts_nr, trx->nr, 0xff,
2894 new_state);
2895}
2896
Harald Welte0f255852009-11-12 14:48:42 +01002897static const char *ipacc_testres_names[] = {
2898 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2899 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2900 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2901 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2902 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2903};
2904
2905const char *ipacc_testres_name(u_int8_t res)
2906{
2907 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2908 ipacc_testres_names[res])
2909 return ipacc_testres_names[res];
2910
2911 return "unknown";
2912}
2913
Harald Welteb40a38f2009-11-13 11:56:05 +01002914void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2915{
2916 cid->mcc = (buf[0] & 0xf) * 100;
2917 cid->mcc += (buf[0] >> 4) * 10;
2918 cid->mcc += (buf[1] & 0xf) * 1;
2919
2920 if (buf[1] >> 4 == 0xf) {
2921 cid->mnc = (buf[2] & 0xf) * 10;
2922 cid->mnc += (buf[2] >> 4) * 1;
2923 } else {
2924 cid->mnc = (buf[2] & 0xf) * 100;
2925 cid->mnc += (buf[2] >> 4) * 10;
2926 cid->mnc += (buf[1] >> 4) * 1;
2927 }
2928
Harald Welteaff237d2009-11-13 14:41:52 +01002929 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2930 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002931}
2932
Harald Welte0f255852009-11-12 14:48:42 +01002933/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2934int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2935{
2936 u_int8_t *cur = buf;
2937 u_int16_t len;
2938
2939 memset(binf, 0, sizeof(binf));
2940
2941 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2942 return -EINVAL;
2943 cur++;
2944
2945 len = ntohs(*(u_int16_t *)cur);
2946 cur += 2;
2947
2948 binf->info_type = ntohs(*(u_int16_t *)cur);
2949 cur += 2;
2950
2951 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2952 binf->freq_qual = *cur >> 2;
2953
2954 binf->arfcn = *cur++ & 3 << 8;
2955 binf->arfcn |= *cur++;
2956
2957 if (binf->info_type & IPAC_BINF_RXLEV)
2958 binf->rx_lev = *cur & 0x3f;
2959 cur++;
2960
2961 if (binf->info_type & IPAC_BINF_RXQUAL)
2962 binf->rx_qual = *cur & 0x7;
2963 cur++;
2964
2965 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2966 binf->freq_err = ntohs(*(u_int16_t *)cur);
2967 cur += 2;
2968
2969 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2970 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2971 cur += 2;
2972
2973 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2974 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2975 cur += 4;
2976
2977 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01002978 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002979 cur++;
2980
Harald Welteb40a38f2009-11-13 11:56:05 +01002981 ipac_parse_cgi(&binf->cgi, cur);
2982 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002983
2984 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2985 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2986 cur += sizeof(binf->ba_list_si2);
2987 }
2988
2989 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2990 memcpy(binf->ba_list_si2bis, cur,
2991 sizeof(binf->ba_list_si2bis));
2992 cur += sizeof(binf->ba_list_si2bis);
2993 }
2994
2995 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2996 memcpy(binf->ba_list_si2ter, cur,
2997 sizeof(binf->ba_list_si2ter));
2998 cur += sizeof(binf->ba_list_si2ter);
2999 }
3000
3001 return 0;
3002}