blob: 8487556251bb128e1b3be20c3852997252072535 [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))) {
Harald Welte6c96ba52009-05-01 13:03:40 +0000969 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200970
Harald Weltea8bd6d42009-10-20 09:56:18 +0200971 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200972
Harald Welte92b1fe42010-03-25 11:45:30 +0800973 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000974
Harald Welte39315c42010-01-10 18:01:52 +0100975 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000976 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200977 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +0000978 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
979 else
980 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200981
Harald Welted8cfc902009-11-17 06:09:56 +0100982 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200983 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000984 }
Harald Weltead384642008-12-26 10:20:07 +0000985#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000986 /* check if last message is to be acked */
987 if (is_ack_nack(nmh->last_msgtype)) {
988 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100989 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000990 /* we got our ACK, continue sending the next msg */
991 } else if (mt == MT_NACK(nmh->last_msgtype)) {
992 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100993 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000994 /* FIXME: somehow signal this to the caller */
995 } else {
996 /* really strange things happen */
997 return -EINVAL;
998 }
999 }
Harald Weltead384642008-12-26 10:20:07 +00001000#endif
1001
Harald Welte97ed1e72009-02-06 13:38:02 +00001002 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001003 case NM_MT_CHG_ADM_STATE_ACK:
1004 return abis_nm_rx_chg_adm_state_ack(mb);
1005 break;
Harald Welte34a99682009-02-13 02:41:40 +00001006 case NM_MT_SW_ACT_REQ:
1007 return abis_nm_rx_sw_act_req(mb);
1008 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001009 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001010 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001011 break;
Harald Welte1989c082009-08-06 17:58:31 +02001012 case NM_MT_CONN_MDROP_LINK_ACK:
1013 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1014 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001015 case NM_MT_IPACC_RESTART_ACK:
1016 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1017 break;
1018 case NM_MT_IPACC_RESTART_NACK:
1019 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1020 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001021 }
1022
Harald Weltead384642008-12-26 10:20:07 +00001023 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001024}
1025
Harald Welte677c21f2009-02-17 13:22:23 +00001026static int abis_nm_rx_ipacc(struct msgb *mb);
1027
1028static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1029{
1030 int rc;
1031 int bts_type = mb->trx->bts->type;
1032
1033 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001034 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001035 rc = abis_nm_rx_ipacc(mb);
1036 break;
1037 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001038 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1039 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001040 rc = 0;
1041 break;
1042 }
1043
1044 return rc;
1045}
1046
Harald Welte52b1f982008-12-23 20:25:15 +00001047/* High-Level API */
1048/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001049int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001050{
Harald Welte52b1f982008-12-23 20:25:15 +00001051 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001052 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001053
1054 /* Various consistency checks */
1055 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001056 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001057 oh->placement);
1058 return -EINVAL;
1059 }
1060 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001061 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001062 oh->sequence);
1063 return -EINVAL;
1064 }
Harald Welte702d8702008-12-26 20:25:35 +00001065#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001066 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1067 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001068 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001069 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001070 oh->length + sizeof(*oh), l2_len);
1071 return -EINVAL;
1072 }
Harald Welte702d8702008-12-26 20:25:35 +00001073 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001074 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 +00001075#endif
Harald Weltead384642008-12-26 10:20:07 +00001076 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001077
1078 switch (oh->mdisc) {
1079 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001080 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001081 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001082 case ABIS_OM_MDISC_MANUF:
1083 rc = abis_nm_rcvmsg_manuf(msg);
1084 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001085 case ABIS_OM_MDISC_MMI:
1086 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001087 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001088 oh->mdisc);
1089 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001090 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001091 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001092 oh->mdisc);
1093 return -EINVAL;
1094 }
1095
Harald Weltead384642008-12-26 10:20:07 +00001096 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001097 return rc;
1098}
1099
1100#if 0
1101/* initialized all resources */
1102struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1103{
1104 struct abis_nm_h *nmh;
1105
1106 nmh = malloc(sizeof(*nmh));
1107 if (!nmh)
1108 return NULL;
1109
1110 nmh->cfg = cfg;
1111
1112 return nmh;
1113}
1114
1115/* free all resources */
1116void abis_nm_fini(struct abis_nm_h *nmh)
1117{
1118 free(nmh);
1119}
1120#endif
1121
1122/* Here we are trying to define a high-level API that can be used by
1123 * the actual BSC implementation. However, the architecture is currently
1124 * still under design. Ideally the calls to this API would be synchronous,
1125 * while the underlying stack behind the APi runs in a traditional select
1126 * based state machine.
1127 */
1128
Harald Welte4724f992009-01-18 18:01:49 +00001129/* 6.2 Software Load: */
1130enum sw_state {
1131 SW_STATE_NONE,
1132 SW_STATE_WAIT_INITACK,
1133 SW_STATE_WAIT_SEGACK,
1134 SW_STATE_WAIT_ENDACK,
1135 SW_STATE_WAIT_ACTACK,
1136 SW_STATE_ERROR,
1137};
Harald Welte52b1f982008-12-23 20:25:15 +00001138
Harald Welte52b1f982008-12-23 20:25:15 +00001139struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001140 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001141 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001142 gsm_cbfn *cbfn;
1143 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001144 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001145
Harald Welte52b1f982008-12-23 20:25:15 +00001146 /* this will become part of the SW LOAD INITIATE */
1147 u_int8_t obj_class;
1148 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001149
1150 u_int8_t file_id[255];
1151 u_int8_t file_id_len;
1152
1153 u_int8_t file_version[255];
1154 u_int8_t file_version_len;
1155
1156 u_int8_t window_size;
1157 u_int8_t seg_in_window;
1158
1159 int fd;
1160 FILE *stream;
1161 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001162 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001163};
1164
Harald Welte4724f992009-01-18 18:01:49 +00001165static struct abis_nm_sw g_sw;
1166
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001167static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1168{
1169 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1170 msgb_v_put(msg, NM_ATT_SW_DESCR);
1171 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1172 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1173 sw->file_version);
1174 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1175 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1176 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1177 sw->file_version);
1178 } else {
1179 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1180 }
1181}
1182
Harald Welte4724f992009-01-18 18:01:49 +00001183/* 6.2.1 / 8.3.1: Load Data Initiate */
1184static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001185{
Harald Welte4724f992009-01-18 18:01:49 +00001186 struct abis_om_hdr *oh;
1187 struct msgb *msg = nm_msgb_alloc();
1188 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1189
1190 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1191 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1192 sw->obj_instance[0], sw->obj_instance[1],
1193 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001194
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001195 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001196 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1197
1198 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001199}
1200
Harald Welte1602ade2009-01-29 21:12:39 +00001201static int is_last_line(FILE *stream)
1202{
1203 char next_seg_buf[256];
1204 long pos;
1205
1206 /* check if we're sending the last line */
1207 pos = ftell(stream);
1208 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1209 fseek(stream, pos, SEEK_SET);
1210 return 1;
1211 }
1212
1213 fseek(stream, pos, SEEK_SET);
1214 return 0;
1215}
1216
Harald Welte4724f992009-01-18 18:01:49 +00001217/* 6.2.2 / 8.3.2 Load Data Segment */
1218static int sw_load_segment(struct abis_nm_sw *sw)
1219{
1220 struct abis_om_hdr *oh;
1221 struct msgb *msg = nm_msgb_alloc();
1222 char seg_buf[256];
1223 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001224 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001225 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001226
1227 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001228
1229 switch (sw->bts->type) {
1230 case GSM_BTS_TYPE_BS11:
1231 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1232 perror("fgets reading segment");
1233 return -EINVAL;
1234 }
1235 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001236
1237 /* check if we're sending the last line */
1238 sw->last_seg = is_last_line(sw->stream);
1239 if (sw->last_seg)
1240 seg_buf[1] = 0;
1241 else
1242 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001243
1244 len = strlen(line_buf) + 2;
1245 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1246 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1247 /* BS11 wants CR + LF in excess of the TLV length !?! */
1248 tlv[1] -= 2;
1249
1250 /* we only now know the exact length for the OM hdr */
1251 len = strlen(line_buf)+2;
1252 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001253 case GSM_BTS_TYPE_NANOBTS: {
1254 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1255 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1256 if (len < 0) {
1257 perror("read failed");
1258 return -EINVAL;
1259 }
1260
1261 if (len != IPACC_SEGMENT_SIZE)
1262 sw->last_seg = 1;
1263
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001264 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001265 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1266 len += 3;
1267 break;
1268 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001269 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001270 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001271 /* FIXME: Other BTS types */
1272 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001273 }
Harald Welte4724f992009-01-18 18:01:49 +00001274
Harald Welte4724f992009-01-18 18:01:49 +00001275 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1276 sw->obj_instance[0], sw->obj_instance[1],
1277 sw->obj_instance[2]);
1278
1279 return abis_nm_sendmsg(sw->bts, msg);
1280}
1281
1282/* 6.2.4 / 8.3.4 Load Data End */
1283static int sw_load_end(struct abis_nm_sw *sw)
1284{
1285 struct abis_om_hdr *oh;
1286 struct msgb *msg = nm_msgb_alloc();
1287 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1288
1289 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1290 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1291 sw->obj_instance[0], sw->obj_instance[1],
1292 sw->obj_instance[2]);
1293
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001294 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001295 return abis_nm_sendmsg(sw->bts, msg);
1296}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001297
Harald Welte52b1f982008-12-23 20:25:15 +00001298/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001299static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001300{
Harald Welte4724f992009-01-18 18:01:49 +00001301 struct abis_om_hdr *oh;
1302 struct msgb *msg = nm_msgb_alloc();
1303 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001304
Harald Welte4724f992009-01-18 18:01:49 +00001305 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1306 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1307 sw->obj_instance[0], sw->obj_instance[1],
1308 sw->obj_instance[2]);
1309
1310 /* FIXME: this is BS11 specific format */
1311 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1312 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1313 sw->file_version);
1314
1315 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001316}
Harald Welte4724f992009-01-18 18:01:49 +00001317
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001318struct sdp_firmware {
1319 char magic[4];
1320 char more_magic[4];
1321 unsigned int header_length;
1322 unsigned int file_length;
1323} __attribute__ ((packed));
1324
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001325static int parse_sdp_header(struct abis_nm_sw *sw)
1326{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001327 struct sdp_firmware firmware_header;
1328 int rc;
1329 struct stat stat;
1330
1331 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1332 if (rc != sizeof(firmware_header)) {
1333 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1334 return -1;
1335 }
1336
1337 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1338 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1339 return -1;
1340 }
1341
1342 if (firmware_header.more_magic[0] != 0x10 ||
1343 firmware_header.more_magic[1] != 0x02 ||
1344 firmware_header.more_magic[2] != 0x00 ||
1345 firmware_header.more_magic[3] != 0x00) {
1346 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1347 return -1;
1348 }
1349
1350
1351 if (fstat(sw->fd, &stat) == -1) {
1352 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1353 return -1;
1354 }
1355
1356 if (ntohl(firmware_header.file_length) != stat.st_size) {
1357 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1358 return -1;
1359 }
1360
1361 /* go back to the start as we checked the whole filesize.. */
1362 lseek(sw->fd, 0l, SEEK_SET);
1363 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1364 "There might be checksums in the file that are not\n"
1365 "verified and incomplete firmware might be flashed.\n"
1366 "There is absolutely no WARRANTY that flashing will\n"
1367 "work.\n");
1368 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001369}
1370
Harald Welte4724f992009-01-18 18:01:49 +00001371static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1372{
1373 char file_id[12+1];
1374 char file_version[80+1];
1375 int rc;
1376
1377 sw->fd = open(fname, O_RDONLY);
1378 if (sw->fd < 0)
1379 return sw->fd;
1380
1381 switch (sw->bts->type) {
1382 case GSM_BTS_TYPE_BS11:
1383 sw->stream = fdopen(sw->fd, "r");
1384 if (!sw->stream) {
1385 perror("fdopen");
1386 return -1;
1387 }
1388 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001389 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001390 file_id, file_version);
1391 if (rc != 2) {
1392 perror("parsing header line of software file");
1393 return -1;
1394 }
1395 strcpy((char *)sw->file_id, file_id);
1396 sw->file_id_len = strlen(file_id);
1397 strcpy((char *)sw->file_version, file_version);
1398 sw->file_version_len = strlen(file_version);
1399 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001400 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001401 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001402 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001403 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001404 rc = parse_sdp_header(sw);
1405 if (rc < 0) {
1406 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1407 return -1;
1408 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001409
1410 strcpy((char *)sw->file_id, "id");
1411 sw->file_id_len = 3;
1412 strcpy((char *)sw->file_version, "version");
1413 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001414 break;
Harald Welte4724f992009-01-18 18:01:49 +00001415 default:
1416 /* We don't know how to treat them yet */
1417 close(sw->fd);
1418 return -EINVAL;
1419 }
1420
1421 return 0;
1422}
1423
1424static void sw_close_file(struct abis_nm_sw *sw)
1425{
1426 switch (sw->bts->type) {
1427 case GSM_BTS_TYPE_BS11:
1428 fclose(sw->stream);
1429 break;
1430 default:
1431 close(sw->fd);
1432 break;
1433 }
1434}
1435
1436/* Fill the window */
1437static int sw_fill_window(struct abis_nm_sw *sw)
1438{
1439 int rc;
1440
1441 while (sw->seg_in_window < sw->window_size) {
1442 rc = sw_load_segment(sw);
1443 if (rc < 0)
1444 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001445 if (sw->last_seg)
1446 break;
Harald Welte4724f992009-01-18 18:01:49 +00001447 }
1448 return 0;
1449}
1450
1451/* callback function from abis_nm_rcvmsg() handler */
1452static int abis_nm_rcvmsg_sw(struct msgb *mb)
1453{
1454 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1455 int rc = -1;
1456 struct abis_nm_sw *sw = &g_sw;
1457 enum sw_state old_state = sw->state;
1458
Harald Welte3ffd1372009-02-01 22:15:49 +00001459 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001460
1461 switch (sw->state) {
1462 case SW_STATE_WAIT_INITACK:
1463 switch (foh->msg_type) {
1464 case NM_MT_LOAD_INIT_ACK:
1465 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001466 if (sw->cbfn)
1467 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1468 NM_MT_LOAD_INIT_ACK, mb,
1469 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001470 rc = sw_fill_window(sw);
1471 sw->state = SW_STATE_WAIT_SEGACK;
1472 break;
1473 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001474 if (sw->forced) {
1475 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1476 "Init NACK\n");
1477 if (sw->cbfn)
1478 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1479 NM_MT_LOAD_INIT_ACK, mb,
1480 sw->cb_data, NULL);
1481 rc = sw_fill_window(sw);
1482 sw->state = SW_STATE_WAIT_SEGACK;
1483 } else {
1484 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001485 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001486 if (sw->cbfn)
1487 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1488 NM_MT_LOAD_INIT_NACK, mb,
1489 sw->cb_data, NULL);
1490 sw->state = SW_STATE_ERROR;
1491 }
Harald Welte4724f992009-01-18 18:01:49 +00001492 break;
1493 }
1494 break;
1495 case SW_STATE_WAIT_SEGACK:
1496 switch (foh->msg_type) {
1497 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001498 if (sw->cbfn)
1499 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1500 NM_MT_LOAD_SEG_ACK, mb,
1501 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001502 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001503 if (!sw->last_seg) {
1504 /* fill window with more segments */
1505 rc = sw_fill_window(sw);
1506 sw->state = SW_STATE_WAIT_SEGACK;
1507 } else {
1508 /* end the transfer */
1509 sw->state = SW_STATE_WAIT_ENDACK;
1510 rc = sw_load_end(sw);
1511 }
Harald Welte4724f992009-01-18 18:01:49 +00001512 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001513 case NM_MT_LOAD_ABORT:
1514 if (sw->cbfn)
1515 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1516 NM_MT_LOAD_ABORT, mb,
1517 sw->cb_data, NULL);
1518 break;
Harald Welte4724f992009-01-18 18:01:49 +00001519 }
1520 break;
1521 case SW_STATE_WAIT_ENDACK:
1522 switch (foh->msg_type) {
1523 case NM_MT_LOAD_END_ACK:
1524 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001525 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1526 sw->bts->nr);
1527 sw->state = SW_STATE_NONE;
1528 if (sw->cbfn)
1529 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1530 NM_MT_LOAD_END_ACK, mb,
1531 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001532 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001533 break;
1534 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001535 if (sw->forced) {
1536 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1537 "End NACK\n");
1538 sw->state = SW_STATE_NONE;
1539 if (sw->cbfn)
1540 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1541 NM_MT_LOAD_END_ACK, mb,
1542 sw->cb_data, NULL);
1543 } else {
1544 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001545 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001546 sw->state = SW_STATE_ERROR;
1547 if (sw->cbfn)
1548 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1549 NM_MT_LOAD_END_NACK, mb,
1550 sw->cb_data, NULL);
1551 }
Harald Welte4724f992009-01-18 18:01:49 +00001552 break;
1553 }
1554 case SW_STATE_WAIT_ACTACK:
1555 switch (foh->msg_type) {
1556 case NM_MT_ACTIVATE_SW_ACK:
1557 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001558 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001559 sw->state = SW_STATE_NONE;
1560 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001561 if (sw->cbfn)
1562 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1563 NM_MT_ACTIVATE_SW_ACK, mb,
1564 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001565 break;
1566 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001567 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001568 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001569 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001570 if (sw->cbfn)
1571 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1572 NM_MT_ACTIVATE_SW_NACK, mb,
1573 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001574 break;
1575 }
1576 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001577 switch (foh->msg_type) {
1578 case NM_MT_ACTIVATE_SW_ACK:
1579 rc = 0;
1580 break;
1581 }
1582 break;
Harald Welte4724f992009-01-18 18:01:49 +00001583 case SW_STATE_ERROR:
1584 break;
1585 }
1586
1587 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001588 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001589 foh->msg_type, old_state, sw->state);
1590
1591 return rc;
1592}
1593
1594/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001595int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001596 u_int8_t win_size, int forced,
1597 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001598{
1599 struct abis_nm_sw *sw = &g_sw;
1600 int rc;
1601
Harald Welte5e4d1b32009-02-01 13:36:56 +00001602 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1603 bts->nr, fname);
1604
Harald Welte4724f992009-01-18 18:01:49 +00001605 if (sw->state != SW_STATE_NONE)
1606 return -EBUSY;
1607
1608 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001609 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001610
1611 switch (bts->type) {
1612 case GSM_BTS_TYPE_BS11:
1613 sw->obj_class = NM_OC_SITE_MANAGER;
1614 sw->obj_instance[0] = 0xff;
1615 sw->obj_instance[1] = 0xff;
1616 sw->obj_instance[2] = 0xff;
1617 break;
1618 case GSM_BTS_TYPE_NANOBTS:
1619 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001620 sw->obj_instance[0] = sw->bts->nr;
1621 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001622 sw->obj_instance[2] = 0xff;
1623 break;
1624 case GSM_BTS_TYPE_UNKNOWN:
1625 default:
1626 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1627 return -1;
1628 break;
1629 }
Harald Welte4724f992009-01-18 18:01:49 +00001630 sw->window_size = win_size;
1631 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001632 sw->cbfn = cbfn;
1633 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001634 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001635
1636 rc = sw_open_file(sw, fname);
1637 if (rc < 0) {
1638 sw->state = SW_STATE_NONE;
1639 return rc;
1640 }
1641
1642 return sw_load_init(sw);
1643}
Harald Welte52b1f982008-12-23 20:25:15 +00001644
Harald Welte1602ade2009-01-29 21:12:39 +00001645int abis_nm_software_load_status(struct gsm_bts *bts)
1646{
1647 struct abis_nm_sw *sw = &g_sw;
1648 struct stat st;
1649 int rc, percent;
1650
1651 rc = fstat(sw->fd, &st);
1652 if (rc < 0) {
1653 perror("ERROR during stat");
1654 return rc;
1655 }
1656
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001657 if (sw->stream)
1658 percent = (ftell(sw->stream) * 100) / st.st_size;
1659 else
1660 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001661 return percent;
1662}
1663
Harald Welte5e4d1b32009-02-01 13:36:56 +00001664/* Activate the specified software into the BTS */
1665int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1666 gsm_cbfn *cbfn, void *cb_data)
1667{
1668 struct abis_nm_sw *sw = &g_sw;
1669 int rc;
1670
1671 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1672 bts->nr, fname);
1673
1674 if (sw->state != SW_STATE_NONE)
1675 return -EBUSY;
1676
1677 sw->bts = bts;
1678 sw->obj_class = NM_OC_SITE_MANAGER;
1679 sw->obj_instance[0] = 0xff;
1680 sw->obj_instance[1] = 0xff;
1681 sw->obj_instance[2] = 0xff;
1682 sw->state = SW_STATE_WAIT_ACTACK;
1683 sw->cbfn = cbfn;
1684 sw->cb_data = cb_data;
1685
1686 /* Open the file in order to fill some sw struct members */
1687 rc = sw_open_file(sw, fname);
1688 if (rc < 0) {
1689 sw->state = SW_STATE_NONE;
1690 return rc;
1691 }
1692 sw_close_file(sw);
1693
1694 return sw_activate(sw);
1695}
1696
Harald Welte8470bf22008-12-25 23:28:35 +00001697static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001698 u_int8_t ts_nr, u_int8_t subslot_nr)
1699{
Harald Welteadaf08b2009-01-18 11:08:10 +00001700 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001701 ch->bts_port = bts_port;
1702 ch->timeslot = ts_nr;
1703 ch->subslot = subslot_nr;
1704}
1705
1706int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1707 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1708 u_int8_t tei)
1709{
1710 struct abis_om_hdr *oh;
1711 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001712 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001713 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001714
1715 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1716 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1717 bts->bts_nr, trx_nr, 0xff);
1718
Harald Welte8470bf22008-12-25 23:28:35 +00001719 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001720
1721 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1722 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1723
1724 return abis_nm_sendmsg(bts, msg);
1725}
1726
1727/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1728int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1729 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1730{
Harald Welte8470bf22008-12-25 23:28:35 +00001731 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001732 struct abis_om_hdr *oh;
1733 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001734 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001735
1736 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001737 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001738 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1739
1740 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1741 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1742
1743 return abis_nm_sendmsg(bts, msg);
1744}
1745
1746#if 0
1747int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1748 struct abis_nm_abis_channel *chan)
1749{
1750}
1751#endif
1752
1753int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1754 u_int8_t e1_port, u_int8_t e1_timeslot,
1755 u_int8_t e1_subslot)
1756{
1757 struct gsm_bts *bts = ts->trx->bts;
1758 struct abis_om_hdr *oh;
1759 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001760 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001761
1762 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1763 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001764 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001765
1766 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1767 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1768
Harald Weltef325eb42009-02-19 17:07:39 +00001769 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1770 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001771 e1_port, e1_timeslot, e1_subslot);
1772
Harald Welte52b1f982008-12-23 20:25:15 +00001773 return abis_nm_sendmsg(bts, msg);
1774}
1775
1776#if 0
1777int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1778 struct abis_nm_abis_channel *chan,
1779 u_int8_t subchan)
1780{
1781}
1782#endif
1783
Harald Welte22af0db2009-02-14 15:41:08 +00001784/* Chapter 8.6.1 */
1785int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1786{
1787 struct abis_om_hdr *oh;
1788 struct msgb *msg = nm_msgb_alloc();
1789 u_int8_t *cur;
1790
1791 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1792
1793 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001794 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001795 cur = msgb_put(msg, attr_len);
1796 memcpy(cur, attr, attr_len);
1797
1798 return abis_nm_sendmsg(bts, msg);
1799}
1800
1801/* Chapter 8.6.2 */
1802int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1803{
1804 struct abis_om_hdr *oh;
1805 struct msgb *msg = nm_msgb_alloc();
1806 u_int8_t *cur;
1807
1808 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1809
1810 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1811 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001812 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001813 cur = msgb_put(msg, attr_len);
1814 memcpy(cur, attr, attr_len);
1815
1816 return abis_nm_sendmsg(trx->bts, msg);
1817}
1818
Harald Welte39c7deb2009-08-09 21:49:48 +02001819static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1820{
1821 int i;
1822
1823 /* As it turns out, the BS-11 has some very peculiar restrictions
1824 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301825 switch (ts->trx->bts->type) {
1826 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001827 switch (chan_comb) {
1828 case NM_CHANC_TCHHalf:
1829 case NM_CHANC_TCHHalf2:
1830 /* not supported */
1831 return -EINVAL;
1832 case NM_CHANC_SDCCH:
1833 /* only one SDCCH/8 per TRX */
1834 for (i = 0; i < TRX_NR_TS; i++) {
1835 if (i == ts->nr)
1836 continue;
1837 if (ts->trx->ts[i].nm_chan_comb ==
1838 NM_CHANC_SDCCH)
1839 return -EINVAL;
1840 }
1841 /* not allowed for TS0 of BCCH-TRX */
1842 if (ts->trx == ts->trx->bts->c0 &&
1843 ts->nr == 0)
1844 return -EINVAL;
1845 /* not on the same TRX that has a BCCH+SDCCH4
1846 * combination */
1847 if (ts->trx == ts->trx->bts->c0 &&
1848 (ts->trx->ts[0].nm_chan_comb == 5 ||
1849 ts->trx->ts[0].nm_chan_comb == 8))
1850 return -EINVAL;
1851 break;
1852 case NM_CHANC_mainBCCH:
1853 case NM_CHANC_BCCHComb:
1854 /* allowed only for TS0 of C0 */
1855 if (ts->trx != ts->trx->bts->c0 ||
1856 ts->nr != 0)
1857 return -EINVAL;
1858 break;
1859 case NM_CHANC_BCCH:
1860 /* allowed only for TS 2/4/6 of C0 */
1861 if (ts->trx != ts->trx->bts->c0)
1862 return -EINVAL;
1863 if (ts->nr != 2 && ts->nr != 4 &&
1864 ts->nr != 6)
1865 return -EINVAL;
1866 break;
1867 case 8: /* this is not like 08.58, but in fact
1868 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1869 /* FIXME: only one CBCH allowed per cell */
1870 break;
1871 }
Harald Welted6575f92009-12-02 02:45:23 +05301872 break;
1873 case GSM_BTS_TYPE_NANOBTS:
1874 switch (ts->nr) {
1875 case 0:
1876 if (ts->trx->nr == 0) {
1877 /* only on TRX0 */
1878 switch (chan_comb) {
1879 case NM_CHANC_BCCH:
1880 case NM_CHANC_mainBCCH:
1881 case NM_CHANC_BCCHComb:
1882 return 0;
1883 break;
1884 default:
1885 return -EINVAL;
1886 }
1887 } else {
1888 switch (chan_comb) {
1889 case NM_CHANC_TCHFull:
1890 case NM_CHANC_TCHHalf:
1891 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1892 return 0;
1893 default:
1894 return -EINVAL;
1895 }
1896 }
1897 break;
1898 case 1:
1899 if (ts->trx->nr == 0) {
1900 switch (chan_comb) {
1901 case NM_CHANC_SDCCH_CBCH:
1902 if (ts->trx->ts[0].nm_chan_comb ==
1903 NM_CHANC_mainBCCH)
1904 return 0;
1905 return -EINVAL;
1906 case NM_CHANC_SDCCH:
1907 case NM_CHANC_TCHFull:
1908 case NM_CHANC_TCHHalf:
1909 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1910 case NM_CHANC_IPAC_TCHFull_PDCH:
1911 return 0;
1912 }
1913 } else {
1914 switch (chan_comb) {
1915 case NM_CHANC_SDCCH:
1916 case NM_CHANC_TCHFull:
1917 case NM_CHANC_TCHHalf:
1918 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1919 return 0;
1920 default:
1921 return -EINVAL;
1922 }
1923 }
1924 break;
1925 case 2:
1926 case 3:
1927 case 4:
1928 case 5:
1929 case 6:
1930 case 7:
1931 switch (chan_comb) {
1932 case NM_CHANC_TCHFull:
1933 case NM_CHANC_TCHHalf:
1934 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1935 return 0;
1936 case NM_CHANC_IPAC_PDCH:
1937 case NM_CHANC_IPAC_TCHFull_PDCH:
1938 if (ts->trx->nr == 0)
1939 return 0;
1940 else
1941 return -EINVAL;
1942 }
1943 break;
1944 }
1945 return -EINVAL;
1946 default:
1947 /* unknown BTS type */
1948 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001949 }
1950 return 0;
1951}
1952
Harald Welte22af0db2009-02-14 15:41:08 +00001953/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001954int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1955{
1956 struct gsm_bts *bts = ts->trx->bts;
1957 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001958 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001959 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001960 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001961 u_int8_t len = 2 + 2;
1962
1963 if (bts->type == GSM_BTS_TYPE_BS11)
1964 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001965
Harald Weltef325eb42009-02-19 17:07:39 +00001966 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001967 if (verify_chan_comb(ts, chan_comb) < 0) {
1968 msgb_free(msg);
1969 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1970 return -EINVAL;
1971 }
1972 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001973
Harald Welte52b1f982008-12-23 20:25:15 +00001974 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001975 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001976 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001977 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001978 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001979 if (ts->hopping.enabled) {
1980 unsigned int i;
1981 uint8_t *len;
1982
Harald Welte6e0cd042009-09-12 13:05:33 +02001983 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1984 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001985
1986 /* build the ARFCN list */
1987 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1988 len = msgb_put(msg, 1);
1989 *len = 0;
1990 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1991 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1992 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001993 /* At least BS-11 wants a TLV16 here */
1994 if (bts->type == GSM_BTS_TYPE_BS11)
1995 *len += 1;
1996 else
1997 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001998 }
1999 }
Harald Weltee0590df2009-02-15 03:34:15 +00002000 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002001 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002002 if (bts->type == GSM_BTS_TYPE_BS11)
2003 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002004
2005 return abis_nm_sendmsg(bts, msg);
2006}
2007
Harald Welte34a99682009-02-13 02:41:40 +00002008int 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 +00002009 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002010{
2011 struct abis_om_hdr *oh;
2012 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002013 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2014 u_int8_t len = att_len;
2015
2016 if (nack) {
2017 len += 2;
2018 msgtype = NM_MT_SW_ACT_REQ_NACK;
2019 }
Harald Welte34a99682009-02-13 02:41:40 +00002020
2021 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002022 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2023
Harald Welte34a99682009-02-13 02:41:40 +00002024 if (attr) {
2025 u_int8_t *ptr = msgb_put(msg, att_len);
2026 memcpy(ptr, attr, att_len);
2027 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002028 if (nack)
2029 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002030
2031 return abis_nm_sendmsg(bts, msg);
2032}
2033
Harald Welte8470bf22008-12-25 23:28:35 +00002034int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002035{
Harald Welte8470bf22008-12-25 23:28:35 +00002036 struct msgb *msg = nm_msgb_alloc();
2037 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002038 u_int8_t *data;
2039
2040 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2041 fill_om_hdr(oh, len);
2042 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002043 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002044
2045 return abis_nm_sendmsg(bts, msg);
2046}
2047
2048/* Siemens specific commands */
2049static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2050{
2051 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002052 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002053
2054 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002055 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002056 0xff, 0xff, 0xff);
2057
2058 return abis_nm_sendmsg(bts, msg);
2059}
2060
Harald Welte34a99682009-02-13 02:41:40 +00002061/* Chapter 8.9.2 */
2062int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2063{
2064 struct abis_om_hdr *oh;
2065 struct msgb *msg = nm_msgb_alloc();
2066
2067 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2068 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2069
Harald Weltea8bd6d42009-10-20 09:56:18 +02002070 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2071 DEBUGPC(DNM, "Sending OPSTART\n");
2072
Harald Welte34a99682009-02-13 02:41:40 +00002073 return abis_nm_sendmsg(bts, msg);
2074}
2075
2076/* Chapter 8.8.5 */
2077int 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 +02002078 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002079{
2080 struct abis_om_hdr *oh;
2081 struct msgb *msg = nm_msgb_alloc();
2082
2083 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2084 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2085 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2086
2087 return abis_nm_sendmsg(bts, msg);
2088}
2089
Harald Welte1989c082009-08-06 17:58:31 +02002090int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2091 u_int8_t e1_port1, u_int8_t ts1)
2092{
2093 struct abis_om_hdr *oh;
2094 struct msgb *msg = nm_msgb_alloc();
2095 u_int8_t *attr;
2096
2097 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2098 e1_port0, ts0, e1_port1, ts1);
2099
2100 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2101 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2102 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2103
2104 attr = msgb_put(msg, 3);
2105 attr[0] = NM_ATT_MDROP_LINK;
2106 attr[1] = e1_port0;
2107 attr[2] = ts0;
2108
2109 attr = msgb_put(msg, 3);
2110 attr[0] = NM_ATT_MDROP_NEXT;
2111 attr[1] = e1_port1;
2112 attr[2] = ts1;
2113
2114 return abis_nm_sendmsg(bts, msg);
2115}
Harald Welte34a99682009-02-13 02:41:40 +00002116
Harald Weltec7310382009-08-08 00:02:36 +02002117/* Chapter 8.7.1 */
2118int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2119 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2120 u_int8_t test_nr, u_int8_t auton_report,
2121 u_int8_t *phys_config, u_int16_t phys_config_len)
2122{
2123 struct abis_om_hdr *oh;
2124 struct msgb *msg = nm_msgb_alloc();
2125 int len = 4; /* 2 TV attributes */
2126
2127 DEBUGP(DNM, "PEFORM TEST\n");
2128
2129 if (phys_config_len)
2130 len += 3 + phys_config_len;
2131
2132 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2133 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2134 obj_class, bts_nr, trx_nr, ts_nr);
2135 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2136 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2137 if (phys_config_len)
2138 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2139 phys_config);
2140
2141 return abis_nm_sendmsg(bts, msg);
2142}
2143
Harald Welte52b1f982008-12-23 20:25:15 +00002144int abis_nm_event_reports(struct gsm_bts *bts, int on)
2145{
2146 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002147 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002148 else
Harald Welte227d4072009-01-03 08:16:25 +00002149 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002150}
2151
Harald Welte47d88ae2009-01-04 12:02:08 +00002152/* Siemens (or BS-11) specific commands */
2153
Harald Welte3ffd1372009-02-01 22:15:49 +00002154int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2155{
2156 if (reconnect == 0)
2157 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2158 else
2159 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2160}
2161
Harald Welteb8427972009-02-05 19:27:17 +00002162int abis_nm_bs11_restart(struct gsm_bts *bts)
2163{
2164 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2165}
2166
2167
Harald Welte268bb402009-02-01 19:11:56 +00002168struct bs11_date_time {
2169 u_int16_t year;
2170 u_int8_t month;
2171 u_int8_t day;
2172 u_int8_t hour;
2173 u_int8_t min;
2174 u_int8_t sec;
2175} __attribute__((packed));
2176
2177
2178void get_bs11_date_time(struct bs11_date_time *aet)
2179{
2180 time_t t;
2181 struct tm *tm;
2182
2183 t = time(NULL);
2184 tm = localtime(&t);
2185 aet->sec = tm->tm_sec;
2186 aet->min = tm->tm_min;
2187 aet->hour = tm->tm_hour;
2188 aet->day = tm->tm_mday;
2189 aet->month = tm->tm_mon;
2190 aet->year = htons(1900 + tm->tm_year);
2191}
2192
Harald Welte05188ee2009-01-18 11:39:08 +00002193int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002194{
Harald Welte4668fda2009-01-03 08:19:29 +00002195 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002196}
2197
Harald Welte05188ee2009-01-18 11:39:08 +00002198int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002199{
2200 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002201 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002202 else
Harald Welte4668fda2009-01-03 08:19:29 +00002203 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002204}
Harald Welte47d88ae2009-01-04 12:02:08 +00002205
Harald Welte05188ee2009-01-18 11:39:08 +00002206int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002207 enum abis_bs11_objtype type, u_int8_t idx,
2208 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002209{
2210 struct abis_om_hdr *oh;
2211 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002212 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002213
2214 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002215 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002216 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002217 cur = msgb_put(msg, attr_len);
2218 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002219
2220 return abis_nm_sendmsg(bts, msg);
2221}
2222
Harald Welte78fc0d42009-02-19 02:50:57 +00002223int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2224 enum abis_bs11_objtype type, u_int8_t idx)
2225{
2226 struct abis_om_hdr *oh;
2227 struct msgb *msg = nm_msgb_alloc();
2228
2229 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2230 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2231 NM_OC_BS11, type, 0, idx);
2232
2233 return abis_nm_sendmsg(bts, msg);
2234}
2235
Harald Welte05188ee2009-01-18 11:39:08 +00002236int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002237{
2238 struct abis_om_hdr *oh;
2239 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002240 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002241
2242 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002243 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002244 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2245 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002246
2247 return abis_nm_sendmsg(bts, msg);
2248}
2249
Harald Welte05188ee2009-01-18 11:39:08 +00002250int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002251{
2252 struct abis_om_hdr *oh;
2253 struct msgb *msg = nm_msgb_alloc();
2254
2255 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2256 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002257 idx, 0xff, 0xff);
2258
2259 return abis_nm_sendmsg(bts, msg);
2260}
2261
2262int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2263{
2264 struct abis_om_hdr *oh;
2265 struct msgb *msg = nm_msgb_alloc();
2266
2267 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2268 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2269 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002270
2271 return abis_nm_sendmsg(bts, msg);
2272}
Harald Welte05188ee2009-01-18 11:39:08 +00002273
Harald Welte78fc0d42009-02-19 02:50:57 +00002274static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2275int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2276{
2277 struct abis_om_hdr *oh;
2278 struct msgb *msg = nm_msgb_alloc();
2279
2280 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2281 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2282 0xff, 0xff, 0xff);
2283 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2284
2285 return abis_nm_sendmsg(bts, msg);
2286}
2287
Harald Welteb6c92ae2009-02-21 20:15:32 +00002288/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002289int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002290 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2291 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002292{
2293 struct abis_om_hdr *oh;
2294 struct abis_nm_channel *ch;
2295 struct msgb *msg = nm_msgb_alloc();
2296
2297 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002298 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002299 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2300
2301 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2302 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002303 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002304
2305 return abis_nm_sendmsg(bts, msg);
2306}
2307
2308int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2309{
2310 struct abis_om_hdr *oh;
2311 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002312
2313 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002314 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002315 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2316 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2317
2318 return abis_nm_sendmsg(trx->bts, msg);
2319}
2320
Harald Welte78fc0d42009-02-19 02:50:57 +00002321int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2322{
2323 struct abis_om_hdr *oh;
2324 struct msgb *msg = nm_msgb_alloc();
2325 u_int8_t attr = NM_ATT_BS11_TXPWR;
2326
2327 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2328 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2329 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2330 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2331
2332 return abis_nm_sendmsg(trx->bts, msg);
2333}
2334
Harald Welteaaf02d92009-04-29 13:25:57 +00002335int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2336{
2337 struct abis_om_hdr *oh;
2338 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002339 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002340
2341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2342 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2343 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002344 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002345
2346 return abis_nm_sendmsg(bts, msg);
2347}
2348
Harald Welteef061952009-05-17 12:43:42 +00002349int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2350{
2351 struct abis_om_hdr *oh;
2352 struct msgb *msg = nm_msgb_alloc();
2353 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2354 NM_ATT_BS11_CCLK_TYPE };
2355
2356 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2357 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2358 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2359 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2360
2361 return abis_nm_sendmsg(bts, msg);
2362
2363}
Harald Welteaaf02d92009-04-29 13:25:57 +00002364
Harald Welte268bb402009-02-01 19:11:56 +00002365//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002366
Harald Welte1bc09062009-01-18 14:17:52 +00002367int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002368{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002369 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2370}
2371
Daniel Willmann4b054c82010-01-07 00:46:26 +01002372int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2373{
2374 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2375}
2376
Daniel Willmann493db4e2010-01-07 00:43:11 +01002377int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2378{
Harald Welte05188ee2009-01-18 11:39:08 +00002379 struct abis_om_hdr *oh;
2380 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002381 struct bs11_date_time bdt;
2382
2383 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002384
2385 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002386 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002387 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002388 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002389 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002390 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002391 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002392 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002393 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002394 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002395 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002396 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002397 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002398 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002399 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002400 }
Harald Welte05188ee2009-01-18 11:39:08 +00002401
2402 return abis_nm_sendmsg(bts, msg);
2403}
Harald Welte1bc09062009-01-18 14:17:52 +00002404
2405int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2406{
2407 struct abis_om_hdr *oh;
2408 struct msgb *msg;
2409
2410 if (strlen(password) != 10)
2411 return -EINVAL;
2412
2413 msg = nm_msgb_alloc();
2414 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002415 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002416 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2417 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2418
2419 return abis_nm_sendmsg(bts, msg);
2420}
2421
Harald Weltee69f5fb2009-04-28 16:31:38 +00002422/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2423int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2424{
2425 struct abis_om_hdr *oh;
2426 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002427 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002428
2429 msg = nm_msgb_alloc();
2430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2431 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2432 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002433
2434 if (locked)
2435 tlv_value = BS11_LI_PLL_LOCKED;
2436 else
2437 tlv_value = BS11_LI_PLL_STANDALONE;
2438
2439 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002440
2441 return abis_nm_sendmsg(bts, msg);
2442}
2443
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002444/* Set the calibration value of the PLL (work value/set value)
2445 * It depends on the login which one is changed */
2446int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2447{
2448 struct abis_om_hdr *oh;
2449 struct msgb *msg;
2450 u_int8_t tlv_value[2];
2451
2452 msg = nm_msgb_alloc();
2453 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2454 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2455 BS11_OBJ_TRX1, 0x00, 0x00);
2456
2457 tlv_value[0] = value>>8;
2458 tlv_value[1] = value&0xff;
2459
2460 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2461
2462 return abis_nm_sendmsg(bts, msg);
2463}
2464
Harald Welte1bc09062009-01-18 14:17:52 +00002465int abis_nm_bs11_get_state(struct gsm_bts *bts)
2466{
2467 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2468}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002469
2470/* BS11 SWL */
2471
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002472void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002473
Harald Welte5e4d1b32009-02-01 13:36:56 +00002474struct abis_nm_bs11_sw {
2475 struct gsm_bts *bts;
2476 char swl_fname[PATH_MAX];
2477 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002478 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002479 struct llist_head file_list;
2480 gsm_cbfn *user_cb; /* specified by the user */
2481};
2482static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2483
2484struct file_list_entry {
2485 struct llist_head list;
2486 char fname[PATH_MAX];
2487};
2488
2489struct file_list_entry *fl_dequeue(struct llist_head *queue)
2490{
2491 struct llist_head *lh;
2492
2493 if (llist_empty(queue))
2494 return NULL;
2495
2496 lh = queue->next;
2497 llist_del(lh);
2498
2499 return llist_entry(lh, struct file_list_entry, list);
2500}
2501
2502static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2503{
2504 char linebuf[255];
2505 struct llist_head *lh, *lh2;
2506 FILE *swl;
2507 int rc = 0;
2508
2509 swl = fopen(bs11_sw->swl_fname, "r");
2510 if (!swl)
2511 return -ENODEV;
2512
2513 /* zero the stale file list, if any */
2514 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2515 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002516 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002517 }
2518
2519 while (fgets(linebuf, sizeof(linebuf), swl)) {
2520 char file_id[12+1];
2521 char file_version[80+1];
2522 struct file_list_entry *fle;
2523 static char dir[PATH_MAX];
2524
2525 if (strlen(linebuf) < 4)
2526 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002527
Harald Welte5e4d1b32009-02-01 13:36:56 +00002528 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2529 if (rc < 0) {
2530 perror("ERR parsing SWL file");
2531 rc = -EINVAL;
2532 goto out;
2533 }
2534 if (rc < 2)
2535 continue;
2536
Harald Welte470ec292009-06-26 20:25:23 +02002537 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002538 if (!fle) {
2539 rc = -ENOMEM;
2540 goto out;
2541 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002542
2543 /* construct new filename */
2544 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2545 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2546 strcat(fle->fname, "/");
2547 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002548
2549 llist_add_tail(&fle->list, &bs11_sw->file_list);
2550 }
2551
2552out:
2553 fclose(swl);
2554 return rc;
2555}
2556
2557/* bs11 swload specific callback, passed to abis_nm core swload */
2558static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2559 struct msgb *msg, void *data, void *param)
2560{
2561 struct abis_nm_bs11_sw *bs11_sw = data;
2562 struct file_list_entry *fle;
2563 int rc = 0;
2564
Harald Welte5e4d1b32009-02-01 13:36:56 +00002565 switch (event) {
2566 case NM_MT_LOAD_END_ACK:
2567 fle = fl_dequeue(&bs11_sw->file_list);
2568 if (fle) {
2569 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002570 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002571 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002572 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002573 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002574 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002575 } else {
2576 /* activate the SWL */
2577 rc = abis_nm_software_activate(bs11_sw->bts,
2578 bs11_sw->swl_fname,
2579 bs11_swload_cbfn,
2580 bs11_sw);
2581 }
2582 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002583 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002584 case NM_MT_LOAD_END_NACK:
2585 case NM_MT_LOAD_INIT_ACK:
2586 case NM_MT_LOAD_INIT_NACK:
2587 case NM_MT_ACTIVATE_SW_NACK:
2588 case NM_MT_ACTIVATE_SW_ACK:
2589 default:
2590 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002591 if (bs11_sw->user_cb)
2592 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002593 break;
2594 }
2595
2596 return rc;
2597}
2598
2599/* Siemens provides a SWL file that is a mere listing of all the other
2600 * files that are part of a software release. We need to upload first
2601 * the list file, and then each file that is listed in the list file */
2602int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002603 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002604{
2605 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2606 struct file_list_entry *fle;
2607 int rc = 0;
2608
2609 INIT_LLIST_HEAD(&bs11_sw->file_list);
2610 bs11_sw->bts = bts;
2611 bs11_sw->win_size = win_size;
2612 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002613 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002614
2615 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2616 rc = bs11_read_swl_file(bs11_sw);
2617 if (rc < 0)
2618 return rc;
2619
2620 /* dequeue next item in file list */
2621 fle = fl_dequeue(&bs11_sw->file_list);
2622 if (!fle)
2623 return -EINVAL;
2624
2625 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002626 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002627 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002628 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002629 return rc;
2630}
2631
Harald Welte5083b0b2009-02-02 19:20:52 +00002632#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002633static u_int8_t req_attr_btse[] = {
2634 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2635 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2636 NM_ATT_BS11_LMT_USER_NAME,
2637
2638 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2639
2640 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2641
2642 NM_ATT_BS11_SW_LOAD_STORED };
2643
2644static u_int8_t req_attr_btsm[] = {
2645 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2646 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2647 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2648 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002649#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002650
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002651static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002652 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2653 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002654 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002655
2656int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2657{
2658 struct abis_om_hdr *oh;
2659 struct msgb *msg = nm_msgb_alloc();
2660
2661 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2662 /* SiemensHW CCTRL object */
2663 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2664 0x03, 0x00, 0x00);
2665 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2666
2667 return abis_nm_sendmsg(bts, msg);
2668}
Harald Welte268bb402009-02-01 19:11:56 +00002669
2670int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2671{
2672 struct abis_om_hdr *oh;
2673 struct msgb *msg = nm_msgb_alloc();
2674 struct bs11_date_time aet;
2675
2676 get_bs11_date_time(&aet);
2677 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2678 /* SiemensHW CCTRL object */
2679 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2680 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002681 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002682
2683 return abis_nm_sendmsg(bts, msg);
2684}
Harald Welte5c1e4582009-02-15 11:57:29 +00002685
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002686int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2687{
2688 struct abis_om_hdr *oh;
2689 struct msgb *msg = nm_msgb_alloc();
2690 struct bs11_date_time aet;
2691
2692 get_bs11_date_time(&aet);
2693 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2694 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2695 bport, 0xff, 0x02);
2696 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2697
2698 return abis_nm_sendmsg(bts, msg);
2699}
2700
Harald Welte5c1e4582009-02-15 11:57:29 +00002701/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002702static const char ipaccess_magic[] = "com.ipaccess";
2703
Harald Welte677c21f2009-02-17 13:22:23 +00002704
2705static int abis_nm_rx_ipacc(struct msgb *msg)
2706{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002707 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002708 struct abis_om_hdr *oh = msgb_l2(msg);
2709 struct abis_om_fom_hdr *foh;
2710 u_int8_t idstrlen = oh->data[0];
2711 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002712 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002713
2714 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002715 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002716 return -EINVAL;
2717 }
2718
Harald Welte193fefc2009-04-30 15:16:27 +00002719 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002720 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002721
Harald Weltea8bd6d42009-10-20 09:56:18 +02002722 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002723
Harald Welte746d6092009-10-19 22:11:11 +02002724 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002725
Harald Welte677c21f2009-02-17 13:22:23 +00002726 switch (foh->msg_type) {
2727 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002728 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002729 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2730 memcpy(&addr,
2731 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2732
2733 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2734 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002735 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002736 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002737 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002738 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002739 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2740 DEBUGPC(DNM, "STREAM=0x%02x ",
2741 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002742 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002743 break;
2744 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002745 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002746 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002747 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002748 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002749 else
2750 DEBUGPC(DNM, "\n");
2751 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002752 case NM_MT_IPACC_SET_NVATTR_ACK:
2753 DEBUGPC(DNM, "SET NVATTR ACK\n");
2754 /* FIXME: decode and show the actual attributes */
2755 break;
2756 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002757 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002758 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002759 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002760 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2761 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002762 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002763 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002764 case NM_MT_IPACC_GET_NVATTR_ACK:
2765 DEBUGPC(DNM, "GET NVATTR ACK\n");
2766 /* FIXME: decode and show the actual attributes */
2767 break;
2768 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002769 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002770 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002771 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002772 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2773 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002774 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002775 break;
Harald Welte15c44172009-10-08 20:15:24 +02002776 case NM_MT_IPACC_SET_ATTR_ACK:
2777 DEBUGPC(DNM, "SET ATTR ACK\n");
2778 break;
2779 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002780 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002781 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002782 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002783 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2784 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002785 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002786 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002787 default:
2788 DEBUGPC(DNM, "unknown\n");
2789 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002790 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002791
2792 /* signal handling */
2793 switch (foh->msg_type) {
2794 case NM_MT_IPACC_RSL_CONNECT_NACK:
2795 case NM_MT_IPACC_SET_NVATTR_NACK:
2796 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002797 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002798 signal.msg_type = foh->msg_type;
2799 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002800 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002801 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002802 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002803 signal.msg_type = foh->msg_type;
2804 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002805 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002806 default:
2807 break;
2808 }
2809
Harald Welte677c21f2009-02-17 13:22:23 +00002810 return 0;
2811}
2812
Harald Welte193fefc2009-04-30 15:16:27 +00002813/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002814int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2815 u_int8_t obj_class, u_int8_t bts_nr,
2816 u_int8_t trx_nr, u_int8_t ts_nr,
2817 u_int8_t *attr, int attr_len)
2818{
2819 struct msgb *msg = nm_msgb_alloc();
2820 struct abis_om_hdr *oh;
2821 struct abis_om_fom_hdr *foh;
2822 u_int8_t *data;
2823
2824 /* construct the 12.21 OM header, observe the erroneous length */
2825 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2826 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2827 oh->mdisc = ABIS_OM_MDISC_MANUF;
2828
2829 /* add the ip.access magic */
2830 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2831 *data++ = sizeof(ipaccess_magic);
2832 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2833
2834 /* fill the 12.21 FOM header */
2835 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2836 foh->msg_type = msg_type;
2837 foh->obj_class = obj_class;
2838 foh->obj_inst.bts_nr = bts_nr;
2839 foh->obj_inst.trx_nr = trx_nr;
2840 foh->obj_inst.ts_nr = ts_nr;
2841
2842 if (attr && attr_len) {
2843 data = msgb_put(msg, attr_len);
2844 memcpy(data, attr, attr_len);
2845 }
2846
2847 return abis_nm_sendmsg(bts, msg);
2848}
Harald Welte677c21f2009-02-17 13:22:23 +00002849
Harald Welte193fefc2009-04-30 15:16:27 +00002850/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002851int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002852 int attr_len)
2853{
Harald Welte2ef156d2010-01-07 20:39:42 +01002854 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2855 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002856 attr_len);
2857}
2858
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002859int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002860 u_int32_t ip, u_int16_t port, u_int8_t stream)
2861{
2862 struct in_addr ia;
2863 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2864 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2865 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2866
2867 int attr_len = sizeof(attr);
2868
2869 ia.s_addr = htonl(ip);
2870 attr[1] = stream;
2871 attr[3] = port >> 8;
2872 attr[4] = port & 0xff;
2873 *(u_int32_t *)(attr+6) = ia.s_addr;
2874
2875 /* if ip == 0, we use the default IP */
2876 if (ip == 0)
2877 attr_len -= 5;
2878
2879 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002880 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002881
2882 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2883 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2884 trx->nr, 0xff, attr, attr_len);
2885}
2886
Harald Welte193fefc2009-04-30 15:16:27 +00002887/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002888int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002889{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002890 struct abis_om_hdr *oh;
2891 struct msgb *msg = nm_msgb_alloc();
2892
2893 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2894 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2895 trx->bts->nr, trx->nr, 0xff);
2896
2897 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002898}
Harald Weltedaef5212009-10-24 10:20:41 +02002899
2900int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2901 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2902 u_int8_t *attr, u_int8_t attr_len)
2903{
2904 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2905 obj_class, bts_nr, trx_nr, ts_nr,
2906 attr, attr_len);
2907}
Harald Welte0f255852009-11-12 14:48:42 +01002908
Harald Welte97a282b2010-03-14 15:37:43 +08002909void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2910{
2911 /* we simply reuse the GSM48 function and overwrite the RAC
2912 * with the Cell ID */
2913 gsm48_ra_id_by_bts(buf, bts);
2914 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2915}
2916
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002917void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2918{
2919 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2920
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002921 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002922 if (!trx->bts || !trx->bts->oml_link)
2923 return;
2924
2925 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2926 trx->bts->bts_nr, trx->nr, 0xff,
2927 new_state);
2928}
2929
Harald Welte92b1fe42010-03-25 11:45:30 +08002930static const struct value_string ipacc_testres_names[] = {
2931 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2932 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2933 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2934 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2935 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2936 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002937};
2938
2939const char *ipacc_testres_name(u_int8_t res)
2940{
Harald Welte92b1fe42010-03-25 11:45:30 +08002941 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002942}
2943
Harald Welteb40a38f2009-11-13 11:56:05 +01002944void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2945{
2946 cid->mcc = (buf[0] & 0xf) * 100;
2947 cid->mcc += (buf[0] >> 4) * 10;
2948 cid->mcc += (buf[1] & 0xf) * 1;
2949
2950 if (buf[1] >> 4 == 0xf) {
2951 cid->mnc = (buf[2] & 0xf) * 10;
2952 cid->mnc += (buf[2] >> 4) * 1;
2953 } else {
2954 cid->mnc = (buf[2] & 0xf) * 100;
2955 cid->mnc += (buf[2] >> 4) * 10;
2956 cid->mnc += (buf[1] >> 4) * 1;
2957 }
2958
Harald Welteaff237d2009-11-13 14:41:52 +01002959 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2960 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002961}
2962
Harald Welte0f255852009-11-12 14:48:42 +01002963/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2964int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2965{
2966 u_int8_t *cur = buf;
2967 u_int16_t len;
2968
2969 memset(binf, 0, sizeof(binf));
2970
2971 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2972 return -EINVAL;
2973 cur++;
2974
2975 len = ntohs(*(u_int16_t *)cur);
2976 cur += 2;
2977
2978 binf->info_type = ntohs(*(u_int16_t *)cur);
2979 cur += 2;
2980
2981 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2982 binf->freq_qual = *cur >> 2;
2983
2984 binf->arfcn = *cur++ & 3 << 8;
2985 binf->arfcn |= *cur++;
2986
2987 if (binf->info_type & IPAC_BINF_RXLEV)
2988 binf->rx_lev = *cur & 0x3f;
2989 cur++;
2990
2991 if (binf->info_type & IPAC_BINF_RXQUAL)
2992 binf->rx_qual = *cur & 0x7;
2993 cur++;
2994
2995 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2996 binf->freq_err = ntohs(*(u_int16_t *)cur);
2997 cur += 2;
2998
2999 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3000 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3001 cur += 2;
3002
3003 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3004 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3005 cur += 4;
3006
3007 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01003008 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003009 cur++;
3010
Harald Welteb40a38f2009-11-13 11:56:05 +01003011 ipac_parse_cgi(&binf->cgi, cur);
3012 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003013
3014 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3015 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3016 cur += sizeof(binf->ba_list_si2);
3017 }
3018
3019 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3020 memcpy(binf->ba_list_si2bis, cur,
3021 sizeof(binf->ba_list_si2bis));
3022 cur += sizeof(binf->ba_list_si2bis);
3023 }
3024
3025 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3026 memcpy(binf->ba_list_si2ter, cur,
3027 sizeof(binf->ba_list_si2ter));
3028 cur += sizeof(binf->ba_list_si2ter);
3029 }
3030
3031 return 0;
3032}