blob: 99d8dd62135dd4b926fb5a766d54e154738f15d4 [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 Welte5c1e4582009-02-15 11:57:29 +0000859 int nack = 0;
Harald Welte34a99682009-02-13 02:41:40 +0000860 int ret;
861
Harald Weltea8bd6d42009-10-20 09:56:18 +0200862 debugp_foh(foh);
863
864 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000865
Harald Welte5c1e4582009-02-15 11:57:29 +0000866 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
867 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
868 nack = 1;
869 } else
870 DEBUGPC(DNM, "ACKing and Activating\n");
871
872 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000873 foh->obj_inst.bts_nr,
874 foh->obj_inst.trx_nr,
Harald Welte5c1e4582009-02-15 11:57:29 +0000875 foh->obj_inst.ts_nr, nack,
Harald Welte34a99682009-02-13 02:41:40 +0000876 foh->data, oh->length-sizeof(*foh));
877
Harald Welte5c1e4582009-02-15 11:57:29 +0000878 if (nack)
879 return ret;
880
Harald Welte39315c42010-01-10 18:01:52 +0100881 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200882 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
883 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
884 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
885 DEBUGP(DNM, "SW config not found! Can't continue.\n");
886 return -EINVAL;
887 } else {
888 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
889 }
890
891 if (sw_config[0] != NM_ATT_SW_DESCR)
892 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
893 if (sw_config[1] != NM_ATT_FILE_ID)
894 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
895 file_id_len = sw_config[2] * 256 + sw_config[3];
896
897 /* Assumes first SW file in list is the one to be activated */
898 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000899 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
900 foh->obj_inst.bts_nr,
901 foh->obj_inst.trx_nr,
902 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200903 sw_config + 4,
904 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000905}
906
Harald Weltee0590df2009-02-15 03:34:15 +0000907/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
908static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
909{
910 struct abis_om_hdr *oh = msgb_l2(mb);
911 struct abis_om_fom_hdr *foh = msgb_l3(mb);
912 struct tlv_parsed tp;
913 u_int8_t adm_state;
914
Harald Welte39315c42010-01-10 18:01:52 +0100915 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000916 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
917 return -EINVAL;
918
919 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
920
921 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
922}
923
Harald Welteee670472009-02-22 21:58:49 +0000924static int abis_nm_rx_lmt_event(struct msgb *mb)
925{
926 struct abis_om_hdr *oh = msgb_l2(mb);
927 struct abis_om_fom_hdr *foh = msgb_l3(mb);
928 struct tlv_parsed tp;
929
930 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100931 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000932 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
933 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
934 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
935 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
936 }
937 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
938 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
939 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
940 DEBUGPC(DNM, "Level=%u ", level);
941 }
942 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
943 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
944 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
945 DEBUGPC(DNM, "Username=%s ", name);
946 }
947 DEBUGPC(DNM, "\n");
948 /* FIXME: parse LMT LOGON TIME */
949 return 0;
950}
951
Harald Welte52b1f982008-12-23 20:25:15 +0000952/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000953static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000954{
Harald Welte6c96ba52009-05-01 13:03:40 +0000955 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000956 struct abis_om_fom_hdr *foh = msgb_l3(mb);
957 u_int8_t mt = foh->msg_type;
958
959 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000960 if (is_report(mt))
961 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000962
Harald Welte4724f992009-01-18 18:01:49 +0000963 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
964 return abis_nm_rcvmsg_sw(mb);
965
Harald Welte78fc0d42009-02-19 02:50:57 +0000966 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +0000967 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200968
Harald Weltea8bd6d42009-10-20 09:56:18 +0200969 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200970
Harald Welte78fc0d42009-02-19 02:50:57 +0000971 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +0200972 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +0000973 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +0000974 else
Harald Welte4bd0a982009-10-08 20:18:59 +0200975 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +0000976
Harald Welte39315c42010-01-10 18:01:52 +0100977 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000978 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
979 DEBUGPC(DNM, "CAUSE=%s\n",
980 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
981 else
982 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200983
Harald Welted8cfc902009-11-17 06:09:56 +0100984 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200985 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000986 }
Harald Weltead384642008-12-26 10:20:07 +0000987#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000988 /* check if last message is to be acked */
989 if (is_ack_nack(nmh->last_msgtype)) {
990 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100991 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000992 /* we got our ACK, continue sending the next msg */
993 } else if (mt == MT_NACK(nmh->last_msgtype)) {
994 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100995 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000996 /* FIXME: somehow signal this to the caller */
997 } else {
998 /* really strange things happen */
999 return -EINVAL;
1000 }
1001 }
Harald Weltead384642008-12-26 10:20:07 +00001002#endif
1003
Harald Welte97ed1e72009-02-06 13:38:02 +00001004 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001005 case NM_MT_CHG_ADM_STATE_ACK:
1006 return abis_nm_rx_chg_adm_state_ack(mb);
1007 break;
Harald Welte34a99682009-02-13 02:41:40 +00001008 case NM_MT_SW_ACT_REQ:
1009 return abis_nm_rx_sw_act_req(mb);
1010 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001011 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001012 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001013 break;
Harald Welte1989c082009-08-06 17:58:31 +02001014 case NM_MT_CONN_MDROP_LINK_ACK:
1015 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1016 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001017 case NM_MT_IPACC_RESTART_ACK:
1018 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1019 break;
1020 case NM_MT_IPACC_RESTART_NACK:
1021 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1022 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001023 }
1024
Harald Weltead384642008-12-26 10:20:07 +00001025 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001026}
1027
Harald Welte677c21f2009-02-17 13:22:23 +00001028static int abis_nm_rx_ipacc(struct msgb *mb);
1029
1030static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1031{
1032 int rc;
1033 int bts_type = mb->trx->bts->type;
1034
1035 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001036 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001037 rc = abis_nm_rx_ipacc(mb);
1038 break;
1039 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001040 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1041 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001042 rc = 0;
1043 break;
1044 }
1045
1046 return rc;
1047}
1048
Harald Welte52b1f982008-12-23 20:25:15 +00001049/* High-Level API */
1050/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001051int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001052{
Harald Welte52b1f982008-12-23 20:25:15 +00001053 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001054 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001055
1056 /* Various consistency checks */
1057 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001058 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001059 oh->placement);
1060 return -EINVAL;
1061 }
1062 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001063 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001064 oh->sequence);
1065 return -EINVAL;
1066 }
Harald Welte702d8702008-12-26 20:25:35 +00001067#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001068 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1069 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001070 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001071 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001072 oh->length + sizeof(*oh), l2_len);
1073 return -EINVAL;
1074 }
Harald Welte702d8702008-12-26 20:25:35 +00001075 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001076 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 +00001077#endif
Harald Weltead384642008-12-26 10:20:07 +00001078 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001079
1080 switch (oh->mdisc) {
1081 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001082 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001083 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001084 case ABIS_OM_MDISC_MANUF:
1085 rc = abis_nm_rcvmsg_manuf(msg);
1086 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001087 case ABIS_OM_MDISC_MMI:
1088 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001089 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001090 oh->mdisc);
1091 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001092 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001093 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001094 oh->mdisc);
1095 return -EINVAL;
1096 }
1097
Harald Weltead384642008-12-26 10:20:07 +00001098 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001099 return rc;
1100}
1101
1102#if 0
1103/* initialized all resources */
1104struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1105{
1106 struct abis_nm_h *nmh;
1107
1108 nmh = malloc(sizeof(*nmh));
1109 if (!nmh)
1110 return NULL;
1111
1112 nmh->cfg = cfg;
1113
1114 return nmh;
1115}
1116
1117/* free all resources */
1118void abis_nm_fini(struct abis_nm_h *nmh)
1119{
1120 free(nmh);
1121}
1122#endif
1123
1124/* Here we are trying to define a high-level API that can be used by
1125 * the actual BSC implementation. However, the architecture is currently
1126 * still under design. Ideally the calls to this API would be synchronous,
1127 * while the underlying stack behind the APi runs in a traditional select
1128 * based state machine.
1129 */
1130
Harald Welte4724f992009-01-18 18:01:49 +00001131/* 6.2 Software Load: */
1132enum sw_state {
1133 SW_STATE_NONE,
1134 SW_STATE_WAIT_INITACK,
1135 SW_STATE_WAIT_SEGACK,
1136 SW_STATE_WAIT_ENDACK,
1137 SW_STATE_WAIT_ACTACK,
1138 SW_STATE_ERROR,
1139};
Harald Welte52b1f982008-12-23 20:25:15 +00001140
Harald Welte52b1f982008-12-23 20:25:15 +00001141struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001142 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001143 gsm_cbfn *cbfn;
1144 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001145 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001146
Harald Welte52b1f982008-12-23 20:25:15 +00001147 /* this will become part of the SW LOAD INITIATE */
1148 u_int8_t obj_class;
1149 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001150
1151 u_int8_t file_id[255];
1152 u_int8_t file_id_len;
1153
1154 u_int8_t file_version[255];
1155 u_int8_t file_version_len;
1156
1157 u_int8_t window_size;
1158 u_int8_t seg_in_window;
1159
1160 int fd;
1161 FILE *stream;
1162 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001163 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001164};
1165
Harald Welte4724f992009-01-18 18:01:49 +00001166static struct abis_nm_sw g_sw;
1167
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001168static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1169{
1170 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1171 msgb_v_put(msg, NM_ATT_SW_DESCR);
1172 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1173 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1174 sw->file_version);
1175 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1176 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1177 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1178 sw->file_version);
1179 } else {
1180 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1181 }
1182}
1183
Harald Welte4724f992009-01-18 18:01:49 +00001184/* 6.2.1 / 8.3.1: Load Data Initiate */
1185static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001186{
Harald Welte4724f992009-01-18 18:01:49 +00001187 struct abis_om_hdr *oh;
1188 struct msgb *msg = nm_msgb_alloc();
1189 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1190
1191 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1192 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1193 sw->obj_instance[0], sw->obj_instance[1],
1194 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001195
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001196 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001197 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1198
1199 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001200}
1201
Harald Welte1602ade2009-01-29 21:12:39 +00001202static int is_last_line(FILE *stream)
1203{
1204 char next_seg_buf[256];
1205 long pos;
1206
1207 /* check if we're sending the last line */
1208 pos = ftell(stream);
1209 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1210 fseek(stream, pos, SEEK_SET);
1211 return 1;
1212 }
1213
1214 fseek(stream, pos, SEEK_SET);
1215 return 0;
1216}
1217
Harald Welte4724f992009-01-18 18:01:49 +00001218/* 6.2.2 / 8.3.2 Load Data Segment */
1219static int sw_load_segment(struct abis_nm_sw *sw)
1220{
1221 struct abis_om_hdr *oh;
1222 struct msgb *msg = nm_msgb_alloc();
1223 char seg_buf[256];
1224 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001225 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001226 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001227
1228 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001229
1230 switch (sw->bts->type) {
1231 case GSM_BTS_TYPE_BS11:
1232 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1233 perror("fgets reading segment");
1234 return -EINVAL;
1235 }
1236 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001237
1238 /* check if we're sending the last line */
1239 sw->last_seg = is_last_line(sw->stream);
1240 if (sw->last_seg)
1241 seg_buf[1] = 0;
1242 else
1243 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001244
1245 len = strlen(line_buf) + 2;
1246 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1247 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1248 /* BS11 wants CR + LF in excess of the TLV length !?! */
1249 tlv[1] -= 2;
1250
1251 /* we only now know the exact length for the OM hdr */
1252 len = strlen(line_buf)+2;
1253 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001254 case GSM_BTS_TYPE_NANOBTS: {
1255 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1256 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1257 if (len < 0) {
1258 perror("read failed");
1259 return -EINVAL;
1260 }
1261
1262 if (len != IPACC_SEGMENT_SIZE)
1263 sw->last_seg = 1;
1264
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001265 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001266 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1267 len += 3;
1268 break;
1269 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001270 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001271 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001272 /* FIXME: Other BTS types */
1273 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001274 }
Harald Welte4724f992009-01-18 18:01:49 +00001275
Harald Welte4724f992009-01-18 18:01:49 +00001276 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1277 sw->obj_instance[0], sw->obj_instance[1],
1278 sw->obj_instance[2]);
1279
1280 return abis_nm_sendmsg(sw->bts, msg);
1281}
1282
1283/* 6.2.4 / 8.3.4 Load Data End */
1284static int sw_load_end(struct abis_nm_sw *sw)
1285{
1286 struct abis_om_hdr *oh;
1287 struct msgb *msg = nm_msgb_alloc();
1288 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1289
1290 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1291 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1292 sw->obj_instance[0], sw->obj_instance[1],
1293 sw->obj_instance[2]);
1294
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001295 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001296 return abis_nm_sendmsg(sw->bts, msg);
1297}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001298
Harald Welte52b1f982008-12-23 20:25:15 +00001299/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001300static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001301{
Harald Welte4724f992009-01-18 18:01:49 +00001302 struct abis_om_hdr *oh;
1303 struct msgb *msg = nm_msgb_alloc();
1304 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001305
Harald Welte4724f992009-01-18 18:01:49 +00001306 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1307 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1308 sw->obj_instance[0], sw->obj_instance[1],
1309 sw->obj_instance[2]);
1310
1311 /* FIXME: this is BS11 specific format */
1312 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1313 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1314 sw->file_version);
1315
1316 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001317}
Harald Welte4724f992009-01-18 18:01:49 +00001318
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001319struct sdp_firmware {
1320 char magic[4];
1321 char more_magic[4];
1322 unsigned int header_length;
1323 unsigned int file_length;
1324} __attribute__ ((packed));
1325
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001326static int parse_sdp_header(struct abis_nm_sw *sw)
1327{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001328 struct sdp_firmware firmware_header;
1329 int rc;
1330 struct stat stat;
1331
1332 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1333 if (rc != sizeof(firmware_header)) {
1334 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1335 return -1;
1336 }
1337
1338 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1339 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1340 return -1;
1341 }
1342
1343 if (firmware_header.more_magic[0] != 0x10 ||
1344 firmware_header.more_magic[1] != 0x02 ||
1345 firmware_header.more_magic[2] != 0x00 ||
1346 firmware_header.more_magic[3] != 0x00) {
1347 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1348 return -1;
1349 }
1350
1351
1352 if (fstat(sw->fd, &stat) == -1) {
1353 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1354 return -1;
1355 }
1356
1357 if (ntohl(firmware_header.file_length) != stat.st_size) {
1358 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1359 return -1;
1360 }
1361
1362 /* go back to the start as we checked the whole filesize.. */
1363 lseek(sw->fd, 0l, SEEK_SET);
1364 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1365 "There might be checksums in the file that are not\n"
1366 "verified and incomplete firmware might be flashed.\n"
1367 "There is absolutely no WARRANTY that flashing will\n"
1368 "work.\n");
1369 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001370}
1371
Harald Welte4724f992009-01-18 18:01:49 +00001372static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1373{
1374 char file_id[12+1];
1375 char file_version[80+1];
1376 int rc;
1377
1378 sw->fd = open(fname, O_RDONLY);
1379 if (sw->fd < 0)
1380 return sw->fd;
1381
1382 switch (sw->bts->type) {
1383 case GSM_BTS_TYPE_BS11:
1384 sw->stream = fdopen(sw->fd, "r");
1385 if (!sw->stream) {
1386 perror("fdopen");
1387 return -1;
1388 }
1389 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001390 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001391 file_id, file_version);
1392 if (rc != 2) {
1393 perror("parsing header line of software file");
1394 return -1;
1395 }
1396 strcpy((char *)sw->file_id, file_id);
1397 sw->file_id_len = strlen(file_id);
1398 strcpy((char *)sw->file_version, file_version);
1399 sw->file_version_len = strlen(file_version);
1400 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001401 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001402 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001403 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001404 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001405 rc = parse_sdp_header(sw);
1406 if (rc < 0) {
1407 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1408 return -1;
1409 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001410
1411 strcpy((char *)sw->file_id, "id");
1412 sw->file_id_len = 3;
1413 strcpy((char *)sw->file_version, "version");
1414 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001415 break;
Harald Welte4724f992009-01-18 18:01:49 +00001416 default:
1417 /* We don't know how to treat them yet */
1418 close(sw->fd);
1419 return -EINVAL;
1420 }
1421
1422 return 0;
1423}
1424
1425static void sw_close_file(struct abis_nm_sw *sw)
1426{
1427 switch (sw->bts->type) {
1428 case GSM_BTS_TYPE_BS11:
1429 fclose(sw->stream);
1430 break;
1431 default:
1432 close(sw->fd);
1433 break;
1434 }
1435}
1436
1437/* Fill the window */
1438static int sw_fill_window(struct abis_nm_sw *sw)
1439{
1440 int rc;
1441
1442 while (sw->seg_in_window < sw->window_size) {
1443 rc = sw_load_segment(sw);
1444 if (rc < 0)
1445 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001446 if (sw->last_seg)
1447 break;
Harald Welte4724f992009-01-18 18:01:49 +00001448 }
1449 return 0;
1450}
1451
1452/* callback function from abis_nm_rcvmsg() handler */
1453static int abis_nm_rcvmsg_sw(struct msgb *mb)
1454{
1455 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1456 int rc = -1;
1457 struct abis_nm_sw *sw = &g_sw;
1458 enum sw_state old_state = sw->state;
1459
Harald Welte3ffd1372009-02-01 22:15:49 +00001460 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001461
1462 switch (sw->state) {
1463 case SW_STATE_WAIT_INITACK:
1464 switch (foh->msg_type) {
1465 case NM_MT_LOAD_INIT_ACK:
1466 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001467 if (sw->cbfn)
1468 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1469 NM_MT_LOAD_INIT_ACK, mb,
1470 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001471 rc = sw_fill_window(sw);
1472 sw->state = SW_STATE_WAIT_SEGACK;
1473 break;
1474 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001475 if (sw->forced) {
1476 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1477 "Init NACK\n");
1478 if (sw->cbfn)
1479 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1480 NM_MT_LOAD_INIT_ACK, mb,
1481 sw->cb_data, NULL);
1482 rc = sw_fill_window(sw);
1483 sw->state = SW_STATE_WAIT_SEGACK;
1484 } else {
1485 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001486 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001487 if (sw->cbfn)
1488 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1489 NM_MT_LOAD_INIT_NACK, mb,
1490 sw->cb_data, NULL);
1491 sw->state = SW_STATE_ERROR;
1492 }
Harald Welte4724f992009-01-18 18:01:49 +00001493 break;
1494 }
1495 break;
1496 case SW_STATE_WAIT_SEGACK:
1497 switch (foh->msg_type) {
1498 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001499 if (sw->cbfn)
1500 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1501 NM_MT_LOAD_SEG_ACK, mb,
1502 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001503 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001504 if (!sw->last_seg) {
1505 /* fill window with more segments */
1506 rc = sw_fill_window(sw);
1507 sw->state = SW_STATE_WAIT_SEGACK;
1508 } else {
1509 /* end the transfer */
1510 sw->state = SW_STATE_WAIT_ENDACK;
1511 rc = sw_load_end(sw);
1512 }
Harald Welte4724f992009-01-18 18:01:49 +00001513 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001514 case NM_MT_LOAD_ABORT:
1515 if (sw->cbfn)
1516 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1517 NM_MT_LOAD_ABORT, mb,
1518 sw->cb_data, NULL);
1519 break;
Harald Welte4724f992009-01-18 18:01:49 +00001520 }
1521 break;
1522 case SW_STATE_WAIT_ENDACK:
1523 switch (foh->msg_type) {
1524 case NM_MT_LOAD_END_ACK:
1525 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001526 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1527 sw->bts->nr);
1528 sw->state = SW_STATE_NONE;
1529 if (sw->cbfn)
1530 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1531 NM_MT_LOAD_END_ACK, mb,
1532 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001533 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001534 break;
1535 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001536 if (sw->forced) {
1537 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1538 "End NACK\n");
1539 sw->state = SW_STATE_NONE;
1540 if (sw->cbfn)
1541 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1542 NM_MT_LOAD_END_ACK, mb,
1543 sw->cb_data, NULL);
1544 } else {
1545 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001546 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001547 sw->state = SW_STATE_ERROR;
1548 if (sw->cbfn)
1549 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1550 NM_MT_LOAD_END_NACK, mb,
1551 sw->cb_data, NULL);
1552 }
Harald Welte4724f992009-01-18 18:01:49 +00001553 break;
1554 }
1555 case SW_STATE_WAIT_ACTACK:
1556 switch (foh->msg_type) {
1557 case NM_MT_ACTIVATE_SW_ACK:
1558 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001559 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001560 sw->state = SW_STATE_NONE;
1561 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001562 if (sw->cbfn)
1563 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1564 NM_MT_ACTIVATE_SW_ACK, mb,
1565 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001566 break;
1567 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001568 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001569 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001570 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001571 if (sw->cbfn)
1572 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1573 NM_MT_ACTIVATE_SW_NACK, mb,
1574 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001575 break;
1576 }
1577 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001578 switch (foh->msg_type) {
1579 case NM_MT_ACTIVATE_SW_ACK:
1580 rc = 0;
1581 break;
1582 }
1583 break;
Harald Welte4724f992009-01-18 18:01:49 +00001584 case SW_STATE_ERROR:
1585 break;
1586 }
1587
1588 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001589 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001590 foh->msg_type, old_state, sw->state);
1591
1592 return rc;
1593}
1594
1595/* Load the specified software into the BTS */
1596int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001597 u_int8_t win_size, int forced,
1598 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001599{
1600 struct abis_nm_sw *sw = &g_sw;
1601 int rc;
1602
Harald Welte5e4d1b32009-02-01 13:36:56 +00001603 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1604 bts->nr, fname);
1605
Harald Welte4724f992009-01-18 18:01:49 +00001606 if (sw->state != SW_STATE_NONE)
1607 return -EBUSY;
1608
1609 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001610
1611 switch (bts->type) {
1612 case GSM_BTS_TYPE_BS11:
1613 sw->obj_class = NM_OC_SITE_MANAGER;
1614 sw->obj_instance[0] = 0xff;
1615 sw->obj_instance[1] = 0xff;
1616 sw->obj_instance[2] = 0xff;
1617 break;
1618 case GSM_BTS_TYPE_NANOBTS:
1619 sw->obj_class = NM_OC_BASEB_TRANSC;
1620 sw->obj_instance[0] = 0x00;
1621 sw->obj_instance[1] = 0x00;
1622 sw->obj_instance[2] = 0xff;
1623 break;
1624 case GSM_BTS_TYPE_UNKNOWN:
1625 default:
1626 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1627 return -1;
1628 break;
1629 }
Harald Welte4724f992009-01-18 18:01:49 +00001630 sw->window_size = win_size;
1631 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001632 sw->cbfn = cbfn;
1633 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001634 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001635
1636 rc = sw_open_file(sw, fname);
1637 if (rc < 0) {
1638 sw->state = SW_STATE_NONE;
1639 return rc;
1640 }
1641
1642 return sw_load_init(sw);
1643}
Harald Welte52b1f982008-12-23 20:25:15 +00001644
Harald Welte1602ade2009-01-29 21:12:39 +00001645int abis_nm_software_load_status(struct gsm_bts *bts)
1646{
1647 struct abis_nm_sw *sw = &g_sw;
1648 struct stat st;
1649 int rc, percent;
1650
1651 rc = fstat(sw->fd, &st);
1652 if (rc < 0) {
1653 perror("ERROR during stat");
1654 return rc;
1655 }
1656
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001657 if (sw->stream)
1658 percent = (ftell(sw->stream) * 100) / st.st_size;
1659 else
1660 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001661 return percent;
1662}
1663
Harald Welte5e4d1b32009-02-01 13:36:56 +00001664/* Activate the specified software into the BTS */
1665int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1666 gsm_cbfn *cbfn, void *cb_data)
1667{
1668 struct abis_nm_sw *sw = &g_sw;
1669 int rc;
1670
1671 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1672 bts->nr, fname);
1673
1674 if (sw->state != SW_STATE_NONE)
1675 return -EBUSY;
1676
1677 sw->bts = bts;
1678 sw->obj_class = NM_OC_SITE_MANAGER;
1679 sw->obj_instance[0] = 0xff;
1680 sw->obj_instance[1] = 0xff;
1681 sw->obj_instance[2] = 0xff;
1682 sw->state = SW_STATE_WAIT_ACTACK;
1683 sw->cbfn = cbfn;
1684 sw->cb_data = cb_data;
1685
1686 /* Open the file in order to fill some sw struct members */
1687 rc = sw_open_file(sw, fname);
1688 if (rc < 0) {
1689 sw->state = SW_STATE_NONE;
1690 return rc;
1691 }
1692 sw_close_file(sw);
1693
1694 return sw_activate(sw);
1695}
1696
Harald Welte8470bf22008-12-25 23:28:35 +00001697static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001698 u_int8_t ts_nr, u_int8_t subslot_nr)
1699{
Harald Welteadaf08b2009-01-18 11:08:10 +00001700 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001701 ch->bts_port = bts_port;
1702 ch->timeslot = ts_nr;
1703 ch->subslot = subslot_nr;
1704}
1705
1706int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1707 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1708 u_int8_t tei)
1709{
1710 struct abis_om_hdr *oh;
1711 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001712 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001713 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001714
1715 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1716 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1717 bts->bts_nr, trx_nr, 0xff);
1718
Harald Welte8470bf22008-12-25 23:28:35 +00001719 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001720
1721 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1722 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1723
1724 return abis_nm_sendmsg(bts, msg);
1725}
1726
1727/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1728int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1729 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1730{
Harald Welte8470bf22008-12-25 23:28:35 +00001731 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001732 struct abis_om_hdr *oh;
1733 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001734 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001735
1736 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001737 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001738 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1739
1740 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1741 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1742
1743 return abis_nm_sendmsg(bts, msg);
1744}
1745
1746#if 0
1747int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1748 struct abis_nm_abis_channel *chan)
1749{
1750}
1751#endif
1752
1753int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1754 u_int8_t e1_port, u_int8_t e1_timeslot,
1755 u_int8_t e1_subslot)
1756{
1757 struct gsm_bts *bts = ts->trx->bts;
1758 struct abis_om_hdr *oh;
1759 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001760 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001761
1762 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1763 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001764 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001765
1766 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1767 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1768
Harald Weltef325eb42009-02-19 17:07:39 +00001769 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1770 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001771 e1_port, e1_timeslot, e1_subslot);
1772
Harald Welte52b1f982008-12-23 20:25:15 +00001773 return abis_nm_sendmsg(bts, msg);
1774}
1775
1776#if 0
1777int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1778 struct abis_nm_abis_channel *chan,
1779 u_int8_t subchan)
1780{
1781}
1782#endif
1783
Harald Welte22af0db2009-02-14 15:41:08 +00001784/* Chapter 8.6.1 */
1785int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1786{
1787 struct abis_om_hdr *oh;
1788 struct msgb *msg = nm_msgb_alloc();
1789 u_int8_t *cur;
1790
1791 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1792
1793 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001794 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 +00001795 cur = msgb_put(msg, attr_len);
1796 memcpy(cur, attr, attr_len);
1797
1798 return abis_nm_sendmsg(bts, msg);
1799}
1800
1801/* Chapter 8.6.2 */
1802int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1803{
1804 struct abis_om_hdr *oh;
1805 struct msgb *msg = nm_msgb_alloc();
1806 u_int8_t *cur;
1807
1808 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1809
1810 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1811 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001812 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001813 cur = msgb_put(msg, attr_len);
1814 memcpy(cur, attr, attr_len);
1815
1816 return abis_nm_sendmsg(trx->bts, msg);
1817}
1818
Harald Welte39c7deb2009-08-09 21:49:48 +02001819static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1820{
1821 int i;
1822
1823 /* As it turns out, the BS-11 has some very peculiar restrictions
1824 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301825 switch (ts->trx->bts->type) {
1826 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001827 switch (chan_comb) {
1828 case NM_CHANC_TCHHalf:
1829 case NM_CHANC_TCHHalf2:
1830 /* not supported */
1831 return -EINVAL;
1832 case NM_CHANC_SDCCH:
1833 /* only one SDCCH/8 per TRX */
1834 for (i = 0; i < TRX_NR_TS; i++) {
1835 if (i == ts->nr)
1836 continue;
1837 if (ts->trx->ts[i].nm_chan_comb ==
1838 NM_CHANC_SDCCH)
1839 return -EINVAL;
1840 }
1841 /* not allowed for TS0 of BCCH-TRX */
1842 if (ts->trx == ts->trx->bts->c0 &&
1843 ts->nr == 0)
1844 return -EINVAL;
1845 /* not on the same TRX that has a BCCH+SDCCH4
1846 * combination */
1847 if (ts->trx == ts->trx->bts->c0 &&
1848 (ts->trx->ts[0].nm_chan_comb == 5 ||
1849 ts->trx->ts[0].nm_chan_comb == 8))
1850 return -EINVAL;
1851 break;
1852 case NM_CHANC_mainBCCH:
1853 case NM_CHANC_BCCHComb:
1854 /* allowed only for TS0 of C0 */
1855 if (ts->trx != ts->trx->bts->c0 ||
1856 ts->nr != 0)
1857 return -EINVAL;
1858 break;
1859 case NM_CHANC_BCCH:
1860 /* allowed only for TS 2/4/6 of C0 */
1861 if (ts->trx != ts->trx->bts->c0)
1862 return -EINVAL;
1863 if (ts->nr != 2 && ts->nr != 4 &&
1864 ts->nr != 6)
1865 return -EINVAL;
1866 break;
1867 case 8: /* this is not like 08.58, but in fact
1868 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1869 /* FIXME: only one CBCH allowed per cell */
1870 break;
1871 }
Harald Welted6575f92009-12-02 02:45:23 +05301872 break;
1873 case GSM_BTS_TYPE_NANOBTS:
1874 switch (ts->nr) {
1875 case 0:
1876 if (ts->trx->nr == 0) {
1877 /* only on TRX0 */
1878 switch (chan_comb) {
1879 case NM_CHANC_BCCH:
1880 case NM_CHANC_mainBCCH:
1881 case NM_CHANC_BCCHComb:
1882 return 0;
1883 break;
1884 default:
1885 return -EINVAL;
1886 }
1887 } else {
1888 switch (chan_comb) {
1889 case NM_CHANC_TCHFull:
1890 case NM_CHANC_TCHHalf:
1891 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1892 return 0;
1893 default:
1894 return -EINVAL;
1895 }
1896 }
1897 break;
1898 case 1:
1899 if (ts->trx->nr == 0) {
1900 switch (chan_comb) {
1901 case NM_CHANC_SDCCH_CBCH:
1902 if (ts->trx->ts[0].nm_chan_comb ==
1903 NM_CHANC_mainBCCH)
1904 return 0;
1905 return -EINVAL;
1906 case NM_CHANC_SDCCH:
1907 case NM_CHANC_TCHFull:
1908 case NM_CHANC_TCHHalf:
1909 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1910 case NM_CHANC_IPAC_TCHFull_PDCH:
1911 return 0;
1912 }
1913 } else {
1914 switch (chan_comb) {
1915 case NM_CHANC_SDCCH:
1916 case NM_CHANC_TCHFull:
1917 case NM_CHANC_TCHHalf:
1918 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1919 return 0;
1920 default:
1921 return -EINVAL;
1922 }
1923 }
1924 break;
1925 case 2:
1926 case 3:
1927 case 4:
1928 case 5:
1929 case 6:
1930 case 7:
1931 switch (chan_comb) {
1932 case NM_CHANC_TCHFull:
1933 case NM_CHANC_TCHHalf:
1934 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1935 return 0;
1936 case NM_CHANC_IPAC_PDCH:
1937 case NM_CHANC_IPAC_TCHFull_PDCH:
1938 if (ts->trx->nr == 0)
1939 return 0;
1940 else
1941 return -EINVAL;
1942 }
1943 break;
1944 }
1945 return -EINVAL;
1946 default:
1947 /* unknown BTS type */
1948 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001949 }
1950 return 0;
1951}
1952
Harald Welte22af0db2009-02-14 15:41:08 +00001953/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001954int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1955{
1956 struct gsm_bts *bts = ts->trx->bts;
1957 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001958 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001959 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001960 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001961 u_int8_t len = 2 + 2;
1962
1963 if (bts->type == GSM_BTS_TYPE_BS11)
1964 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001965
Harald Weltef325eb42009-02-19 17:07:39 +00001966 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001967 if (verify_chan_comb(ts, chan_comb) < 0) {
1968 msgb_free(msg);
1969 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1970 return -EINVAL;
1971 }
1972 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001973
Harald Welte52b1f982008-12-23 20:25:15 +00001974 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001975 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001976 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001977 ts->trx->nr, ts->nr);
1978 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00001979 if (bts->type == GSM_BTS_TYPE_BS11)
1980 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001981 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00001982 if (bts->type == GSM_BTS_TYPE_BS11) {
1983 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1984 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1985 }
Harald Weltee6c22d92009-07-21 20:40:05 +02001986 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001987 if (bts->type == GSM_BTS_TYPE_BS11)
1988 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001989
1990 return abis_nm_sendmsg(bts, msg);
1991}
1992
Harald Welte34a99682009-02-13 02:41:40 +00001993int 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 +00001994 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001995{
1996 struct abis_om_hdr *oh;
1997 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00001998 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1999 u_int8_t len = att_len;
2000
2001 if (nack) {
2002 len += 2;
2003 msgtype = NM_MT_SW_ACT_REQ_NACK;
2004 }
Harald Welte34a99682009-02-13 02:41:40 +00002005
2006 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002007 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2008
Harald Welte34a99682009-02-13 02:41:40 +00002009 if (attr) {
2010 u_int8_t *ptr = msgb_put(msg, att_len);
2011 memcpy(ptr, attr, att_len);
2012 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002013 if (nack)
2014 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002015
2016 return abis_nm_sendmsg(bts, msg);
2017}
2018
Harald Welte8470bf22008-12-25 23:28:35 +00002019int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002020{
Harald Welte8470bf22008-12-25 23:28:35 +00002021 struct msgb *msg = nm_msgb_alloc();
2022 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002023 u_int8_t *data;
2024
2025 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2026 fill_om_hdr(oh, len);
2027 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002028 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002029
2030 return abis_nm_sendmsg(bts, msg);
2031}
2032
2033/* Siemens specific commands */
2034static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2035{
2036 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002037 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002038
2039 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002040 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002041 0xff, 0xff, 0xff);
2042
2043 return abis_nm_sendmsg(bts, msg);
2044}
2045
Harald Welte34a99682009-02-13 02:41:40 +00002046/* Chapter 8.9.2 */
2047int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2048{
2049 struct abis_om_hdr *oh;
2050 struct msgb *msg = nm_msgb_alloc();
2051
2052 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2053 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2054
Harald Weltea8bd6d42009-10-20 09:56:18 +02002055 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2056 DEBUGPC(DNM, "Sending OPSTART\n");
2057
Harald Welte34a99682009-02-13 02:41:40 +00002058 return abis_nm_sendmsg(bts, msg);
2059}
2060
2061/* Chapter 8.8.5 */
2062int 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 +02002063 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002064{
2065 struct abis_om_hdr *oh;
2066 struct msgb *msg = nm_msgb_alloc();
2067
2068 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2069 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2070 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2071
2072 return abis_nm_sendmsg(bts, msg);
2073}
2074
Harald Welte1989c082009-08-06 17:58:31 +02002075int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2076 u_int8_t e1_port1, u_int8_t ts1)
2077{
2078 struct abis_om_hdr *oh;
2079 struct msgb *msg = nm_msgb_alloc();
2080 u_int8_t *attr;
2081
2082 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2083 e1_port0, ts0, e1_port1, ts1);
2084
2085 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2086 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2087 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2088
2089 attr = msgb_put(msg, 3);
2090 attr[0] = NM_ATT_MDROP_LINK;
2091 attr[1] = e1_port0;
2092 attr[2] = ts0;
2093
2094 attr = msgb_put(msg, 3);
2095 attr[0] = NM_ATT_MDROP_NEXT;
2096 attr[1] = e1_port1;
2097 attr[2] = ts1;
2098
2099 return abis_nm_sendmsg(bts, msg);
2100}
Harald Welte34a99682009-02-13 02:41:40 +00002101
Harald Weltec7310382009-08-08 00:02:36 +02002102/* Chapter 8.7.1 */
2103int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2104 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2105 u_int8_t test_nr, u_int8_t auton_report,
2106 u_int8_t *phys_config, u_int16_t phys_config_len)
2107{
2108 struct abis_om_hdr *oh;
2109 struct msgb *msg = nm_msgb_alloc();
2110 int len = 4; /* 2 TV attributes */
2111
2112 DEBUGP(DNM, "PEFORM TEST\n");
2113
2114 if (phys_config_len)
2115 len += 3 + phys_config_len;
2116
2117 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2118 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2119 obj_class, bts_nr, trx_nr, ts_nr);
2120 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2121 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2122 if (phys_config_len)
2123 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2124 phys_config);
2125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
Harald Welte52b1f982008-12-23 20:25:15 +00002129int abis_nm_event_reports(struct gsm_bts *bts, int on)
2130{
2131 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002132 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002133 else
Harald Welte227d4072009-01-03 08:16:25 +00002134 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002135}
2136
Harald Welte47d88ae2009-01-04 12:02:08 +00002137/* Siemens (or BS-11) specific commands */
2138
Harald Welte3ffd1372009-02-01 22:15:49 +00002139int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2140{
2141 if (reconnect == 0)
2142 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2143 else
2144 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2145}
2146
Harald Welteb8427972009-02-05 19:27:17 +00002147int abis_nm_bs11_restart(struct gsm_bts *bts)
2148{
2149 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2150}
2151
2152
Harald Welte268bb402009-02-01 19:11:56 +00002153struct bs11_date_time {
2154 u_int16_t year;
2155 u_int8_t month;
2156 u_int8_t day;
2157 u_int8_t hour;
2158 u_int8_t min;
2159 u_int8_t sec;
2160} __attribute__((packed));
2161
2162
2163void get_bs11_date_time(struct bs11_date_time *aet)
2164{
2165 time_t t;
2166 struct tm *tm;
2167
2168 t = time(NULL);
2169 tm = localtime(&t);
2170 aet->sec = tm->tm_sec;
2171 aet->min = tm->tm_min;
2172 aet->hour = tm->tm_hour;
2173 aet->day = tm->tm_mday;
2174 aet->month = tm->tm_mon;
2175 aet->year = htons(1900 + tm->tm_year);
2176}
2177
Harald Welte05188ee2009-01-18 11:39:08 +00002178int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002179{
Harald Welte4668fda2009-01-03 08:19:29 +00002180 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002181}
2182
Harald Welte05188ee2009-01-18 11:39:08 +00002183int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002184{
2185 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002186 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002187 else
Harald Welte4668fda2009-01-03 08:19:29 +00002188 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002189}
Harald Welte47d88ae2009-01-04 12:02:08 +00002190
Harald Welte05188ee2009-01-18 11:39:08 +00002191int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002192 enum abis_bs11_objtype type, u_int8_t idx,
2193 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002194{
2195 struct abis_om_hdr *oh;
2196 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002197 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002198
2199 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002200 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002201 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002202 cur = msgb_put(msg, attr_len);
2203 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002204
2205 return abis_nm_sendmsg(bts, msg);
2206}
2207
Harald Welte78fc0d42009-02-19 02:50:57 +00002208int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2209 enum abis_bs11_objtype type, u_int8_t idx)
2210{
2211 struct abis_om_hdr *oh;
2212 struct msgb *msg = nm_msgb_alloc();
2213
2214 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2215 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2216 NM_OC_BS11, type, 0, idx);
2217
2218 return abis_nm_sendmsg(bts, msg);
2219}
2220
Harald Welte05188ee2009-01-18 11:39:08 +00002221int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002222{
2223 struct abis_om_hdr *oh;
2224 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002225 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002226
2227 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002228 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002229 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2230 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002231
2232 return abis_nm_sendmsg(bts, msg);
2233}
2234
Harald Welte05188ee2009-01-18 11:39:08 +00002235int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002236{
2237 struct abis_om_hdr *oh;
2238 struct msgb *msg = nm_msgb_alloc();
2239
2240 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2241 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002242 idx, 0xff, 0xff);
2243
2244 return abis_nm_sendmsg(bts, msg);
2245}
2246
2247int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2248{
2249 struct abis_om_hdr *oh;
2250 struct msgb *msg = nm_msgb_alloc();
2251
2252 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2253 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2254 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002255
2256 return abis_nm_sendmsg(bts, msg);
2257}
Harald Welte05188ee2009-01-18 11:39:08 +00002258
Harald Welte78fc0d42009-02-19 02:50:57 +00002259static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2260int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2261{
2262 struct abis_om_hdr *oh;
2263 struct msgb *msg = nm_msgb_alloc();
2264
2265 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2266 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2267 0xff, 0xff, 0xff);
2268 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2269
2270 return abis_nm_sendmsg(bts, msg);
2271}
2272
Harald Welteb6c92ae2009-02-21 20:15:32 +00002273/* like abis_nm_conn_terr_traf + set_tei */
2274int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2275 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2276 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002277{
2278 struct abis_om_hdr *oh;
2279 struct abis_nm_channel *ch;
2280 struct msgb *msg = nm_msgb_alloc();
2281
2282 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002283 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002284 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2285
2286 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2287 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002288 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002289
2290 return abis_nm_sendmsg(bts, msg);
2291}
2292
2293int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2294{
2295 struct abis_om_hdr *oh;
2296 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002297
2298 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002299 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002300 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2301 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2302
2303 return abis_nm_sendmsg(trx->bts, msg);
2304}
2305
Harald Welte78fc0d42009-02-19 02:50:57 +00002306int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2307{
2308 struct abis_om_hdr *oh;
2309 struct msgb *msg = nm_msgb_alloc();
2310 u_int8_t attr = NM_ATT_BS11_TXPWR;
2311
2312 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2313 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2314 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2315 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2316
2317 return abis_nm_sendmsg(trx->bts, msg);
2318}
2319
Harald Welteaaf02d92009-04-29 13:25:57 +00002320int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2321{
2322 struct abis_om_hdr *oh;
2323 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002324 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2327 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2328 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002329 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002330
2331 return abis_nm_sendmsg(bts, msg);
2332}
2333
Harald Welteef061952009-05-17 12:43:42 +00002334int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2335{
2336 struct abis_om_hdr *oh;
2337 struct msgb *msg = nm_msgb_alloc();
2338 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2339 NM_ATT_BS11_CCLK_TYPE };
2340
2341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2342 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2343 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2344 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2345
2346 return abis_nm_sendmsg(bts, msg);
2347
2348}
Harald Welteaaf02d92009-04-29 13:25:57 +00002349
Harald Welte268bb402009-02-01 19:11:56 +00002350//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002351
Harald Welte1bc09062009-01-18 14:17:52 +00002352int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002353{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002354 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2355}
2356
Daniel Willmann4b054c82010-01-07 00:46:26 +01002357int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2358{
2359 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2360}
2361
Daniel Willmann493db4e2010-01-07 00:43:11 +01002362int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2363{
Harald Welte05188ee2009-01-18 11:39:08 +00002364 struct abis_om_hdr *oh;
2365 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002366 struct bs11_date_time bdt;
2367
2368 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002369
2370 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002371 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002372 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002373 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002374 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002375 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002376 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002377 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002378 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002379 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002380 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002381 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002382 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002383 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002384 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002385 }
Harald Welte05188ee2009-01-18 11:39:08 +00002386
2387 return abis_nm_sendmsg(bts, msg);
2388}
Harald Welte1bc09062009-01-18 14:17:52 +00002389
2390int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2391{
2392 struct abis_om_hdr *oh;
2393 struct msgb *msg;
2394
2395 if (strlen(password) != 10)
2396 return -EINVAL;
2397
2398 msg = nm_msgb_alloc();
2399 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002400 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002401 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2402 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2403
2404 return abis_nm_sendmsg(bts, msg);
2405}
2406
Harald Weltee69f5fb2009-04-28 16:31:38 +00002407/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2408int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2409{
2410 struct abis_om_hdr *oh;
2411 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002412 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002413
2414 msg = nm_msgb_alloc();
2415 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2416 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2417 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002418
2419 if (locked)
2420 tlv_value = BS11_LI_PLL_LOCKED;
2421 else
2422 tlv_value = BS11_LI_PLL_STANDALONE;
2423
2424 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002425
2426 return abis_nm_sendmsg(bts, msg);
2427}
2428
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002429/* Set the calibration value of the PLL (work value/set value)
2430 * It depends on the login which one is changed */
2431int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2432{
2433 struct abis_om_hdr *oh;
2434 struct msgb *msg;
2435 u_int8_t tlv_value[2];
2436
2437 msg = nm_msgb_alloc();
2438 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2439 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2440 BS11_OBJ_TRX1, 0x00, 0x00);
2441
2442 tlv_value[0] = value>>8;
2443 tlv_value[1] = value&0xff;
2444
2445 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2446
2447 return abis_nm_sendmsg(bts, msg);
2448}
2449
Harald Welte1bc09062009-01-18 14:17:52 +00002450int abis_nm_bs11_get_state(struct gsm_bts *bts)
2451{
2452 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2453}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002454
2455/* BS11 SWL */
2456
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002457void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002458
Harald Welte5e4d1b32009-02-01 13:36:56 +00002459struct abis_nm_bs11_sw {
2460 struct gsm_bts *bts;
2461 char swl_fname[PATH_MAX];
2462 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002463 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002464 struct llist_head file_list;
2465 gsm_cbfn *user_cb; /* specified by the user */
2466};
2467static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2468
2469struct file_list_entry {
2470 struct llist_head list;
2471 char fname[PATH_MAX];
2472};
2473
2474struct file_list_entry *fl_dequeue(struct llist_head *queue)
2475{
2476 struct llist_head *lh;
2477
2478 if (llist_empty(queue))
2479 return NULL;
2480
2481 lh = queue->next;
2482 llist_del(lh);
2483
2484 return llist_entry(lh, struct file_list_entry, list);
2485}
2486
2487static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2488{
2489 char linebuf[255];
2490 struct llist_head *lh, *lh2;
2491 FILE *swl;
2492 int rc = 0;
2493
2494 swl = fopen(bs11_sw->swl_fname, "r");
2495 if (!swl)
2496 return -ENODEV;
2497
2498 /* zero the stale file list, if any */
2499 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2500 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002501 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002502 }
2503
2504 while (fgets(linebuf, sizeof(linebuf), swl)) {
2505 char file_id[12+1];
2506 char file_version[80+1];
2507 struct file_list_entry *fle;
2508 static char dir[PATH_MAX];
2509
2510 if (strlen(linebuf) < 4)
2511 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002512
Harald Welte5e4d1b32009-02-01 13:36:56 +00002513 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2514 if (rc < 0) {
2515 perror("ERR parsing SWL file");
2516 rc = -EINVAL;
2517 goto out;
2518 }
2519 if (rc < 2)
2520 continue;
2521
Harald Welte470ec292009-06-26 20:25:23 +02002522 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002523 if (!fle) {
2524 rc = -ENOMEM;
2525 goto out;
2526 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002527
2528 /* construct new filename */
2529 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2530 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2531 strcat(fle->fname, "/");
2532 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002533
2534 llist_add_tail(&fle->list, &bs11_sw->file_list);
2535 }
2536
2537out:
2538 fclose(swl);
2539 return rc;
2540}
2541
2542/* bs11 swload specific callback, passed to abis_nm core swload */
2543static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2544 struct msgb *msg, void *data, void *param)
2545{
2546 struct abis_nm_bs11_sw *bs11_sw = data;
2547 struct file_list_entry *fle;
2548 int rc = 0;
2549
Harald Welte5e4d1b32009-02-01 13:36:56 +00002550 switch (event) {
2551 case NM_MT_LOAD_END_ACK:
2552 fle = fl_dequeue(&bs11_sw->file_list);
2553 if (fle) {
2554 /* start download the next file of our file list */
2555 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2556 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002557 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002558 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002559 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002560 } else {
2561 /* activate the SWL */
2562 rc = abis_nm_software_activate(bs11_sw->bts,
2563 bs11_sw->swl_fname,
2564 bs11_swload_cbfn,
2565 bs11_sw);
2566 }
2567 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002568 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002569 case NM_MT_LOAD_END_NACK:
2570 case NM_MT_LOAD_INIT_ACK:
2571 case NM_MT_LOAD_INIT_NACK:
2572 case NM_MT_ACTIVATE_SW_NACK:
2573 case NM_MT_ACTIVATE_SW_ACK:
2574 default:
2575 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002576 if (bs11_sw->user_cb)
2577 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002578 break;
2579 }
2580
2581 return rc;
2582}
2583
2584/* Siemens provides a SWL file that is a mere listing of all the other
2585 * files that are part of a software release. We need to upload first
2586 * the list file, and then each file that is listed in the list file */
2587int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002588 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002589{
2590 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2591 struct file_list_entry *fle;
2592 int rc = 0;
2593
2594 INIT_LLIST_HEAD(&bs11_sw->file_list);
2595 bs11_sw->bts = bts;
2596 bs11_sw->win_size = win_size;
2597 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002598 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002599
2600 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2601 rc = bs11_read_swl_file(bs11_sw);
2602 if (rc < 0)
2603 return rc;
2604
2605 /* dequeue next item in file list */
2606 fle = fl_dequeue(&bs11_sw->file_list);
2607 if (!fle)
2608 return -EINVAL;
2609
2610 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002611 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002612 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002613 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002614 return rc;
2615}
2616
Harald Welte5083b0b2009-02-02 19:20:52 +00002617#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002618static u_int8_t req_attr_btse[] = {
2619 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2620 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2621 NM_ATT_BS11_LMT_USER_NAME,
2622
2623 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2624
2625 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2626
2627 NM_ATT_BS11_SW_LOAD_STORED };
2628
2629static u_int8_t req_attr_btsm[] = {
2630 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2631 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2632 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2633 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002634#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002635
2636static u_int8_t req_attr[] = {
2637 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2638 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002639 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002640
2641int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2642{
2643 struct abis_om_hdr *oh;
2644 struct msgb *msg = nm_msgb_alloc();
2645
2646 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2647 /* SiemensHW CCTRL object */
2648 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2649 0x03, 0x00, 0x00);
2650 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2651
2652 return abis_nm_sendmsg(bts, msg);
2653}
Harald Welte268bb402009-02-01 19:11:56 +00002654
2655int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2656{
2657 struct abis_om_hdr *oh;
2658 struct msgb *msg = nm_msgb_alloc();
2659 struct bs11_date_time aet;
2660
2661 get_bs11_date_time(&aet);
2662 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2663 /* SiemensHW CCTRL object */
2664 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2665 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002666 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002667
2668 return abis_nm_sendmsg(bts, msg);
2669}
Harald Welte5c1e4582009-02-15 11:57:29 +00002670
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002671int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2672{
2673 struct abis_om_hdr *oh;
2674 struct msgb *msg = nm_msgb_alloc();
2675 struct bs11_date_time aet;
2676
2677 get_bs11_date_time(&aet);
2678 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2679 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2680 bport, 0xff, 0x02);
2681 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2682
2683 return abis_nm_sendmsg(bts, msg);
2684}
2685
Harald Welte5c1e4582009-02-15 11:57:29 +00002686/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002687static const char ipaccess_magic[] = "com.ipaccess";
2688
Harald Welte677c21f2009-02-17 13:22:23 +00002689
2690static int abis_nm_rx_ipacc(struct msgb *msg)
2691{
2692 struct abis_om_hdr *oh = msgb_l2(msg);
2693 struct abis_om_fom_hdr *foh;
2694 u_int8_t idstrlen = oh->data[0];
2695 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002696 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002697
2698 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002699 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002700 return -EINVAL;
2701 }
2702
Harald Welte193fefc2009-04-30 15:16:27 +00002703 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002704 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002705
Harald Weltea8bd6d42009-10-20 09:56:18 +02002706 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002707
Harald Welte746d6092009-10-19 22:11:11 +02002708 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002709
Harald Welte677c21f2009-02-17 13:22:23 +00002710 switch (foh->msg_type) {
2711 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002712 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002713 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002714 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002715 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002716 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2717 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002718 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002719 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002720 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002721 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2722 DEBUGPC(DNM, "STREAM=0x%02x ",
2723 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002724 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002725 break;
2726 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002727 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002728 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002729 DEBUGPC(DNM, " CAUSE=%s\n",
2730 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002731 else
2732 DEBUGPC(DNM, "\n");
2733 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002734 case NM_MT_IPACC_SET_NVATTR_ACK:
2735 DEBUGPC(DNM, "SET NVATTR ACK\n");
2736 /* FIXME: decode and show the actual attributes */
2737 break;
2738 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002739 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002740 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002741 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002742 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2743 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002744 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002745 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002746 case NM_MT_IPACC_GET_NVATTR_ACK:
2747 DEBUGPC(DNM, "GET NVATTR ACK\n");
2748 /* FIXME: decode and show the actual attributes */
2749 break;
2750 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002751 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002752 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002753 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002754 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2755 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002756 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002757 break;
Harald Welte15c44172009-10-08 20:15:24 +02002758 case NM_MT_IPACC_SET_ATTR_ACK:
2759 DEBUGPC(DNM, "SET ATTR ACK\n");
2760 break;
2761 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002762 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002763 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002764 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002765 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2766 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002767 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002768 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002769 default:
2770 DEBUGPC(DNM, "unknown\n");
2771 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002772 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002773
2774 /* signal handling */
2775 switch (foh->msg_type) {
2776 case NM_MT_IPACC_RSL_CONNECT_NACK:
2777 case NM_MT_IPACC_SET_NVATTR_NACK:
2778 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002779 signal.bts = msg->trx->bts;
2780 signal.msg_type = foh->msg_type;
2781 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002782 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002783 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002784 signal.bts = msg->trx->bts;
2785 signal.msg_type = foh->msg_type;
2786 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002787 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002788 default:
2789 break;
2790 }
2791
Harald Welte677c21f2009-02-17 13:22:23 +00002792 return 0;
2793}
2794
Harald Welte193fefc2009-04-30 15:16:27 +00002795/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002796int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2797 u_int8_t obj_class, u_int8_t bts_nr,
2798 u_int8_t trx_nr, u_int8_t ts_nr,
2799 u_int8_t *attr, int attr_len)
2800{
2801 struct msgb *msg = nm_msgb_alloc();
2802 struct abis_om_hdr *oh;
2803 struct abis_om_fom_hdr *foh;
2804 u_int8_t *data;
2805
2806 /* construct the 12.21 OM header, observe the erroneous length */
2807 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2808 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2809 oh->mdisc = ABIS_OM_MDISC_MANUF;
2810
2811 /* add the ip.access magic */
2812 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2813 *data++ = sizeof(ipaccess_magic);
2814 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2815
2816 /* fill the 12.21 FOM header */
2817 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2818 foh->msg_type = msg_type;
2819 foh->obj_class = obj_class;
2820 foh->obj_inst.bts_nr = bts_nr;
2821 foh->obj_inst.trx_nr = trx_nr;
2822 foh->obj_inst.ts_nr = ts_nr;
2823
2824 if (attr && attr_len) {
2825 data = msgb_put(msg, attr_len);
2826 memcpy(data, attr, attr_len);
2827 }
2828
2829 return abis_nm_sendmsg(bts, msg);
2830}
Harald Welte677c21f2009-02-17 13:22:23 +00002831
Harald Welte193fefc2009-04-30 15:16:27 +00002832/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002833int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002834 int attr_len)
2835{
Harald Welte2ef156d2010-01-07 20:39:42 +01002836 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2837 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002838 attr_len);
2839}
2840
Harald Welte746d6092009-10-19 22:11:11 +02002841int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2842 u_int32_t ip, u_int16_t port, u_int8_t stream)
2843{
2844 struct in_addr ia;
2845 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2846 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2847 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2848
2849 int attr_len = sizeof(attr);
2850
2851 ia.s_addr = htonl(ip);
2852 attr[1] = stream;
2853 attr[3] = port >> 8;
2854 attr[4] = port & 0xff;
2855 *(u_int32_t *)(attr+6) = ia.s_addr;
2856
2857 /* if ip == 0, we use the default IP */
2858 if (ip == 0)
2859 attr_len -= 5;
2860
2861 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002862 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002863
2864 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2865 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2866 trx->nr, 0xff, attr, attr_len);
2867}
2868
Harald Welte193fefc2009-04-30 15:16:27 +00002869/* restart / reboot an ip.access nanoBTS */
2870int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2871{
2872 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2873}
Harald Weltedaef5212009-10-24 10:20:41 +02002874
2875int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2876 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2877 u_int8_t *attr, u_int8_t attr_len)
2878{
2879 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2880 obj_class, bts_nr, trx_nr, ts_nr,
2881 attr, attr_len);
2882}
Harald Welte0f255852009-11-12 14:48:42 +01002883
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}
3003
3004