blob: c9852bf824625c3519a41dabbc36aa1ee62d4b8d [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
Harald Welte92b1fe42010-03-25 11:45:30 +0800117static const struct value_string nack_names[] = {
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,
139 "CHANGE ADMINISTRATIVE STATE REQUEST" },
140 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
141 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
142 { NM_MT_OPSTART_NACK, "OPSTART" },
143 { NM_MT_REINIT_NACK, "REINIT" },
144 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
145 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
146 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
147 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
148 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
149 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
150 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
151 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
152 { 0, NULL }
Harald Welte78fc0d42009-02-19 02:50:57 +0000153};
154
Harald Welte6c96ba52009-05-01 13:03:40 +0000155/* Chapter 9.4.36 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800156static const struct value_string nack_cause_names[] = {
Harald Welte6c96ba52009-05-01 13:03:40 +0000157 /* General Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800158 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
159 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
160 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
161 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
162 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
163 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
164 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
165 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
166 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
167 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
168 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
169 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
170 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte6c96ba52009-05-01 13:03:40 +0000171 /* Specific Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800172 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
173 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
174 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
175 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
176 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
177 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
178 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
179 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
180 { NM_NACK_TEST_NOSUCH, "No such test" },
181 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
182 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
183 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
184 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
185 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
186 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
187 { NM_NACK_WAIT, "Wait" },
188 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
189 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
190 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
191 { 0, NULL }
Harald Welte6c96ba52009-05-01 13:03:40 +0000192};
193
Harald Welte6c96ba52009-05-01 13:03:40 +0000194static const char *nack_cause_name(u_int8_t cause)
195{
Harald Welte92b1fe42010-03-25 11:45:30 +0800196 return get_value_string(nack_cause_names, cause);
Harald Welte6c96ba52009-05-01 13:03:40 +0000197}
198
Harald Welte0db97b22009-05-01 17:22:47 +0000199/* Chapter 9.4.16: Event Type */
Harald Welte92b1fe42010-03-25 11:45:30 +0800200static const struct value_string event_type_names[] = {
201 { NM_EVT_COMM_FAIL, "communication failure" },
202 { NM_EVT_QOS_FAIL, "quality of service failure" },
203 { NM_EVT_PROC_FAIL, "processing failure" },
204 { NM_EVT_EQUIP_FAIL, "equipment failure" },
205 { NM_EVT_ENV_FAIL, "environment failure" },
206 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000207};
208
209static const char *event_type_name(u_int8_t cause)
210{
Harald Welte92b1fe42010-03-25 11:45:30 +0800211 return get_value_string(event_type_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000212}
213
214/* Chapter 9.4.63: Perceived Severity */
Harald Welte92b1fe42010-03-25 11:45:30 +0800215static const struct value_string severity_names[] = {
216 { NM_SEVER_CEASED, "failure ceased" },
217 { NM_SEVER_CRITICAL, "critical failure" },
218 { NM_SEVER_MAJOR, "major failure" },
219 { NM_SEVER_MINOR, "minor failure" },
220 { NM_SEVER_WARNING, "warning level failure" },
221 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
222 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000223};
224
225static const char *severity_name(u_int8_t cause)
226{
Harald Welte92b1fe42010-03-25 11:45:30 +0800227 return get_value_string(severity_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000228}
229
Harald Welte52b1f982008-12-23 20:25:15 +0000230/* Attributes that the BSC can set, not only get, according to Section 9.4 */
231static const enum abis_nm_attr nm_att_settable[] = {
232 NM_ATT_ADD_INFO,
233 NM_ATT_ADD_TEXT,
234 NM_ATT_DEST,
235 NM_ATT_EVENT_TYPE,
236 NM_ATT_FILE_DATA,
237 NM_ATT_GET_ARI,
238 NM_ATT_HW_CONF_CHG,
239 NM_ATT_LIST_REQ_ATTR,
240 NM_ATT_MDROP_LINK,
241 NM_ATT_MDROP_NEXT,
242 NM_ATT_NACK_CAUSES,
243 NM_ATT_OUTST_ALARM,
244 NM_ATT_PHYS_CONF,
245 NM_ATT_PROB_CAUSE,
246 NM_ATT_RAD_SUBC,
247 NM_ATT_SOURCE,
248 NM_ATT_SPEC_PROB,
249 NM_ATT_START_TIME,
250 NM_ATT_TEST_DUR,
251 NM_ATT_TEST_NO,
252 NM_ATT_TEST_REPORT,
253 NM_ATT_WINDOW_SIZE,
254 NM_ATT_SEVERITY,
255 NM_ATT_MEAS_RES,
256 NM_ATT_MEAS_TYPE,
257};
258
Harald Welte39315c42010-01-10 18:01:52 +0100259const struct tlv_definition nm_att_tlvdef = {
Harald Weltee0590df2009-02-15 03:34:15 +0000260 .def = {
261 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
262 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
264 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
265 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
266 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
267 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
268 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
269 [NM_ATT_BSIC] = { TLV_TYPE_TV },
270 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
272 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
273 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
274 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
275 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
276 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
277 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
279 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
280 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
281 [NM_ATT_HSN] = { TLV_TYPE_TV },
282 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
283 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
284 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
285 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
286 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
287 [NM_ATT_MAIO] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
289 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
290 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
291 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
292 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
294 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
295 [NM_ATT_NY1] = { TLV_TYPE_TV },
296 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
297 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
298 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
299 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
300 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
302 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
303 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
304 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
305 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
306 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
308 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
309 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
310 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
311 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
312 [NM_ATT_TEI] = { TLV_TYPE_TV },
313 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
314 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
315 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
316 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
317 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
318 [NM_ATT_TSC] = { TLV_TYPE_TV },
319 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
320 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
321 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
322 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
323 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000324 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Weltee0590df2009-02-15 03:34:15 +0000325 },
326};
Harald Welte03133942009-02-18 19:51:53 +0000327
Harald Welte21bd3a52009-08-10 12:21:22 +0200328static const enum abis_nm_chan_comb chcomb4pchan[] = {
329 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
330 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
331 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
332 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
333 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200334 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
335 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200336 /* FIXME: bounds check */
337};
338
339int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
340{
341 if (pchan < ARRAY_SIZE(chcomb4pchan))
342 return chcomb4pchan[pchan];
343
344 return -EINVAL;
345}
346
Harald Welte39315c42010-01-10 18:01:52 +0100347int 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 +0000348{
Harald Welte39315c42010-01-10 18:01:52 +0100349 if (!bts->model)
350 return -EIO;
351 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000352}
Harald Weltee0590df2009-02-15 03:34:15 +0000353
Harald Welte52b1f982008-12-23 20:25:15 +0000354static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
355{
356 int i;
357
358 for (i = 0; i < size; i++) {
359 if (arr[i] == mt)
360 return 1;
361 }
362
363 return 0;
364}
365
Holger Freytherca362a62009-01-04 21:05:01 +0000366#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000367/* is this msgtype the usual ACK/NACK type ? */
368static int is_ack_nack(enum abis_nm_msgtype mt)
369{
370 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
371}
Holger Freytherca362a62009-01-04 21:05:01 +0000372#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000373
374/* is this msgtype a report ? */
375static int is_report(enum abis_nm_msgtype mt)
376{
Harald Welte8470bf22008-12-25 23:28:35 +0000377 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000378}
379
380#define MT_ACK(x) (x+1)
381#define MT_NACK(x) (x+2)
382
383static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
384{
385 oh->mdisc = ABIS_OM_MDISC_FOM;
386 oh->placement = ABIS_OM_PLACEMENT_ONLY;
387 oh->sequence = 0;
388 oh->length = len;
389}
390
391static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
392 u_int8_t msg_type, u_int8_t obj_class,
393 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
394{
395 struct abis_om_fom_hdr *foh =
396 (struct abis_om_fom_hdr *) oh->data;
397
Harald Welte702d8702008-12-26 20:25:35 +0000398 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000399 foh->msg_type = msg_type;
400 foh->obj_class = obj_class;
401 foh->obj_inst.bts_nr = bts_nr;
402 foh->obj_inst.trx_nr = trx_nr;
403 foh->obj_inst.ts_nr = ts_nr;
404}
405
Harald Welte8470bf22008-12-25 23:28:35 +0000406static struct msgb *nm_msgb_alloc(void)
407{
Harald Welte966636f2009-06-26 19:39:35 +0200408 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
409 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000410}
411
Harald Welte52b1f982008-12-23 20:25:15 +0000412/* Send a OML NM Message from BSC to BTS */
413int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
414{
Holger Freyther59639e82009-02-09 23:09:55 +0000415 msg->trx = bts->c0;
416
Harald Weltead384642008-12-26 10:20:07 +0000417 return _abis_nm_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000418}
419
Harald Welte4724f992009-01-18 18:01:49 +0000420static int abis_nm_rcvmsg_sw(struct msgb *mb);
421
Harald Welte92b1fe42010-03-25 11:45:30 +0800422static struct value_string obj_class_names[] = {
423 { NM_OC_SITE_MANAGER, "SITE MANAGER" },
424 { NM_OC_BTS, "BTS" },
425 { NM_OC_RADIO_CARRIER, "RADIO CARRIER" },
426 { NM_OC_BASEB_TRANSC, "BASEBAND TRANSCEIVER" },
427 { NM_OC_CHANNEL, "CHANNEL" },
428 { NM_OC_BS11_ADJC, "ADJC" },
429 { NM_OC_BS11_HANDOVER, "HANDOVER" },
430 { NM_OC_BS11_PWR_CTRL, "POWER CONTROL" },
431 { NM_OC_BS11_BTSE, "BTSE" },
432 { NM_OC_BS11_RACK, "RACK" },
433 { NM_OC_BS11_TEST, "TEST" },
434 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
435 { NM_OC_BS11_BPORT, "BPORT" },
436 { NM_OC_GPRS_NSE, "GPRS NSE" },
437 { NM_OC_GPRS_CELL, "GPRS CELL" },
438 { NM_OC_GPRS_NSVC, "GPRS NSVC" },
439 { NM_OC_BS11, "SIEMENSHW" },
440 { 0, NULL }
441};
442
Harald Welte34a99682009-02-13 02:41:40 +0000443static const char *obj_class_name(u_int8_t oc)
444{
Harald Welte92b1fe42010-03-25 11:45:30 +0800445 return get_value_string(obj_class_names, oc);
Harald Welte34a99682009-02-13 02:41:40 +0000446}
447
Harald Welte4d87f242009-03-10 19:43:44 +0000448const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000449{
450 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100451 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000452 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100453 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000454 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100455 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000456 return "NULL";
457 default:
458 return "RFU";
459 }
460}
461
Harald Weltee0590df2009-02-15 03:34:15 +0000462/* Chapter 9.4.7 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800463static const struct value_string avail_names[] = {
464 { 0, "In test" },
465 { 1, "Failed" },
466 { 2, "Power off" },
467 { 3, "Off line" },
468 /* Not used */
469 { 5, "Dependency" },
470 { 6, "Degraded" },
471 { 7, "Not installed" },
472 { 0xff, "OK" },
473 { 0, NULL }
Harald Weltee0590df2009-02-15 03:34:15 +0000474};
475
Harald Welte4d87f242009-03-10 19:43:44 +0000476const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000477{
Harald Welte92b1fe42010-03-25 11:45:30 +0800478 return get_value_string(avail_names, avail);
Harald Weltee0590df2009-02-15 03:34:15 +0000479}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000480
Harald Welte0f255852009-11-12 14:48:42 +0100481static struct value_string test_names[] = {
482 /* FIXME: standard test names */
483 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
484 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
485 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
486 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
487 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
488 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
489 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
490 { 0, NULL }
491};
492
Harald Welte7b26bcb2009-05-28 11:39:21 +0000493const char *nm_adm_name(u_int8_t adm)
494{
495 switch (adm) {
496 case 1:
497 return "Locked";
498 case 2:
499 return "Unlocked";
500 case 3:
501 return "Shutdown";
502 default:
503 return "<not used>";
504 }
505}
Harald Weltee0590df2009-02-15 03:34:15 +0000506
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100507int nm_is_running(struct gsm_nm_state *s) {
508 return (s->operational == NM_OPSTATE_ENABLED) && (
509 (s->availability == NM_AVSTATE_OK) ||
510 (s->availability == 0xff)
511 );
512}
513
Harald Weltea8bd6d42009-10-20 09:56:18 +0200514static void debugp_foh(struct abis_om_fom_hdr *foh)
515{
516 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
517 obj_class_name(foh->obj_class), foh->obj_class,
518 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
519 foh->obj_inst.ts_nr);
520}
521
Harald Weltee0590df2009-02-15 03:34:15 +0000522/* obtain the gsm_nm_state data structure for a given object instance */
523static struct gsm_nm_state *
524objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
525 struct abis_om_obj_inst *obj_inst)
526{
527 struct gsm_bts_trx *trx;
528 struct gsm_nm_state *nm_state = NULL;
529
530 switch (obj_class) {
531 case NM_OC_BTS:
532 nm_state = &bts->nm_state;
533 break;
534 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100535 if (obj_inst->trx_nr >= bts->num_trx) {
536 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000537 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100538 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200539 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000540 nm_state = &trx->nm_state;
541 break;
542 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100543 if (obj_inst->trx_nr >= bts->num_trx) {
544 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000545 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100546 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200547 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000548 nm_state = &trx->bb_transc.nm_state;
549 break;
550 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100551 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100552 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000553 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100554 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200555 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000556 if (obj_inst->ts_nr >= TRX_NR_TS)
557 return NULL;
558 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
559 break;
560 case NM_OC_SITE_MANAGER:
561 nm_state = &bts->site_mgr.nm_state;
562 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000563 case NM_OC_BS11:
564 switch (obj_inst->bts_nr) {
565 case BS11_OBJ_CCLK:
566 nm_state = &bts->bs11.cclk.nm_state;
567 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000568 case BS11_OBJ_BBSIG:
569 if (obj_inst->ts_nr > bts->num_trx)
570 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200571 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000572 nm_state = &trx->bs11.bbsig.nm_state;
573 break;
574 case BS11_OBJ_PA:
575 if (obj_inst->ts_nr > bts->num_trx)
576 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200577 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000578 nm_state = &trx->bs11.pa.nm_state;
579 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000580 default:
581 return NULL;
582 }
583 case NM_OC_BS11_RACK:
584 nm_state = &bts->bs11.rack.nm_state;
585 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000586 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100587 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000588 return NULL;
589 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
590 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200591 case NM_OC_GPRS_NSE:
592 nm_state = &bts->gprs.nse.nm_state;
593 break;
594 case NM_OC_GPRS_CELL:
595 nm_state = &bts->gprs.cell.nm_state;
596 break;
597 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100598 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200599 return NULL;
600 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
601 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000602 }
603 return nm_state;
604}
605
606/* obtain the in-memory data structure of a given object instance */
607static void *
608objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
609 struct abis_om_obj_inst *obj_inst)
610{
611 struct gsm_bts_trx *trx;
612 void *obj = NULL;
613
614 switch (obj_class) {
615 case NM_OC_BTS:
616 obj = bts;
617 break;
618 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100619 if (obj_inst->trx_nr >= bts->num_trx) {
620 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000621 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100622 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200623 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000624 obj = trx;
625 break;
626 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100627 if (obj_inst->trx_nr >= bts->num_trx) {
628 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000629 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100630 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200631 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000632 obj = &trx->bb_transc;
633 break;
634 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100635 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100636 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000637 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100638 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200639 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000640 if (obj_inst->ts_nr >= TRX_NR_TS)
641 return NULL;
642 obj = &trx->ts[obj_inst->ts_nr];
643 break;
644 case NM_OC_SITE_MANAGER:
645 obj = &bts->site_mgr;
646 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200647 case NM_OC_GPRS_NSE:
648 obj = &bts->gprs.nse;
649 break;
650 case NM_OC_GPRS_CELL:
651 obj = &bts->gprs.cell;
652 break;
653 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100654 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200655 return NULL;
656 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
657 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000658 }
659 return obj;
660}
661
662/* Update the administrative state of a given object in our in-memory data
663 * structures and send an event to the higher layer */
664static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
665 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
666{
Harald Welteaeedeb42009-05-01 13:08:14 +0000667 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000668 void *obj;
669 int rc;
670
Harald Weltee0590df2009-02-15 03:34:15 +0000671 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100672 if (!obj)
673 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000674 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
675 if (!nm_state)
676 return -1;
677
678 new_state = *nm_state;
679 new_state.administrative = adm_state;
680
681 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
682
683 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000684
685 return rc;
686}
687
Harald Welte97ed1e72009-02-06 13:38:02 +0000688static int abis_nm_rx_statechg_rep(struct msgb *mb)
689{
Harald Weltee0590df2009-02-15 03:34:15 +0000690 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000691 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000692 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000693 struct tlv_parsed tp;
694 struct gsm_nm_state *nm_state, new_state;
695 int rc;
696
Harald Welte23897662009-05-01 14:52:51 +0000697 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000698
Harald Welte8b697c72009-06-05 19:18:45 +0000699 memset(&new_state, 0, sizeof(new_state));
700
Harald Weltee0590df2009-02-15 03:34:15 +0000701 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
702 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100703 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000704 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000705 }
Harald Weltee0590df2009-02-15 03:34:15 +0000706
707 new_state = *nm_state;
708
Harald Welte39315c42010-01-10 18:01:52 +0100709 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000710 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
711 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000712 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000713 }
714 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000715 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
716 new_state.availability = 0xff;
717 else
718 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000719 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000720 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100721 } else
722 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000723 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
724 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200725 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000726 }
727 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000728
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100729 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
730 new_state.operational != nm_state->operational ||
731 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000732 /* Update the operational state of a given object in our in-memory data
733 * structures and send an event to the higher layer */
734 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
735 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100736 nm_state->operational = new_state.operational;
737 nm_state->availability = new_state.availability;
738 if (nm_state->administrative == 0)
739 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000740 }
741#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000742 if (op_state == 1) {
743 /* try to enable objects that are disabled */
744 abis_nm_opstart(bts, foh->obj_class,
745 foh->obj_inst.bts_nr,
746 foh->obj_inst.trx_nr,
747 foh->obj_inst.ts_nr);
748 }
Harald Weltee0590df2009-02-15 03:34:15 +0000749#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000750 return 0;
751}
752
Harald Welte0db97b22009-05-01 17:22:47 +0000753static int rx_fail_evt_rep(struct msgb *mb)
754{
755 struct abis_om_hdr *oh = msgb_l2(mb);
756 struct abis_om_fom_hdr *foh = msgb_l3(mb);
757 struct tlv_parsed tp;
758
759 DEBUGPC(DNM, "Failure Event Report ");
760
Harald Welte39315c42010-01-10 18:01:52 +0100761 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000762
763 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
764 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
765 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
766 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
767
768 DEBUGPC(DNM, "\n");
769
770 return 0;
771}
772
Harald Welte97ed1e72009-02-06 13:38:02 +0000773static int abis_nm_rcvmsg_report(struct msgb *mb)
774{
775 struct abis_om_fom_hdr *foh = msgb_l3(mb);
776 u_int8_t mt = foh->msg_type;
777
Harald Weltea8bd6d42009-10-20 09:56:18 +0200778 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000779
Harald Welte97ed1e72009-02-06 13:38:02 +0000780 //nmh->cfg->report_cb(mb, foh);
781
782 switch (mt) {
783 case NM_MT_STATECHG_EVENT_REP:
784 return abis_nm_rx_statechg_rep(mb);
785 break;
Harald Welte34a99682009-02-13 02:41:40 +0000786 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000787 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000788 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000789 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000790 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000791 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000792 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000793 break;
Harald Weltec7310382009-08-08 00:02:36 +0200794 case NM_MT_TEST_REP:
795 DEBUGPC(DNM, "Test Report\n");
796 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
797 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000798 default:
Harald Welte23897662009-05-01 14:52:51 +0000799 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000800 break;
801
Harald Welte97ed1e72009-02-06 13:38:02 +0000802 };
803
Harald Welte97ed1e72009-02-06 13:38:02 +0000804 return 0;
805}
806
Harald Welte34a99682009-02-13 02:41:40 +0000807/* Activate the specified software into the BTS */
808static 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 +0200809 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000810{
811 struct abis_om_hdr *oh;
812 struct msgb *msg = nm_msgb_alloc();
813 u_int8_t len = swdesc_len;
814 u_int8_t *trailer;
815
816 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
817 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
818
819 trailer = msgb_put(msg, swdesc_len);
820 memcpy(trailer, sw_desc, swdesc_len);
821
822 return abis_nm_sendmsg(bts, msg);
823}
824
825static int abis_nm_rx_sw_act_req(struct msgb *mb)
826{
827 struct abis_om_hdr *oh = msgb_l2(mb);
828 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200829 struct tlv_parsed tp;
830 const u_int8_t *sw_config;
831 int sw_config_len;
832 int file_id_len;
Harald Welte34a99682009-02-13 02:41:40 +0000833 int ret;
834
Harald Weltea8bd6d42009-10-20 09:56:18 +0200835 debugp_foh(foh);
836
837 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000838
Harald Welte97a282b2010-03-14 15:37:43 +0800839 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000840
841 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000842 foh->obj_inst.bts_nr,
843 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800844 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000845 foh->data, oh->length-sizeof(*foh));
846
Harald Welte39315c42010-01-10 18:01:52 +0100847 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200848 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
849 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
850 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
851 DEBUGP(DNM, "SW config not found! Can't continue.\n");
852 return -EINVAL;
853 } else {
854 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
855 }
856
857 if (sw_config[0] != NM_ATT_SW_DESCR)
858 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
859 if (sw_config[1] != NM_ATT_FILE_ID)
860 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
861 file_id_len = sw_config[2] * 256 + sw_config[3];
862
863 /* Assumes first SW file in list is the one to be activated */
864 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000865 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
866 foh->obj_inst.bts_nr,
867 foh->obj_inst.trx_nr,
868 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200869 sw_config + 4,
870 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000871}
872
Harald Weltee0590df2009-02-15 03:34:15 +0000873/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
874static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
875{
876 struct abis_om_hdr *oh = msgb_l2(mb);
877 struct abis_om_fom_hdr *foh = msgb_l3(mb);
878 struct tlv_parsed tp;
879 u_int8_t adm_state;
880
Harald Welte39315c42010-01-10 18:01:52 +0100881 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000882 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
883 return -EINVAL;
884
885 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
886
887 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
888}
889
Harald Welteee670472009-02-22 21:58:49 +0000890static int abis_nm_rx_lmt_event(struct msgb *mb)
891{
892 struct abis_om_hdr *oh = msgb_l2(mb);
893 struct abis_om_fom_hdr *foh = msgb_l3(mb);
894 struct tlv_parsed tp;
895
896 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100897 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000898 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
899 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
900 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
901 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
902 }
903 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
904 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
905 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
906 DEBUGPC(DNM, "Level=%u ", level);
907 }
908 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
909 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
910 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
911 DEBUGPC(DNM, "Username=%s ", name);
912 }
913 DEBUGPC(DNM, "\n");
914 /* FIXME: parse LMT LOGON TIME */
915 return 0;
916}
917
Harald Welte52b1f982008-12-23 20:25:15 +0000918/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000919static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000920{
Harald Welte6c96ba52009-05-01 13:03:40 +0000921 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000922 struct abis_om_fom_hdr *foh = msgb_l3(mb);
923 u_int8_t mt = foh->msg_type;
924
925 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000926 if (is_report(mt))
927 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000928
Harald Welte4724f992009-01-18 18:01:49 +0000929 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
930 return abis_nm_rcvmsg_sw(mb);
931
Harald Welte78fc0d42009-02-19 02:50:57 +0000932 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +0000933 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200934
Harald Weltea8bd6d42009-10-20 09:56:18 +0200935 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200936
Harald Welte92b1fe42010-03-25 11:45:30 +0800937 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000938
Harald Welte39315c42010-01-10 18:01:52 +0100939 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000940 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
941 DEBUGPC(DNM, "CAUSE=%s\n",
942 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
943 else
944 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200945
Harald Welted8cfc902009-11-17 06:09:56 +0100946 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200947 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000948 }
Harald Weltead384642008-12-26 10:20:07 +0000949#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000950 /* check if last message is to be acked */
951 if (is_ack_nack(nmh->last_msgtype)) {
952 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100953 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000954 /* we got our ACK, continue sending the next msg */
955 } else if (mt == MT_NACK(nmh->last_msgtype)) {
956 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100957 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000958 /* FIXME: somehow signal this to the caller */
959 } else {
960 /* really strange things happen */
961 return -EINVAL;
962 }
963 }
Harald Weltead384642008-12-26 10:20:07 +0000964#endif
965
Harald Welte97ed1e72009-02-06 13:38:02 +0000966 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000967 case NM_MT_CHG_ADM_STATE_ACK:
968 return abis_nm_rx_chg_adm_state_ack(mb);
969 break;
Harald Welte34a99682009-02-13 02:41:40 +0000970 case NM_MT_SW_ACT_REQ:
971 return abis_nm_rx_sw_act_req(mb);
972 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000973 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +0000974 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000975 break;
Harald Welte1989c082009-08-06 17:58:31 +0200976 case NM_MT_CONN_MDROP_LINK_ACK:
977 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
978 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100979 case NM_MT_IPACC_RESTART_ACK:
980 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
981 break;
982 case NM_MT_IPACC_RESTART_NACK:
983 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
984 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000985 }
986
Harald Weltead384642008-12-26 10:20:07 +0000987 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000988}
989
Harald Welte677c21f2009-02-17 13:22:23 +0000990static int abis_nm_rx_ipacc(struct msgb *mb);
991
992static int abis_nm_rcvmsg_manuf(struct msgb *mb)
993{
994 int rc;
995 int bts_type = mb->trx->bts->type;
996
997 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100998 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000999 rc = abis_nm_rx_ipacc(mb);
1000 break;
1001 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001002 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1003 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001004 rc = 0;
1005 break;
1006 }
1007
1008 return rc;
1009}
1010
Harald Welte52b1f982008-12-23 20:25:15 +00001011/* High-Level API */
1012/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001013int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001014{
Harald Welte52b1f982008-12-23 20:25:15 +00001015 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001016 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001017
1018 /* Various consistency checks */
1019 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001020 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001021 oh->placement);
1022 return -EINVAL;
1023 }
1024 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001025 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001026 oh->sequence);
1027 return -EINVAL;
1028 }
Harald Welte702d8702008-12-26 20:25:35 +00001029#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001030 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1031 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001032 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001033 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001034 oh->length + sizeof(*oh), l2_len);
1035 return -EINVAL;
1036 }
Harald Welte702d8702008-12-26 20:25:35 +00001037 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001038 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 +00001039#endif
Harald Weltead384642008-12-26 10:20:07 +00001040 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001041
1042 switch (oh->mdisc) {
1043 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001044 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001045 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001046 case ABIS_OM_MDISC_MANUF:
1047 rc = abis_nm_rcvmsg_manuf(msg);
1048 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001049 case ABIS_OM_MDISC_MMI:
1050 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001051 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001052 oh->mdisc);
1053 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001054 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001055 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001056 oh->mdisc);
1057 return -EINVAL;
1058 }
1059
Harald Weltead384642008-12-26 10:20:07 +00001060 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001061 return rc;
1062}
1063
1064#if 0
1065/* initialized all resources */
1066struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1067{
1068 struct abis_nm_h *nmh;
1069
1070 nmh = malloc(sizeof(*nmh));
1071 if (!nmh)
1072 return NULL;
1073
1074 nmh->cfg = cfg;
1075
1076 return nmh;
1077}
1078
1079/* free all resources */
1080void abis_nm_fini(struct abis_nm_h *nmh)
1081{
1082 free(nmh);
1083}
1084#endif
1085
1086/* Here we are trying to define a high-level API that can be used by
1087 * the actual BSC implementation. However, the architecture is currently
1088 * still under design. Ideally the calls to this API would be synchronous,
1089 * while the underlying stack behind the APi runs in a traditional select
1090 * based state machine.
1091 */
1092
Harald Welte4724f992009-01-18 18:01:49 +00001093/* 6.2 Software Load: */
1094enum sw_state {
1095 SW_STATE_NONE,
1096 SW_STATE_WAIT_INITACK,
1097 SW_STATE_WAIT_SEGACK,
1098 SW_STATE_WAIT_ENDACK,
1099 SW_STATE_WAIT_ACTACK,
1100 SW_STATE_ERROR,
1101};
Harald Welte52b1f982008-12-23 20:25:15 +00001102
Harald Welte52b1f982008-12-23 20:25:15 +00001103struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001104 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001105 gsm_cbfn *cbfn;
1106 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001107 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001108
Harald Welte52b1f982008-12-23 20:25:15 +00001109 /* this will become part of the SW LOAD INITIATE */
1110 u_int8_t obj_class;
1111 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001112
1113 u_int8_t file_id[255];
1114 u_int8_t file_id_len;
1115
1116 u_int8_t file_version[255];
1117 u_int8_t file_version_len;
1118
1119 u_int8_t window_size;
1120 u_int8_t seg_in_window;
1121
1122 int fd;
1123 FILE *stream;
1124 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001125 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001126};
1127
Harald Welte4724f992009-01-18 18:01:49 +00001128static struct abis_nm_sw g_sw;
1129
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001130static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1131{
1132 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1133 msgb_v_put(msg, NM_ATT_SW_DESCR);
1134 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1135 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1136 sw->file_version);
1137 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1138 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1139 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1140 sw->file_version);
1141 } else {
1142 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1143 }
1144}
1145
Harald Welte4724f992009-01-18 18:01:49 +00001146/* 6.2.1 / 8.3.1: Load Data Initiate */
1147static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001148{
Harald Welte4724f992009-01-18 18:01:49 +00001149 struct abis_om_hdr *oh;
1150 struct msgb *msg = nm_msgb_alloc();
1151 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1152
1153 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1154 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1155 sw->obj_instance[0], sw->obj_instance[1],
1156 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001157
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001158 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001159 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1160
1161 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001162}
1163
Harald Welte1602ade2009-01-29 21:12:39 +00001164static int is_last_line(FILE *stream)
1165{
1166 char next_seg_buf[256];
1167 long pos;
1168
1169 /* check if we're sending the last line */
1170 pos = ftell(stream);
1171 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1172 fseek(stream, pos, SEEK_SET);
1173 return 1;
1174 }
1175
1176 fseek(stream, pos, SEEK_SET);
1177 return 0;
1178}
1179
Harald Welte4724f992009-01-18 18:01:49 +00001180/* 6.2.2 / 8.3.2 Load Data Segment */
1181static int sw_load_segment(struct abis_nm_sw *sw)
1182{
1183 struct abis_om_hdr *oh;
1184 struct msgb *msg = nm_msgb_alloc();
1185 char seg_buf[256];
1186 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001187 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001188 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001189
1190 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001191
1192 switch (sw->bts->type) {
1193 case GSM_BTS_TYPE_BS11:
1194 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1195 perror("fgets reading segment");
1196 return -EINVAL;
1197 }
1198 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001199
1200 /* check if we're sending the last line */
1201 sw->last_seg = is_last_line(sw->stream);
1202 if (sw->last_seg)
1203 seg_buf[1] = 0;
1204 else
1205 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001206
1207 len = strlen(line_buf) + 2;
1208 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1209 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1210 /* BS11 wants CR + LF in excess of the TLV length !?! */
1211 tlv[1] -= 2;
1212
1213 /* we only now know the exact length for the OM hdr */
1214 len = strlen(line_buf)+2;
1215 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001216 case GSM_BTS_TYPE_NANOBTS: {
1217 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1218 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1219 if (len < 0) {
1220 perror("read failed");
1221 return -EINVAL;
1222 }
1223
1224 if (len != IPACC_SEGMENT_SIZE)
1225 sw->last_seg = 1;
1226
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001227 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001228 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1229 len += 3;
1230 break;
1231 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001232 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001233 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001234 /* FIXME: Other BTS types */
1235 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001236 }
Harald Welte4724f992009-01-18 18:01:49 +00001237
Harald Welte4724f992009-01-18 18:01:49 +00001238 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1239 sw->obj_instance[0], sw->obj_instance[1],
1240 sw->obj_instance[2]);
1241
1242 return abis_nm_sendmsg(sw->bts, msg);
1243}
1244
1245/* 6.2.4 / 8.3.4 Load Data End */
1246static int sw_load_end(struct abis_nm_sw *sw)
1247{
1248 struct abis_om_hdr *oh;
1249 struct msgb *msg = nm_msgb_alloc();
1250 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1251
1252 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1253 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1254 sw->obj_instance[0], sw->obj_instance[1],
1255 sw->obj_instance[2]);
1256
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001257 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001258 return abis_nm_sendmsg(sw->bts, msg);
1259}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001260
Harald Welte52b1f982008-12-23 20:25:15 +00001261/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001262static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001263{
Harald Welte4724f992009-01-18 18:01:49 +00001264 struct abis_om_hdr *oh;
1265 struct msgb *msg = nm_msgb_alloc();
1266 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001267
Harald Welte4724f992009-01-18 18:01:49 +00001268 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1269 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1270 sw->obj_instance[0], sw->obj_instance[1],
1271 sw->obj_instance[2]);
1272
1273 /* FIXME: this is BS11 specific format */
1274 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1275 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1276 sw->file_version);
1277
1278 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001279}
Harald Welte4724f992009-01-18 18:01:49 +00001280
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001281struct sdp_firmware {
1282 char magic[4];
1283 char more_magic[4];
1284 unsigned int header_length;
1285 unsigned int file_length;
1286} __attribute__ ((packed));
1287
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001288static int parse_sdp_header(struct abis_nm_sw *sw)
1289{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001290 struct sdp_firmware firmware_header;
1291 int rc;
1292 struct stat stat;
1293
1294 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1295 if (rc != sizeof(firmware_header)) {
1296 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1297 return -1;
1298 }
1299
1300 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1301 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1302 return -1;
1303 }
1304
1305 if (firmware_header.more_magic[0] != 0x10 ||
1306 firmware_header.more_magic[1] != 0x02 ||
1307 firmware_header.more_magic[2] != 0x00 ||
1308 firmware_header.more_magic[3] != 0x00) {
1309 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1310 return -1;
1311 }
1312
1313
1314 if (fstat(sw->fd, &stat) == -1) {
1315 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1316 return -1;
1317 }
1318
1319 if (ntohl(firmware_header.file_length) != stat.st_size) {
1320 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1321 return -1;
1322 }
1323
1324 /* go back to the start as we checked the whole filesize.. */
1325 lseek(sw->fd, 0l, SEEK_SET);
1326 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1327 "There might be checksums in the file that are not\n"
1328 "verified and incomplete firmware might be flashed.\n"
1329 "There is absolutely no WARRANTY that flashing will\n"
1330 "work.\n");
1331 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001332}
1333
Harald Welte4724f992009-01-18 18:01:49 +00001334static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1335{
1336 char file_id[12+1];
1337 char file_version[80+1];
1338 int rc;
1339
1340 sw->fd = open(fname, O_RDONLY);
1341 if (sw->fd < 0)
1342 return sw->fd;
1343
1344 switch (sw->bts->type) {
1345 case GSM_BTS_TYPE_BS11:
1346 sw->stream = fdopen(sw->fd, "r");
1347 if (!sw->stream) {
1348 perror("fdopen");
1349 return -1;
1350 }
1351 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001352 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001353 file_id, file_version);
1354 if (rc != 2) {
1355 perror("parsing header line of software file");
1356 return -1;
1357 }
1358 strcpy((char *)sw->file_id, file_id);
1359 sw->file_id_len = strlen(file_id);
1360 strcpy((char *)sw->file_version, file_version);
1361 sw->file_version_len = strlen(file_version);
1362 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001363 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001364 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001365 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001366 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001367 rc = parse_sdp_header(sw);
1368 if (rc < 0) {
1369 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1370 return -1;
1371 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001372
1373 strcpy((char *)sw->file_id, "id");
1374 sw->file_id_len = 3;
1375 strcpy((char *)sw->file_version, "version");
1376 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001377 break;
Harald Welte4724f992009-01-18 18:01:49 +00001378 default:
1379 /* We don't know how to treat them yet */
1380 close(sw->fd);
1381 return -EINVAL;
1382 }
1383
1384 return 0;
1385}
1386
1387static void sw_close_file(struct abis_nm_sw *sw)
1388{
1389 switch (sw->bts->type) {
1390 case GSM_BTS_TYPE_BS11:
1391 fclose(sw->stream);
1392 break;
1393 default:
1394 close(sw->fd);
1395 break;
1396 }
1397}
1398
1399/* Fill the window */
1400static int sw_fill_window(struct abis_nm_sw *sw)
1401{
1402 int rc;
1403
1404 while (sw->seg_in_window < sw->window_size) {
1405 rc = sw_load_segment(sw);
1406 if (rc < 0)
1407 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001408 if (sw->last_seg)
1409 break;
Harald Welte4724f992009-01-18 18:01:49 +00001410 }
1411 return 0;
1412}
1413
1414/* callback function from abis_nm_rcvmsg() handler */
1415static int abis_nm_rcvmsg_sw(struct msgb *mb)
1416{
1417 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1418 int rc = -1;
1419 struct abis_nm_sw *sw = &g_sw;
1420 enum sw_state old_state = sw->state;
1421
Harald Welte3ffd1372009-02-01 22:15:49 +00001422 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001423
1424 switch (sw->state) {
1425 case SW_STATE_WAIT_INITACK:
1426 switch (foh->msg_type) {
1427 case NM_MT_LOAD_INIT_ACK:
1428 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001429 if (sw->cbfn)
1430 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1431 NM_MT_LOAD_INIT_ACK, mb,
1432 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001433 rc = sw_fill_window(sw);
1434 sw->state = SW_STATE_WAIT_SEGACK;
1435 break;
1436 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001437 if (sw->forced) {
1438 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1439 "Init NACK\n");
1440 if (sw->cbfn)
1441 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1442 NM_MT_LOAD_INIT_ACK, mb,
1443 sw->cb_data, NULL);
1444 rc = sw_fill_window(sw);
1445 sw->state = SW_STATE_WAIT_SEGACK;
1446 } else {
1447 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001448 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001449 if (sw->cbfn)
1450 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1451 NM_MT_LOAD_INIT_NACK, mb,
1452 sw->cb_data, NULL);
1453 sw->state = SW_STATE_ERROR;
1454 }
Harald Welte4724f992009-01-18 18:01:49 +00001455 break;
1456 }
1457 break;
1458 case SW_STATE_WAIT_SEGACK:
1459 switch (foh->msg_type) {
1460 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001461 if (sw->cbfn)
1462 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1463 NM_MT_LOAD_SEG_ACK, mb,
1464 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001465 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001466 if (!sw->last_seg) {
1467 /* fill window with more segments */
1468 rc = sw_fill_window(sw);
1469 sw->state = SW_STATE_WAIT_SEGACK;
1470 } else {
1471 /* end the transfer */
1472 sw->state = SW_STATE_WAIT_ENDACK;
1473 rc = sw_load_end(sw);
1474 }
Harald Welte4724f992009-01-18 18:01:49 +00001475 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001476 case NM_MT_LOAD_ABORT:
1477 if (sw->cbfn)
1478 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1479 NM_MT_LOAD_ABORT, mb,
1480 sw->cb_data, NULL);
1481 break;
Harald Welte4724f992009-01-18 18:01:49 +00001482 }
1483 break;
1484 case SW_STATE_WAIT_ENDACK:
1485 switch (foh->msg_type) {
1486 case NM_MT_LOAD_END_ACK:
1487 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001488 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1489 sw->bts->nr);
1490 sw->state = SW_STATE_NONE;
1491 if (sw->cbfn)
1492 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1493 NM_MT_LOAD_END_ACK, mb,
1494 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001495 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001496 break;
1497 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001498 if (sw->forced) {
1499 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1500 "End NACK\n");
1501 sw->state = SW_STATE_NONE;
1502 if (sw->cbfn)
1503 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1504 NM_MT_LOAD_END_ACK, mb,
1505 sw->cb_data, NULL);
1506 } else {
1507 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001508 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001509 sw->state = SW_STATE_ERROR;
1510 if (sw->cbfn)
1511 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1512 NM_MT_LOAD_END_NACK, mb,
1513 sw->cb_data, NULL);
1514 }
Harald Welte4724f992009-01-18 18:01:49 +00001515 break;
1516 }
1517 case SW_STATE_WAIT_ACTACK:
1518 switch (foh->msg_type) {
1519 case NM_MT_ACTIVATE_SW_ACK:
1520 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001521 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001522 sw->state = SW_STATE_NONE;
1523 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001524 if (sw->cbfn)
1525 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1526 NM_MT_ACTIVATE_SW_ACK, mb,
1527 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001528 break;
1529 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001530 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001531 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001532 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001533 if (sw->cbfn)
1534 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1535 NM_MT_ACTIVATE_SW_NACK, mb,
1536 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001537 break;
1538 }
1539 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001540 switch (foh->msg_type) {
1541 case NM_MT_ACTIVATE_SW_ACK:
1542 rc = 0;
1543 break;
1544 }
1545 break;
Harald Welte4724f992009-01-18 18:01:49 +00001546 case SW_STATE_ERROR:
1547 break;
1548 }
1549
1550 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001551 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001552 foh->msg_type, old_state, sw->state);
1553
1554 return rc;
1555}
1556
1557/* Load the specified software into the BTS */
1558int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001559 u_int8_t win_size, int forced,
1560 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001561{
1562 struct abis_nm_sw *sw = &g_sw;
1563 int rc;
1564
Harald Welte5e4d1b32009-02-01 13:36:56 +00001565 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1566 bts->nr, fname);
1567
Harald Welte4724f992009-01-18 18:01:49 +00001568 if (sw->state != SW_STATE_NONE)
1569 return -EBUSY;
1570
1571 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001572
1573 switch (bts->type) {
1574 case GSM_BTS_TYPE_BS11:
1575 sw->obj_class = NM_OC_SITE_MANAGER;
1576 sw->obj_instance[0] = 0xff;
1577 sw->obj_instance[1] = 0xff;
1578 sw->obj_instance[2] = 0xff;
1579 break;
1580 case GSM_BTS_TYPE_NANOBTS:
1581 sw->obj_class = NM_OC_BASEB_TRANSC;
1582 sw->obj_instance[0] = 0x00;
1583 sw->obj_instance[1] = 0x00;
1584 sw->obj_instance[2] = 0xff;
1585 break;
1586 case GSM_BTS_TYPE_UNKNOWN:
1587 default:
1588 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1589 return -1;
1590 break;
1591 }
Harald Welte4724f992009-01-18 18:01:49 +00001592 sw->window_size = win_size;
1593 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001594 sw->cbfn = cbfn;
1595 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001596 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001597
1598 rc = sw_open_file(sw, fname);
1599 if (rc < 0) {
1600 sw->state = SW_STATE_NONE;
1601 return rc;
1602 }
1603
1604 return sw_load_init(sw);
1605}
Harald Welte52b1f982008-12-23 20:25:15 +00001606
Harald Welte1602ade2009-01-29 21:12:39 +00001607int abis_nm_software_load_status(struct gsm_bts *bts)
1608{
1609 struct abis_nm_sw *sw = &g_sw;
1610 struct stat st;
1611 int rc, percent;
1612
1613 rc = fstat(sw->fd, &st);
1614 if (rc < 0) {
1615 perror("ERROR during stat");
1616 return rc;
1617 }
1618
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001619 if (sw->stream)
1620 percent = (ftell(sw->stream) * 100) / st.st_size;
1621 else
1622 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001623 return percent;
1624}
1625
Harald Welte5e4d1b32009-02-01 13:36:56 +00001626/* Activate the specified software into the BTS */
1627int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1628 gsm_cbfn *cbfn, void *cb_data)
1629{
1630 struct abis_nm_sw *sw = &g_sw;
1631 int rc;
1632
1633 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1634 bts->nr, fname);
1635
1636 if (sw->state != SW_STATE_NONE)
1637 return -EBUSY;
1638
1639 sw->bts = bts;
1640 sw->obj_class = NM_OC_SITE_MANAGER;
1641 sw->obj_instance[0] = 0xff;
1642 sw->obj_instance[1] = 0xff;
1643 sw->obj_instance[2] = 0xff;
1644 sw->state = SW_STATE_WAIT_ACTACK;
1645 sw->cbfn = cbfn;
1646 sw->cb_data = cb_data;
1647
1648 /* Open the file in order to fill some sw struct members */
1649 rc = sw_open_file(sw, fname);
1650 if (rc < 0) {
1651 sw->state = SW_STATE_NONE;
1652 return rc;
1653 }
1654 sw_close_file(sw);
1655
1656 return sw_activate(sw);
1657}
1658
Harald Welte8470bf22008-12-25 23:28:35 +00001659static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001660 u_int8_t ts_nr, u_int8_t subslot_nr)
1661{
Harald Welteadaf08b2009-01-18 11:08:10 +00001662 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001663 ch->bts_port = bts_port;
1664 ch->timeslot = ts_nr;
1665 ch->subslot = subslot_nr;
1666}
1667
1668int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1669 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1670 u_int8_t tei)
1671{
1672 struct abis_om_hdr *oh;
1673 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001674 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001675 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001676
1677 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1678 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1679 bts->bts_nr, trx_nr, 0xff);
1680
Harald Welte8470bf22008-12-25 23:28:35 +00001681 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001682
1683 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1684 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1685
1686 return abis_nm_sendmsg(bts, msg);
1687}
1688
1689/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1690int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1691 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1692{
Harald Welte8470bf22008-12-25 23:28:35 +00001693 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001694 struct abis_om_hdr *oh;
1695 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001696 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001697
1698 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001699 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001700 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1701
1702 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1703 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1704
1705 return abis_nm_sendmsg(bts, msg);
1706}
1707
1708#if 0
1709int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1710 struct abis_nm_abis_channel *chan)
1711{
1712}
1713#endif
1714
1715int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1716 u_int8_t e1_port, u_int8_t e1_timeslot,
1717 u_int8_t e1_subslot)
1718{
1719 struct gsm_bts *bts = ts->trx->bts;
1720 struct abis_om_hdr *oh;
1721 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001722 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001723
1724 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1725 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001726 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001727
1728 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1729 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1730
Harald Weltef325eb42009-02-19 17:07:39 +00001731 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1732 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001733 e1_port, e1_timeslot, e1_subslot);
1734
Harald Welte52b1f982008-12-23 20:25:15 +00001735 return abis_nm_sendmsg(bts, msg);
1736}
1737
1738#if 0
1739int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1740 struct abis_nm_abis_channel *chan,
1741 u_int8_t subchan)
1742{
1743}
1744#endif
1745
Harald Welte22af0db2009-02-14 15:41:08 +00001746/* Chapter 8.6.1 */
1747int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1748{
1749 struct abis_om_hdr *oh;
1750 struct msgb *msg = nm_msgb_alloc();
1751 u_int8_t *cur;
1752
1753 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1754
1755 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001756 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 +00001757 cur = msgb_put(msg, attr_len);
1758 memcpy(cur, attr, attr_len);
1759
1760 return abis_nm_sendmsg(bts, msg);
1761}
1762
1763/* Chapter 8.6.2 */
1764int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1765{
1766 struct abis_om_hdr *oh;
1767 struct msgb *msg = nm_msgb_alloc();
1768 u_int8_t *cur;
1769
1770 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1771
1772 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1773 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001774 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001775 cur = msgb_put(msg, attr_len);
1776 memcpy(cur, attr, attr_len);
1777
1778 return abis_nm_sendmsg(trx->bts, msg);
1779}
1780
Harald Welte39c7deb2009-08-09 21:49:48 +02001781static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1782{
1783 int i;
1784
1785 /* As it turns out, the BS-11 has some very peculiar restrictions
1786 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301787 switch (ts->trx->bts->type) {
1788 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001789 switch (chan_comb) {
1790 case NM_CHANC_TCHHalf:
1791 case NM_CHANC_TCHHalf2:
1792 /* not supported */
1793 return -EINVAL;
1794 case NM_CHANC_SDCCH:
1795 /* only one SDCCH/8 per TRX */
1796 for (i = 0; i < TRX_NR_TS; i++) {
1797 if (i == ts->nr)
1798 continue;
1799 if (ts->trx->ts[i].nm_chan_comb ==
1800 NM_CHANC_SDCCH)
1801 return -EINVAL;
1802 }
1803 /* not allowed for TS0 of BCCH-TRX */
1804 if (ts->trx == ts->trx->bts->c0 &&
1805 ts->nr == 0)
1806 return -EINVAL;
1807 /* not on the same TRX that has a BCCH+SDCCH4
1808 * combination */
1809 if (ts->trx == ts->trx->bts->c0 &&
1810 (ts->trx->ts[0].nm_chan_comb == 5 ||
1811 ts->trx->ts[0].nm_chan_comb == 8))
1812 return -EINVAL;
1813 break;
1814 case NM_CHANC_mainBCCH:
1815 case NM_CHANC_BCCHComb:
1816 /* allowed only for TS0 of C0 */
1817 if (ts->trx != ts->trx->bts->c0 ||
1818 ts->nr != 0)
1819 return -EINVAL;
1820 break;
1821 case NM_CHANC_BCCH:
1822 /* allowed only for TS 2/4/6 of C0 */
1823 if (ts->trx != ts->trx->bts->c0)
1824 return -EINVAL;
1825 if (ts->nr != 2 && ts->nr != 4 &&
1826 ts->nr != 6)
1827 return -EINVAL;
1828 break;
1829 case 8: /* this is not like 08.58, but in fact
1830 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1831 /* FIXME: only one CBCH allowed per cell */
1832 break;
1833 }
Harald Welted6575f92009-12-02 02:45:23 +05301834 break;
1835 case GSM_BTS_TYPE_NANOBTS:
1836 switch (ts->nr) {
1837 case 0:
1838 if (ts->trx->nr == 0) {
1839 /* only on TRX0 */
1840 switch (chan_comb) {
1841 case NM_CHANC_BCCH:
1842 case NM_CHANC_mainBCCH:
1843 case NM_CHANC_BCCHComb:
1844 return 0;
1845 break;
1846 default:
1847 return -EINVAL;
1848 }
1849 } else {
1850 switch (chan_comb) {
1851 case NM_CHANC_TCHFull:
1852 case NM_CHANC_TCHHalf:
1853 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1854 return 0;
1855 default:
1856 return -EINVAL;
1857 }
1858 }
1859 break;
1860 case 1:
1861 if (ts->trx->nr == 0) {
1862 switch (chan_comb) {
1863 case NM_CHANC_SDCCH_CBCH:
1864 if (ts->trx->ts[0].nm_chan_comb ==
1865 NM_CHANC_mainBCCH)
1866 return 0;
1867 return -EINVAL;
1868 case NM_CHANC_SDCCH:
1869 case NM_CHANC_TCHFull:
1870 case NM_CHANC_TCHHalf:
1871 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1872 case NM_CHANC_IPAC_TCHFull_PDCH:
1873 return 0;
1874 }
1875 } else {
1876 switch (chan_comb) {
1877 case NM_CHANC_SDCCH:
1878 case NM_CHANC_TCHFull:
1879 case NM_CHANC_TCHHalf:
1880 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1881 return 0;
1882 default:
1883 return -EINVAL;
1884 }
1885 }
1886 break;
1887 case 2:
1888 case 3:
1889 case 4:
1890 case 5:
1891 case 6:
1892 case 7:
1893 switch (chan_comb) {
1894 case NM_CHANC_TCHFull:
1895 case NM_CHANC_TCHHalf:
1896 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1897 return 0;
1898 case NM_CHANC_IPAC_PDCH:
1899 case NM_CHANC_IPAC_TCHFull_PDCH:
1900 if (ts->trx->nr == 0)
1901 return 0;
1902 else
1903 return -EINVAL;
1904 }
1905 break;
1906 }
1907 return -EINVAL;
1908 default:
1909 /* unknown BTS type */
1910 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001911 }
1912 return 0;
1913}
1914
Harald Welte22af0db2009-02-14 15:41:08 +00001915/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001916int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1917{
1918 struct gsm_bts *bts = ts->trx->bts;
1919 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001920 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001921 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001922 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001923 u_int8_t len = 2 + 2;
1924
1925 if (bts->type == GSM_BTS_TYPE_BS11)
1926 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001927
Harald Weltef325eb42009-02-19 17:07:39 +00001928 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001929 if (verify_chan_comb(ts, chan_comb) < 0) {
1930 msgb_free(msg);
1931 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1932 return -EINVAL;
1933 }
1934 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001935
Harald Welte52b1f982008-12-23 20:25:15 +00001936 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001937 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001938 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001939 ts->trx->nr, ts->nr);
1940 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00001941 if (bts->type == GSM_BTS_TYPE_BS11)
1942 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001943 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00001944 if (bts->type == GSM_BTS_TYPE_BS11) {
1945 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1946 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1947 }
Harald Weltee6c22d92009-07-21 20:40:05 +02001948 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001949 if (bts->type == GSM_BTS_TYPE_BS11)
1950 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001951
1952 return abis_nm_sendmsg(bts, msg);
1953}
1954
Harald Welte34a99682009-02-13 02:41:40 +00001955int 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 +00001956 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001957{
1958 struct abis_om_hdr *oh;
1959 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00001960 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1961 u_int8_t len = att_len;
1962
1963 if (nack) {
1964 len += 2;
1965 msgtype = NM_MT_SW_ACT_REQ_NACK;
1966 }
Harald Welte34a99682009-02-13 02:41:40 +00001967
1968 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001969 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1970
Harald Welte34a99682009-02-13 02:41:40 +00001971 if (attr) {
1972 u_int8_t *ptr = msgb_put(msg, att_len);
1973 memcpy(ptr, attr, att_len);
1974 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001975 if (nack)
1976 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001977
1978 return abis_nm_sendmsg(bts, msg);
1979}
1980
Harald Welte8470bf22008-12-25 23:28:35 +00001981int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001982{
Harald Welte8470bf22008-12-25 23:28:35 +00001983 struct msgb *msg = nm_msgb_alloc();
1984 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00001985 u_int8_t *data;
1986
1987 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1988 fill_om_hdr(oh, len);
1989 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001990 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001991
1992 return abis_nm_sendmsg(bts, msg);
1993}
1994
1995/* Siemens specific commands */
1996static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
1997{
1998 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001999 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002000
2001 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002002 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002003 0xff, 0xff, 0xff);
2004
2005 return abis_nm_sendmsg(bts, msg);
2006}
2007
Harald Welte34a99682009-02-13 02:41:40 +00002008/* Chapter 8.9.2 */
2009int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2010{
2011 struct abis_om_hdr *oh;
2012 struct msgb *msg = nm_msgb_alloc();
2013
2014 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2015 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2016
Harald Weltea8bd6d42009-10-20 09:56:18 +02002017 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2018 DEBUGPC(DNM, "Sending OPSTART\n");
2019
Harald Welte34a99682009-02-13 02:41:40 +00002020 return abis_nm_sendmsg(bts, msg);
2021}
2022
2023/* Chapter 8.8.5 */
2024int 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 +02002025 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002026{
2027 struct abis_om_hdr *oh;
2028 struct msgb *msg = nm_msgb_alloc();
2029
2030 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2031 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2032 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2033
2034 return abis_nm_sendmsg(bts, msg);
2035}
2036
Harald Welte1989c082009-08-06 17:58:31 +02002037int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2038 u_int8_t e1_port1, u_int8_t ts1)
2039{
2040 struct abis_om_hdr *oh;
2041 struct msgb *msg = nm_msgb_alloc();
2042 u_int8_t *attr;
2043
2044 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2045 e1_port0, ts0, e1_port1, ts1);
2046
2047 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2048 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2049 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2050
2051 attr = msgb_put(msg, 3);
2052 attr[0] = NM_ATT_MDROP_LINK;
2053 attr[1] = e1_port0;
2054 attr[2] = ts0;
2055
2056 attr = msgb_put(msg, 3);
2057 attr[0] = NM_ATT_MDROP_NEXT;
2058 attr[1] = e1_port1;
2059 attr[2] = ts1;
2060
2061 return abis_nm_sendmsg(bts, msg);
2062}
Harald Welte34a99682009-02-13 02:41:40 +00002063
Harald Weltec7310382009-08-08 00:02:36 +02002064/* Chapter 8.7.1 */
2065int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2066 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2067 u_int8_t test_nr, u_int8_t auton_report,
2068 u_int8_t *phys_config, u_int16_t phys_config_len)
2069{
2070 struct abis_om_hdr *oh;
2071 struct msgb *msg = nm_msgb_alloc();
2072 int len = 4; /* 2 TV attributes */
2073
2074 DEBUGP(DNM, "PEFORM TEST\n");
2075
2076 if (phys_config_len)
2077 len += 3 + phys_config_len;
2078
2079 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2080 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2081 obj_class, bts_nr, trx_nr, ts_nr);
2082 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2083 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2084 if (phys_config_len)
2085 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2086 phys_config);
2087
2088 return abis_nm_sendmsg(bts, msg);
2089}
2090
Harald Welte52b1f982008-12-23 20:25:15 +00002091int abis_nm_event_reports(struct gsm_bts *bts, int on)
2092{
2093 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002094 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002095 else
Harald Welte227d4072009-01-03 08:16:25 +00002096 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002097}
2098
Harald Welte47d88ae2009-01-04 12:02:08 +00002099/* Siemens (or BS-11) specific commands */
2100
Harald Welte3ffd1372009-02-01 22:15:49 +00002101int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2102{
2103 if (reconnect == 0)
2104 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2105 else
2106 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2107}
2108
Harald Welteb8427972009-02-05 19:27:17 +00002109int abis_nm_bs11_restart(struct gsm_bts *bts)
2110{
2111 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2112}
2113
2114
Harald Welte268bb402009-02-01 19:11:56 +00002115struct bs11_date_time {
2116 u_int16_t year;
2117 u_int8_t month;
2118 u_int8_t day;
2119 u_int8_t hour;
2120 u_int8_t min;
2121 u_int8_t sec;
2122} __attribute__((packed));
2123
2124
2125void get_bs11_date_time(struct bs11_date_time *aet)
2126{
2127 time_t t;
2128 struct tm *tm;
2129
2130 t = time(NULL);
2131 tm = localtime(&t);
2132 aet->sec = tm->tm_sec;
2133 aet->min = tm->tm_min;
2134 aet->hour = tm->tm_hour;
2135 aet->day = tm->tm_mday;
2136 aet->month = tm->tm_mon;
2137 aet->year = htons(1900 + tm->tm_year);
2138}
2139
Harald Welte05188ee2009-01-18 11:39:08 +00002140int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002141{
Harald Welte4668fda2009-01-03 08:19:29 +00002142 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002143}
2144
Harald Welte05188ee2009-01-18 11:39:08 +00002145int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002146{
2147 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002148 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002149 else
Harald Welte4668fda2009-01-03 08:19:29 +00002150 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002151}
Harald Welte47d88ae2009-01-04 12:02:08 +00002152
Harald Welte05188ee2009-01-18 11:39:08 +00002153int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002154 enum abis_bs11_objtype type, u_int8_t idx,
2155 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002156{
2157 struct abis_om_hdr *oh;
2158 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002159 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002160
2161 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002162 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002163 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002164 cur = msgb_put(msg, attr_len);
2165 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002166
2167 return abis_nm_sendmsg(bts, msg);
2168}
2169
Harald Welte78fc0d42009-02-19 02:50:57 +00002170int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2171 enum abis_bs11_objtype type, u_int8_t idx)
2172{
2173 struct abis_om_hdr *oh;
2174 struct msgb *msg = nm_msgb_alloc();
2175
2176 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2177 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2178 NM_OC_BS11, type, 0, idx);
2179
2180 return abis_nm_sendmsg(bts, msg);
2181}
2182
Harald Welte05188ee2009-01-18 11:39:08 +00002183int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002184{
2185 struct abis_om_hdr *oh;
2186 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002187 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002188
2189 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002190 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002191 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2192 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002193
2194 return abis_nm_sendmsg(bts, msg);
2195}
2196
Harald Welte05188ee2009-01-18 11:39:08 +00002197int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002198{
2199 struct abis_om_hdr *oh;
2200 struct msgb *msg = nm_msgb_alloc();
2201
2202 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2203 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002204 idx, 0xff, 0xff);
2205
2206 return abis_nm_sendmsg(bts, msg);
2207}
2208
2209int abis_nm_bs11_delete_bport(struct gsm_bts *bts, 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, NM_OC_BS11_BPORT,
2216 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002217
2218 return abis_nm_sendmsg(bts, msg);
2219}
Harald Welte05188ee2009-01-18 11:39:08 +00002220
Harald Welte78fc0d42009-02-19 02:50:57 +00002221static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2222int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2223{
2224 struct abis_om_hdr *oh;
2225 struct msgb *msg = nm_msgb_alloc();
2226
2227 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2228 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2229 0xff, 0xff, 0xff);
2230 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2231
2232 return abis_nm_sendmsg(bts, msg);
2233}
2234
Harald Welteb6c92ae2009-02-21 20:15:32 +00002235/* like abis_nm_conn_terr_traf + set_tei */
2236int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2237 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2238 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002239{
2240 struct abis_om_hdr *oh;
2241 struct abis_nm_channel *ch;
2242 struct msgb *msg = nm_msgb_alloc();
2243
2244 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002245 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002246 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2247
2248 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2249 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002250 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002251
2252 return abis_nm_sendmsg(bts, msg);
2253}
2254
2255int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2256{
2257 struct abis_om_hdr *oh;
2258 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002259
2260 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002261 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002262 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2263 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2264
2265 return abis_nm_sendmsg(trx->bts, msg);
2266}
2267
Harald Welte78fc0d42009-02-19 02:50:57 +00002268int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2269{
2270 struct abis_om_hdr *oh;
2271 struct msgb *msg = nm_msgb_alloc();
2272 u_int8_t attr = NM_ATT_BS11_TXPWR;
2273
2274 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2275 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2276 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2277 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2278
2279 return abis_nm_sendmsg(trx->bts, msg);
2280}
2281
Harald Welteaaf02d92009-04-29 13:25:57 +00002282int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2283{
2284 struct abis_om_hdr *oh;
2285 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002286 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002287
2288 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2289 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2290 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002291 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002292
2293 return abis_nm_sendmsg(bts, msg);
2294}
2295
Harald Welteef061952009-05-17 12:43:42 +00002296int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2297{
2298 struct abis_om_hdr *oh;
2299 struct msgb *msg = nm_msgb_alloc();
2300 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2301 NM_ATT_BS11_CCLK_TYPE };
2302
2303 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2304 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2305 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2306 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2307
2308 return abis_nm_sendmsg(bts, msg);
2309
2310}
Harald Welteaaf02d92009-04-29 13:25:57 +00002311
Harald Welte268bb402009-02-01 19:11:56 +00002312//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002313
Harald Welte1bc09062009-01-18 14:17:52 +00002314int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002315{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002316 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2317}
2318
Daniel Willmann4b054c82010-01-07 00:46:26 +01002319int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2320{
2321 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2322}
2323
Daniel Willmann493db4e2010-01-07 00:43:11 +01002324int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2325{
Harald Welte05188ee2009-01-18 11:39:08 +00002326 struct abis_om_hdr *oh;
2327 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002328 struct bs11_date_time bdt;
2329
2330 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002331
2332 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002333 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002334 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002335 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002336 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002337 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002338 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002339 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002340 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002341 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002342 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002343 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002344 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002345 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002346 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002347 }
Harald Welte05188ee2009-01-18 11:39:08 +00002348
2349 return abis_nm_sendmsg(bts, msg);
2350}
Harald Welte1bc09062009-01-18 14:17:52 +00002351
2352int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2353{
2354 struct abis_om_hdr *oh;
2355 struct msgb *msg;
2356
2357 if (strlen(password) != 10)
2358 return -EINVAL;
2359
2360 msg = nm_msgb_alloc();
2361 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002362 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002363 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2364 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2365
2366 return abis_nm_sendmsg(bts, msg);
2367}
2368
Harald Weltee69f5fb2009-04-28 16:31:38 +00002369/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2370int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2371{
2372 struct abis_om_hdr *oh;
2373 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002374 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002375
2376 msg = nm_msgb_alloc();
2377 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2378 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2379 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002380
2381 if (locked)
2382 tlv_value = BS11_LI_PLL_LOCKED;
2383 else
2384 tlv_value = BS11_LI_PLL_STANDALONE;
2385
2386 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002387
2388 return abis_nm_sendmsg(bts, msg);
2389}
2390
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002391/* Set the calibration value of the PLL (work value/set value)
2392 * It depends on the login which one is changed */
2393int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2394{
2395 struct abis_om_hdr *oh;
2396 struct msgb *msg;
2397 u_int8_t tlv_value[2];
2398
2399 msg = nm_msgb_alloc();
2400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2401 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2402 BS11_OBJ_TRX1, 0x00, 0x00);
2403
2404 tlv_value[0] = value>>8;
2405 tlv_value[1] = value&0xff;
2406
2407 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2408
2409 return abis_nm_sendmsg(bts, msg);
2410}
2411
Harald Welte1bc09062009-01-18 14:17:52 +00002412int abis_nm_bs11_get_state(struct gsm_bts *bts)
2413{
2414 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2415}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002416
2417/* BS11 SWL */
2418
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002419void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002420
Harald Welte5e4d1b32009-02-01 13:36:56 +00002421struct abis_nm_bs11_sw {
2422 struct gsm_bts *bts;
2423 char swl_fname[PATH_MAX];
2424 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002425 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002426 struct llist_head file_list;
2427 gsm_cbfn *user_cb; /* specified by the user */
2428};
2429static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2430
2431struct file_list_entry {
2432 struct llist_head list;
2433 char fname[PATH_MAX];
2434};
2435
2436struct file_list_entry *fl_dequeue(struct llist_head *queue)
2437{
2438 struct llist_head *lh;
2439
2440 if (llist_empty(queue))
2441 return NULL;
2442
2443 lh = queue->next;
2444 llist_del(lh);
2445
2446 return llist_entry(lh, struct file_list_entry, list);
2447}
2448
2449static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2450{
2451 char linebuf[255];
2452 struct llist_head *lh, *lh2;
2453 FILE *swl;
2454 int rc = 0;
2455
2456 swl = fopen(bs11_sw->swl_fname, "r");
2457 if (!swl)
2458 return -ENODEV;
2459
2460 /* zero the stale file list, if any */
2461 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2462 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002463 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002464 }
2465
2466 while (fgets(linebuf, sizeof(linebuf), swl)) {
2467 char file_id[12+1];
2468 char file_version[80+1];
2469 struct file_list_entry *fle;
2470 static char dir[PATH_MAX];
2471
2472 if (strlen(linebuf) < 4)
2473 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002474
Harald Welte5e4d1b32009-02-01 13:36:56 +00002475 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2476 if (rc < 0) {
2477 perror("ERR parsing SWL file");
2478 rc = -EINVAL;
2479 goto out;
2480 }
2481 if (rc < 2)
2482 continue;
2483
Harald Welte470ec292009-06-26 20:25:23 +02002484 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002485 if (!fle) {
2486 rc = -ENOMEM;
2487 goto out;
2488 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002489
2490 /* construct new filename */
2491 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2492 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2493 strcat(fle->fname, "/");
2494 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002495
2496 llist_add_tail(&fle->list, &bs11_sw->file_list);
2497 }
2498
2499out:
2500 fclose(swl);
2501 return rc;
2502}
2503
2504/* bs11 swload specific callback, passed to abis_nm core swload */
2505static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2506 struct msgb *msg, void *data, void *param)
2507{
2508 struct abis_nm_bs11_sw *bs11_sw = data;
2509 struct file_list_entry *fle;
2510 int rc = 0;
2511
Harald Welte5e4d1b32009-02-01 13:36:56 +00002512 switch (event) {
2513 case NM_MT_LOAD_END_ACK:
2514 fle = fl_dequeue(&bs11_sw->file_list);
2515 if (fle) {
2516 /* start download the next file of our file list */
2517 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2518 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002519 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002520 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002521 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002522 } else {
2523 /* activate the SWL */
2524 rc = abis_nm_software_activate(bs11_sw->bts,
2525 bs11_sw->swl_fname,
2526 bs11_swload_cbfn,
2527 bs11_sw);
2528 }
2529 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002530 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002531 case NM_MT_LOAD_END_NACK:
2532 case NM_MT_LOAD_INIT_ACK:
2533 case NM_MT_LOAD_INIT_NACK:
2534 case NM_MT_ACTIVATE_SW_NACK:
2535 case NM_MT_ACTIVATE_SW_ACK:
2536 default:
2537 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002538 if (bs11_sw->user_cb)
2539 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002540 break;
2541 }
2542
2543 return rc;
2544}
2545
2546/* Siemens provides a SWL file that is a mere listing of all the other
2547 * files that are part of a software release. We need to upload first
2548 * the list file, and then each file that is listed in the list file */
2549int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002550 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002551{
2552 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2553 struct file_list_entry *fle;
2554 int rc = 0;
2555
2556 INIT_LLIST_HEAD(&bs11_sw->file_list);
2557 bs11_sw->bts = bts;
2558 bs11_sw->win_size = win_size;
2559 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002560 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002561
2562 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2563 rc = bs11_read_swl_file(bs11_sw);
2564 if (rc < 0)
2565 return rc;
2566
2567 /* dequeue next item in file list */
2568 fle = fl_dequeue(&bs11_sw->file_list);
2569 if (!fle)
2570 return -EINVAL;
2571
2572 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002573 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002574 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002575 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002576 return rc;
2577}
2578
Harald Welte5083b0b2009-02-02 19:20:52 +00002579#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002580static u_int8_t req_attr_btse[] = {
2581 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2582 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2583 NM_ATT_BS11_LMT_USER_NAME,
2584
2585 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2586
2587 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2588
2589 NM_ATT_BS11_SW_LOAD_STORED };
2590
2591static u_int8_t req_attr_btsm[] = {
2592 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2593 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2594 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2595 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002596#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002597
2598static u_int8_t req_attr[] = {
2599 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2600 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002601 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002602
2603int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2604{
2605 struct abis_om_hdr *oh;
2606 struct msgb *msg = nm_msgb_alloc();
2607
2608 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2609 /* SiemensHW CCTRL object */
2610 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2611 0x03, 0x00, 0x00);
2612 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2613
2614 return abis_nm_sendmsg(bts, msg);
2615}
Harald Welte268bb402009-02-01 19:11:56 +00002616
2617int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2618{
2619 struct abis_om_hdr *oh;
2620 struct msgb *msg = nm_msgb_alloc();
2621 struct bs11_date_time aet;
2622
2623 get_bs11_date_time(&aet);
2624 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2625 /* SiemensHW CCTRL object */
2626 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2627 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002628 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002629
2630 return abis_nm_sendmsg(bts, msg);
2631}
Harald Welte5c1e4582009-02-15 11:57:29 +00002632
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002633int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2634{
2635 struct abis_om_hdr *oh;
2636 struct msgb *msg = nm_msgb_alloc();
2637 struct bs11_date_time aet;
2638
2639 get_bs11_date_time(&aet);
2640 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2641 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2642 bport, 0xff, 0x02);
2643 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2644
2645 return abis_nm_sendmsg(bts, msg);
2646}
2647
Harald Welte5c1e4582009-02-15 11:57:29 +00002648/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002649static const char ipaccess_magic[] = "com.ipaccess";
2650
Harald Welte677c21f2009-02-17 13:22:23 +00002651
2652static int abis_nm_rx_ipacc(struct msgb *msg)
2653{
2654 struct abis_om_hdr *oh = msgb_l2(msg);
2655 struct abis_om_fom_hdr *foh;
2656 u_int8_t idstrlen = oh->data[0];
2657 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002658 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002659
2660 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002661 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002662 return -EINVAL;
2663 }
2664
Harald Welte193fefc2009-04-30 15:16:27 +00002665 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002666 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002667
Harald Weltea8bd6d42009-10-20 09:56:18 +02002668 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002669
Harald Welte746d6092009-10-19 22:11:11 +02002670 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002671
Harald Welte677c21f2009-02-17 13:22:23 +00002672 switch (foh->msg_type) {
2673 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002674 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002675 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002676 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002677 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002678 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2679 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002680 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002681 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002682 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002683 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2684 DEBUGPC(DNM, "STREAM=0x%02x ",
2685 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002686 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002687 break;
2688 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002689 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002690 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002691 DEBUGPC(DNM, " CAUSE=%s\n",
2692 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002693 else
2694 DEBUGPC(DNM, "\n");
2695 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002696 case NM_MT_IPACC_SET_NVATTR_ACK:
2697 DEBUGPC(DNM, "SET NVATTR ACK\n");
2698 /* FIXME: decode and show the actual attributes */
2699 break;
2700 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002701 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002702 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002703 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002704 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2705 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002706 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002707 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002708 case NM_MT_IPACC_GET_NVATTR_ACK:
2709 DEBUGPC(DNM, "GET NVATTR ACK\n");
2710 /* FIXME: decode and show the actual attributes */
2711 break;
2712 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002713 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002714 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002715 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002716 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2717 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002718 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002719 break;
Harald Welte15c44172009-10-08 20:15:24 +02002720 case NM_MT_IPACC_SET_ATTR_ACK:
2721 DEBUGPC(DNM, "SET ATTR ACK\n");
2722 break;
2723 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002724 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002725 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002726 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002727 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2728 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002729 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002730 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002731 default:
2732 DEBUGPC(DNM, "unknown\n");
2733 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002734 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002735
2736 /* signal handling */
2737 switch (foh->msg_type) {
2738 case NM_MT_IPACC_RSL_CONNECT_NACK:
2739 case NM_MT_IPACC_SET_NVATTR_NACK:
2740 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002741 signal.bts = msg->trx->bts;
2742 signal.msg_type = foh->msg_type;
2743 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002744 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002745 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002746 signal.bts = msg->trx->bts;
2747 signal.msg_type = foh->msg_type;
2748 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002749 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002750 default:
2751 break;
2752 }
2753
Harald Welte677c21f2009-02-17 13:22:23 +00002754 return 0;
2755}
2756
Harald Welte193fefc2009-04-30 15:16:27 +00002757/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002758int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2759 u_int8_t obj_class, u_int8_t bts_nr,
2760 u_int8_t trx_nr, u_int8_t ts_nr,
2761 u_int8_t *attr, int attr_len)
2762{
2763 struct msgb *msg = nm_msgb_alloc();
2764 struct abis_om_hdr *oh;
2765 struct abis_om_fom_hdr *foh;
2766 u_int8_t *data;
2767
2768 /* construct the 12.21 OM header, observe the erroneous length */
2769 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2770 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2771 oh->mdisc = ABIS_OM_MDISC_MANUF;
2772
2773 /* add the ip.access magic */
2774 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2775 *data++ = sizeof(ipaccess_magic);
2776 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2777
2778 /* fill the 12.21 FOM header */
2779 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2780 foh->msg_type = msg_type;
2781 foh->obj_class = obj_class;
2782 foh->obj_inst.bts_nr = bts_nr;
2783 foh->obj_inst.trx_nr = trx_nr;
2784 foh->obj_inst.ts_nr = ts_nr;
2785
2786 if (attr && attr_len) {
2787 data = msgb_put(msg, attr_len);
2788 memcpy(data, attr, attr_len);
2789 }
2790
2791 return abis_nm_sendmsg(bts, msg);
2792}
Harald Welte677c21f2009-02-17 13:22:23 +00002793
Harald Welte193fefc2009-04-30 15:16:27 +00002794/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002795int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002796 int attr_len)
2797{
Harald Welte2ef156d2010-01-07 20:39:42 +01002798 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2799 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002800 attr_len);
2801}
2802
Harald Welte746d6092009-10-19 22:11:11 +02002803int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2804 u_int32_t ip, u_int16_t port, u_int8_t stream)
2805{
2806 struct in_addr ia;
2807 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2808 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2809 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2810
2811 int attr_len = sizeof(attr);
2812
2813 ia.s_addr = htonl(ip);
2814 attr[1] = stream;
2815 attr[3] = port >> 8;
2816 attr[4] = port & 0xff;
2817 *(u_int32_t *)(attr+6) = ia.s_addr;
2818
2819 /* if ip == 0, we use the default IP */
2820 if (ip == 0)
2821 attr_len -= 5;
2822
2823 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002824 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002825
2826 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2827 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2828 trx->nr, 0xff, attr, attr_len);
2829}
2830
Harald Welte193fefc2009-04-30 15:16:27 +00002831/* restart / reboot an ip.access nanoBTS */
2832int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2833{
2834 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2835}
Harald Weltedaef5212009-10-24 10:20:41 +02002836
2837int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2838 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2839 u_int8_t *attr, u_int8_t attr_len)
2840{
2841 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2842 obj_class, bts_nr, trx_nr, ts_nr,
2843 attr, attr_len);
2844}
Harald Welte0f255852009-11-12 14:48:42 +01002845
Harald Welte97a282b2010-03-14 15:37:43 +08002846void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2847{
2848 /* we simply reuse the GSM48 function and overwrite the RAC
2849 * with the Cell ID */
2850 gsm48_ra_id_by_bts(buf, bts);
2851 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2852}
2853
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002854void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2855{
2856 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2857
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002858 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002859 if (!trx->bts || !trx->bts->oml_link)
2860 return;
2861
2862 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2863 trx->bts->bts_nr, trx->nr, 0xff,
2864 new_state);
2865}
2866
Harald Welte92b1fe42010-03-25 11:45:30 +08002867static const struct value_string ipacc_testres_names[] = {
2868 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2869 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2870 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2871 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2872 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2873 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002874};
2875
2876const char *ipacc_testres_name(u_int8_t res)
2877{
Harald Welte92b1fe42010-03-25 11:45:30 +08002878 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002879}
2880
Harald Welteb40a38f2009-11-13 11:56:05 +01002881void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2882{
2883 cid->mcc = (buf[0] & 0xf) * 100;
2884 cid->mcc += (buf[0] >> 4) * 10;
2885 cid->mcc += (buf[1] & 0xf) * 1;
2886
2887 if (buf[1] >> 4 == 0xf) {
2888 cid->mnc = (buf[2] & 0xf) * 10;
2889 cid->mnc += (buf[2] >> 4) * 1;
2890 } else {
2891 cid->mnc = (buf[2] & 0xf) * 100;
2892 cid->mnc += (buf[2] >> 4) * 10;
2893 cid->mnc += (buf[1] >> 4) * 1;
2894 }
2895
Harald Welteaff237d2009-11-13 14:41:52 +01002896 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2897 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002898}
2899
Harald Welte0f255852009-11-12 14:48:42 +01002900/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2901int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2902{
2903 u_int8_t *cur = buf;
2904 u_int16_t len;
2905
2906 memset(binf, 0, sizeof(binf));
2907
2908 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2909 return -EINVAL;
2910 cur++;
2911
2912 len = ntohs(*(u_int16_t *)cur);
2913 cur += 2;
2914
2915 binf->info_type = ntohs(*(u_int16_t *)cur);
2916 cur += 2;
2917
2918 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2919 binf->freq_qual = *cur >> 2;
2920
2921 binf->arfcn = *cur++ & 3 << 8;
2922 binf->arfcn |= *cur++;
2923
2924 if (binf->info_type & IPAC_BINF_RXLEV)
2925 binf->rx_lev = *cur & 0x3f;
2926 cur++;
2927
2928 if (binf->info_type & IPAC_BINF_RXQUAL)
2929 binf->rx_qual = *cur & 0x7;
2930 cur++;
2931
2932 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2933 binf->freq_err = ntohs(*(u_int16_t *)cur);
2934 cur += 2;
2935
2936 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2937 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2938 cur += 2;
2939
2940 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2941 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2942 cur += 4;
2943
2944 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01002945 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002946 cur++;
2947
Harald Welteb40a38f2009-11-13 11:56:05 +01002948 ipac_parse_cgi(&binf->cgi, cur);
2949 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002950
2951 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2952 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2953 cur += sizeof(binf->ba_list_si2);
2954 }
2955
2956 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2957 memcpy(binf->ba_list_si2bis, cur,
2958 sizeof(binf->ba_list_si2bis));
2959 cur += sizeof(binf->ba_list_si2bis);
2960 }
2961
2962 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2963 memcpy(binf->ba_list_si2ter, cur,
2964 sizeof(binf->ba_list_si2ter));
2965 cur += sizeof(binf->ba_list_si2ter);
2966 }
2967
2968 return 0;
2969}