blob: 2d8f687ecb737169eef66f48173e780cdede9ca3 [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);
1061 return -EINVAL;
1062 }
1063 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001064 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001065 oh->sequence);
1066 return -EINVAL;
1067 }
Harald Welte702d8702008-12-26 20:25:35 +00001068#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001069 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1070 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001071 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001072 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001073 oh->length + sizeof(*oh), l2_len);
1074 return -EINVAL;
1075 }
Harald Welte702d8702008-12-26 20:25:35 +00001076 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001077 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 +00001078#endif
Harald Weltead384642008-12-26 10:20:07 +00001079 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001080
1081 switch (oh->mdisc) {
1082 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001083 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001084 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001085 case ABIS_OM_MDISC_MANUF:
1086 rc = abis_nm_rcvmsg_manuf(msg);
1087 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001088 case ABIS_OM_MDISC_MMI:
1089 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001090 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001091 oh->mdisc);
1092 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001093 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001094 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001095 oh->mdisc);
1096 return -EINVAL;
1097 }
1098
Harald Weltead384642008-12-26 10:20:07 +00001099 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001100 return rc;
1101}
1102
1103#if 0
1104/* initialized all resources */
1105struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1106{
1107 struct abis_nm_h *nmh;
1108
1109 nmh = malloc(sizeof(*nmh));
1110 if (!nmh)
1111 return NULL;
1112
1113 nmh->cfg = cfg;
1114
1115 return nmh;
1116}
1117
1118/* free all resources */
1119void abis_nm_fini(struct abis_nm_h *nmh)
1120{
1121 free(nmh);
1122}
1123#endif
1124
1125/* Here we are trying to define a high-level API that can be used by
1126 * the actual BSC implementation. However, the architecture is currently
1127 * still under design. Ideally the calls to this API would be synchronous,
1128 * while the underlying stack behind the APi runs in a traditional select
1129 * based state machine.
1130 */
1131
Harald Welte4724f992009-01-18 18:01:49 +00001132/* 6.2 Software Load: */
1133enum sw_state {
1134 SW_STATE_NONE,
1135 SW_STATE_WAIT_INITACK,
1136 SW_STATE_WAIT_SEGACK,
1137 SW_STATE_WAIT_ENDACK,
1138 SW_STATE_WAIT_ACTACK,
1139 SW_STATE_ERROR,
1140};
Harald Welte52b1f982008-12-23 20:25:15 +00001141
Harald Welte52b1f982008-12-23 20:25:15 +00001142struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001143 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001144 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001145 gsm_cbfn *cbfn;
1146 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001147 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001148
Harald Welte52b1f982008-12-23 20:25:15 +00001149 /* this will become part of the SW LOAD INITIATE */
1150 u_int8_t obj_class;
1151 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001152
1153 u_int8_t file_id[255];
1154 u_int8_t file_id_len;
1155
1156 u_int8_t file_version[255];
1157 u_int8_t file_version_len;
1158
1159 u_int8_t window_size;
1160 u_int8_t seg_in_window;
1161
1162 int fd;
1163 FILE *stream;
1164 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001165 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001166};
1167
Harald Welte4724f992009-01-18 18:01:49 +00001168static struct abis_nm_sw g_sw;
1169
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001170static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1171{
1172 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1173 msgb_v_put(msg, NM_ATT_SW_DESCR);
1174 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1175 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1176 sw->file_version);
1177 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1178 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1179 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1180 sw->file_version);
1181 } else {
1182 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1183 }
1184}
1185
Harald Welte4724f992009-01-18 18:01:49 +00001186/* 6.2.1 / 8.3.1: Load Data Initiate */
1187static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001188{
Harald Welte4724f992009-01-18 18:01:49 +00001189 struct abis_om_hdr *oh;
1190 struct msgb *msg = nm_msgb_alloc();
1191 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1192
1193 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1194 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1195 sw->obj_instance[0], sw->obj_instance[1],
1196 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001197
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001198 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001199 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1200
1201 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001202}
1203
Harald Welte1602ade2009-01-29 21:12:39 +00001204static int is_last_line(FILE *stream)
1205{
1206 char next_seg_buf[256];
1207 long pos;
1208
1209 /* check if we're sending the last line */
1210 pos = ftell(stream);
1211 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1212 fseek(stream, pos, SEEK_SET);
1213 return 1;
1214 }
1215
1216 fseek(stream, pos, SEEK_SET);
1217 return 0;
1218}
1219
Harald Welte4724f992009-01-18 18:01:49 +00001220/* 6.2.2 / 8.3.2 Load Data Segment */
1221static int sw_load_segment(struct abis_nm_sw *sw)
1222{
1223 struct abis_om_hdr *oh;
1224 struct msgb *msg = nm_msgb_alloc();
1225 char seg_buf[256];
1226 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001227 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001228 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001229
1230 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001231
1232 switch (sw->bts->type) {
1233 case GSM_BTS_TYPE_BS11:
1234 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1235 perror("fgets reading segment");
1236 return -EINVAL;
1237 }
1238 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001239
1240 /* check if we're sending the last line */
1241 sw->last_seg = is_last_line(sw->stream);
1242 if (sw->last_seg)
1243 seg_buf[1] = 0;
1244 else
1245 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001246
1247 len = strlen(line_buf) + 2;
1248 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1249 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1250 /* BS11 wants CR + LF in excess of the TLV length !?! */
1251 tlv[1] -= 2;
1252
1253 /* we only now know the exact length for the OM hdr */
1254 len = strlen(line_buf)+2;
1255 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001256 case GSM_BTS_TYPE_NANOBTS: {
1257 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1258 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1259 if (len < 0) {
1260 perror("read failed");
1261 return -EINVAL;
1262 }
1263
1264 if (len != IPACC_SEGMENT_SIZE)
1265 sw->last_seg = 1;
1266
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001267 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001268 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1269 len += 3;
1270 break;
1271 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001272 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001273 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001274 /* FIXME: Other BTS types */
1275 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001276 }
Harald Welte4724f992009-01-18 18:01:49 +00001277
Harald Welte4724f992009-01-18 18:01:49 +00001278 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1279 sw->obj_instance[0], sw->obj_instance[1],
1280 sw->obj_instance[2]);
1281
1282 return abis_nm_sendmsg(sw->bts, msg);
1283}
1284
1285/* 6.2.4 / 8.3.4 Load Data End */
1286static int sw_load_end(struct abis_nm_sw *sw)
1287{
1288 struct abis_om_hdr *oh;
1289 struct msgb *msg = nm_msgb_alloc();
1290 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1291
1292 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1293 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1294 sw->obj_instance[0], sw->obj_instance[1],
1295 sw->obj_instance[2]);
1296
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001297 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001298 return abis_nm_sendmsg(sw->bts, msg);
1299}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001300
Harald Welte52b1f982008-12-23 20:25:15 +00001301/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001302static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001303{
Harald Welte4724f992009-01-18 18:01:49 +00001304 struct abis_om_hdr *oh;
1305 struct msgb *msg = nm_msgb_alloc();
1306 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001307
Harald Welte4724f992009-01-18 18:01:49 +00001308 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1309 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1310 sw->obj_instance[0], sw->obj_instance[1],
1311 sw->obj_instance[2]);
1312
1313 /* FIXME: this is BS11 specific format */
1314 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1315 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1316 sw->file_version);
1317
1318 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001319}
Harald Welte4724f992009-01-18 18:01:49 +00001320
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001321struct sdp_firmware {
1322 char magic[4];
1323 char more_magic[4];
1324 unsigned int header_length;
1325 unsigned int file_length;
1326} __attribute__ ((packed));
1327
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001328static int parse_sdp_header(struct abis_nm_sw *sw)
1329{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001330 struct sdp_firmware firmware_header;
1331 int rc;
1332 struct stat stat;
1333
1334 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1335 if (rc != sizeof(firmware_header)) {
1336 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1337 return -1;
1338 }
1339
1340 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1341 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1342 return -1;
1343 }
1344
1345 if (firmware_header.more_magic[0] != 0x10 ||
1346 firmware_header.more_magic[1] != 0x02 ||
1347 firmware_header.more_magic[2] != 0x00 ||
1348 firmware_header.more_magic[3] != 0x00) {
1349 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1350 return -1;
1351 }
1352
1353
1354 if (fstat(sw->fd, &stat) == -1) {
1355 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1356 return -1;
1357 }
1358
1359 if (ntohl(firmware_header.file_length) != stat.st_size) {
1360 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1361 return -1;
1362 }
1363
1364 /* go back to the start as we checked the whole filesize.. */
1365 lseek(sw->fd, 0l, SEEK_SET);
1366 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1367 "There might be checksums in the file that are not\n"
1368 "verified and incomplete firmware might be flashed.\n"
1369 "There is absolutely no WARRANTY that flashing will\n"
1370 "work.\n");
1371 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001372}
1373
Harald Welte4724f992009-01-18 18:01:49 +00001374static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1375{
1376 char file_id[12+1];
1377 char file_version[80+1];
1378 int rc;
1379
1380 sw->fd = open(fname, O_RDONLY);
1381 if (sw->fd < 0)
1382 return sw->fd;
1383
1384 switch (sw->bts->type) {
1385 case GSM_BTS_TYPE_BS11:
1386 sw->stream = fdopen(sw->fd, "r");
1387 if (!sw->stream) {
1388 perror("fdopen");
1389 return -1;
1390 }
1391 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001392 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001393 file_id, file_version);
1394 if (rc != 2) {
1395 perror("parsing header line of software file");
1396 return -1;
1397 }
1398 strcpy((char *)sw->file_id, file_id);
1399 sw->file_id_len = strlen(file_id);
1400 strcpy((char *)sw->file_version, file_version);
1401 sw->file_version_len = strlen(file_version);
1402 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001403 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001404 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001405 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001406 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001407 rc = parse_sdp_header(sw);
1408 if (rc < 0) {
1409 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1410 return -1;
1411 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001412
1413 strcpy((char *)sw->file_id, "id");
1414 sw->file_id_len = 3;
1415 strcpy((char *)sw->file_version, "version");
1416 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001417 break;
Harald Welte4724f992009-01-18 18:01:49 +00001418 default:
1419 /* We don't know how to treat them yet */
1420 close(sw->fd);
1421 return -EINVAL;
1422 }
1423
1424 return 0;
1425}
1426
1427static void sw_close_file(struct abis_nm_sw *sw)
1428{
1429 switch (sw->bts->type) {
1430 case GSM_BTS_TYPE_BS11:
1431 fclose(sw->stream);
1432 break;
1433 default:
1434 close(sw->fd);
1435 break;
1436 }
1437}
1438
1439/* Fill the window */
1440static int sw_fill_window(struct abis_nm_sw *sw)
1441{
1442 int rc;
1443
1444 while (sw->seg_in_window < sw->window_size) {
1445 rc = sw_load_segment(sw);
1446 if (rc < 0)
1447 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001448 if (sw->last_seg)
1449 break;
Harald Welte4724f992009-01-18 18:01:49 +00001450 }
1451 return 0;
1452}
1453
1454/* callback function from abis_nm_rcvmsg() handler */
1455static int abis_nm_rcvmsg_sw(struct msgb *mb)
1456{
1457 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1458 int rc = -1;
1459 struct abis_nm_sw *sw = &g_sw;
1460 enum sw_state old_state = sw->state;
1461
Harald Welte3ffd1372009-02-01 22:15:49 +00001462 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001463
1464 switch (sw->state) {
1465 case SW_STATE_WAIT_INITACK:
1466 switch (foh->msg_type) {
1467 case NM_MT_LOAD_INIT_ACK:
1468 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001469 if (sw->cbfn)
1470 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1471 NM_MT_LOAD_INIT_ACK, mb,
1472 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001473 rc = sw_fill_window(sw);
1474 sw->state = SW_STATE_WAIT_SEGACK;
1475 break;
1476 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001477 if (sw->forced) {
1478 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1479 "Init NACK\n");
1480 if (sw->cbfn)
1481 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1482 NM_MT_LOAD_INIT_ACK, mb,
1483 sw->cb_data, NULL);
1484 rc = sw_fill_window(sw);
1485 sw->state = SW_STATE_WAIT_SEGACK;
1486 } else {
1487 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001488 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001489 if (sw->cbfn)
1490 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1491 NM_MT_LOAD_INIT_NACK, mb,
1492 sw->cb_data, NULL);
1493 sw->state = SW_STATE_ERROR;
1494 }
Harald Welte4724f992009-01-18 18:01:49 +00001495 break;
1496 }
1497 break;
1498 case SW_STATE_WAIT_SEGACK:
1499 switch (foh->msg_type) {
1500 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001501 if (sw->cbfn)
1502 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1503 NM_MT_LOAD_SEG_ACK, mb,
1504 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001505 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001506 if (!sw->last_seg) {
1507 /* fill window with more segments */
1508 rc = sw_fill_window(sw);
1509 sw->state = SW_STATE_WAIT_SEGACK;
1510 } else {
1511 /* end the transfer */
1512 sw->state = SW_STATE_WAIT_ENDACK;
1513 rc = sw_load_end(sw);
1514 }
Harald Welte4724f992009-01-18 18:01:49 +00001515 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001516 case NM_MT_LOAD_ABORT:
1517 if (sw->cbfn)
1518 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1519 NM_MT_LOAD_ABORT, mb,
1520 sw->cb_data, NULL);
1521 break;
Harald Welte4724f992009-01-18 18:01:49 +00001522 }
1523 break;
1524 case SW_STATE_WAIT_ENDACK:
1525 switch (foh->msg_type) {
1526 case NM_MT_LOAD_END_ACK:
1527 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001528 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1529 sw->bts->nr);
1530 sw->state = SW_STATE_NONE;
1531 if (sw->cbfn)
1532 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1533 NM_MT_LOAD_END_ACK, mb,
1534 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001535 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001536 break;
1537 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001538 if (sw->forced) {
1539 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1540 "End NACK\n");
1541 sw->state = SW_STATE_NONE;
1542 if (sw->cbfn)
1543 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1544 NM_MT_LOAD_END_ACK, mb,
1545 sw->cb_data, NULL);
1546 } else {
1547 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001548 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001549 sw->state = SW_STATE_ERROR;
1550 if (sw->cbfn)
1551 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1552 NM_MT_LOAD_END_NACK, mb,
1553 sw->cb_data, NULL);
1554 }
Harald Welte4724f992009-01-18 18:01:49 +00001555 break;
1556 }
1557 case SW_STATE_WAIT_ACTACK:
1558 switch (foh->msg_type) {
1559 case NM_MT_ACTIVATE_SW_ACK:
1560 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001561 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001562 sw->state = SW_STATE_NONE;
1563 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001564 if (sw->cbfn)
1565 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1566 NM_MT_ACTIVATE_SW_ACK, mb,
1567 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001568 break;
1569 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001570 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001571 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001572 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001573 if (sw->cbfn)
1574 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1575 NM_MT_ACTIVATE_SW_NACK, mb,
1576 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001577 break;
1578 }
1579 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001580 switch (foh->msg_type) {
1581 case NM_MT_ACTIVATE_SW_ACK:
1582 rc = 0;
1583 break;
1584 }
1585 break;
Harald Welte4724f992009-01-18 18:01:49 +00001586 case SW_STATE_ERROR:
1587 break;
1588 }
1589
1590 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001591 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001592 foh->msg_type, old_state, sw->state);
1593
1594 return rc;
1595}
1596
1597/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001598int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001599 u_int8_t win_size, int forced,
1600 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001601{
1602 struct abis_nm_sw *sw = &g_sw;
1603 int rc;
1604
Harald Welte5e4d1b32009-02-01 13:36:56 +00001605 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1606 bts->nr, fname);
1607
Harald Welte4724f992009-01-18 18:01:49 +00001608 if (sw->state != SW_STATE_NONE)
1609 return -EBUSY;
1610
1611 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001612 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001613
1614 switch (bts->type) {
1615 case GSM_BTS_TYPE_BS11:
1616 sw->obj_class = NM_OC_SITE_MANAGER;
1617 sw->obj_instance[0] = 0xff;
1618 sw->obj_instance[1] = 0xff;
1619 sw->obj_instance[2] = 0xff;
1620 break;
1621 case GSM_BTS_TYPE_NANOBTS:
1622 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001623 sw->obj_instance[0] = sw->bts->nr;
1624 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001625 sw->obj_instance[2] = 0xff;
1626 break;
1627 case GSM_BTS_TYPE_UNKNOWN:
1628 default:
1629 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1630 return -1;
1631 break;
1632 }
Harald Welte4724f992009-01-18 18:01:49 +00001633 sw->window_size = win_size;
1634 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001635 sw->cbfn = cbfn;
1636 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001637 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001638
1639 rc = sw_open_file(sw, fname);
1640 if (rc < 0) {
1641 sw->state = SW_STATE_NONE;
1642 return rc;
1643 }
1644
1645 return sw_load_init(sw);
1646}
Harald Welte52b1f982008-12-23 20:25:15 +00001647
Harald Welte1602ade2009-01-29 21:12:39 +00001648int abis_nm_software_load_status(struct gsm_bts *bts)
1649{
1650 struct abis_nm_sw *sw = &g_sw;
1651 struct stat st;
1652 int rc, percent;
1653
1654 rc = fstat(sw->fd, &st);
1655 if (rc < 0) {
1656 perror("ERROR during stat");
1657 return rc;
1658 }
1659
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001660 if (sw->stream)
1661 percent = (ftell(sw->stream) * 100) / st.st_size;
1662 else
1663 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001664 return percent;
1665}
1666
Harald Welte5e4d1b32009-02-01 13:36:56 +00001667/* Activate the specified software into the BTS */
1668int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1669 gsm_cbfn *cbfn, void *cb_data)
1670{
1671 struct abis_nm_sw *sw = &g_sw;
1672 int rc;
1673
1674 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1675 bts->nr, fname);
1676
1677 if (sw->state != SW_STATE_NONE)
1678 return -EBUSY;
1679
1680 sw->bts = bts;
1681 sw->obj_class = NM_OC_SITE_MANAGER;
1682 sw->obj_instance[0] = 0xff;
1683 sw->obj_instance[1] = 0xff;
1684 sw->obj_instance[2] = 0xff;
1685 sw->state = SW_STATE_WAIT_ACTACK;
1686 sw->cbfn = cbfn;
1687 sw->cb_data = cb_data;
1688
1689 /* Open the file in order to fill some sw struct members */
1690 rc = sw_open_file(sw, fname);
1691 if (rc < 0) {
1692 sw->state = SW_STATE_NONE;
1693 return rc;
1694 }
1695 sw_close_file(sw);
1696
1697 return sw_activate(sw);
1698}
1699
Harald Welte8470bf22008-12-25 23:28:35 +00001700static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001701 u_int8_t ts_nr, u_int8_t subslot_nr)
1702{
Harald Welteadaf08b2009-01-18 11:08:10 +00001703 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001704 ch->bts_port = bts_port;
1705 ch->timeslot = ts_nr;
1706 ch->subslot = subslot_nr;
1707}
1708
1709int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1710 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1711 u_int8_t tei)
1712{
1713 struct abis_om_hdr *oh;
1714 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001715 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001716 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001717
1718 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1719 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1720 bts->bts_nr, trx_nr, 0xff);
1721
Harald Welte8470bf22008-12-25 23:28:35 +00001722 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001723
1724 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1725 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1726
1727 return abis_nm_sendmsg(bts, msg);
1728}
1729
1730/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1731int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1732 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1733{
Harald Welte8470bf22008-12-25 23:28:35 +00001734 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001735 struct abis_om_hdr *oh;
1736 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001737 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001738
1739 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001740 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001741 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1742
1743 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1744 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1745
1746 return abis_nm_sendmsg(bts, msg);
1747}
1748
1749#if 0
1750int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1751 struct abis_nm_abis_channel *chan)
1752{
1753}
1754#endif
1755
1756int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1757 u_int8_t e1_port, u_int8_t e1_timeslot,
1758 u_int8_t e1_subslot)
1759{
1760 struct gsm_bts *bts = ts->trx->bts;
1761 struct abis_om_hdr *oh;
1762 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001763 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001764
1765 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1766 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001767 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001768
1769 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1770 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1771
Harald Weltef325eb42009-02-19 17:07:39 +00001772 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1773 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001774 e1_port, e1_timeslot, e1_subslot);
1775
Harald Welte52b1f982008-12-23 20:25:15 +00001776 return abis_nm_sendmsg(bts, msg);
1777}
1778
1779#if 0
1780int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1781 struct abis_nm_abis_channel *chan,
1782 u_int8_t subchan)
1783{
1784}
1785#endif
1786
Harald Welte22af0db2009-02-14 15:41:08 +00001787/* Chapter 8.6.1 */
1788int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1789{
1790 struct abis_om_hdr *oh;
1791 struct msgb *msg = nm_msgb_alloc();
1792 u_int8_t *cur;
1793
1794 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1795
1796 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001797 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 +00001798 cur = msgb_put(msg, attr_len);
1799 memcpy(cur, attr, attr_len);
1800
1801 return abis_nm_sendmsg(bts, msg);
1802}
1803
1804/* Chapter 8.6.2 */
1805int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1806{
1807 struct abis_om_hdr *oh;
1808 struct msgb *msg = nm_msgb_alloc();
1809 u_int8_t *cur;
1810
1811 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1812
1813 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1814 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001815 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001816 cur = msgb_put(msg, attr_len);
1817 memcpy(cur, attr, attr_len);
1818
1819 return abis_nm_sendmsg(trx->bts, msg);
1820}
1821
Harald Welte39c7deb2009-08-09 21:49:48 +02001822static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1823{
1824 int i;
1825
1826 /* As it turns out, the BS-11 has some very peculiar restrictions
1827 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301828 switch (ts->trx->bts->type) {
1829 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001830 switch (chan_comb) {
1831 case NM_CHANC_TCHHalf:
1832 case NM_CHANC_TCHHalf2:
1833 /* not supported */
1834 return -EINVAL;
1835 case NM_CHANC_SDCCH:
1836 /* only one SDCCH/8 per TRX */
1837 for (i = 0; i < TRX_NR_TS; i++) {
1838 if (i == ts->nr)
1839 continue;
1840 if (ts->trx->ts[i].nm_chan_comb ==
1841 NM_CHANC_SDCCH)
1842 return -EINVAL;
1843 }
1844 /* not allowed for TS0 of BCCH-TRX */
1845 if (ts->trx == ts->trx->bts->c0 &&
1846 ts->nr == 0)
1847 return -EINVAL;
1848 /* not on the same TRX that has a BCCH+SDCCH4
1849 * combination */
1850 if (ts->trx == ts->trx->bts->c0 &&
1851 (ts->trx->ts[0].nm_chan_comb == 5 ||
1852 ts->trx->ts[0].nm_chan_comb == 8))
1853 return -EINVAL;
1854 break;
1855 case NM_CHANC_mainBCCH:
1856 case NM_CHANC_BCCHComb:
1857 /* allowed only for TS0 of C0 */
1858 if (ts->trx != ts->trx->bts->c0 ||
1859 ts->nr != 0)
1860 return -EINVAL;
1861 break;
1862 case NM_CHANC_BCCH:
1863 /* allowed only for TS 2/4/6 of C0 */
1864 if (ts->trx != ts->trx->bts->c0)
1865 return -EINVAL;
1866 if (ts->nr != 2 && ts->nr != 4 &&
1867 ts->nr != 6)
1868 return -EINVAL;
1869 break;
1870 case 8: /* this is not like 08.58, but in fact
1871 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1872 /* FIXME: only one CBCH allowed per cell */
1873 break;
1874 }
Harald Welted6575f92009-12-02 02:45:23 +05301875 break;
1876 case GSM_BTS_TYPE_NANOBTS:
1877 switch (ts->nr) {
1878 case 0:
1879 if (ts->trx->nr == 0) {
1880 /* only on TRX0 */
1881 switch (chan_comb) {
1882 case NM_CHANC_BCCH:
1883 case NM_CHANC_mainBCCH:
1884 case NM_CHANC_BCCHComb:
1885 return 0;
1886 break;
1887 default:
1888 return -EINVAL;
1889 }
1890 } else {
1891 switch (chan_comb) {
1892 case NM_CHANC_TCHFull:
1893 case NM_CHANC_TCHHalf:
1894 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1895 return 0;
1896 default:
1897 return -EINVAL;
1898 }
1899 }
1900 break;
1901 case 1:
1902 if (ts->trx->nr == 0) {
1903 switch (chan_comb) {
1904 case NM_CHANC_SDCCH_CBCH:
1905 if (ts->trx->ts[0].nm_chan_comb ==
1906 NM_CHANC_mainBCCH)
1907 return 0;
1908 return -EINVAL;
1909 case NM_CHANC_SDCCH:
1910 case NM_CHANC_TCHFull:
1911 case NM_CHANC_TCHHalf:
1912 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1913 case NM_CHANC_IPAC_TCHFull_PDCH:
1914 return 0;
1915 }
1916 } else {
1917 switch (chan_comb) {
1918 case NM_CHANC_SDCCH:
1919 case NM_CHANC_TCHFull:
1920 case NM_CHANC_TCHHalf:
1921 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1922 return 0;
1923 default:
1924 return -EINVAL;
1925 }
1926 }
1927 break;
1928 case 2:
1929 case 3:
1930 case 4:
1931 case 5:
1932 case 6:
1933 case 7:
1934 switch (chan_comb) {
1935 case NM_CHANC_TCHFull:
1936 case NM_CHANC_TCHHalf:
1937 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1938 return 0;
1939 case NM_CHANC_IPAC_PDCH:
1940 case NM_CHANC_IPAC_TCHFull_PDCH:
1941 if (ts->trx->nr == 0)
1942 return 0;
1943 else
1944 return -EINVAL;
1945 }
1946 break;
1947 }
1948 return -EINVAL;
1949 default:
1950 /* unknown BTS type */
1951 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001952 }
1953 return 0;
1954}
1955
Harald Welte22af0db2009-02-14 15:41:08 +00001956/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001957int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1958{
1959 struct gsm_bts *bts = ts->trx->bts;
1960 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001961 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001962 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001963 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001964 u_int8_t len = 2 + 2;
1965
1966 if (bts->type == GSM_BTS_TYPE_BS11)
1967 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001968
Harald Weltef325eb42009-02-19 17:07:39 +00001969 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001970 if (verify_chan_comb(ts, chan_comb) < 0) {
1971 msgb_free(msg);
1972 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1973 return -EINVAL;
1974 }
1975 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001976
Harald Welte52b1f982008-12-23 20:25:15 +00001977 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001978 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001979 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001980 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001981 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001982 if (ts->hopping.enabled) {
1983 unsigned int i;
1984 uint8_t *len;
1985
Harald Welte6e0cd042009-09-12 13:05:33 +02001986 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1987 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001988
1989 /* build the ARFCN list */
1990 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1991 len = msgb_put(msg, 1);
1992 *len = 0;
1993 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1994 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1995 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001996 /* At least BS-11 wants a TLV16 here */
1997 if (bts->type == GSM_BTS_TYPE_BS11)
1998 *len += 1;
1999 else
2000 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002001 }
2002 }
Harald Weltee0590df2009-02-15 03:34:15 +00002003 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002004 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002005 if (bts->type == GSM_BTS_TYPE_BS11)
2006 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002007
2008 return abis_nm_sendmsg(bts, msg);
2009}
2010
Harald Welte34a99682009-02-13 02:41:40 +00002011int 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 +00002012 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002013{
2014 struct abis_om_hdr *oh;
2015 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002016 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2017 u_int8_t len = att_len;
2018
2019 if (nack) {
2020 len += 2;
2021 msgtype = NM_MT_SW_ACT_REQ_NACK;
2022 }
Harald Welte34a99682009-02-13 02:41:40 +00002023
2024 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002025 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2026
Harald Welte34a99682009-02-13 02:41:40 +00002027 if (attr) {
2028 u_int8_t *ptr = msgb_put(msg, att_len);
2029 memcpy(ptr, attr, att_len);
2030 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002031 if (nack)
2032 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002033
2034 return abis_nm_sendmsg(bts, msg);
2035}
2036
Harald Welte8470bf22008-12-25 23:28:35 +00002037int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002038{
Harald Welte8470bf22008-12-25 23:28:35 +00002039 struct msgb *msg = nm_msgb_alloc();
2040 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002041 u_int8_t *data;
2042
2043 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2044 fill_om_hdr(oh, len);
2045 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002046 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002047
2048 return abis_nm_sendmsg(bts, msg);
2049}
2050
2051/* Siemens specific commands */
2052static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2053{
2054 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002055 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002056
2057 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002058 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002059 0xff, 0xff, 0xff);
2060
2061 return abis_nm_sendmsg(bts, msg);
2062}
2063
Harald Welte34a99682009-02-13 02:41:40 +00002064/* Chapter 8.9.2 */
2065int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2066{
2067 struct abis_om_hdr *oh;
2068 struct msgb *msg = nm_msgb_alloc();
2069
2070 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2071 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2072
Harald Weltea8bd6d42009-10-20 09:56:18 +02002073 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2074 DEBUGPC(DNM, "Sending OPSTART\n");
2075
Harald Welte34a99682009-02-13 02:41:40 +00002076 return abis_nm_sendmsg(bts, msg);
2077}
2078
2079/* Chapter 8.8.5 */
2080int 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 +02002081 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002082{
2083 struct abis_om_hdr *oh;
2084 struct msgb *msg = nm_msgb_alloc();
2085
2086 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2087 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2088 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2089
2090 return abis_nm_sendmsg(bts, msg);
2091}
2092
Harald Welte1989c082009-08-06 17:58:31 +02002093int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2094 u_int8_t e1_port1, u_int8_t ts1)
2095{
2096 struct abis_om_hdr *oh;
2097 struct msgb *msg = nm_msgb_alloc();
2098 u_int8_t *attr;
2099
2100 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2101 e1_port0, ts0, e1_port1, ts1);
2102
2103 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2104 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2105 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2106
2107 attr = msgb_put(msg, 3);
2108 attr[0] = NM_ATT_MDROP_LINK;
2109 attr[1] = e1_port0;
2110 attr[2] = ts0;
2111
2112 attr = msgb_put(msg, 3);
2113 attr[0] = NM_ATT_MDROP_NEXT;
2114 attr[1] = e1_port1;
2115 attr[2] = ts1;
2116
2117 return abis_nm_sendmsg(bts, msg);
2118}
Harald Welte34a99682009-02-13 02:41:40 +00002119
Harald Weltec7310382009-08-08 00:02:36 +02002120/* Chapter 8.7.1 */
2121int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2122 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002123 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002124{
2125 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002126
2127 DEBUGP(DNM, "PEFORM TEST\n");
Harald Welte887deab2010-03-06 11:38:05 +01002128
2129 if (!msg)
2130 msg = nm_msgb_alloc();
2131
2132 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2133 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2134 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2135 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002136 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002137
2138 return abis_nm_sendmsg(bts, msg);
2139}
2140
Harald Welte52b1f982008-12-23 20:25:15 +00002141int abis_nm_event_reports(struct gsm_bts *bts, int on)
2142{
2143 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002144 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002145 else
Harald Welte227d4072009-01-03 08:16:25 +00002146 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002147}
2148
Harald Welte47d88ae2009-01-04 12:02:08 +00002149/* Siemens (or BS-11) specific commands */
2150
Harald Welte3ffd1372009-02-01 22:15:49 +00002151int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2152{
2153 if (reconnect == 0)
2154 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2155 else
2156 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2157}
2158
Harald Welteb8427972009-02-05 19:27:17 +00002159int abis_nm_bs11_restart(struct gsm_bts *bts)
2160{
2161 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2162}
2163
2164
Harald Welte268bb402009-02-01 19:11:56 +00002165struct bs11_date_time {
2166 u_int16_t year;
2167 u_int8_t month;
2168 u_int8_t day;
2169 u_int8_t hour;
2170 u_int8_t min;
2171 u_int8_t sec;
2172} __attribute__((packed));
2173
2174
2175void get_bs11_date_time(struct bs11_date_time *aet)
2176{
2177 time_t t;
2178 struct tm *tm;
2179
2180 t = time(NULL);
2181 tm = localtime(&t);
2182 aet->sec = tm->tm_sec;
2183 aet->min = tm->tm_min;
2184 aet->hour = tm->tm_hour;
2185 aet->day = tm->tm_mday;
2186 aet->month = tm->tm_mon;
2187 aet->year = htons(1900 + tm->tm_year);
2188}
2189
Harald Welte05188ee2009-01-18 11:39:08 +00002190int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002191{
Harald Welte4668fda2009-01-03 08:19:29 +00002192 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002193}
2194
Harald Welte05188ee2009-01-18 11:39:08 +00002195int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002196{
2197 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002198 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002199 else
Harald Welte4668fda2009-01-03 08:19:29 +00002200 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002201}
Harald Welte47d88ae2009-01-04 12:02:08 +00002202
Harald Welte05188ee2009-01-18 11:39:08 +00002203int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002204 enum abis_bs11_objtype type, u_int8_t idx,
2205 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002206{
2207 struct abis_om_hdr *oh;
2208 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002209 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002210
2211 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002212 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002213 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002214 cur = msgb_put(msg, attr_len);
2215 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002216
2217 return abis_nm_sendmsg(bts, msg);
2218}
2219
Harald Welte78fc0d42009-02-19 02:50:57 +00002220int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2221 enum abis_bs11_objtype type, u_int8_t idx)
2222{
2223 struct abis_om_hdr *oh;
2224 struct msgb *msg = nm_msgb_alloc();
2225
2226 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2227 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2228 NM_OC_BS11, type, 0, idx);
2229
2230 return abis_nm_sendmsg(bts, msg);
2231}
2232
Harald Welte05188ee2009-01-18 11:39:08 +00002233int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002234{
2235 struct abis_om_hdr *oh;
2236 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002237 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002238
2239 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002240 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002241 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2242 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002243
2244 return abis_nm_sendmsg(bts, msg);
2245}
2246
Harald Welte05188ee2009-01-18 11:39:08 +00002247int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002248{
2249 struct abis_om_hdr *oh;
2250 struct msgb *msg = nm_msgb_alloc();
2251
2252 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2253 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002254 idx, 0xff, 0xff);
2255
2256 return abis_nm_sendmsg(bts, msg);
2257}
2258
2259int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2260{
2261 struct abis_om_hdr *oh;
2262 struct msgb *msg = nm_msgb_alloc();
2263
2264 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2265 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2266 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002267
2268 return abis_nm_sendmsg(bts, msg);
2269}
Harald Welte05188ee2009-01-18 11:39:08 +00002270
Harald Welte78fc0d42009-02-19 02:50:57 +00002271static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2272int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2273{
2274 struct abis_om_hdr *oh;
2275 struct msgb *msg = nm_msgb_alloc();
2276
2277 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2278 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2279 0xff, 0xff, 0xff);
2280 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2281
2282 return abis_nm_sendmsg(bts, msg);
2283}
2284
Harald Welteb6c92ae2009-02-21 20:15:32 +00002285/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002286int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002287 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2288 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002289{
2290 struct abis_om_hdr *oh;
2291 struct abis_nm_channel *ch;
2292 struct msgb *msg = nm_msgb_alloc();
2293
2294 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002295 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002296 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2297
2298 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2299 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002300 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002301
2302 return abis_nm_sendmsg(bts, msg);
2303}
2304
2305int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2306{
2307 struct abis_om_hdr *oh;
2308 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002309
2310 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002311 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002312 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2313 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2314
2315 return abis_nm_sendmsg(trx->bts, msg);
2316}
2317
Harald Welte78fc0d42009-02-19 02:50:57 +00002318int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2319{
2320 struct abis_om_hdr *oh;
2321 struct msgb *msg = nm_msgb_alloc();
2322 u_int8_t attr = NM_ATT_BS11_TXPWR;
2323
2324 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2325 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2326 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2327 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2328
2329 return abis_nm_sendmsg(trx->bts, msg);
2330}
2331
Harald Welteaaf02d92009-04-29 13:25:57 +00002332int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2333{
2334 struct abis_om_hdr *oh;
2335 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002336 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002337
2338 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2339 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2340 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002341 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002342
2343 return abis_nm_sendmsg(bts, msg);
2344}
2345
Harald Welteef061952009-05-17 12:43:42 +00002346int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2347{
2348 struct abis_om_hdr *oh;
2349 struct msgb *msg = nm_msgb_alloc();
2350 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2351 NM_ATT_BS11_CCLK_TYPE };
2352
2353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2354 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2355 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2356 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2357
2358 return abis_nm_sendmsg(bts, msg);
2359
2360}
Harald Welteaaf02d92009-04-29 13:25:57 +00002361
Harald Welte268bb402009-02-01 19:11:56 +00002362//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002363
Harald Welte1bc09062009-01-18 14:17:52 +00002364int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002365{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002366 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2367}
2368
Daniel Willmann4b054c82010-01-07 00:46:26 +01002369int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2370{
2371 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2372}
2373
Daniel Willmann493db4e2010-01-07 00:43:11 +01002374int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2375{
Harald Welte05188ee2009-01-18 11:39:08 +00002376 struct abis_om_hdr *oh;
2377 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002378 struct bs11_date_time bdt;
2379
2380 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002381
2382 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002383 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002384 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002385 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002386 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002387 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002388 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002389 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002390 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002391 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002392 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002393 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002394 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002395 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002396 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002397 }
Harald Welte05188ee2009-01-18 11:39:08 +00002398
2399 return abis_nm_sendmsg(bts, msg);
2400}
Harald Welte1bc09062009-01-18 14:17:52 +00002401
2402int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2403{
2404 struct abis_om_hdr *oh;
2405 struct msgb *msg;
2406
2407 if (strlen(password) != 10)
2408 return -EINVAL;
2409
2410 msg = nm_msgb_alloc();
2411 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002412 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002413 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2414 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2415
2416 return abis_nm_sendmsg(bts, msg);
2417}
2418
Harald Weltee69f5fb2009-04-28 16:31:38 +00002419/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2420int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2421{
2422 struct abis_om_hdr *oh;
2423 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002424 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002425
2426 msg = nm_msgb_alloc();
2427 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2428 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2429 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002430
2431 if (locked)
2432 tlv_value = BS11_LI_PLL_LOCKED;
2433 else
2434 tlv_value = BS11_LI_PLL_STANDALONE;
2435
2436 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002437
2438 return abis_nm_sendmsg(bts, msg);
2439}
2440
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002441/* Set the calibration value of the PLL (work value/set value)
2442 * It depends on the login which one is changed */
2443int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2444{
2445 struct abis_om_hdr *oh;
2446 struct msgb *msg;
2447 u_int8_t tlv_value[2];
2448
2449 msg = nm_msgb_alloc();
2450 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2451 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2452 BS11_OBJ_TRX1, 0x00, 0x00);
2453
2454 tlv_value[0] = value>>8;
2455 tlv_value[1] = value&0xff;
2456
2457 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2458
2459 return abis_nm_sendmsg(bts, msg);
2460}
2461
Harald Welte1bc09062009-01-18 14:17:52 +00002462int abis_nm_bs11_get_state(struct gsm_bts *bts)
2463{
2464 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2465}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002466
2467/* BS11 SWL */
2468
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002469void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002470
Harald Welte5e4d1b32009-02-01 13:36:56 +00002471struct abis_nm_bs11_sw {
2472 struct gsm_bts *bts;
2473 char swl_fname[PATH_MAX];
2474 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002475 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002476 struct llist_head file_list;
2477 gsm_cbfn *user_cb; /* specified by the user */
2478};
2479static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2480
2481struct file_list_entry {
2482 struct llist_head list;
2483 char fname[PATH_MAX];
2484};
2485
2486struct file_list_entry *fl_dequeue(struct llist_head *queue)
2487{
2488 struct llist_head *lh;
2489
2490 if (llist_empty(queue))
2491 return NULL;
2492
2493 lh = queue->next;
2494 llist_del(lh);
2495
2496 return llist_entry(lh, struct file_list_entry, list);
2497}
2498
2499static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2500{
2501 char linebuf[255];
2502 struct llist_head *lh, *lh2;
2503 FILE *swl;
2504 int rc = 0;
2505
2506 swl = fopen(bs11_sw->swl_fname, "r");
2507 if (!swl)
2508 return -ENODEV;
2509
2510 /* zero the stale file list, if any */
2511 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2512 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002513 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002514 }
2515
2516 while (fgets(linebuf, sizeof(linebuf), swl)) {
2517 char file_id[12+1];
2518 char file_version[80+1];
2519 struct file_list_entry *fle;
2520 static char dir[PATH_MAX];
2521
2522 if (strlen(linebuf) < 4)
2523 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002524
Harald Welte5e4d1b32009-02-01 13:36:56 +00002525 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2526 if (rc < 0) {
2527 perror("ERR parsing SWL file");
2528 rc = -EINVAL;
2529 goto out;
2530 }
2531 if (rc < 2)
2532 continue;
2533
Harald Welte470ec292009-06-26 20:25:23 +02002534 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002535 if (!fle) {
2536 rc = -ENOMEM;
2537 goto out;
2538 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002539
2540 /* construct new filename */
2541 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2542 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2543 strcat(fle->fname, "/");
2544 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002545
2546 llist_add_tail(&fle->list, &bs11_sw->file_list);
2547 }
2548
2549out:
2550 fclose(swl);
2551 return rc;
2552}
2553
2554/* bs11 swload specific callback, passed to abis_nm core swload */
2555static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2556 struct msgb *msg, void *data, void *param)
2557{
2558 struct abis_nm_bs11_sw *bs11_sw = data;
2559 struct file_list_entry *fle;
2560 int rc = 0;
2561
Harald Welte5e4d1b32009-02-01 13:36:56 +00002562 switch (event) {
2563 case NM_MT_LOAD_END_ACK:
2564 fle = fl_dequeue(&bs11_sw->file_list);
2565 if (fle) {
2566 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002567 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002568 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002569 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002570 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002571 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002572 } else {
2573 /* activate the SWL */
2574 rc = abis_nm_software_activate(bs11_sw->bts,
2575 bs11_sw->swl_fname,
2576 bs11_swload_cbfn,
2577 bs11_sw);
2578 }
2579 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002580 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002581 case NM_MT_LOAD_END_NACK:
2582 case NM_MT_LOAD_INIT_ACK:
2583 case NM_MT_LOAD_INIT_NACK:
2584 case NM_MT_ACTIVATE_SW_NACK:
2585 case NM_MT_ACTIVATE_SW_ACK:
2586 default:
2587 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002588 if (bs11_sw->user_cb)
2589 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002590 break;
2591 }
2592
2593 return rc;
2594}
2595
2596/* Siemens provides a SWL file that is a mere listing of all the other
2597 * files that are part of a software release. We need to upload first
2598 * the list file, and then each file that is listed in the list file */
2599int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002600 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002601{
2602 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2603 struct file_list_entry *fle;
2604 int rc = 0;
2605
2606 INIT_LLIST_HEAD(&bs11_sw->file_list);
2607 bs11_sw->bts = bts;
2608 bs11_sw->win_size = win_size;
2609 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002610 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002611
2612 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2613 rc = bs11_read_swl_file(bs11_sw);
2614 if (rc < 0)
2615 return rc;
2616
2617 /* dequeue next item in file list */
2618 fle = fl_dequeue(&bs11_sw->file_list);
2619 if (!fle)
2620 return -EINVAL;
2621
2622 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002623 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002624 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002625 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002626 return rc;
2627}
2628
Harald Welte5083b0b2009-02-02 19:20:52 +00002629#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002630static u_int8_t req_attr_btse[] = {
2631 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2632 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2633 NM_ATT_BS11_LMT_USER_NAME,
2634
2635 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2636
2637 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2638
2639 NM_ATT_BS11_SW_LOAD_STORED };
2640
2641static u_int8_t req_attr_btsm[] = {
2642 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2643 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2644 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2645 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002646#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002647
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002648static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002649 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2650 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002651 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002652
2653int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2654{
2655 struct abis_om_hdr *oh;
2656 struct msgb *msg = nm_msgb_alloc();
2657
2658 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2659 /* SiemensHW CCTRL object */
2660 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2661 0x03, 0x00, 0x00);
2662 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2663
2664 return abis_nm_sendmsg(bts, msg);
2665}
Harald Welte268bb402009-02-01 19:11:56 +00002666
2667int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2668{
2669 struct abis_om_hdr *oh;
2670 struct msgb *msg = nm_msgb_alloc();
2671 struct bs11_date_time aet;
2672
2673 get_bs11_date_time(&aet);
2674 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2675 /* SiemensHW CCTRL object */
2676 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2677 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002678 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002679
2680 return abis_nm_sendmsg(bts, msg);
2681}
Harald Welte5c1e4582009-02-15 11:57:29 +00002682
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002683int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2684{
2685 struct abis_om_hdr *oh;
2686 struct msgb *msg = nm_msgb_alloc();
2687 struct bs11_date_time aet;
2688
2689 get_bs11_date_time(&aet);
2690 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2691 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2692 bport, 0xff, 0x02);
2693 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2694
2695 return abis_nm_sendmsg(bts, msg);
2696}
2697
Harald Welte5c1e4582009-02-15 11:57:29 +00002698/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002699static const char ipaccess_magic[] = "com.ipaccess";
2700
Harald Welte677c21f2009-02-17 13:22:23 +00002701
2702static int abis_nm_rx_ipacc(struct msgb *msg)
2703{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002704 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002705 struct abis_om_hdr *oh = msgb_l2(msg);
2706 struct abis_om_fom_hdr *foh;
2707 u_int8_t idstrlen = oh->data[0];
2708 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002709 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002710
2711 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002712 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002713 return -EINVAL;
2714 }
2715
Harald Welte193fefc2009-04-30 15:16:27 +00002716 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002717 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002718
Harald Weltea8bd6d42009-10-20 09:56:18 +02002719 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002720
Harald Welte746d6092009-10-19 22:11:11 +02002721 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002722
Harald Welte677c21f2009-02-17 13:22:23 +00002723 switch (foh->msg_type) {
2724 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002725 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002726 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2727 memcpy(&addr,
2728 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2729
2730 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2731 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002732 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002733 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002734 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002735 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002736 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2737 DEBUGPC(DNM, "STREAM=0x%02x ",
2738 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002739 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002740 break;
2741 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002742 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002743 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002744 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002745 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002746 else
2747 DEBUGPC(DNM, "\n");
2748 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002749 case NM_MT_IPACC_SET_NVATTR_ACK:
2750 DEBUGPC(DNM, "SET NVATTR ACK\n");
2751 /* FIXME: decode and show the actual attributes */
2752 break;
2753 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002754 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002755 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002756 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002757 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2758 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002759 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002760 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002761 case NM_MT_IPACC_GET_NVATTR_ACK:
2762 DEBUGPC(DNM, "GET NVATTR ACK\n");
2763 /* FIXME: decode and show the actual attributes */
2764 break;
2765 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002766 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002767 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002768 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002769 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2770 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002771 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002772 break;
Harald Welte15c44172009-10-08 20:15:24 +02002773 case NM_MT_IPACC_SET_ATTR_ACK:
2774 DEBUGPC(DNM, "SET ATTR ACK\n");
2775 break;
2776 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002777 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002778 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002779 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002780 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2781 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002782 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002783 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002784 default:
2785 DEBUGPC(DNM, "unknown\n");
2786 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002787 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002788
2789 /* signal handling */
2790 switch (foh->msg_type) {
2791 case NM_MT_IPACC_RSL_CONNECT_NACK:
2792 case NM_MT_IPACC_SET_NVATTR_NACK:
2793 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002794 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002795 signal.msg_type = foh->msg_type;
2796 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002797 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002798 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002799 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002800 signal.msg_type = foh->msg_type;
2801 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002802 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002803 default:
2804 break;
2805 }
2806
Harald Welte677c21f2009-02-17 13:22:23 +00002807 return 0;
2808}
2809
Harald Welte193fefc2009-04-30 15:16:27 +00002810/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002811int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2812 u_int8_t obj_class, u_int8_t bts_nr,
2813 u_int8_t trx_nr, u_int8_t ts_nr,
2814 u_int8_t *attr, int attr_len)
2815{
2816 struct msgb *msg = nm_msgb_alloc();
2817 struct abis_om_hdr *oh;
2818 struct abis_om_fom_hdr *foh;
2819 u_int8_t *data;
2820
2821 /* construct the 12.21 OM header, observe the erroneous length */
2822 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2823 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2824 oh->mdisc = ABIS_OM_MDISC_MANUF;
2825
2826 /* add the ip.access magic */
2827 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2828 *data++ = sizeof(ipaccess_magic);
2829 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2830
2831 /* fill the 12.21 FOM header */
2832 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2833 foh->msg_type = msg_type;
2834 foh->obj_class = obj_class;
2835 foh->obj_inst.bts_nr = bts_nr;
2836 foh->obj_inst.trx_nr = trx_nr;
2837 foh->obj_inst.ts_nr = ts_nr;
2838
2839 if (attr && attr_len) {
2840 data = msgb_put(msg, attr_len);
2841 memcpy(data, attr, attr_len);
2842 }
2843
2844 return abis_nm_sendmsg(bts, msg);
2845}
Harald Welte677c21f2009-02-17 13:22:23 +00002846
Harald Welte193fefc2009-04-30 15:16:27 +00002847/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002848int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002849 int attr_len)
2850{
Harald Welte2ef156d2010-01-07 20:39:42 +01002851 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2852 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002853 attr_len);
2854}
2855
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002856int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002857 u_int32_t ip, u_int16_t port, u_int8_t stream)
2858{
2859 struct in_addr ia;
2860 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2861 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2862 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2863
2864 int attr_len = sizeof(attr);
2865
2866 ia.s_addr = htonl(ip);
2867 attr[1] = stream;
2868 attr[3] = port >> 8;
2869 attr[4] = port & 0xff;
2870 *(u_int32_t *)(attr+6) = ia.s_addr;
2871
2872 /* if ip == 0, we use the default IP */
2873 if (ip == 0)
2874 attr_len -= 5;
2875
2876 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002877 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002878
2879 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2880 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2881 trx->nr, 0xff, attr, attr_len);
2882}
2883
Harald Welte193fefc2009-04-30 15:16:27 +00002884/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002885int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002886{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002887 struct abis_om_hdr *oh;
2888 struct msgb *msg = nm_msgb_alloc();
2889
2890 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2891 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2892 trx->bts->nr, trx->nr, 0xff);
2893
2894 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002895}
Harald Weltedaef5212009-10-24 10:20:41 +02002896
2897int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2898 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2899 u_int8_t *attr, u_int8_t attr_len)
2900{
2901 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2902 obj_class, bts_nr, trx_nr, ts_nr,
2903 attr, attr_len);
2904}
Harald Welte0f255852009-11-12 14:48:42 +01002905
Harald Welte97a282b2010-03-14 15:37:43 +08002906void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2907{
2908 /* we simply reuse the GSM48 function and overwrite the RAC
2909 * with the Cell ID */
2910 gsm48_ra_id_by_bts(buf, bts);
2911 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2912}
2913
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002914void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2915{
2916 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2917
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002918 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002919 if (!trx->bts || !trx->bts->oml_link)
2920 return;
2921
2922 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2923 trx->bts->bts_nr, trx->nr, 0xff,
2924 new_state);
2925}
2926
Harald Welte92b1fe42010-03-25 11:45:30 +08002927static const struct value_string ipacc_testres_names[] = {
2928 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2929 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2930 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2931 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2932 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2933 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002934};
2935
2936const char *ipacc_testres_name(u_int8_t res)
2937{
Harald Welte92b1fe42010-03-25 11:45:30 +08002938 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002939}
2940
Harald Welteb40a38f2009-11-13 11:56:05 +01002941void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2942{
2943 cid->mcc = (buf[0] & 0xf) * 100;
2944 cid->mcc += (buf[0] >> 4) * 10;
2945 cid->mcc += (buf[1] & 0xf) * 1;
2946
2947 if (buf[1] >> 4 == 0xf) {
2948 cid->mnc = (buf[2] & 0xf) * 10;
2949 cid->mnc += (buf[2] >> 4) * 1;
2950 } else {
2951 cid->mnc = (buf[2] & 0xf) * 100;
2952 cid->mnc += (buf[2] >> 4) * 10;
2953 cid->mnc += (buf[1] >> 4) * 1;
2954 }
2955
Harald Welteaff237d2009-11-13 14:41:52 +01002956 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2957 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002958}
2959
Harald Welte0f255852009-11-12 14:48:42 +01002960/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2961int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2962{
2963 u_int8_t *cur = buf;
2964 u_int16_t len;
2965
Harald Welteaf109b92010-07-22 18:14:36 +02002966 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002967
2968 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2969 return -EINVAL;
2970 cur++;
2971
2972 len = ntohs(*(u_int16_t *)cur);
2973 cur += 2;
2974
2975 binf->info_type = ntohs(*(u_int16_t *)cur);
2976 cur += 2;
2977
2978 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2979 binf->freq_qual = *cur >> 2;
2980
Harald Welteaf109b92010-07-22 18:14:36 +02002981 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002982 binf->arfcn |= *cur++;
2983
2984 if (binf->info_type & IPAC_BINF_RXLEV)
2985 binf->rx_lev = *cur & 0x3f;
2986 cur++;
2987
2988 if (binf->info_type & IPAC_BINF_RXQUAL)
2989 binf->rx_qual = *cur & 0x7;
2990 cur++;
2991
2992 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2993 binf->freq_err = ntohs(*(u_int16_t *)cur);
2994 cur += 2;
2995
2996 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2997 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2998 cur += 2;
2999
3000 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3001 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3002 cur += 4;
3003
3004 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01003005 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003006 cur++;
3007
Harald Welteb40a38f2009-11-13 11:56:05 +01003008 ipac_parse_cgi(&binf->cgi, cur);
3009 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003010
3011 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3012 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3013 cur += sizeof(binf->ba_list_si2);
3014 }
3015
3016 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3017 memcpy(binf->ba_list_si2bis, cur,
3018 sizeof(binf->ba_list_si2bis));
3019 cur += sizeof(binf->ba_list_si2bis);
3020 }
3021
3022 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3023 memcpy(binf->ba_list_si2ter, cur,
3024 sizeof(binf->ba_list_si2ter));
3025 cur += sizeof(binf->ba_list_si2ter);
3026 }
3027
3028 return 0;
3029}