blob: 9f55d3510f53fc07289f8193cd884c2df1425d0d [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 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 Welte81c9b9c2010-05-31 16:40:40 +0200422const struct value_string abis_nm_obj_class_names[] = {
423 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800424 { NM_OC_BTS, "BTS" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200425 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
426 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800427 { NM_OC_CHANNEL, "CHANNEL" },
428 { NM_OC_BS11_ADJC, "ADJC" },
429 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200430 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800431 { 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" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200436 { NM_OC_GPRS_NSE, "GPRS-NSE" },
437 { NM_OC_GPRS_CELL, "GPRS-CELL" },
438 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800439 { 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 Welte81c9b9c2010-05-31 16:40:40 +0200445 return get_value_string(abis_nm_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 Welte81c9b9c2010-05-31 16:40:40 +0200493const struct value_string abis_nm_adm_state_names[] = {
494 { NM_STATE_LOCKED, "Locked" },
495 { NM_STATE_UNLOCKED, "Unlocked" },
496 { NM_STATE_SHUTDOWN, "Shutdown" },
497 { NM_STATE_NULL, "NULL" },
498 { 0, NULL }
499};
500
Harald Welte7b26bcb2009-05-28 11:39:21 +0000501const char *nm_adm_name(u_int8_t adm)
502{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200503 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte7b26bcb2009-05-28 11:39:21 +0000504}
Harald Weltee0590df2009-02-15 03:34:15 +0000505
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100506int nm_is_running(struct gsm_nm_state *s) {
507 return (s->operational == NM_OPSTATE_ENABLED) && (
508 (s->availability == NM_AVSTATE_OK) ||
509 (s->availability == 0xff)
510 );
511}
512
Harald Weltea8bd6d42009-10-20 09:56:18 +0200513static void debugp_foh(struct abis_om_fom_hdr *foh)
514{
515 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200516 obj_class_name(foh->obj_class), foh->obj_class,
Harald Weltea8bd6d42009-10-20 09:56:18 +0200517 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
518 foh->obj_inst.ts_nr);
519}
520
Harald Weltee0590df2009-02-15 03:34:15 +0000521/* obtain the gsm_nm_state data structure for a given object instance */
522static struct gsm_nm_state *
523objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
524 struct abis_om_obj_inst *obj_inst)
525{
526 struct gsm_bts_trx *trx;
527 struct gsm_nm_state *nm_state = NULL;
528
529 switch (obj_class) {
530 case NM_OC_BTS:
531 nm_state = &bts->nm_state;
532 break;
533 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100534 if (obj_inst->trx_nr >= bts->num_trx) {
535 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000536 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100537 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200538 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000539 nm_state = &trx->nm_state;
540 break;
541 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100542 if (obj_inst->trx_nr >= bts->num_trx) {
543 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000544 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100545 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200546 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000547 nm_state = &trx->bb_transc.nm_state;
548 break;
549 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100550 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100551 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000552 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100553 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200554 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000555 if (obj_inst->ts_nr >= TRX_NR_TS)
556 return NULL;
557 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
558 break;
559 case NM_OC_SITE_MANAGER:
560 nm_state = &bts->site_mgr.nm_state;
561 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000562 case NM_OC_BS11:
563 switch (obj_inst->bts_nr) {
564 case BS11_OBJ_CCLK:
565 nm_state = &bts->bs11.cclk.nm_state;
566 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000567 case BS11_OBJ_BBSIG:
568 if (obj_inst->ts_nr > bts->num_trx)
569 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200570 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000571 nm_state = &trx->bs11.bbsig.nm_state;
572 break;
573 case BS11_OBJ_PA:
574 if (obj_inst->ts_nr > bts->num_trx)
575 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200576 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000577 nm_state = &trx->bs11.pa.nm_state;
578 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000579 default:
580 return NULL;
581 }
582 case NM_OC_BS11_RACK:
583 nm_state = &bts->bs11.rack.nm_state;
584 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000585 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100586 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000587 return NULL;
588 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
589 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200590 case NM_OC_GPRS_NSE:
591 nm_state = &bts->gprs.nse.nm_state;
592 break;
593 case NM_OC_GPRS_CELL:
594 nm_state = &bts->gprs.cell.nm_state;
595 break;
596 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100597 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200598 return NULL;
599 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
600 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000601 }
602 return nm_state;
603}
604
605/* obtain the in-memory data structure of a given object instance */
606static void *
607objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
608 struct abis_om_obj_inst *obj_inst)
609{
610 struct gsm_bts_trx *trx;
611 void *obj = NULL;
612
613 switch (obj_class) {
614 case NM_OC_BTS:
615 obj = bts;
616 break;
617 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100618 if (obj_inst->trx_nr >= bts->num_trx) {
619 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000620 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100621 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200622 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000623 obj = trx;
624 break;
625 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100626 if (obj_inst->trx_nr >= bts->num_trx) {
627 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000628 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100629 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200630 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000631 obj = &trx->bb_transc;
632 break;
633 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100634 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100635 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000636 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100637 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200638 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000639 if (obj_inst->ts_nr >= TRX_NR_TS)
640 return NULL;
641 obj = &trx->ts[obj_inst->ts_nr];
642 break;
643 case NM_OC_SITE_MANAGER:
644 obj = &bts->site_mgr;
645 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200646 case NM_OC_GPRS_NSE:
647 obj = &bts->gprs.nse;
648 break;
649 case NM_OC_GPRS_CELL:
650 obj = &bts->gprs.cell;
651 break;
652 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100653 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200654 return NULL;
655 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
656 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000657 }
658 return obj;
659}
660
661/* Update the administrative state of a given object in our in-memory data
662 * structures and send an event to the higher layer */
663static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
664 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
665{
Harald Welteaeedeb42009-05-01 13:08:14 +0000666 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000667 void *obj;
668 int rc;
669
Harald Weltee0590df2009-02-15 03:34:15 +0000670 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100671 if (!obj)
672 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000673 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
674 if (!nm_state)
675 return -1;
676
677 new_state = *nm_state;
678 new_state.administrative = adm_state;
679
Holger Hans Peter Freytheraa0db802010-05-13 00:37:48 +0800680 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000681
682 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000683
684 return rc;
685}
686
Harald Welte97ed1e72009-02-06 13:38:02 +0000687static int abis_nm_rx_statechg_rep(struct msgb *mb)
688{
Harald Weltee0590df2009-02-15 03:34:15 +0000689 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000690 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000691 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000692 struct tlv_parsed tp;
693 struct gsm_nm_state *nm_state, new_state;
694 int rc;
695
Harald Welte23897662009-05-01 14:52:51 +0000696 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000697
Harald Welte8b697c72009-06-05 19:18:45 +0000698 memset(&new_state, 0, sizeof(new_state));
699
Harald Weltee0590df2009-02-15 03:34:15 +0000700 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
701 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100702 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000703 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000704 }
Harald Weltee0590df2009-02-15 03:34:15 +0000705
706 new_state = *nm_state;
707
Harald Welte39315c42010-01-10 18:01:52 +0100708 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000709 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
710 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000711 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000712 }
713 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000714 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
715 new_state.availability = 0xff;
716 else
717 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000718 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000719 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100720 } else
721 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000722 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
723 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200724 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000725 }
726 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000727
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100728 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
729 new_state.operational != nm_state->operational ||
730 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000731 /* Update the operational state of a given object in our in-memory data
732 * structures and send an event to the higher layer */
733 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Holger Hans Peter Freytheraa0db802010-05-13 00:37:48 +0800734 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100735 nm_state->operational = new_state.operational;
736 nm_state->availability = new_state.availability;
737 if (nm_state->administrative == 0)
738 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000739 }
740#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000741 if (op_state == 1) {
742 /* try to enable objects that are disabled */
743 abis_nm_opstart(bts, foh->obj_class,
744 foh->obj_inst.bts_nr,
745 foh->obj_inst.trx_nr,
746 foh->obj_inst.ts_nr);
747 }
Harald Weltee0590df2009-02-15 03:34:15 +0000748#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000749 return 0;
750}
751
Harald Welte0db97b22009-05-01 17:22:47 +0000752static int rx_fail_evt_rep(struct msgb *mb)
753{
754 struct abis_om_hdr *oh = msgb_l2(mb);
755 struct abis_om_fom_hdr *foh = msgb_l3(mb);
756 struct tlv_parsed tp;
757
758 DEBUGPC(DNM, "Failure Event Report ");
759
Harald Welte39315c42010-01-10 18:01:52 +0100760 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000761
762 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
763 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
764 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
765 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
766
767 DEBUGPC(DNM, "\n");
768
769 return 0;
770}
771
Harald Welte97ed1e72009-02-06 13:38:02 +0000772static int abis_nm_rcvmsg_report(struct msgb *mb)
773{
774 struct abis_om_fom_hdr *foh = msgb_l3(mb);
775 u_int8_t mt = foh->msg_type;
776
Harald Weltea8bd6d42009-10-20 09:56:18 +0200777 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000778
Harald Welte97ed1e72009-02-06 13:38:02 +0000779 //nmh->cfg->report_cb(mb, foh);
780
781 switch (mt) {
782 case NM_MT_STATECHG_EVENT_REP:
783 return abis_nm_rx_statechg_rep(mb);
784 break;
Harald Welte34a99682009-02-13 02:41:40 +0000785 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000786 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000787 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000788 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000789 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000790 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000791 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000792 break;
Harald Weltec7310382009-08-08 00:02:36 +0200793 case NM_MT_TEST_REP:
794 DEBUGPC(DNM, "Test Report\n");
795 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
796 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000797 default:
Harald Welte23897662009-05-01 14:52:51 +0000798 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000799 break;
800
Harald Welte97ed1e72009-02-06 13:38:02 +0000801 };
802
Harald Welte97ed1e72009-02-06 13:38:02 +0000803 return 0;
804}
805
Harald Welte34a99682009-02-13 02:41:40 +0000806/* Activate the specified software into the BTS */
807static 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 +0200808 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000809{
810 struct abis_om_hdr *oh;
811 struct msgb *msg = nm_msgb_alloc();
812 u_int8_t len = swdesc_len;
813 u_int8_t *trailer;
814
815 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
816 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
817
818 trailer = msgb_put(msg, swdesc_len);
819 memcpy(trailer, sw_desc, swdesc_len);
820
821 return abis_nm_sendmsg(bts, msg);
822}
823
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100824static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
825{
826 static const struct tlv_definition sw_descr_def = {
827 .def = {
828 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
829 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
830 },
831 };
832
833 u_int8_t tag;
834 u_int16_t tag_len;
835 const u_int8_t *val;
836 int ofs = 0, len;
837
838 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
839 * nested nature and the fact you have to assume it contains only two sub
840 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
841
842 if (sw_descr[0] != NM_ATT_SW_DESCR) {
843 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
844 return -1;
845 }
846 ofs += 1;
847
848 len = tlv_parse_one(&tag, &tag_len, &val,
849 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
850 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
851 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
852 return -2;
853 }
854 ofs += len;
855
856 len = tlv_parse_one(&tag, &tag_len, &val,
857 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
858 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
859 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
860 return -3;
861 }
862 ofs += len;
863
864 return ofs;
865}
866
Harald Welte34a99682009-02-13 02:41:40 +0000867static int abis_nm_rx_sw_act_req(struct msgb *mb)
868{
869 struct abis_om_hdr *oh = msgb_l2(mb);
870 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200871 struct tlv_parsed tp;
872 const u_int8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100873 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000874
Harald Weltea8bd6d42009-10-20 09:56:18 +0200875 debugp_foh(foh);
876
877 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000878
Harald Welte97a282b2010-03-14 15:37:43 +0800879 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000880
881 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000882 foh->obj_inst.bts_nr,
883 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800884 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000885 foh->data, oh->length-sizeof(*foh));
886
Harald Welte39315c42010-01-10 18:01:52 +0100887 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200888 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
889 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
890 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
891 DEBUGP(DNM, "SW config not found! Can't continue.\n");
892 return -EINVAL;
893 } else {
894 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
895 }
896
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100897 /* Use the first SW_DESCR present in SW config */
898 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
899 if (sw_descr_len < 0)
900 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200901
Harald Welte34a99682009-02-13 02:41:40 +0000902 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
903 foh->obj_inst.bts_nr,
904 foh->obj_inst.trx_nr,
905 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100906 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000907}
908
Harald Weltee0590df2009-02-15 03:34:15 +0000909/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
910static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
911{
912 struct abis_om_hdr *oh = msgb_l2(mb);
913 struct abis_om_fom_hdr *foh = msgb_l3(mb);
914 struct tlv_parsed tp;
915 u_int8_t adm_state;
916
Harald Welte39315c42010-01-10 18:01:52 +0100917 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000918 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
919 return -EINVAL;
920
921 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
922
923 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
924}
925
Harald Welteee670472009-02-22 21:58:49 +0000926static int abis_nm_rx_lmt_event(struct msgb *mb)
927{
928 struct abis_om_hdr *oh = msgb_l2(mb);
929 struct abis_om_fom_hdr *foh = msgb_l3(mb);
930 struct tlv_parsed tp;
931
932 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100933 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000934 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
935 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
936 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
937 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
938 }
939 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
940 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
941 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
942 DEBUGPC(DNM, "Level=%u ", level);
943 }
944 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
945 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
946 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
947 DEBUGPC(DNM, "Username=%s ", name);
948 }
949 DEBUGPC(DNM, "\n");
950 /* FIXME: parse LMT LOGON TIME */
951 return 0;
952}
953
Harald Welte52b1f982008-12-23 20:25:15 +0000954/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000955static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000956{
Harald Welte6c96ba52009-05-01 13:03:40 +0000957 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000958 struct abis_om_fom_hdr *foh = msgb_l3(mb);
959 u_int8_t mt = foh->msg_type;
960
961 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000962 if (is_report(mt))
963 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000964
Harald Welte4724f992009-01-18 18:01:49 +0000965 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
966 return abis_nm_rcvmsg_sw(mb);
967
Harald Welte78fc0d42009-02-19 02:50:57 +0000968 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800969 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000970 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200971
Harald Weltea8bd6d42009-10-20 09:56:18 +0200972 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200973
Harald Welte92b1fe42010-03-25 11:45:30 +0800974 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000975
Harald Welte39315c42010-01-10 18:01:52 +0100976 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000977 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200978 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +0000979 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
980 else
981 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200982
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800983 nack_data.msg = mb;
984 nack_data.mt = mt;
985 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200986 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000987 }
Harald Weltead384642008-12-26 10:20:07 +0000988#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000989 /* check if last message is to be acked */
990 if (is_ack_nack(nmh->last_msgtype)) {
991 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100992 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000993 /* we got our ACK, continue sending the next msg */
994 } else if (mt == MT_NACK(nmh->last_msgtype)) {
995 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100996 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000997 /* FIXME: somehow signal this to the caller */
998 } else {
999 /* really strange things happen */
1000 return -EINVAL;
1001 }
1002 }
Harald Weltead384642008-12-26 10:20:07 +00001003#endif
1004
Harald Welte97ed1e72009-02-06 13:38:02 +00001005 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001006 case NM_MT_CHG_ADM_STATE_ACK:
1007 return abis_nm_rx_chg_adm_state_ack(mb);
1008 break;
Harald Welte34a99682009-02-13 02:41:40 +00001009 case NM_MT_SW_ACT_REQ:
1010 return abis_nm_rx_sw_act_req(mb);
1011 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001012 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001013 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001014 break;
Harald Welte1989c082009-08-06 17:58:31 +02001015 case NM_MT_CONN_MDROP_LINK_ACK:
1016 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1017 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001018 case NM_MT_IPACC_RESTART_ACK:
1019 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1020 break;
1021 case NM_MT_IPACC_RESTART_NACK:
1022 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1023 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001024 }
1025
Harald Weltead384642008-12-26 10:20:07 +00001026 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001027}
1028
Harald Welte677c21f2009-02-17 13:22:23 +00001029static int abis_nm_rx_ipacc(struct msgb *mb);
1030
1031static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1032{
1033 int rc;
1034 int bts_type = mb->trx->bts->type;
1035
1036 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001037 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001038 rc = abis_nm_rx_ipacc(mb);
1039 break;
1040 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001041 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1042 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001043 rc = 0;
1044 break;
1045 }
1046
1047 return rc;
1048}
1049
Harald Welte52b1f982008-12-23 20:25:15 +00001050/* High-Level API */
1051/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001052int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001053{
Harald Welte52b1f982008-12-23 20:25:15 +00001054 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001055 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001056
1057 /* Various consistency checks */
1058 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001059 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001060 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001061 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1062 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001063 }
1064 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001065 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001066 oh->sequence);
1067 return -EINVAL;
1068 }
Harald Welte702d8702008-12-26 20:25:35 +00001069#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001070 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1071 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001072 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001073 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001074 oh->length + sizeof(*oh), l2_len);
1075 return -EINVAL;
1076 }
Harald Welte702d8702008-12-26 20:25:35 +00001077 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001078 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 +00001079#endif
Harald Weltead384642008-12-26 10:20:07 +00001080 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001081
1082 switch (oh->mdisc) {
1083 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001084 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001085 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001086 case ABIS_OM_MDISC_MANUF:
1087 rc = abis_nm_rcvmsg_manuf(msg);
1088 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001089 case ABIS_OM_MDISC_MMI:
1090 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001091 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001092 oh->mdisc);
1093 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001094 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001095 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001096 oh->mdisc);
1097 return -EINVAL;
1098 }
1099
Harald Weltead384642008-12-26 10:20:07 +00001100 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001101 return rc;
1102}
1103
1104#if 0
1105/* initialized all resources */
1106struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1107{
1108 struct abis_nm_h *nmh;
1109
1110 nmh = malloc(sizeof(*nmh));
1111 if (!nmh)
1112 return NULL;
1113
1114 nmh->cfg = cfg;
1115
1116 return nmh;
1117}
1118
1119/* free all resources */
1120void abis_nm_fini(struct abis_nm_h *nmh)
1121{
1122 free(nmh);
1123}
1124#endif
1125
1126/* Here we are trying to define a high-level API that can be used by
1127 * the actual BSC implementation. However, the architecture is currently
1128 * still under design. Ideally the calls to this API would be synchronous,
1129 * while the underlying stack behind the APi runs in a traditional select
1130 * based state machine.
1131 */
1132
Harald Welte4724f992009-01-18 18:01:49 +00001133/* 6.2 Software Load: */
1134enum sw_state {
1135 SW_STATE_NONE,
1136 SW_STATE_WAIT_INITACK,
1137 SW_STATE_WAIT_SEGACK,
1138 SW_STATE_WAIT_ENDACK,
1139 SW_STATE_WAIT_ACTACK,
1140 SW_STATE_ERROR,
1141};
Harald Welte52b1f982008-12-23 20:25:15 +00001142
Harald Welte52b1f982008-12-23 20:25:15 +00001143struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001144 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001145 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001146 gsm_cbfn *cbfn;
1147 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001148 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001149
Harald Welte52b1f982008-12-23 20:25:15 +00001150 /* this will become part of the SW LOAD INITIATE */
1151 u_int8_t obj_class;
1152 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001153
1154 u_int8_t file_id[255];
1155 u_int8_t file_id_len;
1156
1157 u_int8_t file_version[255];
1158 u_int8_t file_version_len;
1159
1160 u_int8_t window_size;
1161 u_int8_t seg_in_window;
1162
1163 int fd;
1164 FILE *stream;
1165 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001166 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001167};
1168
Harald Welte4724f992009-01-18 18:01:49 +00001169static struct abis_nm_sw g_sw;
1170
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001171static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1172{
1173 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1174 msgb_v_put(msg, NM_ATT_SW_DESCR);
1175 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1176 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1177 sw->file_version);
1178 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1179 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1180 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1181 sw->file_version);
1182 } else {
1183 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1184 }
1185}
1186
Harald Welte4724f992009-01-18 18:01:49 +00001187/* 6.2.1 / 8.3.1: Load Data Initiate */
1188static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001189{
Harald Welte4724f992009-01-18 18:01:49 +00001190 struct abis_om_hdr *oh;
1191 struct msgb *msg = nm_msgb_alloc();
1192 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1193
1194 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1195 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1196 sw->obj_instance[0], sw->obj_instance[1],
1197 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001198
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001199 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001200 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1201
1202 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001203}
1204
Harald Welte1602ade2009-01-29 21:12:39 +00001205static int is_last_line(FILE *stream)
1206{
1207 char next_seg_buf[256];
1208 long pos;
1209
1210 /* check if we're sending the last line */
1211 pos = ftell(stream);
1212 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1213 fseek(stream, pos, SEEK_SET);
1214 return 1;
1215 }
1216
1217 fseek(stream, pos, SEEK_SET);
1218 return 0;
1219}
1220
Harald Welte4724f992009-01-18 18:01:49 +00001221/* 6.2.2 / 8.3.2 Load Data Segment */
1222static int sw_load_segment(struct abis_nm_sw *sw)
1223{
1224 struct abis_om_hdr *oh;
1225 struct msgb *msg = nm_msgb_alloc();
1226 char seg_buf[256];
1227 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001228 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001229 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001230
1231 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001232
1233 switch (sw->bts->type) {
1234 case GSM_BTS_TYPE_BS11:
1235 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1236 perror("fgets reading segment");
1237 return -EINVAL;
1238 }
1239 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001240
1241 /* check if we're sending the last line */
1242 sw->last_seg = is_last_line(sw->stream);
1243 if (sw->last_seg)
1244 seg_buf[1] = 0;
1245 else
1246 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001247
1248 len = strlen(line_buf) + 2;
1249 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1250 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1251 /* BS11 wants CR + LF in excess of the TLV length !?! */
1252 tlv[1] -= 2;
1253
1254 /* we only now know the exact length for the OM hdr */
1255 len = strlen(line_buf)+2;
1256 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001257 case GSM_BTS_TYPE_NANOBTS: {
1258 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1259 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1260 if (len < 0) {
1261 perror("read failed");
1262 return -EINVAL;
1263 }
1264
1265 if (len != IPACC_SEGMENT_SIZE)
1266 sw->last_seg = 1;
1267
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001268 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001269 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1270 len += 3;
1271 break;
1272 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001273 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001274 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001275 /* FIXME: Other BTS types */
1276 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001277 }
Harald Welte4724f992009-01-18 18:01:49 +00001278
Harald Welte4724f992009-01-18 18:01:49 +00001279 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1280 sw->obj_instance[0], sw->obj_instance[1],
1281 sw->obj_instance[2]);
1282
1283 return abis_nm_sendmsg(sw->bts, msg);
1284}
1285
1286/* 6.2.4 / 8.3.4 Load Data End */
1287static int sw_load_end(struct abis_nm_sw *sw)
1288{
1289 struct abis_om_hdr *oh;
1290 struct msgb *msg = nm_msgb_alloc();
1291 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1292
1293 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1294 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1295 sw->obj_instance[0], sw->obj_instance[1],
1296 sw->obj_instance[2]);
1297
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001298 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001299 return abis_nm_sendmsg(sw->bts, msg);
1300}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001301
Harald Welte52b1f982008-12-23 20:25:15 +00001302/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001303static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001304{
Harald Welte4724f992009-01-18 18:01:49 +00001305 struct abis_om_hdr *oh;
1306 struct msgb *msg = nm_msgb_alloc();
1307 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001308
Harald Welte4724f992009-01-18 18:01:49 +00001309 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1310 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1311 sw->obj_instance[0], sw->obj_instance[1],
1312 sw->obj_instance[2]);
1313
1314 /* FIXME: this is BS11 specific format */
1315 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1316 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1317 sw->file_version);
1318
1319 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001320}
Harald Welte4724f992009-01-18 18:01:49 +00001321
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001322struct sdp_firmware {
1323 char magic[4];
1324 char more_magic[4];
1325 unsigned int header_length;
1326 unsigned int file_length;
1327} __attribute__ ((packed));
1328
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001329static int parse_sdp_header(struct abis_nm_sw *sw)
1330{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001331 struct sdp_firmware firmware_header;
1332 int rc;
1333 struct stat stat;
1334
1335 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1336 if (rc != sizeof(firmware_header)) {
1337 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1338 return -1;
1339 }
1340
1341 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1342 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1343 return -1;
1344 }
1345
1346 if (firmware_header.more_magic[0] != 0x10 ||
1347 firmware_header.more_magic[1] != 0x02 ||
1348 firmware_header.more_magic[2] != 0x00 ||
1349 firmware_header.more_magic[3] != 0x00) {
1350 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1351 return -1;
1352 }
1353
1354
1355 if (fstat(sw->fd, &stat) == -1) {
1356 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1357 return -1;
1358 }
1359
1360 if (ntohl(firmware_header.file_length) != stat.st_size) {
1361 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1362 return -1;
1363 }
1364
1365 /* go back to the start as we checked the whole filesize.. */
1366 lseek(sw->fd, 0l, SEEK_SET);
1367 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1368 "There might be checksums in the file that are not\n"
1369 "verified and incomplete firmware might be flashed.\n"
1370 "There is absolutely no WARRANTY that flashing will\n"
1371 "work.\n");
1372 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001373}
1374
Harald Welte4724f992009-01-18 18:01:49 +00001375static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1376{
1377 char file_id[12+1];
1378 char file_version[80+1];
1379 int rc;
1380
1381 sw->fd = open(fname, O_RDONLY);
1382 if (sw->fd < 0)
1383 return sw->fd;
1384
1385 switch (sw->bts->type) {
1386 case GSM_BTS_TYPE_BS11:
1387 sw->stream = fdopen(sw->fd, "r");
1388 if (!sw->stream) {
1389 perror("fdopen");
1390 return -1;
1391 }
1392 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001393 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001394 file_id, file_version);
1395 if (rc != 2) {
1396 perror("parsing header line of software file");
1397 return -1;
1398 }
1399 strcpy((char *)sw->file_id, file_id);
1400 sw->file_id_len = strlen(file_id);
1401 strcpy((char *)sw->file_version, file_version);
1402 sw->file_version_len = strlen(file_version);
1403 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001404 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001405 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001406 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001407 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001408 rc = parse_sdp_header(sw);
1409 if (rc < 0) {
1410 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1411 return -1;
1412 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001413
1414 strcpy((char *)sw->file_id, "id");
1415 sw->file_id_len = 3;
1416 strcpy((char *)sw->file_version, "version");
1417 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001418 break;
Harald Welte4724f992009-01-18 18:01:49 +00001419 default:
1420 /* We don't know how to treat them yet */
1421 close(sw->fd);
1422 return -EINVAL;
1423 }
1424
1425 return 0;
1426}
1427
1428static void sw_close_file(struct abis_nm_sw *sw)
1429{
1430 switch (sw->bts->type) {
1431 case GSM_BTS_TYPE_BS11:
1432 fclose(sw->stream);
1433 break;
1434 default:
1435 close(sw->fd);
1436 break;
1437 }
1438}
1439
1440/* Fill the window */
1441static int sw_fill_window(struct abis_nm_sw *sw)
1442{
1443 int rc;
1444
1445 while (sw->seg_in_window < sw->window_size) {
1446 rc = sw_load_segment(sw);
1447 if (rc < 0)
1448 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001449 if (sw->last_seg)
1450 break;
Harald Welte4724f992009-01-18 18:01:49 +00001451 }
1452 return 0;
1453}
1454
1455/* callback function from abis_nm_rcvmsg() handler */
1456static int abis_nm_rcvmsg_sw(struct msgb *mb)
1457{
1458 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1459 int rc = -1;
1460 struct abis_nm_sw *sw = &g_sw;
1461 enum sw_state old_state = sw->state;
1462
Harald Welte3ffd1372009-02-01 22:15:49 +00001463 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001464
1465 switch (sw->state) {
1466 case SW_STATE_WAIT_INITACK:
1467 switch (foh->msg_type) {
1468 case NM_MT_LOAD_INIT_ACK:
1469 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001470 if (sw->cbfn)
1471 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1472 NM_MT_LOAD_INIT_ACK, mb,
1473 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001474 rc = sw_fill_window(sw);
1475 sw->state = SW_STATE_WAIT_SEGACK;
1476 break;
1477 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001478 if (sw->forced) {
1479 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1480 "Init NACK\n");
1481 if (sw->cbfn)
1482 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1483 NM_MT_LOAD_INIT_ACK, mb,
1484 sw->cb_data, NULL);
1485 rc = sw_fill_window(sw);
1486 sw->state = SW_STATE_WAIT_SEGACK;
1487 } else {
1488 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001489 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001490 if (sw->cbfn)
1491 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1492 NM_MT_LOAD_INIT_NACK, mb,
1493 sw->cb_data, NULL);
1494 sw->state = SW_STATE_ERROR;
1495 }
Harald Welte4724f992009-01-18 18:01:49 +00001496 break;
1497 }
1498 break;
1499 case SW_STATE_WAIT_SEGACK:
1500 switch (foh->msg_type) {
1501 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001502 if (sw->cbfn)
1503 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1504 NM_MT_LOAD_SEG_ACK, mb,
1505 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001506 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001507 if (!sw->last_seg) {
1508 /* fill window with more segments */
1509 rc = sw_fill_window(sw);
1510 sw->state = SW_STATE_WAIT_SEGACK;
1511 } else {
1512 /* end the transfer */
1513 sw->state = SW_STATE_WAIT_ENDACK;
1514 rc = sw_load_end(sw);
1515 }
Harald Welte4724f992009-01-18 18:01:49 +00001516 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001517 case NM_MT_LOAD_ABORT:
1518 if (sw->cbfn)
1519 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1520 NM_MT_LOAD_ABORT, mb,
1521 sw->cb_data, NULL);
1522 break;
Harald Welte4724f992009-01-18 18:01:49 +00001523 }
1524 break;
1525 case SW_STATE_WAIT_ENDACK:
1526 switch (foh->msg_type) {
1527 case NM_MT_LOAD_END_ACK:
1528 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001529 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1530 sw->bts->nr);
1531 sw->state = SW_STATE_NONE;
1532 if (sw->cbfn)
1533 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1534 NM_MT_LOAD_END_ACK, mb,
1535 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001536 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001537 break;
1538 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001539 if (sw->forced) {
1540 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1541 "End NACK\n");
1542 sw->state = SW_STATE_NONE;
1543 if (sw->cbfn)
1544 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1545 NM_MT_LOAD_END_ACK, mb,
1546 sw->cb_data, NULL);
1547 } else {
1548 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001549 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001550 sw->state = SW_STATE_ERROR;
1551 if (sw->cbfn)
1552 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1553 NM_MT_LOAD_END_NACK, mb,
1554 sw->cb_data, NULL);
1555 }
Harald Welte4724f992009-01-18 18:01:49 +00001556 break;
1557 }
1558 case SW_STATE_WAIT_ACTACK:
1559 switch (foh->msg_type) {
1560 case NM_MT_ACTIVATE_SW_ACK:
1561 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001562 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001563 sw->state = SW_STATE_NONE;
1564 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001565 if (sw->cbfn)
1566 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1567 NM_MT_ACTIVATE_SW_ACK, mb,
1568 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001569 break;
1570 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001571 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001572 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001573 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001574 if (sw->cbfn)
1575 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1576 NM_MT_ACTIVATE_SW_NACK, mb,
1577 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001578 break;
1579 }
1580 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001581 switch (foh->msg_type) {
1582 case NM_MT_ACTIVATE_SW_ACK:
1583 rc = 0;
1584 break;
1585 }
1586 break;
Harald Welte4724f992009-01-18 18:01:49 +00001587 case SW_STATE_ERROR:
1588 break;
1589 }
1590
1591 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001592 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001593 foh->msg_type, old_state, sw->state);
1594
1595 return rc;
1596}
1597
1598/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001599int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001600 u_int8_t win_size, int forced,
1601 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001602{
1603 struct abis_nm_sw *sw = &g_sw;
1604 int rc;
1605
Harald Welte5e4d1b32009-02-01 13:36:56 +00001606 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1607 bts->nr, fname);
1608
Harald Welte4724f992009-01-18 18:01:49 +00001609 if (sw->state != SW_STATE_NONE)
1610 return -EBUSY;
1611
1612 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001613 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001614
1615 switch (bts->type) {
1616 case GSM_BTS_TYPE_BS11:
1617 sw->obj_class = NM_OC_SITE_MANAGER;
1618 sw->obj_instance[0] = 0xff;
1619 sw->obj_instance[1] = 0xff;
1620 sw->obj_instance[2] = 0xff;
1621 break;
1622 case GSM_BTS_TYPE_NANOBTS:
1623 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001624 sw->obj_instance[0] = sw->bts->nr;
1625 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001626 sw->obj_instance[2] = 0xff;
1627 break;
1628 case GSM_BTS_TYPE_UNKNOWN:
1629 default:
1630 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1631 return -1;
1632 break;
1633 }
Harald Welte4724f992009-01-18 18:01:49 +00001634 sw->window_size = win_size;
1635 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001636 sw->cbfn = cbfn;
1637 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001638 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001639
1640 rc = sw_open_file(sw, fname);
1641 if (rc < 0) {
1642 sw->state = SW_STATE_NONE;
1643 return rc;
1644 }
1645
1646 return sw_load_init(sw);
1647}
Harald Welte52b1f982008-12-23 20:25:15 +00001648
Harald Welte1602ade2009-01-29 21:12:39 +00001649int abis_nm_software_load_status(struct gsm_bts *bts)
1650{
1651 struct abis_nm_sw *sw = &g_sw;
1652 struct stat st;
1653 int rc, percent;
1654
1655 rc = fstat(sw->fd, &st);
1656 if (rc < 0) {
1657 perror("ERROR during stat");
1658 return rc;
1659 }
1660
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001661 if (sw->stream)
1662 percent = (ftell(sw->stream) * 100) / st.st_size;
1663 else
1664 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001665 return percent;
1666}
1667
Harald Welte5e4d1b32009-02-01 13:36:56 +00001668/* Activate the specified software into the BTS */
1669int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1670 gsm_cbfn *cbfn, void *cb_data)
1671{
1672 struct abis_nm_sw *sw = &g_sw;
1673 int rc;
1674
1675 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1676 bts->nr, fname);
1677
1678 if (sw->state != SW_STATE_NONE)
1679 return -EBUSY;
1680
1681 sw->bts = bts;
1682 sw->obj_class = NM_OC_SITE_MANAGER;
1683 sw->obj_instance[0] = 0xff;
1684 sw->obj_instance[1] = 0xff;
1685 sw->obj_instance[2] = 0xff;
1686 sw->state = SW_STATE_WAIT_ACTACK;
1687 sw->cbfn = cbfn;
1688 sw->cb_data = cb_data;
1689
1690 /* Open the file in order to fill some sw struct members */
1691 rc = sw_open_file(sw, fname);
1692 if (rc < 0) {
1693 sw->state = SW_STATE_NONE;
1694 return rc;
1695 }
1696 sw_close_file(sw);
1697
1698 return sw_activate(sw);
1699}
1700
Harald Welte8470bf22008-12-25 23:28:35 +00001701static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001702 u_int8_t ts_nr, u_int8_t subslot_nr)
1703{
Harald Welteadaf08b2009-01-18 11:08:10 +00001704 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001705 ch->bts_port = bts_port;
1706 ch->timeslot = ts_nr;
1707 ch->subslot = subslot_nr;
1708}
1709
1710int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1711 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1712 u_int8_t tei)
1713{
1714 struct abis_om_hdr *oh;
1715 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001716 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001717 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001718
1719 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1720 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1721 bts->bts_nr, trx_nr, 0xff);
1722
Harald Welte8470bf22008-12-25 23:28:35 +00001723 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001724
1725 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1726 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1727
1728 return abis_nm_sendmsg(bts, msg);
1729}
1730
1731/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1732int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1733 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1734{
Harald Welte8470bf22008-12-25 23:28:35 +00001735 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001736 struct abis_om_hdr *oh;
1737 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001738 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001739
1740 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001741 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001742 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1743
1744 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1745 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1746
1747 return abis_nm_sendmsg(bts, msg);
1748}
1749
1750#if 0
1751int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1752 struct abis_nm_abis_channel *chan)
1753{
1754}
1755#endif
1756
1757int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1758 u_int8_t e1_port, u_int8_t e1_timeslot,
1759 u_int8_t e1_subslot)
1760{
1761 struct gsm_bts *bts = ts->trx->bts;
1762 struct abis_om_hdr *oh;
1763 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001764 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001765
1766 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1767 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001768 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001769
1770 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1771 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1772
Harald Weltef325eb42009-02-19 17:07:39 +00001773 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1774 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001775 e1_port, e1_timeslot, e1_subslot);
1776
Harald Welte52b1f982008-12-23 20:25:15 +00001777 return abis_nm_sendmsg(bts, msg);
1778}
1779
1780#if 0
1781int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1782 struct abis_nm_abis_channel *chan,
1783 u_int8_t subchan)
1784{
1785}
1786#endif
1787
Harald Welte22af0db2009-02-14 15:41:08 +00001788/* Chapter 8.6.1 */
1789int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1790{
1791 struct abis_om_hdr *oh;
1792 struct msgb *msg = nm_msgb_alloc();
1793 u_int8_t *cur;
1794
1795 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1796
1797 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001798 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 +00001799 cur = msgb_put(msg, attr_len);
1800 memcpy(cur, attr, attr_len);
1801
1802 return abis_nm_sendmsg(bts, msg);
1803}
1804
1805/* Chapter 8.6.2 */
1806int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1807{
1808 struct abis_om_hdr *oh;
1809 struct msgb *msg = nm_msgb_alloc();
1810 u_int8_t *cur;
1811
1812 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1813
1814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1815 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001816 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001817 cur = msgb_put(msg, attr_len);
1818 memcpy(cur, attr, attr_len);
1819
1820 return abis_nm_sendmsg(trx->bts, msg);
1821}
1822
Harald Welte39c7deb2009-08-09 21:49:48 +02001823static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1824{
1825 int i;
1826
1827 /* As it turns out, the BS-11 has some very peculiar restrictions
1828 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301829 switch (ts->trx->bts->type) {
1830 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001831 switch (chan_comb) {
1832 case NM_CHANC_TCHHalf:
1833 case NM_CHANC_TCHHalf2:
1834 /* not supported */
1835 return -EINVAL;
1836 case NM_CHANC_SDCCH:
1837 /* only one SDCCH/8 per TRX */
1838 for (i = 0; i < TRX_NR_TS; i++) {
1839 if (i == ts->nr)
1840 continue;
1841 if (ts->trx->ts[i].nm_chan_comb ==
1842 NM_CHANC_SDCCH)
1843 return -EINVAL;
1844 }
1845 /* not allowed for TS0 of BCCH-TRX */
1846 if (ts->trx == ts->trx->bts->c0 &&
1847 ts->nr == 0)
1848 return -EINVAL;
1849 /* not on the same TRX that has a BCCH+SDCCH4
1850 * combination */
1851 if (ts->trx == ts->trx->bts->c0 &&
1852 (ts->trx->ts[0].nm_chan_comb == 5 ||
1853 ts->trx->ts[0].nm_chan_comb == 8))
1854 return -EINVAL;
1855 break;
1856 case NM_CHANC_mainBCCH:
1857 case NM_CHANC_BCCHComb:
1858 /* allowed only for TS0 of C0 */
1859 if (ts->trx != ts->trx->bts->c0 ||
1860 ts->nr != 0)
1861 return -EINVAL;
1862 break;
1863 case NM_CHANC_BCCH:
1864 /* allowed only for TS 2/4/6 of C0 */
1865 if (ts->trx != ts->trx->bts->c0)
1866 return -EINVAL;
1867 if (ts->nr != 2 && ts->nr != 4 &&
1868 ts->nr != 6)
1869 return -EINVAL;
1870 break;
1871 case 8: /* this is not like 08.58, but in fact
1872 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1873 /* FIXME: only one CBCH allowed per cell */
1874 break;
1875 }
Harald Welted6575f92009-12-02 02:45:23 +05301876 break;
1877 case GSM_BTS_TYPE_NANOBTS:
1878 switch (ts->nr) {
1879 case 0:
1880 if (ts->trx->nr == 0) {
1881 /* only on TRX0 */
1882 switch (chan_comb) {
1883 case NM_CHANC_BCCH:
1884 case NM_CHANC_mainBCCH:
1885 case NM_CHANC_BCCHComb:
1886 return 0;
1887 break;
1888 default:
1889 return -EINVAL;
1890 }
1891 } else {
1892 switch (chan_comb) {
1893 case NM_CHANC_TCHFull:
1894 case NM_CHANC_TCHHalf:
1895 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1896 return 0;
1897 default:
1898 return -EINVAL;
1899 }
1900 }
1901 break;
1902 case 1:
1903 if (ts->trx->nr == 0) {
1904 switch (chan_comb) {
1905 case NM_CHANC_SDCCH_CBCH:
1906 if (ts->trx->ts[0].nm_chan_comb ==
1907 NM_CHANC_mainBCCH)
1908 return 0;
1909 return -EINVAL;
1910 case NM_CHANC_SDCCH:
1911 case NM_CHANC_TCHFull:
1912 case NM_CHANC_TCHHalf:
1913 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1914 case NM_CHANC_IPAC_TCHFull_PDCH:
1915 return 0;
1916 }
1917 } else {
1918 switch (chan_comb) {
1919 case NM_CHANC_SDCCH:
1920 case NM_CHANC_TCHFull:
1921 case NM_CHANC_TCHHalf:
1922 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1923 return 0;
1924 default:
1925 return -EINVAL;
1926 }
1927 }
1928 break;
1929 case 2:
1930 case 3:
1931 case 4:
1932 case 5:
1933 case 6:
1934 case 7:
1935 switch (chan_comb) {
1936 case NM_CHANC_TCHFull:
1937 case NM_CHANC_TCHHalf:
1938 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1939 return 0;
1940 case NM_CHANC_IPAC_PDCH:
1941 case NM_CHANC_IPAC_TCHFull_PDCH:
1942 if (ts->trx->nr == 0)
1943 return 0;
1944 else
1945 return -EINVAL;
1946 }
1947 break;
1948 }
1949 return -EINVAL;
1950 default:
1951 /* unknown BTS type */
1952 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001953 }
1954 return 0;
1955}
1956
Harald Welte22af0db2009-02-14 15:41:08 +00001957/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001958int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1959{
1960 struct gsm_bts *bts = ts->trx->bts;
1961 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001962 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001963 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001964 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001965 u_int8_t len = 2 + 2;
1966
1967 if (bts->type == GSM_BTS_TYPE_BS11)
1968 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001969
Harald Weltef325eb42009-02-19 17:07:39 +00001970 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001971 if (verify_chan_comb(ts, chan_comb) < 0) {
1972 msgb_free(msg);
1973 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1974 return -EINVAL;
1975 }
1976 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001977
Harald Welte52b1f982008-12-23 20:25:15 +00001978 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001979 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001980 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001981 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001982 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001983 if (ts->hopping.enabled) {
1984 unsigned int i;
1985 uint8_t *len;
1986
Harald Welte6e0cd042009-09-12 13:05:33 +02001987 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1988 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001989
1990 /* build the ARFCN list */
1991 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1992 len = msgb_put(msg, 1);
1993 *len = 0;
1994 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1995 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1996 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001997 /* At least BS-11 wants a TLV16 here */
1998 if (bts->type == GSM_BTS_TYPE_BS11)
1999 *len += 1;
2000 else
2001 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002002 }
2003 }
Harald Weltee0590df2009-02-15 03:34:15 +00002004 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002005 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002006 if (bts->type == GSM_BTS_TYPE_BS11)
2007 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002008
2009 return abis_nm_sendmsg(bts, msg);
2010}
2011
Harald Welte34a99682009-02-13 02:41:40 +00002012int 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 +00002013 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002014{
2015 struct abis_om_hdr *oh;
2016 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002017 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2018 u_int8_t len = att_len;
2019
2020 if (nack) {
2021 len += 2;
2022 msgtype = NM_MT_SW_ACT_REQ_NACK;
2023 }
Harald Welte34a99682009-02-13 02:41:40 +00002024
2025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002026 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2027
Harald Welte34a99682009-02-13 02:41:40 +00002028 if (attr) {
2029 u_int8_t *ptr = msgb_put(msg, att_len);
2030 memcpy(ptr, attr, att_len);
2031 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002032 if (nack)
2033 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002034
2035 return abis_nm_sendmsg(bts, msg);
2036}
2037
Harald Welte8470bf22008-12-25 23:28:35 +00002038int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002039{
Harald Welte8470bf22008-12-25 23:28:35 +00002040 struct msgb *msg = nm_msgb_alloc();
2041 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002042 u_int8_t *data;
2043
2044 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2045 fill_om_hdr(oh, len);
2046 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002047 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002048
2049 return abis_nm_sendmsg(bts, msg);
2050}
2051
2052/* Siemens specific commands */
2053static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2054{
2055 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002056 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002057
2058 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002059 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002060 0xff, 0xff, 0xff);
2061
2062 return abis_nm_sendmsg(bts, msg);
2063}
2064
Harald Welte34a99682009-02-13 02:41:40 +00002065/* Chapter 8.9.2 */
2066int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2067{
2068 struct abis_om_hdr *oh;
2069 struct msgb *msg = nm_msgb_alloc();
2070
2071 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2072 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2073
Harald Weltea8bd6d42009-10-20 09:56:18 +02002074 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2075 DEBUGPC(DNM, "Sending OPSTART\n");
2076
Harald Welte34a99682009-02-13 02:41:40 +00002077 return abis_nm_sendmsg(bts, msg);
2078}
2079
2080/* Chapter 8.8.5 */
2081int 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 +02002082 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002083{
2084 struct abis_om_hdr *oh;
2085 struct msgb *msg = nm_msgb_alloc();
2086
2087 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2088 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2089 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2090
2091 return abis_nm_sendmsg(bts, msg);
2092}
2093
Harald Welte1989c082009-08-06 17:58:31 +02002094int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2095 u_int8_t e1_port1, u_int8_t ts1)
2096{
2097 struct abis_om_hdr *oh;
2098 struct msgb *msg = nm_msgb_alloc();
2099 u_int8_t *attr;
2100
2101 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2102 e1_port0, ts0, e1_port1, ts1);
2103
2104 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2105 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2106 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2107
2108 attr = msgb_put(msg, 3);
2109 attr[0] = NM_ATT_MDROP_LINK;
2110 attr[1] = e1_port0;
2111 attr[2] = ts0;
2112
2113 attr = msgb_put(msg, 3);
2114 attr[0] = NM_ATT_MDROP_NEXT;
2115 attr[1] = e1_port1;
2116 attr[2] = ts1;
2117
2118 return abis_nm_sendmsg(bts, msg);
2119}
Harald Welte34a99682009-02-13 02:41:40 +00002120
Harald Weltec7310382009-08-08 00:02:36 +02002121/* Chapter 8.7.1 */
2122int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2123 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002124 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002125{
2126 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002127
2128 DEBUGP(DNM, "PEFORM TEST\n");
Harald Welte887deab2010-03-06 11:38:05 +01002129
2130 if (!msg)
2131 msg = nm_msgb_alloc();
2132
2133 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2134 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2135 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2136 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002137 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002138
2139 return abis_nm_sendmsg(bts, msg);
2140}
2141
Harald Welte52b1f982008-12-23 20:25:15 +00002142int abis_nm_event_reports(struct gsm_bts *bts, int on)
2143{
2144 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002145 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002146 else
Harald Welte227d4072009-01-03 08:16:25 +00002147 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002148}
2149
Harald Welte47d88ae2009-01-04 12:02:08 +00002150/* Siemens (or BS-11) specific commands */
2151
Harald Welte3ffd1372009-02-01 22:15:49 +00002152int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2153{
2154 if (reconnect == 0)
2155 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2156 else
2157 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2158}
2159
Harald Welteb8427972009-02-05 19:27:17 +00002160int abis_nm_bs11_restart(struct gsm_bts *bts)
2161{
2162 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2163}
2164
2165
Harald Welte268bb402009-02-01 19:11:56 +00002166struct bs11_date_time {
2167 u_int16_t year;
2168 u_int8_t month;
2169 u_int8_t day;
2170 u_int8_t hour;
2171 u_int8_t min;
2172 u_int8_t sec;
2173} __attribute__((packed));
2174
2175
2176void get_bs11_date_time(struct bs11_date_time *aet)
2177{
2178 time_t t;
2179 struct tm *tm;
2180
2181 t = time(NULL);
2182 tm = localtime(&t);
2183 aet->sec = tm->tm_sec;
2184 aet->min = tm->tm_min;
2185 aet->hour = tm->tm_hour;
2186 aet->day = tm->tm_mday;
2187 aet->month = tm->tm_mon;
2188 aet->year = htons(1900 + tm->tm_year);
2189}
2190
Harald Welte05188ee2009-01-18 11:39:08 +00002191int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002192{
Harald Welte4668fda2009-01-03 08:19:29 +00002193 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002194}
2195
Harald Welte05188ee2009-01-18 11:39:08 +00002196int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002197{
2198 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002199 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002200 else
Harald Welte4668fda2009-01-03 08:19:29 +00002201 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002202}
Harald Welte47d88ae2009-01-04 12:02:08 +00002203
Harald Welte05188ee2009-01-18 11:39:08 +00002204int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002205 enum abis_bs11_objtype type, u_int8_t idx,
2206 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002207{
2208 struct abis_om_hdr *oh;
2209 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002210 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002211
2212 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002213 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002214 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002215 cur = msgb_put(msg, attr_len);
2216 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002217
2218 return abis_nm_sendmsg(bts, msg);
2219}
2220
Harald Welte78fc0d42009-02-19 02:50:57 +00002221int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2222 enum abis_bs11_objtype type, u_int8_t idx)
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, 0, NM_MT_BS11_DELETE_OBJ,
2229 NM_OC_BS11, type, 0, idx);
2230
2231 return abis_nm_sendmsg(bts, msg);
2232}
2233
Harald Welte05188ee2009-01-18 11:39:08 +00002234int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002235{
2236 struct abis_om_hdr *oh;
2237 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002238 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002239
2240 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002241 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002242 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2243 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002244
2245 return abis_nm_sendmsg(bts, msg);
2246}
2247
Harald Welte05188ee2009-01-18 11:39:08 +00002248int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002249{
2250 struct abis_om_hdr *oh;
2251 struct msgb *msg = nm_msgb_alloc();
2252
2253 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2254 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002255 idx, 0xff, 0xff);
2256
2257 return abis_nm_sendmsg(bts, msg);
2258}
2259
2260int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2261{
2262 struct abis_om_hdr *oh;
2263 struct msgb *msg = nm_msgb_alloc();
2264
2265 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2266 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2267 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002268
2269 return abis_nm_sendmsg(bts, msg);
2270}
Harald Welte05188ee2009-01-18 11:39:08 +00002271
Harald Welte78fc0d42009-02-19 02:50:57 +00002272static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2273int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2274{
2275 struct abis_om_hdr *oh;
2276 struct msgb *msg = nm_msgb_alloc();
2277
2278 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2279 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2280 0xff, 0xff, 0xff);
2281 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2282
2283 return abis_nm_sendmsg(bts, msg);
2284}
2285
Harald Welteb6c92ae2009-02-21 20:15:32 +00002286/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002287int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002288 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2289 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002290{
2291 struct abis_om_hdr *oh;
2292 struct abis_nm_channel *ch;
2293 struct msgb *msg = nm_msgb_alloc();
2294
2295 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002296 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002297 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2298
2299 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2300 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002301 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002302
2303 return abis_nm_sendmsg(bts, msg);
2304}
2305
2306int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2307{
2308 struct abis_om_hdr *oh;
2309 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002310
2311 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002312 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002313 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2314 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2315
2316 return abis_nm_sendmsg(trx->bts, msg);
2317}
2318
Harald Welte78fc0d42009-02-19 02:50:57 +00002319int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2320{
2321 struct abis_om_hdr *oh;
2322 struct msgb *msg = nm_msgb_alloc();
2323 u_int8_t attr = NM_ATT_BS11_TXPWR;
2324
2325 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2326 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2327 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2328 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2329
2330 return abis_nm_sendmsg(trx->bts, msg);
2331}
2332
Harald Welteaaf02d92009-04-29 13:25:57 +00002333int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2334{
2335 struct abis_om_hdr *oh;
2336 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002337 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002338
2339 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2340 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2341 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002342 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002343
2344 return abis_nm_sendmsg(bts, msg);
2345}
2346
Harald Welteef061952009-05-17 12:43:42 +00002347int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2348{
2349 struct abis_om_hdr *oh;
2350 struct msgb *msg = nm_msgb_alloc();
2351 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2352 NM_ATT_BS11_CCLK_TYPE };
2353
2354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2355 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2356 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2357 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2358
2359 return abis_nm_sendmsg(bts, msg);
2360
2361}
Harald Welteaaf02d92009-04-29 13:25:57 +00002362
Harald Welte268bb402009-02-01 19:11:56 +00002363//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002364
Harald Welte1bc09062009-01-18 14:17:52 +00002365int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002366{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002367 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2368}
2369
Daniel Willmann4b054c82010-01-07 00:46:26 +01002370int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2371{
2372 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2373}
2374
Daniel Willmann493db4e2010-01-07 00:43:11 +01002375int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2376{
Harald Welte05188ee2009-01-18 11:39:08 +00002377 struct abis_om_hdr *oh;
2378 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002379 struct bs11_date_time bdt;
2380
2381 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002382
2383 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002384 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002385 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002386 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002387 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002388 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002389 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002390 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002391 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002392 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002393 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002394 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002395 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002396 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002397 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002398 }
Harald Welte05188ee2009-01-18 11:39:08 +00002399
2400 return abis_nm_sendmsg(bts, msg);
2401}
Harald Welte1bc09062009-01-18 14:17:52 +00002402
2403int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2404{
2405 struct abis_om_hdr *oh;
2406 struct msgb *msg;
2407
2408 if (strlen(password) != 10)
2409 return -EINVAL;
2410
2411 msg = nm_msgb_alloc();
2412 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002413 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002414 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2415 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2416
2417 return abis_nm_sendmsg(bts, msg);
2418}
2419
Harald Weltee69f5fb2009-04-28 16:31:38 +00002420/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2421int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2422{
2423 struct abis_om_hdr *oh;
2424 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002425 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002426
2427 msg = nm_msgb_alloc();
2428 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2429 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2430 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002431
2432 if (locked)
2433 tlv_value = BS11_LI_PLL_LOCKED;
2434 else
2435 tlv_value = BS11_LI_PLL_STANDALONE;
2436
2437 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002438
2439 return abis_nm_sendmsg(bts, msg);
2440}
2441
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002442/* Set the calibration value of the PLL (work value/set value)
2443 * It depends on the login which one is changed */
2444int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2445{
2446 struct abis_om_hdr *oh;
2447 struct msgb *msg;
2448 u_int8_t tlv_value[2];
2449
2450 msg = nm_msgb_alloc();
2451 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2452 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2453 BS11_OBJ_TRX1, 0x00, 0x00);
2454
2455 tlv_value[0] = value>>8;
2456 tlv_value[1] = value&0xff;
2457
2458 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2459
2460 return abis_nm_sendmsg(bts, msg);
2461}
2462
Harald Welte1bc09062009-01-18 14:17:52 +00002463int abis_nm_bs11_get_state(struct gsm_bts *bts)
2464{
2465 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2466}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002467
2468/* BS11 SWL */
2469
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002470void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002471
Harald Welte5e4d1b32009-02-01 13:36:56 +00002472struct abis_nm_bs11_sw {
2473 struct gsm_bts *bts;
2474 char swl_fname[PATH_MAX];
2475 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002476 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002477 struct llist_head file_list;
2478 gsm_cbfn *user_cb; /* specified by the user */
2479};
2480static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2481
2482struct file_list_entry {
2483 struct llist_head list;
2484 char fname[PATH_MAX];
2485};
2486
2487struct file_list_entry *fl_dequeue(struct llist_head *queue)
2488{
2489 struct llist_head *lh;
2490
2491 if (llist_empty(queue))
2492 return NULL;
2493
2494 lh = queue->next;
2495 llist_del(lh);
2496
2497 return llist_entry(lh, struct file_list_entry, list);
2498}
2499
2500static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2501{
2502 char linebuf[255];
2503 struct llist_head *lh, *lh2;
2504 FILE *swl;
2505 int rc = 0;
2506
2507 swl = fopen(bs11_sw->swl_fname, "r");
2508 if (!swl)
2509 return -ENODEV;
2510
2511 /* zero the stale file list, if any */
2512 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2513 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002514 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002515 }
2516
2517 while (fgets(linebuf, sizeof(linebuf), swl)) {
2518 char file_id[12+1];
2519 char file_version[80+1];
2520 struct file_list_entry *fle;
2521 static char dir[PATH_MAX];
2522
2523 if (strlen(linebuf) < 4)
2524 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002525
Harald Welte5e4d1b32009-02-01 13:36:56 +00002526 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2527 if (rc < 0) {
2528 perror("ERR parsing SWL file");
2529 rc = -EINVAL;
2530 goto out;
2531 }
2532 if (rc < 2)
2533 continue;
2534
Harald Welte470ec292009-06-26 20:25:23 +02002535 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002536 if (!fle) {
2537 rc = -ENOMEM;
2538 goto out;
2539 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002540
2541 /* construct new filename */
2542 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2543 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2544 strcat(fle->fname, "/");
2545 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002546
2547 llist_add_tail(&fle->list, &bs11_sw->file_list);
2548 }
2549
2550out:
2551 fclose(swl);
2552 return rc;
2553}
2554
2555/* bs11 swload specific callback, passed to abis_nm core swload */
2556static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2557 struct msgb *msg, void *data, void *param)
2558{
2559 struct abis_nm_bs11_sw *bs11_sw = data;
2560 struct file_list_entry *fle;
2561 int rc = 0;
2562
Harald Welte5e4d1b32009-02-01 13:36:56 +00002563 switch (event) {
2564 case NM_MT_LOAD_END_ACK:
2565 fle = fl_dequeue(&bs11_sw->file_list);
2566 if (fle) {
2567 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002568 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002569 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002570 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002571 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002572 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002573 } else {
2574 /* activate the SWL */
2575 rc = abis_nm_software_activate(bs11_sw->bts,
2576 bs11_sw->swl_fname,
2577 bs11_swload_cbfn,
2578 bs11_sw);
2579 }
2580 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002581 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002582 case NM_MT_LOAD_END_NACK:
2583 case NM_MT_LOAD_INIT_ACK:
2584 case NM_MT_LOAD_INIT_NACK:
2585 case NM_MT_ACTIVATE_SW_NACK:
2586 case NM_MT_ACTIVATE_SW_ACK:
2587 default:
2588 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002589 if (bs11_sw->user_cb)
2590 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002591 break;
2592 }
2593
2594 return rc;
2595}
2596
2597/* Siemens provides a SWL file that is a mere listing of all the other
2598 * files that are part of a software release. We need to upload first
2599 * the list file, and then each file that is listed in the list file */
2600int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002601 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002602{
2603 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2604 struct file_list_entry *fle;
2605 int rc = 0;
2606
2607 INIT_LLIST_HEAD(&bs11_sw->file_list);
2608 bs11_sw->bts = bts;
2609 bs11_sw->win_size = win_size;
2610 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002611 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002612
2613 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2614 rc = bs11_read_swl_file(bs11_sw);
2615 if (rc < 0)
2616 return rc;
2617
2618 /* dequeue next item in file list */
2619 fle = fl_dequeue(&bs11_sw->file_list);
2620 if (!fle)
2621 return -EINVAL;
2622
2623 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002624 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002625 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002626 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002627 return rc;
2628}
2629
Harald Welte5083b0b2009-02-02 19:20:52 +00002630#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002631static u_int8_t req_attr_btse[] = {
2632 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2633 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2634 NM_ATT_BS11_LMT_USER_NAME,
2635
2636 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2637
2638 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2639
2640 NM_ATT_BS11_SW_LOAD_STORED };
2641
2642static u_int8_t req_attr_btsm[] = {
2643 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2644 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2645 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2646 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002647#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002648
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002649static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002650 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2651 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002652 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002653
2654int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2655{
2656 struct abis_om_hdr *oh;
2657 struct msgb *msg = nm_msgb_alloc();
2658
2659 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2660 /* SiemensHW CCTRL object */
2661 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2662 0x03, 0x00, 0x00);
2663 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2664
2665 return abis_nm_sendmsg(bts, msg);
2666}
Harald Welte268bb402009-02-01 19:11:56 +00002667
2668int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2669{
2670 struct abis_om_hdr *oh;
2671 struct msgb *msg = nm_msgb_alloc();
2672 struct bs11_date_time aet;
2673
2674 get_bs11_date_time(&aet);
2675 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2676 /* SiemensHW CCTRL object */
2677 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2678 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002679 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002680
2681 return abis_nm_sendmsg(bts, msg);
2682}
Harald Welte5c1e4582009-02-15 11:57:29 +00002683
Harald Weltef751a102010-12-14 12:52:16 +01002684int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2685{
2686 struct abis_om_hdr *oh;
2687 struct msgb *msg = nm_msgb_alloc();
2688 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2689
2690 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2691 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2692 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2693 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2694
2695 return abis_nm_sendmsg(bts, msg);
2696}
2697
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002698int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2699{
2700 struct abis_om_hdr *oh;
2701 struct msgb *msg = nm_msgb_alloc();
2702 struct bs11_date_time aet;
2703
2704 get_bs11_date_time(&aet);
2705 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2706 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2707 bport, 0xff, 0x02);
2708 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2709
2710 return abis_nm_sendmsg(bts, msg);
2711}
2712
Harald Welte5c1e4582009-02-15 11:57:29 +00002713/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002714static const char ipaccess_magic[] = "com.ipaccess";
2715
Harald Welte677c21f2009-02-17 13:22:23 +00002716
2717static int abis_nm_rx_ipacc(struct msgb *msg)
2718{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002719 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002720 struct abis_om_hdr *oh = msgb_l2(msg);
2721 struct abis_om_fom_hdr *foh;
2722 u_int8_t idstrlen = oh->data[0];
2723 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002724 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002725
2726 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002727 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002728 return -EINVAL;
2729 }
2730
Harald Welte193fefc2009-04-30 15:16:27 +00002731 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002732 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002733
Harald Weltea8bd6d42009-10-20 09:56:18 +02002734 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002735
Harald Welte746d6092009-10-19 22:11:11 +02002736 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002737
Harald Welte677c21f2009-02-17 13:22:23 +00002738 switch (foh->msg_type) {
2739 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002740 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002741 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2742 memcpy(&addr,
2743 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2744
2745 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2746 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002747 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002748 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002749 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002750 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002751 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2752 DEBUGPC(DNM, "STREAM=0x%02x ",
2753 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002754 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002755 break;
2756 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002757 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002758 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002759 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002760 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002761 else
2762 DEBUGPC(DNM, "\n");
2763 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002764 case NM_MT_IPACC_SET_NVATTR_ACK:
2765 DEBUGPC(DNM, "SET NVATTR ACK\n");
2766 /* FIXME: decode and show the actual attributes */
2767 break;
2768 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002769 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002770 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002771 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002772 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2773 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002774 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002775 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002776 case NM_MT_IPACC_GET_NVATTR_ACK:
2777 DEBUGPC(DNM, "GET NVATTR ACK\n");
2778 /* FIXME: decode and show the actual attributes */
2779 break;
2780 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002781 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002782 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002783 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002784 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2785 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002786 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002787 break;
Harald Welte15c44172009-10-08 20:15:24 +02002788 case NM_MT_IPACC_SET_ATTR_ACK:
2789 DEBUGPC(DNM, "SET ATTR ACK\n");
2790 break;
2791 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002792 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002793 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002794 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002795 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2796 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002797 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002798 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002799 default:
2800 DEBUGPC(DNM, "unknown\n");
2801 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002802 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002803
2804 /* signal handling */
2805 switch (foh->msg_type) {
2806 case NM_MT_IPACC_RSL_CONNECT_NACK:
2807 case NM_MT_IPACC_SET_NVATTR_NACK:
2808 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002809 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002810 signal.msg_type = foh->msg_type;
2811 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002812 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002813 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002814 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002815 signal.msg_type = foh->msg_type;
2816 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002817 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002818 default:
2819 break;
2820 }
2821
Harald Welte677c21f2009-02-17 13:22:23 +00002822 return 0;
2823}
2824
Harald Welte193fefc2009-04-30 15:16:27 +00002825/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002826int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2827 u_int8_t obj_class, u_int8_t bts_nr,
2828 u_int8_t trx_nr, u_int8_t ts_nr,
2829 u_int8_t *attr, int attr_len)
2830{
2831 struct msgb *msg = nm_msgb_alloc();
2832 struct abis_om_hdr *oh;
2833 struct abis_om_fom_hdr *foh;
2834 u_int8_t *data;
2835
2836 /* construct the 12.21 OM header, observe the erroneous length */
2837 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2838 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2839 oh->mdisc = ABIS_OM_MDISC_MANUF;
2840
2841 /* add the ip.access magic */
2842 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2843 *data++ = sizeof(ipaccess_magic);
2844 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2845
2846 /* fill the 12.21 FOM header */
2847 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2848 foh->msg_type = msg_type;
2849 foh->obj_class = obj_class;
2850 foh->obj_inst.bts_nr = bts_nr;
2851 foh->obj_inst.trx_nr = trx_nr;
2852 foh->obj_inst.ts_nr = ts_nr;
2853
2854 if (attr && attr_len) {
2855 data = msgb_put(msg, attr_len);
2856 memcpy(data, attr, attr_len);
2857 }
2858
2859 return abis_nm_sendmsg(bts, msg);
2860}
Harald Welte677c21f2009-02-17 13:22:23 +00002861
Harald Welte193fefc2009-04-30 15:16:27 +00002862/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002863int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002864 int attr_len)
2865{
Harald Welte2ef156d2010-01-07 20:39:42 +01002866 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2867 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002868 attr_len);
2869}
2870
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002871int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002872 u_int32_t ip, u_int16_t port, u_int8_t stream)
2873{
2874 struct in_addr ia;
2875 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2876 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2877 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2878
2879 int attr_len = sizeof(attr);
2880
2881 ia.s_addr = htonl(ip);
2882 attr[1] = stream;
2883 attr[3] = port >> 8;
2884 attr[4] = port & 0xff;
2885 *(u_int32_t *)(attr+6) = ia.s_addr;
2886
2887 /* if ip == 0, we use the default IP */
2888 if (ip == 0)
2889 attr_len -= 5;
2890
2891 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002892 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002893
2894 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2895 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2896 trx->nr, 0xff, attr, attr_len);
2897}
2898
Harald Welte193fefc2009-04-30 15:16:27 +00002899/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002900int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002901{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002902 struct abis_om_hdr *oh;
2903 struct msgb *msg = nm_msgb_alloc();
2904
2905 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2906 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2907 trx->bts->nr, trx->nr, 0xff);
2908
2909 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002910}
Harald Weltedaef5212009-10-24 10:20:41 +02002911
2912int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2913 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2914 u_int8_t *attr, u_int8_t attr_len)
2915{
2916 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2917 obj_class, bts_nr, trx_nr, ts_nr,
2918 attr, attr_len);
2919}
Harald Welte0f255852009-11-12 14:48:42 +01002920
Harald Welte97a282b2010-03-14 15:37:43 +08002921void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2922{
2923 /* we simply reuse the GSM48 function and overwrite the RAC
2924 * with the Cell ID */
2925 gsm48_ra_id_by_bts(buf, bts);
2926 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2927}
2928
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002929void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2930{
2931 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2932
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002933 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002934 if (!trx->bts || !trx->bts->oml_link)
2935 return;
2936
2937 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2938 trx->bts->bts_nr, trx->nr, 0xff,
2939 new_state);
2940}
2941
Harald Welte92b1fe42010-03-25 11:45:30 +08002942static const struct value_string ipacc_testres_names[] = {
2943 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2944 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2945 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2946 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2947 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2948 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002949};
2950
2951const char *ipacc_testres_name(u_int8_t res)
2952{
Harald Welte92b1fe42010-03-25 11:45:30 +08002953 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002954}
2955
Harald Welteb40a38f2009-11-13 11:56:05 +01002956void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2957{
2958 cid->mcc = (buf[0] & 0xf) * 100;
2959 cid->mcc += (buf[0] >> 4) * 10;
2960 cid->mcc += (buf[1] & 0xf) * 1;
2961
2962 if (buf[1] >> 4 == 0xf) {
2963 cid->mnc = (buf[2] & 0xf) * 10;
2964 cid->mnc += (buf[2] >> 4) * 1;
2965 } else {
2966 cid->mnc = (buf[2] & 0xf) * 100;
2967 cid->mnc += (buf[2] >> 4) * 10;
2968 cid->mnc += (buf[1] >> 4) * 1;
2969 }
2970
Harald Welteaff237d2009-11-13 14:41:52 +01002971 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2972 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002973}
2974
Harald Welte0f255852009-11-12 14:48:42 +01002975/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2976int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2977{
2978 u_int8_t *cur = buf;
2979 u_int16_t len;
2980
Harald Welteaf109b92010-07-22 18:14:36 +02002981 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002982
2983 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2984 return -EINVAL;
2985 cur++;
2986
2987 len = ntohs(*(u_int16_t *)cur);
2988 cur += 2;
2989
2990 binf->info_type = ntohs(*(u_int16_t *)cur);
2991 cur += 2;
2992
2993 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2994 binf->freq_qual = *cur >> 2;
2995
Harald Welteaf109b92010-07-22 18:14:36 +02002996 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002997 binf->arfcn |= *cur++;
2998
2999 if (binf->info_type & IPAC_BINF_RXLEV)
3000 binf->rx_lev = *cur & 0x3f;
3001 cur++;
3002
3003 if (binf->info_type & IPAC_BINF_RXQUAL)
3004 binf->rx_qual = *cur & 0x7;
3005 cur++;
3006
3007 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3008 binf->freq_err = ntohs(*(u_int16_t *)cur);
3009 cur += 2;
3010
3011 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3012 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3013 cur += 2;
3014
3015 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3016 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3017 cur += 4;
3018
Harald Weltea780a3d2010-07-30 22:34:42 +02003019#if 0
3020 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003021 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003022#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003023 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003024 cur++;
3025
Harald Welteb40a38f2009-11-13 11:56:05 +01003026 ipac_parse_cgi(&binf->cgi, cur);
3027 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003028
3029 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3030 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3031 cur += sizeof(binf->ba_list_si2);
3032 }
3033
3034 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3035 memcpy(binf->ba_list_si2bis, cur,
3036 sizeof(binf->ba_list_si2bis));
3037 cur += sizeof(binf->ba_list_si2bis);
3038 }
3039
3040 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3041 memcpy(binf->ba_list_si2ter, cur,
3042 sizeof(binf->ba_list_si2ter));
3043 cur += sizeof(binf->ba_list_si2ter);
3044 }
3045
3046 return 0;
3047}