blob: 7a67fdf3bb18bf03ae609c1c9227bd56360be905 [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001/* GSM Network Management (OML) messages on the A-bis interface
2 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000026#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000027#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000028#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000029#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000030#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000031#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000032#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000033
Harald Welte52b1f982008-12-23 20:25:15 +000034#include <sys/types.h>
Harald Welte4724f992009-01-18 18:01:49 +000035#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000036#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000037#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000038
Harald Welte8470bf22008-12-25 23:28:35 +000039#include <openbsc/gsm_data.h>
40#include <openbsc/debug.h>
41#include <openbsc/msgb.h>
42#include <openbsc/tlv.h>
43#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020046#include <openbsc/talloc.h>
Harald Welte52b1f982008-12-23 20:25:15 +000047
Harald Welte8470bf22008-12-25 23:28:35 +000048#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000051
52/* unidirectional messages from BTS to BSC */
53static const enum abis_nm_msgtype reports[] = {
54 NM_MT_SW_ACTIVATED_REP,
55 NM_MT_TEST_REP,
56 NM_MT_STATECHG_EVENT_REP,
57 NM_MT_FAILURE_EVENT_REP,
58};
59
60/* messages without ACK/NACK */
61static const enum abis_nm_msgtype no_ack_nack[] = {
62 NM_MT_MEAS_RES_REQ,
63 NM_MT_STOP_MEAS,
64 NM_MT_START_MEAS,
65};
66
Harald Welte4724f992009-01-18 18:01:49 +000067/* Messages related to software load */
68static const enum abis_nm_msgtype sw_load_msgs[] = {
69 NM_MT_LOAD_INIT_ACK,
70 NM_MT_LOAD_INIT_NACK,
71 NM_MT_LOAD_SEG_ACK,
72 NM_MT_LOAD_ABORT,
73 NM_MT_LOAD_END_ACK,
74 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000075 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000076 NM_MT_ACTIVATE_SW_ACK,
77 NM_MT_ACTIVATE_SW_NACK,
78 NM_MT_SW_ACTIVATED_REP,
79};
80
Harald Weltee0590df2009-02-15 03:34:15 +000081static const enum abis_nm_msgtype nacks[] = {
82 NM_MT_LOAD_INIT_NACK,
83 NM_MT_LOAD_END_NACK,
84 NM_MT_SW_ACT_REQ_NACK,
85 NM_MT_ACTIVATE_SW_NACK,
86 NM_MT_ESTABLISH_TEI_NACK,
87 NM_MT_CONN_TERR_SIGN_NACK,
88 NM_MT_DISC_TERR_SIGN_NACK,
89 NM_MT_CONN_TERR_TRAF_NACK,
90 NM_MT_DISC_TERR_TRAF_NACK,
91 NM_MT_CONN_MDROP_LINK_NACK,
92 NM_MT_DISC_MDROP_LINK_NACK,
93 NM_MT_SET_BTS_ATTR_NACK,
94 NM_MT_SET_RADIO_ATTR_NACK,
95 NM_MT_SET_CHAN_ATTR_NACK,
96 NM_MT_PERF_TEST_NACK,
97 NM_MT_SEND_TEST_REP_NACK,
98 NM_MT_STOP_TEST_NACK,
99 NM_MT_STOP_EVENT_REP_NACK,
100 NM_MT_REST_EVENT_REP_NACK,
101 NM_MT_CHG_ADM_STATE_NACK,
102 NM_MT_CHG_ADM_STATE_REQ_NACK,
103 NM_MT_REP_OUTST_ALARMS_NACK,
104 NM_MT_CHANGEOVER_NACK,
105 NM_MT_OPSTART_NACK,
106 NM_MT_REINIT_NACK,
107 NM_MT_SET_SITE_OUT_NACK,
108 NM_MT_CHG_HW_CONF_NACK,
109 NM_MT_GET_ATTR_NACK,
110 NM_MT_SET_ALARM_THRES_NACK,
111 NM_MT_BS11_BEGIN_DB_TX_NACK,
112 NM_MT_BS11_END_DB_TX_NACK,
113 NM_MT_BS11_CREATE_OBJ_NACK,
114 NM_MT_BS11_DELETE_OBJ_NACK,
115};
Harald Welte78fc0d42009-02-19 02:50:57 +0000116
117static const char *nack_names[0xff] = {
118 [NM_MT_LOAD_INIT_NACK] = "SOFTWARE LOAD INIT",
119 [NM_MT_LOAD_END_NACK] = "SOFTWARE LOAD END",
120 [NM_MT_SW_ACT_REQ_NACK] = "SOFTWARE ACTIVATE REQUEST",
121 [NM_MT_ACTIVATE_SW_NACK] = "ACTIVATE SOFTWARE",
122 [NM_MT_ESTABLISH_TEI_NACK] = "ESTABLISH TEI",
123 [NM_MT_CONN_TERR_SIGN_NACK] = "CONNECT TERRESTRIAL SIGNALLING",
124 [NM_MT_DISC_TERR_SIGN_NACK] = "DISCONNECT TERRESTRIAL SIGNALLING",
125 [NM_MT_CONN_TERR_TRAF_NACK] = "CONNECT TERRESTRIAL TRAFFIC",
126 [NM_MT_DISC_TERR_TRAF_NACK] = "DISCONNECT TERRESTRIAL TRAFFIC",
127 [NM_MT_CONN_MDROP_LINK_NACK] = "CONNECT MULTI-DROP LINK",
128 [NM_MT_DISC_MDROP_LINK_NACK] = "DISCONNECT MULTI-DROP LINK",
129 [NM_MT_SET_BTS_ATTR_NACK] = "SET BTS ATTRIBUTE",
130 [NM_MT_SET_RADIO_ATTR_NACK] = "SET RADIO ATTRIBUTE",
131 [NM_MT_SET_CHAN_ATTR_NACK] = "SET CHANNEL ATTRIBUTE",
132 [NM_MT_PERF_TEST_NACK] = "PERFORM TEST",
133 [NM_MT_SEND_TEST_REP_NACK] = "SEND TEST REPORT",
134 [NM_MT_STOP_TEST_NACK] = "STOP TEST",
135 [NM_MT_STOP_EVENT_REP_NACK] = "STOP EVENT REPORT",
136 [NM_MT_REST_EVENT_REP_NACK] = "RESET EVENT REPORT",
137 [NM_MT_CHG_ADM_STATE_NACK] = "CHANGE ADMINISTRATIVE STATE",
138 [NM_MT_CHG_ADM_STATE_REQ_NACK] = "CHANGE ADMINISTRATIVE STATE REQUEST",
139 [NM_MT_REP_OUTST_ALARMS_NACK] = "REPORT OUTSTANDING ALARMS",
140 [NM_MT_CHANGEOVER_NACK] = "CHANGEOVER",
141 [NM_MT_OPSTART_NACK] = "OPSTART",
142 [NM_MT_REINIT_NACK] = "REINIT",
143 [NM_MT_SET_SITE_OUT_NACK] = "SET SITE OUTPUT",
144 [NM_MT_CHG_HW_CONF_NACK] = "CHANGE HARDWARE CONFIGURATION",
145 [NM_MT_GET_ATTR_NACK] = "GET ATTRIBUTE",
146 [NM_MT_SET_ALARM_THRES_NACK] = "SET ALARM THRESHOLD",
147 [NM_MT_BS11_BEGIN_DB_TX_NACK] = "BS11 BEGIN DATABASE TRANSMISSION",
148 [NM_MT_BS11_END_DB_TX_NACK] = "BS11 END DATABASE TRANSMISSION",
149 [NM_MT_BS11_CREATE_OBJ_NACK] = "BS11 CREATE OBJECT",
150 [NM_MT_BS11_DELETE_OBJ_NACK] = "BS11 DELETE OBJECT",
151};
152
Harald Welte6c96ba52009-05-01 13:03:40 +0000153/* Chapter 9.4.36 */
154static const char *nack_cause_names[] = {
155 /* General Nack Causes */
156 [NM_NACK_INCORR_STRUCT] = "Incorrect message structure",
157 [NM_NACK_MSGTYPE_INVAL] = "Invalid message type value",
158 [NM_NACK_OBJCLASS_INVAL] = "Invalid Object class value",
159 [NM_NACK_OBJCLASS_NOTSUPP] = "Object class not supported",
160 [NM_NACK_BTSNR_UNKN] = "BTS no. unknown",
161 [NM_NACK_TRXNR_UNKN] = "Baseband Transceiver no. unknown",
162 [NM_NACK_OBJINST_UNKN] = "Object Instance unknown",
163 [NM_NACK_ATTRID_INVAL] = "Invalid attribute identifier value",
164 [NM_NACK_ATTRID_NOTSUPP] = "Attribute identifier not supported",
165 [NM_NACK_PARAM_RANGE] = "Parameter value outside permitted range",
166 [NM_NACK_ATTRLIST_INCONSISTENT] = "Inconsistency in attribute list",
167 [NM_NACK_SPEC_IMPL_NOTSUPP] = "Specified implementation not supported",
168 [NM_NACK_CANT_PERFORM] = "Message cannot be performed",
169 /* Specific Nack Causes */
170 [NM_NACK_RES_NOTIMPL] = "Resource not implemented",
171 [NM_NACK_RES_NOTAVAIL] = "Resource not available",
172 [NM_NACK_FREQ_NOTAVAIL] = "Frequency not available",
173 [NM_NACK_TEST_NOTSUPP] = "Test not supported",
174 [NM_NACK_CAPACITY_RESTR] = "Capacity restrictions",
175 [NM_NACK_PHYSCFG_NOTPERFORM] = "Physical configuration cannot be performed",
176 [NM_NACK_TEST_NOTINIT] = "Test not initiated",
177 [NM_NACK_PHYSCFG_NOTRESTORE] = "Physical configuration cannot be restored",
178 [NM_NACK_TEST_NOSUCH] = "No such test",
179 [NM_NACK_TEST_NOSTOP] = "Test cannot be stopped",
180 [NM_NACK_MSGINCONSIST_PHYSCFG] = "Message inconsistent with physical configuration",
181 [NM_NACK_FILE_INCOMPLETE] = "Complete file notreceived",
182 [NM_NACK_FILE_NOTAVAIL] = "File not available at destination",
Harald Welte560982b2009-06-26 13:21:57 +0200183 [NM_NACK_FILE_NOTACTIVATE] = "File cannot be activate",
Harald Welte6c96ba52009-05-01 13:03:40 +0000184 [NM_NACK_REQ_NOT_GRANT] = "Request not granted",
185 [NM_NACK_WAIT] = "Wait",
186 [NM_NACK_NOTH_REPORT_EXIST] = "Nothing reportable existing",
187 [NM_NACK_MEAS_NOTSUPP] = "Measurement not supported",
188 [NM_NACK_MEAS_NOTSTART] = "Measurement not started",
189};
190
191static char namebuf[255];
192static const char *nack_cause_name(u_int8_t cause)
193{
194 if (cause < ARRAY_SIZE(nack_cause_names) && nack_cause_names[cause])
195 return nack_cause_names[cause];
196
197 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
198 return namebuf;
199}
200
Harald Welte0db97b22009-05-01 17:22:47 +0000201/* Chapter 9.4.16: Event Type */
202static const char *event_type_names[] = {
203 [NM_EVT_COMM_FAIL] = "communication failure",
204 [NM_EVT_QOS_FAIL] = "quality of service failure",
205 [NM_EVT_PROC_FAIL] = "processing failure",
206 [NM_EVT_EQUIP_FAIL] = "equipment failure",
207 [NM_EVT_ENV_FAIL] = "environment failure",
208};
209
210static const char *event_type_name(u_int8_t cause)
211{
212 if (cause < ARRAY_SIZE(event_type_names) && event_type_names[cause])
213 return event_type_names[cause];
214
215 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
216 return namebuf;
217}
218
219/* Chapter 9.4.63: Perceived Severity */
220static const char *severity_names[] = {
221 [NM_SEVER_CEASED] = "failure ceased",
222 [NM_SEVER_CRITICAL] = "critical failure",
223 [NM_SEVER_MAJOR] = "major failure",
224 [NM_SEVER_MINOR] = "minor failure",
225 [NM_SEVER_WARNING] = "warning level failure",
226 [NM_SEVER_INDETERMINATE] = "indeterminate failure",
227};
228
229static const char *severity_name(u_int8_t cause)
230{
231 if (cause < ARRAY_SIZE(severity_names) && severity_names[cause])
232 return severity_names[cause];
233
234 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
235 return namebuf;
236}
237
Harald Welte52b1f982008-12-23 20:25:15 +0000238/* Attributes that the BSC can set, not only get, according to Section 9.4 */
239static const enum abis_nm_attr nm_att_settable[] = {
240 NM_ATT_ADD_INFO,
241 NM_ATT_ADD_TEXT,
242 NM_ATT_DEST,
243 NM_ATT_EVENT_TYPE,
244 NM_ATT_FILE_DATA,
245 NM_ATT_GET_ARI,
246 NM_ATT_HW_CONF_CHG,
247 NM_ATT_LIST_REQ_ATTR,
248 NM_ATT_MDROP_LINK,
249 NM_ATT_MDROP_NEXT,
250 NM_ATT_NACK_CAUSES,
251 NM_ATT_OUTST_ALARM,
252 NM_ATT_PHYS_CONF,
253 NM_ATT_PROB_CAUSE,
254 NM_ATT_RAD_SUBC,
255 NM_ATT_SOURCE,
256 NM_ATT_SPEC_PROB,
257 NM_ATT_START_TIME,
258 NM_ATT_TEST_DUR,
259 NM_ATT_TEST_NO,
260 NM_ATT_TEST_REPORT,
261 NM_ATT_WINDOW_SIZE,
262 NM_ATT_SEVERITY,
263 NM_ATT_MEAS_RES,
264 NM_ATT_MEAS_TYPE,
265};
266
Harald Weltee0590df2009-02-15 03:34:15 +0000267static const struct tlv_definition nm_att_tlvdef = {
268 .def = {
269 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
270 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
271 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
272 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
273 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
274 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
275 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
276 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
277 [NM_ATT_BSIC] = { TLV_TYPE_TV },
278 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
279 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
280 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
281 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
282 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
283 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
284 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
285 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
286 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
287 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
288 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
289 [NM_ATT_HSN] = { TLV_TYPE_TV },
290 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
291 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
292 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
293 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
294 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
295 [NM_ATT_MAIO] = { TLV_TYPE_TV },
296 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
297 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
298 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
299 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
300 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
301 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
302 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
303 [NM_ATT_NY1] = { TLV_TYPE_TV },
304 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
305 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
306 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
307 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
308 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
309 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
310 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
311 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
312 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
313 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
314 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
315 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
316 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
317 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
318 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
319 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
320 [NM_ATT_TEI] = { TLV_TYPE_TV },
321 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
322 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
323 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
324 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
325 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
326 [NM_ATT_TSC] = { TLV_TYPE_TV },
327 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
328 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
329 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
330 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
331 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000332 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
333 /* BS11 specifics */
Harald Welte78fc0d42009-02-19 02:50:57 +0000334 [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV },
335 [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV },
336 [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV },
337 [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV },
338 [0xd5] = { TLV_TYPE_TLV },
339 [0xa8] = { TLV_TYPE_TLV },
Harald Weltee0590df2009-02-15 03:34:15 +0000340 [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV },
341 [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV },
342 [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV },
343 [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV },
344 [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV },
345 [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 },
346 [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV },
Harald Welteee670472009-02-22 21:58:49 +0000347 [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },
Harald Weltee0590df2009-02-15 03:34:15 +0000348 [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV },
349 [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
350 [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV },
Harald Welte03133942009-02-18 19:51:53 +0000351 [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV },
352 [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV },
Harald Welteaaf02d92009-04-29 13:25:57 +0000353 [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV },
Harald Weltea7cfa032009-04-29 22:33:02 +0000354 [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV },
Harald Welteef061952009-05-17 12:43:42 +0000355 [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV },
356 [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV },
Harald Welte677c21f2009-02-17 13:22:23 +0000357 /* ip.access specifics */
Harald Welte0efe9b72009-07-12 09:33:54 +0200358 [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
359 [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200360 [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
361 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, },
362 [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
363 [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
364 [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
365 [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
366 [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
367 [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
368 [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
369 [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
370 [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
Harald Welte0efe9b72009-07-12 09:33:54 +0200371 [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200372 [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
373 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
Harald Welte0efe9b72009-07-12 09:33:54 +0200374 [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200375 [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
376 [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
377 [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
378 [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
379 [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
380 [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
381 [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
382 [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
383 [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
384 [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
385 [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
386 [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
387 [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200388 [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200389 [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
390 [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
391 [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
392 [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
393 [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
394 [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
395 [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
396 [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
397 [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
398 [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
399 [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
400 [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200401 //[0x95] = { TLV_TYPE_FIXED, 2 },
Harald Welte677c21f2009-02-17 13:22:23 +0000402 [0x85] = { TLV_TYPE_TV },
403
Harald Weltee0590df2009-02-15 03:34:15 +0000404 },
405};
Harald Welte03133942009-02-18 19:51:53 +0000406
Harald Welte21bd3a52009-08-10 12:21:22 +0200407static const enum abis_nm_chan_comb chcomb4pchan[] = {
408 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
409 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
410 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
411 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
412 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200413 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
414 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200415 /* FIXME: bounds check */
416};
417
418int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
419{
420 if (pchan < ARRAY_SIZE(chcomb4pchan))
421 return chcomb4pchan[pchan];
422
423 return -EINVAL;
424}
425
Harald Welte03133942009-02-18 19:51:53 +0000426int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
427{
Harald Weltea4d49e92009-05-23 06:39:58 +0000428 return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000429}
Harald Weltee0590df2009-02-15 03:34:15 +0000430
Harald Welte52b1f982008-12-23 20:25:15 +0000431static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
432{
433 int i;
434
435 for (i = 0; i < size; i++) {
436 if (arr[i] == mt)
437 return 1;
438 }
439
440 return 0;
441}
442
Holger Freytherca362a62009-01-04 21:05:01 +0000443#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000444/* is this msgtype the usual ACK/NACK type ? */
445static int is_ack_nack(enum abis_nm_msgtype mt)
446{
447 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
448}
Holger Freytherca362a62009-01-04 21:05:01 +0000449#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000450
451/* is this msgtype a report ? */
452static int is_report(enum abis_nm_msgtype mt)
453{
Harald Welte8470bf22008-12-25 23:28:35 +0000454 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000455}
456
457#define MT_ACK(x) (x+1)
458#define MT_NACK(x) (x+2)
459
460static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
461{
462 oh->mdisc = ABIS_OM_MDISC_FOM;
463 oh->placement = ABIS_OM_PLACEMENT_ONLY;
464 oh->sequence = 0;
465 oh->length = len;
466}
467
468static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
469 u_int8_t msg_type, u_int8_t obj_class,
470 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
471{
472 struct abis_om_fom_hdr *foh =
473 (struct abis_om_fom_hdr *) oh->data;
474
Harald Welte702d8702008-12-26 20:25:35 +0000475 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000476 foh->msg_type = msg_type;
477 foh->obj_class = obj_class;
478 foh->obj_inst.bts_nr = bts_nr;
479 foh->obj_inst.trx_nr = trx_nr;
480 foh->obj_inst.ts_nr = ts_nr;
481}
482
Harald Welte8470bf22008-12-25 23:28:35 +0000483static struct msgb *nm_msgb_alloc(void)
484{
Harald Welte966636f2009-06-26 19:39:35 +0200485 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
486 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000487}
488
Harald Welte52b1f982008-12-23 20:25:15 +0000489/* Send a OML NM Message from BSC to BTS */
490int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
491{
Holger Freyther59639e82009-02-09 23:09:55 +0000492 msg->trx = bts->c0;
493
Harald Weltead384642008-12-26 10:20:07 +0000494 return _abis_nm_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000495}
496
Harald Welte4724f992009-01-18 18:01:49 +0000497static int abis_nm_rcvmsg_sw(struct msgb *mb);
498
Harald Welte34a99682009-02-13 02:41:40 +0000499static const char *obj_class_name(u_int8_t oc)
500{
Harald Welte7b26bcb2009-05-28 11:39:21 +0000501 switch (oc) {
502 case NM_OC_SITE_MANAGER:
503 return "SITE MANAGER";
504 case NM_OC_BTS:
505 return "BTS";
506 case NM_OC_RADIO_CARRIER:
507 return "RADIO CARRIER";
508 case NM_OC_BASEB_TRANSC:
509 return "BASEBAND TRANSCEIVER";
510 case NM_OC_CHANNEL:
Harald Weltebd8f7e32009-06-09 20:17:12 +0000511 return "CHANNEL";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000512 case NM_OC_BS11_ADJC:
513 return "ADJC";
514 case NM_OC_BS11_HANDOVER:
515 return "HANDOVER";
516 case NM_OC_BS11_PWR_CTRL:
517 return "POWER CONTROL";
518 case NM_OC_BS11_BTSE:
519 return "BTSE";
520 case NM_OC_BS11_RACK:
521 return "RACK";
522 case NM_OC_BS11_TEST:
523 return "TEST";
524 case NM_OC_BS11_ENVABTSE:
525 return "ENVABTSE";
526 case NM_OC_BS11_BPORT:
527 return "BPORT";
528 case NM_OC_GPRS_NSE:
529 return "GPRS NSE";
530 case NM_OC_GPRS_CELL:
531 return "GPRS CELL";
Harald Welted83a1272009-07-12 10:56:06 +0200532 case NM_OC_GPRS_NSVC:
533 return "GPRS NSVC";
Harald Welte8b697c72009-06-05 19:18:45 +0000534 case NM_OC_BS11:
535 return "SIEMENSHW";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000536 }
537
538 return "UNKNOWN";
Harald Welte34a99682009-02-13 02:41:40 +0000539}
540
Harald Welte4d87f242009-03-10 19:43:44 +0000541const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000542{
543 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100544 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000545 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100546 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000547 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100548 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000549 return "NULL";
550 default:
551 return "RFU";
552 }
553}
554
Harald Weltee0590df2009-02-15 03:34:15 +0000555/* Chapter 9.4.7 */
Harald Welte4d87f242009-03-10 19:43:44 +0000556static const char *avail_names[] = {
Harald Weltee0590df2009-02-15 03:34:15 +0000557 "In test",
558 "Failed",
559 "Power off",
560 "Off line",
561 "<not used>",
562 "Dependency",
563 "Degraded",
564 "Not installed",
565};
566
Harald Welte4d87f242009-03-10 19:43:44 +0000567const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000568{
Harald Welte0b8348d2009-02-18 03:43:01 +0000569 if (avail == 0xff)
570 return "OK";
Harald Weltee0590df2009-02-15 03:34:15 +0000571 if (avail >= ARRAY_SIZE(avail_names))
572 return "UNKNOWN";
573 return avail_names[avail];
574}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000575
Harald Welte0f255852009-11-12 14:48:42 +0100576static struct value_string test_names[] = {
577 /* FIXME: standard test names */
578 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
579 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
580 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
581 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
582 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
583 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
584 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
585 { 0, NULL }
586};
587
Harald Welte7b26bcb2009-05-28 11:39:21 +0000588const char *nm_adm_name(u_int8_t adm)
589{
590 switch (adm) {
591 case 1:
592 return "Locked";
593 case 2:
594 return "Unlocked";
595 case 3:
596 return "Shutdown";
597 default:
598 return "<not used>";
599 }
600}
Harald Weltee0590df2009-02-15 03:34:15 +0000601
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100602int nm_is_running(struct gsm_nm_state *s) {
603 return (s->operational == NM_OPSTATE_ENABLED) && (
604 (s->availability == NM_AVSTATE_OK) ||
605 (s->availability == 0xff)
606 );
607}
608
Harald Weltea8bd6d42009-10-20 09:56:18 +0200609static void debugp_foh(struct abis_om_fom_hdr *foh)
610{
611 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
612 obj_class_name(foh->obj_class), foh->obj_class,
613 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
614 foh->obj_inst.ts_nr);
615}
616
Harald Weltee0590df2009-02-15 03:34:15 +0000617/* obtain the gsm_nm_state data structure for a given object instance */
618static struct gsm_nm_state *
619objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
620 struct abis_om_obj_inst *obj_inst)
621{
622 struct gsm_bts_trx *trx;
623 struct gsm_nm_state *nm_state = NULL;
624
625 switch (obj_class) {
626 case NM_OC_BTS:
627 nm_state = &bts->nm_state;
628 break;
629 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100630 if (obj_inst->trx_nr >= bts->num_trx) {
631 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000632 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100633 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200634 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000635 nm_state = &trx->nm_state;
636 break;
637 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100638 if (obj_inst->trx_nr >= bts->num_trx) {
639 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000640 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100641 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200642 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000643 nm_state = &trx->bb_transc.nm_state;
644 break;
645 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100646 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100647 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000648 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100649 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200650 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000651 if (obj_inst->ts_nr >= TRX_NR_TS)
652 return NULL;
653 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
654 break;
655 case NM_OC_SITE_MANAGER:
656 nm_state = &bts->site_mgr.nm_state;
657 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000658 case NM_OC_BS11:
659 switch (obj_inst->bts_nr) {
660 case BS11_OBJ_CCLK:
661 nm_state = &bts->bs11.cclk.nm_state;
662 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000663 case BS11_OBJ_BBSIG:
664 if (obj_inst->ts_nr > bts->num_trx)
665 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200666 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000667 nm_state = &trx->bs11.bbsig.nm_state;
668 break;
669 case BS11_OBJ_PA:
670 if (obj_inst->ts_nr > bts->num_trx)
671 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200672 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000673 nm_state = &trx->bs11.pa.nm_state;
674 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000675 default:
676 return NULL;
677 }
678 case NM_OC_BS11_RACK:
679 nm_state = &bts->bs11.rack.nm_state;
680 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000681 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100682 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000683 return NULL;
684 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
685 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200686 case NM_OC_GPRS_NSE:
687 nm_state = &bts->gprs.nse.nm_state;
688 break;
689 case NM_OC_GPRS_CELL:
690 nm_state = &bts->gprs.cell.nm_state;
691 break;
692 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100693 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200694 return NULL;
695 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
696 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000697 }
698 return nm_state;
699}
700
701/* obtain the in-memory data structure of a given object instance */
702static void *
703objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
704 struct abis_om_obj_inst *obj_inst)
705{
706 struct gsm_bts_trx *trx;
707 void *obj = NULL;
708
709 switch (obj_class) {
710 case NM_OC_BTS:
711 obj = bts;
712 break;
713 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100714 if (obj_inst->trx_nr >= bts->num_trx) {
715 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000716 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100717 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200718 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000719 obj = trx;
720 break;
721 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100722 if (obj_inst->trx_nr >= bts->num_trx) {
723 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000724 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100725 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200726 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000727 obj = &trx->bb_transc;
728 break;
729 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100730 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100731 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000732 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100733 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200734 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000735 if (obj_inst->ts_nr >= TRX_NR_TS)
736 return NULL;
737 obj = &trx->ts[obj_inst->ts_nr];
738 break;
739 case NM_OC_SITE_MANAGER:
740 obj = &bts->site_mgr;
741 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200742 case NM_OC_GPRS_NSE:
743 obj = &bts->gprs.nse;
744 break;
745 case NM_OC_GPRS_CELL:
746 obj = &bts->gprs.cell;
747 break;
748 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100749 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200750 return NULL;
751 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
752 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000753 }
754 return obj;
755}
756
757/* Update the administrative state of a given object in our in-memory data
758 * structures and send an event to the higher layer */
759static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
760 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
761{
Harald Welteaeedeb42009-05-01 13:08:14 +0000762 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000763 void *obj;
764 int rc;
765
Harald Weltee0590df2009-02-15 03:34:15 +0000766 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100767 if (!obj)
768 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000769 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
770 if (!nm_state)
771 return -1;
772
773 new_state = *nm_state;
774 new_state.administrative = adm_state;
775
776 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
777
778 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000779
780 return rc;
781}
782
Harald Welte97ed1e72009-02-06 13:38:02 +0000783static int abis_nm_rx_statechg_rep(struct msgb *mb)
784{
Harald Weltee0590df2009-02-15 03:34:15 +0000785 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000786 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000787 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000788 struct tlv_parsed tp;
789 struct gsm_nm_state *nm_state, new_state;
790 int rc;
791
Harald Welte23897662009-05-01 14:52:51 +0000792 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000793
Harald Welte8b697c72009-06-05 19:18:45 +0000794 memset(&new_state, 0, sizeof(new_state));
795
Harald Weltee0590df2009-02-15 03:34:15 +0000796 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
797 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100798 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000799 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000800 }
Harald Weltee0590df2009-02-15 03:34:15 +0000801
802 new_state = *nm_state;
803
Harald Welte03133942009-02-18 19:51:53 +0000804 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000805 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
806 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000807 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000808 }
809 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000810 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
811 new_state.availability = 0xff;
812 else
813 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000814 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000815 new_state.availability);
816 }
817 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
818 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200819 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000820 }
821 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000822
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100823 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
824 new_state.operational != nm_state->operational ||
825 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000826 /* Update the operational state of a given object in our in-memory data
827 * structures and send an event to the higher layer */
828 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
829 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100830 nm_state->operational = new_state.operational;
831 nm_state->availability = new_state.availability;
832 if (nm_state->administrative == 0)
833 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000834 }
835#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000836 if (op_state == 1) {
837 /* try to enable objects that are disabled */
838 abis_nm_opstart(bts, foh->obj_class,
839 foh->obj_inst.bts_nr,
840 foh->obj_inst.trx_nr,
841 foh->obj_inst.ts_nr);
842 }
Harald Weltee0590df2009-02-15 03:34:15 +0000843#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000844 return 0;
845}
846
Harald Welte0db97b22009-05-01 17:22:47 +0000847static int rx_fail_evt_rep(struct msgb *mb)
848{
849 struct abis_om_hdr *oh = msgb_l2(mb);
850 struct abis_om_fom_hdr *foh = msgb_l3(mb);
851 struct tlv_parsed tp;
852
853 DEBUGPC(DNM, "Failure Event Report ");
854
855 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
856
857 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
858 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
859 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
860 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
861
862 DEBUGPC(DNM, "\n");
863
864 return 0;
865}
866
Harald Welte97ed1e72009-02-06 13:38:02 +0000867static int abis_nm_rcvmsg_report(struct msgb *mb)
868{
869 struct abis_om_fom_hdr *foh = msgb_l3(mb);
870 u_int8_t mt = foh->msg_type;
871
Harald Weltea8bd6d42009-10-20 09:56:18 +0200872 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000873
Harald Welte97ed1e72009-02-06 13:38:02 +0000874 //nmh->cfg->report_cb(mb, foh);
875
876 switch (mt) {
877 case NM_MT_STATECHG_EVENT_REP:
878 return abis_nm_rx_statechg_rep(mb);
879 break;
Harald Welte34a99682009-02-13 02:41:40 +0000880 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000881 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000882 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000883 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000884 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000885 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000886 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000887 break;
Harald Weltec7310382009-08-08 00:02:36 +0200888 case NM_MT_TEST_REP:
889 DEBUGPC(DNM, "Test Report\n");
890 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
891 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000892 default:
Harald Welte23897662009-05-01 14:52:51 +0000893 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000894 break;
895
Harald Welte97ed1e72009-02-06 13:38:02 +0000896 };
897
Harald Welte97ed1e72009-02-06 13:38:02 +0000898 return 0;
899}
900
Harald Welte34a99682009-02-13 02:41:40 +0000901/* Activate the specified software into the BTS */
902static 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 +0200903 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000904{
905 struct abis_om_hdr *oh;
906 struct msgb *msg = nm_msgb_alloc();
907 u_int8_t len = swdesc_len;
908 u_int8_t *trailer;
909
910 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
911 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
912
913 trailer = msgb_put(msg, swdesc_len);
914 memcpy(trailer, sw_desc, swdesc_len);
915
916 return abis_nm_sendmsg(bts, msg);
917}
918
919static int abis_nm_rx_sw_act_req(struct msgb *mb)
920{
921 struct abis_om_hdr *oh = msgb_l2(mb);
922 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200923 struct tlv_parsed tp;
924 const u_int8_t *sw_config;
925 int sw_config_len;
926 int file_id_len;
Harald Welte5c1e4582009-02-15 11:57:29 +0000927 int nack = 0;
Harald Welte34a99682009-02-13 02:41:40 +0000928 int ret;
929
Harald Weltea8bd6d42009-10-20 09:56:18 +0200930 debugp_foh(foh);
931
932 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000933
Harald Welte5c1e4582009-02-15 11:57:29 +0000934 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
935 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
936 nack = 1;
937 } else
938 DEBUGPC(DNM, "ACKing and Activating\n");
939
940 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000941 foh->obj_inst.bts_nr,
942 foh->obj_inst.trx_nr,
Harald Welte5c1e4582009-02-15 11:57:29 +0000943 foh->obj_inst.ts_nr, nack,
Harald Welte34a99682009-02-13 02:41:40 +0000944 foh->data, oh->length-sizeof(*foh));
945
Harald Welte5c1e4582009-02-15 11:57:29 +0000946 if (nack)
947 return ret;
948
Mike Habena03f9772009-10-01 14:56:13 +0200949 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
950 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
951 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
952 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
953 DEBUGP(DNM, "SW config not found! Can't continue.\n");
954 return -EINVAL;
955 } else {
956 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
957 }
958
959 if (sw_config[0] != NM_ATT_SW_DESCR)
960 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
961 if (sw_config[1] != NM_ATT_FILE_ID)
962 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
963 file_id_len = sw_config[2] * 256 + sw_config[3];
964
965 /* Assumes first SW file in list is the one to be activated */
966 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000967 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
968 foh->obj_inst.bts_nr,
969 foh->obj_inst.trx_nr,
970 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200971 sw_config + 4,
972 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000973}
974
Harald Weltee0590df2009-02-15 03:34:15 +0000975/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
976static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
977{
978 struct abis_om_hdr *oh = msgb_l2(mb);
979 struct abis_om_fom_hdr *foh = msgb_l3(mb);
980 struct tlv_parsed tp;
981 u_int8_t adm_state;
982
Harald Welte03133942009-02-18 19:51:53 +0000983 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000984 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
985 return -EINVAL;
986
987 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
988
989 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
990}
991
Harald Welteee670472009-02-22 21:58:49 +0000992static int abis_nm_rx_lmt_event(struct msgb *mb)
993{
994 struct abis_om_hdr *oh = msgb_l2(mb);
995 struct abis_om_fom_hdr *foh = msgb_l3(mb);
996 struct tlv_parsed tp;
997
998 DEBUGP(DNM, "LMT Event ");
999 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1000 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
1001 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
1002 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
1003 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
1004 }
1005 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
1006 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
1007 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
1008 DEBUGPC(DNM, "Level=%u ", level);
1009 }
1010 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
1011 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
1012 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1013 DEBUGPC(DNM, "Username=%s ", name);
1014 }
1015 DEBUGPC(DNM, "\n");
1016 /* FIXME: parse LMT LOGON TIME */
1017 return 0;
1018}
1019
Harald Welte52b1f982008-12-23 20:25:15 +00001020/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001021static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001022{
Harald Welte6c96ba52009-05-01 13:03:40 +00001023 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001024 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1025 u_int8_t mt = foh->msg_type;
1026
1027 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001028 if (is_report(mt))
1029 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001030
Harald Welte4724f992009-01-18 18:01:49 +00001031 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1032 return abis_nm_rcvmsg_sw(mb);
1033
Harald Welte78fc0d42009-02-19 02:50:57 +00001034 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +00001035 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001036
Harald Weltea8bd6d42009-10-20 09:56:18 +02001037 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001038
Harald Welte78fc0d42009-02-19 02:50:57 +00001039 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +02001040 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +00001041 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +00001042 else
Harald Welte4bd0a982009-10-08 20:18:59 +02001043 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +00001044
1045 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1046 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1047 DEBUGPC(DNM, "CAUSE=%s\n",
1048 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1049 else
1050 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001051
Harald Welted8cfc902009-11-17 06:09:56 +01001052 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001053 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001054 }
Harald Weltead384642008-12-26 10:20:07 +00001055#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001056 /* check if last message is to be acked */
1057 if (is_ack_nack(nmh->last_msgtype)) {
1058 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001059 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001060 /* we got our ACK, continue sending the next msg */
1061 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1062 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001063 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001064 /* FIXME: somehow signal this to the caller */
1065 } else {
1066 /* really strange things happen */
1067 return -EINVAL;
1068 }
1069 }
Harald Weltead384642008-12-26 10:20:07 +00001070#endif
1071
Harald Welte97ed1e72009-02-06 13:38:02 +00001072 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001073 case NM_MT_CHG_ADM_STATE_ACK:
1074 return abis_nm_rx_chg_adm_state_ack(mb);
1075 break;
Harald Welte34a99682009-02-13 02:41:40 +00001076 case NM_MT_SW_ACT_REQ:
1077 return abis_nm_rx_sw_act_req(mb);
1078 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001079 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001080 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001081 break;
Harald Welte1989c082009-08-06 17:58:31 +02001082 case NM_MT_CONN_MDROP_LINK_ACK:
1083 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1084 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001085 case NM_MT_IPACC_RESTART_ACK:
1086 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1087 break;
1088 case NM_MT_IPACC_RESTART_NACK:
1089 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1090 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001091 }
1092
Harald Weltead384642008-12-26 10:20:07 +00001093 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001094}
1095
Harald Welte677c21f2009-02-17 13:22:23 +00001096static int abis_nm_rx_ipacc(struct msgb *mb);
1097
1098static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1099{
1100 int rc;
1101 int bts_type = mb->trx->bts->type;
1102
1103 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001104 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001105 rc = abis_nm_rx_ipacc(mb);
1106 break;
1107 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001108 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1109 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001110 rc = 0;
1111 break;
1112 }
1113
1114 return rc;
1115}
1116
Harald Welte52b1f982008-12-23 20:25:15 +00001117/* High-Level API */
1118/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001119int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001120{
Harald Welte52b1f982008-12-23 20:25:15 +00001121 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001122 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001123
1124 /* Various consistency checks */
1125 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001126 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001127 oh->placement);
1128 return -EINVAL;
1129 }
1130 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001131 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001132 oh->sequence);
1133 return -EINVAL;
1134 }
Harald Welte702d8702008-12-26 20:25:35 +00001135#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001136 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1137 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001138 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001139 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001140 oh->length + sizeof(*oh), l2_len);
1141 return -EINVAL;
1142 }
Harald Welte702d8702008-12-26 20:25:35 +00001143 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001144 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 +00001145#endif
Harald Weltead384642008-12-26 10:20:07 +00001146 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001147
1148 switch (oh->mdisc) {
1149 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001150 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001151 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001152 case ABIS_OM_MDISC_MANUF:
1153 rc = abis_nm_rcvmsg_manuf(msg);
1154 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001155 case ABIS_OM_MDISC_MMI:
1156 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001157 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001158 oh->mdisc);
1159 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001160 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001161 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001162 oh->mdisc);
1163 return -EINVAL;
1164 }
1165
Harald Weltead384642008-12-26 10:20:07 +00001166 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001167 return rc;
1168}
1169
1170#if 0
1171/* initialized all resources */
1172struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1173{
1174 struct abis_nm_h *nmh;
1175
1176 nmh = malloc(sizeof(*nmh));
1177 if (!nmh)
1178 return NULL;
1179
1180 nmh->cfg = cfg;
1181
1182 return nmh;
1183}
1184
1185/* free all resources */
1186void abis_nm_fini(struct abis_nm_h *nmh)
1187{
1188 free(nmh);
1189}
1190#endif
1191
1192/* Here we are trying to define a high-level API that can be used by
1193 * the actual BSC implementation. However, the architecture is currently
1194 * still under design. Ideally the calls to this API would be synchronous,
1195 * while the underlying stack behind the APi runs in a traditional select
1196 * based state machine.
1197 */
1198
Harald Welte4724f992009-01-18 18:01:49 +00001199/* 6.2 Software Load: */
1200enum sw_state {
1201 SW_STATE_NONE,
1202 SW_STATE_WAIT_INITACK,
1203 SW_STATE_WAIT_SEGACK,
1204 SW_STATE_WAIT_ENDACK,
1205 SW_STATE_WAIT_ACTACK,
1206 SW_STATE_ERROR,
1207};
Harald Welte52b1f982008-12-23 20:25:15 +00001208
Harald Welte52b1f982008-12-23 20:25:15 +00001209struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001210 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001211 gsm_cbfn *cbfn;
1212 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001213 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001214
Harald Welte52b1f982008-12-23 20:25:15 +00001215 /* this will become part of the SW LOAD INITIATE */
1216 u_int8_t obj_class;
1217 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001218
1219 u_int8_t file_id[255];
1220 u_int8_t file_id_len;
1221
1222 u_int8_t file_version[255];
1223 u_int8_t file_version_len;
1224
1225 u_int8_t window_size;
1226 u_int8_t seg_in_window;
1227
1228 int fd;
1229 FILE *stream;
1230 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001231 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001232};
1233
Harald Welte4724f992009-01-18 18:01:49 +00001234static struct abis_nm_sw g_sw;
1235
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001236static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1237{
1238 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1239 msgb_v_put(msg, NM_ATT_SW_DESCR);
1240 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1241 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1242 sw->file_version);
1243 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1244 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1245 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1246 sw->file_version);
1247 } else {
1248 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1249 }
1250}
1251
Harald Welte4724f992009-01-18 18:01:49 +00001252/* 6.2.1 / 8.3.1: Load Data Initiate */
1253static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001254{
Harald Welte4724f992009-01-18 18:01:49 +00001255 struct abis_om_hdr *oh;
1256 struct msgb *msg = nm_msgb_alloc();
1257 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1258
1259 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1260 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1261 sw->obj_instance[0], sw->obj_instance[1],
1262 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001263
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001264 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001265 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1266
1267 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001268}
1269
Harald Welte1602ade2009-01-29 21:12:39 +00001270static int is_last_line(FILE *stream)
1271{
1272 char next_seg_buf[256];
1273 long pos;
1274
1275 /* check if we're sending the last line */
1276 pos = ftell(stream);
1277 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1278 fseek(stream, pos, SEEK_SET);
1279 return 1;
1280 }
1281
1282 fseek(stream, pos, SEEK_SET);
1283 return 0;
1284}
1285
Harald Welte4724f992009-01-18 18:01:49 +00001286/* 6.2.2 / 8.3.2 Load Data Segment */
1287static int sw_load_segment(struct abis_nm_sw *sw)
1288{
1289 struct abis_om_hdr *oh;
1290 struct msgb *msg = nm_msgb_alloc();
1291 char seg_buf[256];
1292 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001293 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001294 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001295
1296 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001297
1298 switch (sw->bts->type) {
1299 case GSM_BTS_TYPE_BS11:
1300 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1301 perror("fgets reading segment");
1302 return -EINVAL;
1303 }
1304 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001305
1306 /* check if we're sending the last line */
1307 sw->last_seg = is_last_line(sw->stream);
1308 if (sw->last_seg)
1309 seg_buf[1] = 0;
1310 else
1311 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001312
1313 len = strlen(line_buf) + 2;
1314 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1315 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1316 /* BS11 wants CR + LF in excess of the TLV length !?! */
1317 tlv[1] -= 2;
1318
1319 /* we only now know the exact length for the OM hdr */
1320 len = strlen(line_buf)+2;
1321 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001322 case GSM_BTS_TYPE_NANOBTS: {
1323 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1324 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1325 if (len < 0) {
1326 perror("read failed");
1327 return -EINVAL;
1328 }
1329
1330 if (len != IPACC_SEGMENT_SIZE)
1331 sw->last_seg = 1;
1332
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001333 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001334 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1335 len += 3;
1336 break;
1337 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001338 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001339 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001340 /* FIXME: Other BTS types */
1341 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001342 }
Harald Welte4724f992009-01-18 18:01:49 +00001343
Harald Welte4724f992009-01-18 18:01:49 +00001344 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1345 sw->obj_instance[0], sw->obj_instance[1],
1346 sw->obj_instance[2]);
1347
1348 return abis_nm_sendmsg(sw->bts, msg);
1349}
1350
1351/* 6.2.4 / 8.3.4 Load Data End */
1352static int sw_load_end(struct abis_nm_sw *sw)
1353{
1354 struct abis_om_hdr *oh;
1355 struct msgb *msg = nm_msgb_alloc();
1356 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1357
1358 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1359 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1360 sw->obj_instance[0], sw->obj_instance[1],
1361 sw->obj_instance[2]);
1362
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001363 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001364 return abis_nm_sendmsg(sw->bts, msg);
1365}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001366
Harald Welte52b1f982008-12-23 20:25:15 +00001367/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001368static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001369{
Harald Welte4724f992009-01-18 18:01:49 +00001370 struct abis_om_hdr *oh;
1371 struct msgb *msg = nm_msgb_alloc();
1372 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001373
Harald Welte4724f992009-01-18 18:01:49 +00001374 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1375 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1376 sw->obj_instance[0], sw->obj_instance[1],
1377 sw->obj_instance[2]);
1378
1379 /* FIXME: this is BS11 specific format */
1380 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1381 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1382 sw->file_version);
1383
1384 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001385}
Harald Welte4724f992009-01-18 18:01:49 +00001386
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001387struct sdp_firmware {
1388 char magic[4];
1389 char more_magic[4];
1390 unsigned int header_length;
1391 unsigned int file_length;
1392} __attribute__ ((packed));
1393
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001394static int parse_sdp_header(struct abis_nm_sw *sw)
1395{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001396 struct sdp_firmware firmware_header;
1397 int rc;
1398 struct stat stat;
1399
1400 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1401 if (rc != sizeof(firmware_header)) {
1402 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1403 return -1;
1404 }
1405
1406 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1407 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1408 return -1;
1409 }
1410
1411 if (firmware_header.more_magic[0] != 0x10 ||
1412 firmware_header.more_magic[1] != 0x02 ||
1413 firmware_header.more_magic[2] != 0x00 ||
1414 firmware_header.more_magic[3] != 0x00) {
1415 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1416 return -1;
1417 }
1418
1419
1420 if (fstat(sw->fd, &stat) == -1) {
1421 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1422 return -1;
1423 }
1424
1425 if (ntohl(firmware_header.file_length) != stat.st_size) {
1426 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1427 return -1;
1428 }
1429
1430 /* go back to the start as we checked the whole filesize.. */
1431 lseek(sw->fd, 0l, SEEK_SET);
1432 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1433 "There might be checksums in the file that are not\n"
1434 "verified and incomplete firmware might be flashed.\n"
1435 "There is absolutely no WARRANTY that flashing will\n"
1436 "work.\n");
1437 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001438}
1439
Harald Welte4724f992009-01-18 18:01:49 +00001440static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1441{
1442 char file_id[12+1];
1443 char file_version[80+1];
1444 int rc;
1445
1446 sw->fd = open(fname, O_RDONLY);
1447 if (sw->fd < 0)
1448 return sw->fd;
1449
1450 switch (sw->bts->type) {
1451 case GSM_BTS_TYPE_BS11:
1452 sw->stream = fdopen(sw->fd, "r");
1453 if (!sw->stream) {
1454 perror("fdopen");
1455 return -1;
1456 }
1457 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001458 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001459 file_id, file_version);
1460 if (rc != 2) {
1461 perror("parsing header line of software file");
1462 return -1;
1463 }
1464 strcpy((char *)sw->file_id, file_id);
1465 sw->file_id_len = strlen(file_id);
1466 strcpy((char *)sw->file_version, file_version);
1467 sw->file_version_len = strlen(file_version);
1468 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001469 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001470 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001471 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001472 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001473 rc = parse_sdp_header(sw);
1474 if (rc < 0) {
1475 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1476 return -1;
1477 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001478
1479 strcpy((char *)sw->file_id, "id");
1480 sw->file_id_len = 3;
1481 strcpy((char *)sw->file_version, "version");
1482 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001483 break;
Harald Welte4724f992009-01-18 18:01:49 +00001484 default:
1485 /* We don't know how to treat them yet */
1486 close(sw->fd);
1487 return -EINVAL;
1488 }
1489
1490 return 0;
1491}
1492
1493static void sw_close_file(struct abis_nm_sw *sw)
1494{
1495 switch (sw->bts->type) {
1496 case GSM_BTS_TYPE_BS11:
1497 fclose(sw->stream);
1498 break;
1499 default:
1500 close(sw->fd);
1501 break;
1502 }
1503}
1504
1505/* Fill the window */
1506static int sw_fill_window(struct abis_nm_sw *sw)
1507{
1508 int rc;
1509
1510 while (sw->seg_in_window < sw->window_size) {
1511 rc = sw_load_segment(sw);
1512 if (rc < 0)
1513 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001514 if (sw->last_seg)
1515 break;
Harald Welte4724f992009-01-18 18:01:49 +00001516 }
1517 return 0;
1518}
1519
1520/* callback function from abis_nm_rcvmsg() handler */
1521static int abis_nm_rcvmsg_sw(struct msgb *mb)
1522{
1523 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1524 int rc = -1;
1525 struct abis_nm_sw *sw = &g_sw;
1526 enum sw_state old_state = sw->state;
1527
Harald Welte3ffd1372009-02-01 22:15:49 +00001528 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001529
1530 switch (sw->state) {
1531 case SW_STATE_WAIT_INITACK:
1532 switch (foh->msg_type) {
1533 case NM_MT_LOAD_INIT_ACK:
1534 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001535 if (sw->cbfn)
1536 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1537 NM_MT_LOAD_INIT_ACK, mb,
1538 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001539 rc = sw_fill_window(sw);
1540 sw->state = SW_STATE_WAIT_SEGACK;
1541 break;
1542 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001543 if (sw->forced) {
1544 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1545 "Init NACK\n");
1546 if (sw->cbfn)
1547 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1548 NM_MT_LOAD_INIT_ACK, mb,
1549 sw->cb_data, NULL);
1550 rc = sw_fill_window(sw);
1551 sw->state = SW_STATE_WAIT_SEGACK;
1552 } else {
1553 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001554 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001555 if (sw->cbfn)
1556 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1557 NM_MT_LOAD_INIT_NACK, mb,
1558 sw->cb_data, NULL);
1559 sw->state = SW_STATE_ERROR;
1560 }
Harald Welte4724f992009-01-18 18:01:49 +00001561 break;
1562 }
1563 break;
1564 case SW_STATE_WAIT_SEGACK:
1565 switch (foh->msg_type) {
1566 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001567 if (sw->cbfn)
1568 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1569 NM_MT_LOAD_SEG_ACK, mb,
1570 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001571 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001572 if (!sw->last_seg) {
1573 /* fill window with more segments */
1574 rc = sw_fill_window(sw);
1575 sw->state = SW_STATE_WAIT_SEGACK;
1576 } else {
1577 /* end the transfer */
1578 sw->state = SW_STATE_WAIT_ENDACK;
1579 rc = sw_load_end(sw);
1580 }
Harald Welte4724f992009-01-18 18:01:49 +00001581 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001582 case NM_MT_LOAD_ABORT:
1583 if (sw->cbfn)
1584 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1585 NM_MT_LOAD_ABORT, mb,
1586 sw->cb_data, NULL);
1587 break;
Harald Welte4724f992009-01-18 18:01:49 +00001588 }
1589 break;
1590 case SW_STATE_WAIT_ENDACK:
1591 switch (foh->msg_type) {
1592 case NM_MT_LOAD_END_ACK:
1593 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001594 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1595 sw->bts->nr);
1596 sw->state = SW_STATE_NONE;
1597 if (sw->cbfn)
1598 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1599 NM_MT_LOAD_END_ACK, mb,
1600 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001601 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001602 break;
1603 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001604 if (sw->forced) {
1605 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1606 "End NACK\n");
1607 sw->state = SW_STATE_NONE;
1608 if (sw->cbfn)
1609 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1610 NM_MT_LOAD_END_ACK, mb,
1611 sw->cb_data, NULL);
1612 } else {
1613 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001614 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001615 sw->state = SW_STATE_ERROR;
1616 if (sw->cbfn)
1617 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1618 NM_MT_LOAD_END_NACK, mb,
1619 sw->cb_data, NULL);
1620 }
Harald Welte4724f992009-01-18 18:01:49 +00001621 break;
1622 }
1623 case SW_STATE_WAIT_ACTACK:
1624 switch (foh->msg_type) {
1625 case NM_MT_ACTIVATE_SW_ACK:
1626 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001627 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001628 sw->state = SW_STATE_NONE;
1629 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001630 if (sw->cbfn)
1631 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1632 NM_MT_ACTIVATE_SW_ACK, mb,
1633 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001634 break;
1635 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001636 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001637 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001638 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001639 if (sw->cbfn)
1640 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1641 NM_MT_ACTIVATE_SW_NACK, mb,
1642 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001643 break;
1644 }
1645 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001646 switch (foh->msg_type) {
1647 case NM_MT_ACTIVATE_SW_ACK:
1648 rc = 0;
1649 break;
1650 }
1651 break;
Harald Welte4724f992009-01-18 18:01:49 +00001652 case SW_STATE_ERROR:
1653 break;
1654 }
1655
1656 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001657 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001658 foh->msg_type, old_state, sw->state);
1659
1660 return rc;
1661}
1662
1663/* Load the specified software into the BTS */
1664int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001665 u_int8_t win_size, int forced,
1666 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001667{
1668 struct abis_nm_sw *sw = &g_sw;
1669 int rc;
1670
Harald Welte5e4d1b32009-02-01 13:36:56 +00001671 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1672 bts->nr, fname);
1673
Harald Welte4724f992009-01-18 18:01:49 +00001674 if (sw->state != SW_STATE_NONE)
1675 return -EBUSY;
1676
1677 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001678
1679 switch (bts->type) {
1680 case GSM_BTS_TYPE_BS11:
1681 sw->obj_class = NM_OC_SITE_MANAGER;
1682 sw->obj_instance[0] = 0xff;
1683 sw->obj_instance[1] = 0xff;
1684 sw->obj_instance[2] = 0xff;
1685 break;
1686 case GSM_BTS_TYPE_NANOBTS:
1687 sw->obj_class = NM_OC_BASEB_TRANSC;
1688 sw->obj_instance[0] = 0x00;
1689 sw->obj_instance[1] = 0x00;
1690 sw->obj_instance[2] = 0xff;
1691 break;
1692 case GSM_BTS_TYPE_UNKNOWN:
1693 default:
1694 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1695 return -1;
1696 break;
1697 }
Harald Welte4724f992009-01-18 18:01:49 +00001698 sw->window_size = win_size;
1699 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001700 sw->cbfn = cbfn;
1701 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001702 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001703
1704 rc = sw_open_file(sw, fname);
1705 if (rc < 0) {
1706 sw->state = SW_STATE_NONE;
1707 return rc;
1708 }
1709
1710 return sw_load_init(sw);
1711}
Harald Welte52b1f982008-12-23 20:25:15 +00001712
Harald Welte1602ade2009-01-29 21:12:39 +00001713int abis_nm_software_load_status(struct gsm_bts *bts)
1714{
1715 struct abis_nm_sw *sw = &g_sw;
1716 struct stat st;
1717 int rc, percent;
1718
1719 rc = fstat(sw->fd, &st);
1720 if (rc < 0) {
1721 perror("ERROR during stat");
1722 return rc;
1723 }
1724
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001725 if (sw->stream)
1726 percent = (ftell(sw->stream) * 100) / st.st_size;
1727 else
1728 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001729 return percent;
1730}
1731
Harald Welte5e4d1b32009-02-01 13:36:56 +00001732/* Activate the specified software into the BTS */
1733int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1734 gsm_cbfn *cbfn, void *cb_data)
1735{
1736 struct abis_nm_sw *sw = &g_sw;
1737 int rc;
1738
1739 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1740 bts->nr, fname);
1741
1742 if (sw->state != SW_STATE_NONE)
1743 return -EBUSY;
1744
1745 sw->bts = bts;
1746 sw->obj_class = NM_OC_SITE_MANAGER;
1747 sw->obj_instance[0] = 0xff;
1748 sw->obj_instance[1] = 0xff;
1749 sw->obj_instance[2] = 0xff;
1750 sw->state = SW_STATE_WAIT_ACTACK;
1751 sw->cbfn = cbfn;
1752 sw->cb_data = cb_data;
1753
1754 /* Open the file in order to fill some sw struct members */
1755 rc = sw_open_file(sw, fname);
1756 if (rc < 0) {
1757 sw->state = SW_STATE_NONE;
1758 return rc;
1759 }
1760 sw_close_file(sw);
1761
1762 return sw_activate(sw);
1763}
1764
Harald Welte8470bf22008-12-25 23:28:35 +00001765static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001766 u_int8_t ts_nr, u_int8_t subslot_nr)
1767{
Harald Welteadaf08b2009-01-18 11:08:10 +00001768 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001769 ch->bts_port = bts_port;
1770 ch->timeslot = ts_nr;
1771 ch->subslot = subslot_nr;
1772}
1773
1774int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1775 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1776 u_int8_t tei)
1777{
1778 struct abis_om_hdr *oh;
1779 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001780 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001781 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001782
1783 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1784 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1785 bts->bts_nr, trx_nr, 0xff);
1786
Harald Welte8470bf22008-12-25 23:28:35 +00001787 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001788
1789 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1790 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1791
1792 return abis_nm_sendmsg(bts, msg);
1793}
1794
1795/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1796int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1797 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1798{
Harald Welte8470bf22008-12-25 23:28:35 +00001799 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001800 struct abis_om_hdr *oh;
1801 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001802 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001803
1804 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001805 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001806 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1807
1808 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1809 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1810
1811 return abis_nm_sendmsg(bts, msg);
1812}
1813
1814#if 0
1815int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1816 struct abis_nm_abis_channel *chan)
1817{
1818}
1819#endif
1820
1821int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1822 u_int8_t e1_port, u_int8_t e1_timeslot,
1823 u_int8_t e1_subslot)
1824{
1825 struct gsm_bts *bts = ts->trx->bts;
1826 struct abis_om_hdr *oh;
1827 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001828 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001829
1830 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1831 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001832 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001833
1834 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1835 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1836
Harald Weltef325eb42009-02-19 17:07:39 +00001837 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1838 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001839 e1_port, e1_timeslot, e1_subslot);
1840
Harald Welte52b1f982008-12-23 20:25:15 +00001841 return abis_nm_sendmsg(bts, msg);
1842}
1843
1844#if 0
1845int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1846 struct abis_nm_abis_channel *chan,
1847 u_int8_t subchan)
1848{
1849}
1850#endif
1851
Harald Welte22af0db2009-02-14 15:41:08 +00001852/* Chapter 8.6.1 */
1853int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1854{
1855 struct abis_om_hdr *oh;
1856 struct msgb *msg = nm_msgb_alloc();
1857 u_int8_t *cur;
1858
1859 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1860
1861 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001862 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 +00001863 cur = msgb_put(msg, attr_len);
1864 memcpy(cur, attr, attr_len);
1865
1866 return abis_nm_sendmsg(bts, msg);
1867}
1868
1869/* Chapter 8.6.2 */
1870int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1871{
1872 struct abis_om_hdr *oh;
1873 struct msgb *msg = nm_msgb_alloc();
1874 u_int8_t *cur;
1875
1876 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1877
1878 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1879 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001880 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001881 cur = msgb_put(msg, attr_len);
1882 memcpy(cur, attr, attr_len);
1883
1884 return abis_nm_sendmsg(trx->bts, msg);
1885}
1886
Harald Welte39c7deb2009-08-09 21:49:48 +02001887static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1888{
1889 int i;
1890
1891 /* As it turns out, the BS-11 has some very peculiar restrictions
1892 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301893 switch (ts->trx->bts->type) {
1894 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001895 switch (chan_comb) {
1896 case NM_CHANC_TCHHalf:
1897 case NM_CHANC_TCHHalf2:
1898 /* not supported */
1899 return -EINVAL;
1900 case NM_CHANC_SDCCH:
1901 /* only one SDCCH/8 per TRX */
1902 for (i = 0; i < TRX_NR_TS; i++) {
1903 if (i == ts->nr)
1904 continue;
1905 if (ts->trx->ts[i].nm_chan_comb ==
1906 NM_CHANC_SDCCH)
1907 return -EINVAL;
1908 }
1909 /* not allowed for TS0 of BCCH-TRX */
1910 if (ts->trx == ts->trx->bts->c0 &&
1911 ts->nr == 0)
1912 return -EINVAL;
1913 /* not on the same TRX that has a BCCH+SDCCH4
1914 * combination */
1915 if (ts->trx == ts->trx->bts->c0 &&
1916 (ts->trx->ts[0].nm_chan_comb == 5 ||
1917 ts->trx->ts[0].nm_chan_comb == 8))
1918 return -EINVAL;
1919 break;
1920 case NM_CHANC_mainBCCH:
1921 case NM_CHANC_BCCHComb:
1922 /* allowed only for TS0 of C0 */
1923 if (ts->trx != ts->trx->bts->c0 ||
1924 ts->nr != 0)
1925 return -EINVAL;
1926 break;
1927 case NM_CHANC_BCCH:
1928 /* allowed only for TS 2/4/6 of C0 */
1929 if (ts->trx != ts->trx->bts->c0)
1930 return -EINVAL;
1931 if (ts->nr != 2 && ts->nr != 4 &&
1932 ts->nr != 6)
1933 return -EINVAL;
1934 break;
1935 case 8: /* this is not like 08.58, but in fact
1936 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1937 /* FIXME: only one CBCH allowed per cell */
1938 break;
1939 }
Harald Welted6575f92009-12-02 02:45:23 +05301940 break;
1941 case GSM_BTS_TYPE_NANOBTS:
1942 switch (ts->nr) {
1943 case 0:
1944 if (ts->trx->nr == 0) {
1945 /* only on TRX0 */
1946 switch (chan_comb) {
1947 case NM_CHANC_BCCH:
1948 case NM_CHANC_mainBCCH:
1949 case NM_CHANC_BCCHComb:
1950 return 0;
1951 break;
1952 default:
1953 return -EINVAL;
1954 }
1955 } else {
1956 switch (chan_comb) {
1957 case NM_CHANC_TCHFull:
1958 case NM_CHANC_TCHHalf:
1959 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1960 return 0;
1961 default:
1962 return -EINVAL;
1963 }
1964 }
1965 break;
1966 case 1:
1967 if (ts->trx->nr == 0) {
1968 switch (chan_comb) {
1969 case NM_CHANC_SDCCH_CBCH:
1970 if (ts->trx->ts[0].nm_chan_comb ==
1971 NM_CHANC_mainBCCH)
1972 return 0;
1973 return -EINVAL;
1974 case NM_CHANC_SDCCH:
1975 case NM_CHANC_TCHFull:
1976 case NM_CHANC_TCHHalf:
1977 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1978 case NM_CHANC_IPAC_TCHFull_PDCH:
1979 return 0;
1980 }
1981 } else {
1982 switch (chan_comb) {
1983 case NM_CHANC_SDCCH:
1984 case NM_CHANC_TCHFull:
1985 case NM_CHANC_TCHHalf:
1986 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1987 return 0;
1988 default:
1989 return -EINVAL;
1990 }
1991 }
1992 break;
1993 case 2:
1994 case 3:
1995 case 4:
1996 case 5:
1997 case 6:
1998 case 7:
1999 switch (chan_comb) {
2000 case NM_CHANC_TCHFull:
2001 case NM_CHANC_TCHHalf:
2002 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2003 return 0;
2004 case NM_CHANC_IPAC_PDCH:
2005 case NM_CHANC_IPAC_TCHFull_PDCH:
2006 if (ts->trx->nr == 0)
2007 return 0;
2008 else
2009 return -EINVAL;
2010 }
2011 break;
2012 }
2013 return -EINVAL;
2014 default:
2015 /* unknown BTS type */
2016 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002017 }
2018 return 0;
2019}
2020
Harald Welte22af0db2009-02-14 15:41:08 +00002021/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002022int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2023{
2024 struct gsm_bts *bts = ts->trx->bts;
2025 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002026 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002027 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002028 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002029 u_int8_t len = 2 + 2;
2030
2031 if (bts->type == GSM_BTS_TYPE_BS11)
2032 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002033
Harald Weltef325eb42009-02-19 17:07:39 +00002034 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002035 if (verify_chan_comb(ts, chan_comb) < 0) {
2036 msgb_free(msg);
2037 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2038 return -EINVAL;
2039 }
2040 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002041
Harald Welte52b1f982008-12-23 20:25:15 +00002042 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002043 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002044 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002045 ts->trx->nr, ts->nr);
2046 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00002047 if (bts->type == GSM_BTS_TYPE_BS11)
2048 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002049 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00002050 if (bts->type == GSM_BTS_TYPE_BS11) {
2051 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2052 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2053 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002054 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002055 if (bts->type == GSM_BTS_TYPE_BS11)
2056 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002057
2058 return abis_nm_sendmsg(bts, msg);
2059}
2060
Harald Welte34a99682009-02-13 02:41:40 +00002061int 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 +00002062 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002063{
2064 struct abis_om_hdr *oh;
2065 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002066 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2067 u_int8_t len = att_len;
2068
2069 if (nack) {
2070 len += 2;
2071 msgtype = NM_MT_SW_ACT_REQ_NACK;
2072 }
Harald Welte34a99682009-02-13 02:41:40 +00002073
2074 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002075 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2076
Harald Welte34a99682009-02-13 02:41:40 +00002077 if (attr) {
2078 u_int8_t *ptr = msgb_put(msg, att_len);
2079 memcpy(ptr, attr, att_len);
2080 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002081 if (nack)
2082 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002083
2084 return abis_nm_sendmsg(bts, msg);
2085}
2086
Harald Welte8470bf22008-12-25 23:28:35 +00002087int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002088{
Harald Welte8470bf22008-12-25 23:28:35 +00002089 struct msgb *msg = nm_msgb_alloc();
2090 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002091 u_int8_t *data;
2092
2093 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2094 fill_om_hdr(oh, len);
2095 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002096 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002097
2098 return abis_nm_sendmsg(bts, msg);
2099}
2100
2101/* Siemens specific commands */
2102static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2103{
2104 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002105 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002106
2107 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002108 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002109 0xff, 0xff, 0xff);
2110
2111 return abis_nm_sendmsg(bts, msg);
2112}
2113
Harald Welte34a99682009-02-13 02:41:40 +00002114/* Chapter 8.9.2 */
2115int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2116{
2117 struct abis_om_hdr *oh;
2118 struct msgb *msg = nm_msgb_alloc();
2119
2120 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2121 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2122
Harald Weltea8bd6d42009-10-20 09:56:18 +02002123 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2124 DEBUGPC(DNM, "Sending OPSTART\n");
2125
Harald Welte34a99682009-02-13 02:41:40 +00002126 return abis_nm_sendmsg(bts, msg);
2127}
2128
2129/* Chapter 8.8.5 */
2130int 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 +02002131 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002132{
2133 struct abis_om_hdr *oh;
2134 struct msgb *msg = nm_msgb_alloc();
2135
2136 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2137 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2138 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2139
2140 return abis_nm_sendmsg(bts, msg);
2141}
2142
Harald Welte1989c082009-08-06 17:58:31 +02002143int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2144 u_int8_t e1_port1, u_int8_t ts1)
2145{
2146 struct abis_om_hdr *oh;
2147 struct msgb *msg = nm_msgb_alloc();
2148 u_int8_t *attr;
2149
2150 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2151 e1_port0, ts0, e1_port1, ts1);
2152
2153 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2154 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2155 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2156
2157 attr = msgb_put(msg, 3);
2158 attr[0] = NM_ATT_MDROP_LINK;
2159 attr[1] = e1_port0;
2160 attr[2] = ts0;
2161
2162 attr = msgb_put(msg, 3);
2163 attr[0] = NM_ATT_MDROP_NEXT;
2164 attr[1] = e1_port1;
2165 attr[2] = ts1;
2166
2167 return abis_nm_sendmsg(bts, msg);
2168}
Harald Welte34a99682009-02-13 02:41:40 +00002169
Harald Weltec7310382009-08-08 00:02:36 +02002170/* Chapter 8.7.1 */
2171int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2172 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2173 u_int8_t test_nr, u_int8_t auton_report,
2174 u_int8_t *phys_config, u_int16_t phys_config_len)
2175{
2176 struct abis_om_hdr *oh;
2177 struct msgb *msg = nm_msgb_alloc();
2178 int len = 4; /* 2 TV attributes */
2179
2180 DEBUGP(DNM, "PEFORM TEST\n");
2181
2182 if (phys_config_len)
2183 len += 3 + phys_config_len;
2184
2185 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2186 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2187 obj_class, bts_nr, trx_nr, ts_nr);
2188 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2189 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2190 if (phys_config_len)
2191 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2192 phys_config);
2193
2194 return abis_nm_sendmsg(bts, msg);
2195}
2196
Harald Welte52b1f982008-12-23 20:25:15 +00002197int abis_nm_event_reports(struct gsm_bts *bts, int on)
2198{
2199 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002200 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002201 else
Harald Welte227d4072009-01-03 08:16:25 +00002202 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002203}
2204
Harald Welte47d88ae2009-01-04 12:02:08 +00002205/* Siemens (or BS-11) specific commands */
2206
Harald Welte3ffd1372009-02-01 22:15:49 +00002207int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2208{
2209 if (reconnect == 0)
2210 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2211 else
2212 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2213}
2214
Harald Welteb8427972009-02-05 19:27:17 +00002215int abis_nm_bs11_restart(struct gsm_bts *bts)
2216{
2217 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2218}
2219
2220
Harald Welte268bb402009-02-01 19:11:56 +00002221struct bs11_date_time {
2222 u_int16_t year;
2223 u_int8_t month;
2224 u_int8_t day;
2225 u_int8_t hour;
2226 u_int8_t min;
2227 u_int8_t sec;
2228} __attribute__((packed));
2229
2230
2231void get_bs11_date_time(struct bs11_date_time *aet)
2232{
2233 time_t t;
2234 struct tm *tm;
2235
2236 t = time(NULL);
2237 tm = localtime(&t);
2238 aet->sec = tm->tm_sec;
2239 aet->min = tm->tm_min;
2240 aet->hour = tm->tm_hour;
2241 aet->day = tm->tm_mday;
2242 aet->month = tm->tm_mon;
2243 aet->year = htons(1900 + tm->tm_year);
2244}
2245
Harald Welte05188ee2009-01-18 11:39:08 +00002246int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002247{
Harald Welte4668fda2009-01-03 08:19:29 +00002248 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002249}
2250
Harald Welte05188ee2009-01-18 11:39:08 +00002251int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002252{
2253 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002254 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002255 else
Harald Welte4668fda2009-01-03 08:19:29 +00002256 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002257}
Harald Welte47d88ae2009-01-04 12:02:08 +00002258
Harald Welte05188ee2009-01-18 11:39:08 +00002259int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002260 enum abis_bs11_objtype type, u_int8_t idx,
2261 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002262{
2263 struct abis_om_hdr *oh;
2264 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002265 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002266
2267 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002268 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002269 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002270 cur = msgb_put(msg, attr_len);
2271 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002272
2273 return abis_nm_sendmsg(bts, msg);
2274}
2275
Harald Welte78fc0d42009-02-19 02:50:57 +00002276int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2277 enum abis_bs11_objtype type, u_int8_t idx)
2278{
2279 struct abis_om_hdr *oh;
2280 struct msgb *msg = nm_msgb_alloc();
2281
2282 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2283 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2284 NM_OC_BS11, type, 0, idx);
2285
2286 return abis_nm_sendmsg(bts, msg);
2287}
2288
Harald Welte05188ee2009-01-18 11:39:08 +00002289int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002290{
2291 struct abis_om_hdr *oh;
2292 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002293 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002294
2295 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002296 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002297 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2298 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002299
2300 return abis_nm_sendmsg(bts, msg);
2301}
2302
Harald Welte05188ee2009-01-18 11:39:08 +00002303int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002304{
2305 struct abis_om_hdr *oh;
2306 struct msgb *msg = nm_msgb_alloc();
2307
2308 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2309 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002310 idx, 0xff, 0xff);
2311
2312 return abis_nm_sendmsg(bts, msg);
2313}
2314
2315int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2316{
2317 struct abis_om_hdr *oh;
2318 struct msgb *msg = nm_msgb_alloc();
2319
2320 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2321 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2322 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002323
2324 return abis_nm_sendmsg(bts, msg);
2325}
Harald Welte05188ee2009-01-18 11:39:08 +00002326
Harald Welte78fc0d42009-02-19 02:50:57 +00002327static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2328int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2329{
2330 struct abis_om_hdr *oh;
2331 struct msgb *msg = nm_msgb_alloc();
2332
2333 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2334 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2335 0xff, 0xff, 0xff);
2336 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2337
2338 return abis_nm_sendmsg(bts, msg);
2339}
2340
Harald Welteb6c92ae2009-02-21 20:15:32 +00002341/* like abis_nm_conn_terr_traf + set_tei */
2342int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2343 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2344 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002345{
2346 struct abis_om_hdr *oh;
2347 struct abis_nm_channel *ch;
2348 struct msgb *msg = nm_msgb_alloc();
2349
2350 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002351 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002352 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2353
2354 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2355 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002356 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002357
2358 return abis_nm_sendmsg(bts, msg);
2359}
2360
2361int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2362{
2363 struct abis_om_hdr *oh;
2364 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002365
2366 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002367 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002368 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2369 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2370
2371 return abis_nm_sendmsg(trx->bts, msg);
2372}
2373
Harald Welte78fc0d42009-02-19 02:50:57 +00002374int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2375{
2376 struct abis_om_hdr *oh;
2377 struct msgb *msg = nm_msgb_alloc();
2378 u_int8_t attr = NM_ATT_BS11_TXPWR;
2379
2380 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2381 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2382 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2383 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2384
2385 return abis_nm_sendmsg(trx->bts, msg);
2386}
2387
Harald Welteaaf02d92009-04-29 13:25:57 +00002388int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2389{
2390 struct abis_om_hdr *oh;
2391 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002392 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002393
2394 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2395 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2396 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002397 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002398
2399 return abis_nm_sendmsg(bts, msg);
2400}
2401
Harald Welteef061952009-05-17 12:43:42 +00002402int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2403{
2404 struct abis_om_hdr *oh;
2405 struct msgb *msg = nm_msgb_alloc();
2406 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2407 NM_ATT_BS11_CCLK_TYPE };
2408
2409 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2410 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2411 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2412 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2413
2414 return abis_nm_sendmsg(bts, msg);
2415
2416}
Harald Welteaaf02d92009-04-29 13:25:57 +00002417
Harald Welte268bb402009-02-01 19:11:56 +00002418//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +00002419static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +00002420static const u_int8_t bs11_logon_c9[] = "FACTORY";
2421
Harald Welte1bc09062009-01-18 14:17:52 +00002422int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002423{
2424 struct abis_om_hdr *oh;
2425 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002426 struct bs11_date_time bdt;
2427
2428 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002429
2430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002431 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002432 u_int8_t len = 3*2 + sizeof(bdt)
Harald Welte6f676a32009-01-18 14:27:48 +00002433 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +00002434 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002435 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002436 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002437 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002438 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2439 sizeof(bs11_logon_c8), bs11_logon_c8);
2440 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2441 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +00002442 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002443 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002444 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002445 }
Harald Welte05188ee2009-01-18 11:39:08 +00002446
2447 return abis_nm_sendmsg(bts, msg);
2448}
Harald Welte1bc09062009-01-18 14:17:52 +00002449
2450int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2451{
2452 struct abis_om_hdr *oh;
2453 struct msgb *msg;
2454
2455 if (strlen(password) != 10)
2456 return -EINVAL;
2457
2458 msg = nm_msgb_alloc();
2459 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002460 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002461 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2462 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2463
2464 return abis_nm_sendmsg(bts, msg);
2465}
2466
Harald Weltee69f5fb2009-04-28 16:31:38 +00002467/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2468int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2469{
2470 struct abis_om_hdr *oh;
2471 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002472 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002473
2474 msg = nm_msgb_alloc();
2475 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2476 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2477 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002478
2479 if (locked)
2480 tlv_value = BS11_LI_PLL_LOCKED;
2481 else
2482 tlv_value = BS11_LI_PLL_STANDALONE;
2483
2484 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002485
2486 return abis_nm_sendmsg(bts, msg);
2487}
2488
Harald Welte1bc09062009-01-18 14:17:52 +00002489int abis_nm_bs11_get_state(struct gsm_bts *bts)
2490{
2491 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2492}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002493
2494/* BS11 SWL */
2495
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002496void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002497
Harald Welte5e4d1b32009-02-01 13:36:56 +00002498struct abis_nm_bs11_sw {
2499 struct gsm_bts *bts;
2500 char swl_fname[PATH_MAX];
2501 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002502 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002503 struct llist_head file_list;
2504 gsm_cbfn *user_cb; /* specified by the user */
2505};
2506static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2507
2508struct file_list_entry {
2509 struct llist_head list;
2510 char fname[PATH_MAX];
2511};
2512
2513struct file_list_entry *fl_dequeue(struct llist_head *queue)
2514{
2515 struct llist_head *lh;
2516
2517 if (llist_empty(queue))
2518 return NULL;
2519
2520 lh = queue->next;
2521 llist_del(lh);
2522
2523 return llist_entry(lh, struct file_list_entry, list);
2524}
2525
2526static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2527{
2528 char linebuf[255];
2529 struct llist_head *lh, *lh2;
2530 FILE *swl;
2531 int rc = 0;
2532
2533 swl = fopen(bs11_sw->swl_fname, "r");
2534 if (!swl)
2535 return -ENODEV;
2536
2537 /* zero the stale file list, if any */
2538 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2539 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002540 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002541 }
2542
2543 while (fgets(linebuf, sizeof(linebuf), swl)) {
2544 char file_id[12+1];
2545 char file_version[80+1];
2546 struct file_list_entry *fle;
2547 static char dir[PATH_MAX];
2548
2549 if (strlen(linebuf) < 4)
2550 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002551
Harald Welte5e4d1b32009-02-01 13:36:56 +00002552 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2553 if (rc < 0) {
2554 perror("ERR parsing SWL file");
2555 rc = -EINVAL;
2556 goto out;
2557 }
2558 if (rc < 2)
2559 continue;
2560
Harald Welte470ec292009-06-26 20:25:23 +02002561 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002562 if (!fle) {
2563 rc = -ENOMEM;
2564 goto out;
2565 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002566
2567 /* construct new filename */
2568 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2569 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2570 strcat(fle->fname, "/");
2571 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002572
2573 llist_add_tail(&fle->list, &bs11_sw->file_list);
2574 }
2575
2576out:
2577 fclose(swl);
2578 return rc;
2579}
2580
2581/* bs11 swload specific callback, passed to abis_nm core swload */
2582static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2583 struct msgb *msg, void *data, void *param)
2584{
2585 struct abis_nm_bs11_sw *bs11_sw = data;
2586 struct file_list_entry *fle;
2587 int rc = 0;
2588
Harald Welte5e4d1b32009-02-01 13:36:56 +00002589 switch (event) {
2590 case NM_MT_LOAD_END_ACK:
2591 fle = fl_dequeue(&bs11_sw->file_list);
2592 if (fle) {
2593 /* start download the next file of our file list */
2594 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2595 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002596 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002597 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002598 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002599 } else {
2600 /* activate the SWL */
2601 rc = abis_nm_software_activate(bs11_sw->bts,
2602 bs11_sw->swl_fname,
2603 bs11_swload_cbfn,
2604 bs11_sw);
2605 }
2606 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002607 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002608 case NM_MT_LOAD_END_NACK:
2609 case NM_MT_LOAD_INIT_ACK:
2610 case NM_MT_LOAD_INIT_NACK:
2611 case NM_MT_ACTIVATE_SW_NACK:
2612 case NM_MT_ACTIVATE_SW_ACK:
2613 default:
2614 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002615 if (bs11_sw->user_cb)
2616 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002617 break;
2618 }
2619
2620 return rc;
2621}
2622
2623/* Siemens provides a SWL file that is a mere listing of all the other
2624 * files that are part of a software release. We need to upload first
2625 * the list file, and then each file that is listed in the list file */
2626int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002627 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002628{
2629 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2630 struct file_list_entry *fle;
2631 int rc = 0;
2632
2633 INIT_LLIST_HEAD(&bs11_sw->file_list);
2634 bs11_sw->bts = bts;
2635 bs11_sw->win_size = win_size;
2636 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002637 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002638
2639 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2640 rc = bs11_read_swl_file(bs11_sw);
2641 if (rc < 0)
2642 return rc;
2643
2644 /* dequeue next item in file list */
2645 fle = fl_dequeue(&bs11_sw->file_list);
2646 if (!fle)
2647 return -EINVAL;
2648
2649 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002650 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002651 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002652 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002653 return rc;
2654}
2655
Harald Welte5083b0b2009-02-02 19:20:52 +00002656#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002657static u_int8_t req_attr_btse[] = {
2658 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2659 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2660 NM_ATT_BS11_LMT_USER_NAME,
2661
2662 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2663
2664 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2665
2666 NM_ATT_BS11_SW_LOAD_STORED };
2667
2668static u_int8_t req_attr_btsm[] = {
2669 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2670 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2671 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2672 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002673#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002674
2675static u_int8_t req_attr[] = {
2676 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2677 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002678 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002679
2680int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2681{
2682 struct abis_om_hdr *oh;
2683 struct msgb *msg = nm_msgb_alloc();
2684
2685 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2686 /* SiemensHW CCTRL object */
2687 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2688 0x03, 0x00, 0x00);
2689 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2690
2691 return abis_nm_sendmsg(bts, msg);
2692}
Harald Welte268bb402009-02-01 19:11:56 +00002693
2694int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2695{
2696 struct abis_om_hdr *oh;
2697 struct msgb *msg = nm_msgb_alloc();
2698 struct bs11_date_time aet;
2699
2700 get_bs11_date_time(&aet);
2701 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2702 /* SiemensHW CCTRL object */
2703 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2704 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002705 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002706
2707 return abis_nm_sendmsg(bts, msg);
2708}
Harald Welte5c1e4582009-02-15 11:57:29 +00002709
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002710int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2711{
2712 struct abis_om_hdr *oh;
2713 struct msgb *msg = nm_msgb_alloc();
2714 struct bs11_date_time aet;
2715
2716 get_bs11_date_time(&aet);
2717 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2718 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2719 bport, 0xff, 0x02);
2720 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2721
2722 return abis_nm_sendmsg(bts, msg);
2723}
2724
Harald Welte5c1e4582009-02-15 11:57:29 +00002725/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002726static const char ipaccess_magic[] = "com.ipaccess";
2727
Harald Welte677c21f2009-02-17 13:22:23 +00002728
2729static int abis_nm_rx_ipacc(struct msgb *msg)
2730{
2731 struct abis_om_hdr *oh = msgb_l2(msg);
2732 struct abis_om_fom_hdr *foh;
2733 u_int8_t idstrlen = oh->data[0];
2734 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002735 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002736
2737 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002738 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002739 return -EINVAL;
2740 }
2741
Harald Welte193fefc2009-04-30 15:16:27 +00002742 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002743 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002744
Harald Weltea8bd6d42009-10-20 09:56:18 +02002745 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002746
Harald Welte746d6092009-10-19 22:11:11 +02002747 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002748
Harald Welte677c21f2009-02-17 13:22:23 +00002749 switch (foh->msg_type) {
2750 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002751 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002752 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002753 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002754 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002755 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2756 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002757 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002758 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002759 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002760 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2761 DEBUGPC(DNM, "STREAM=0x%02x ",
2762 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002763 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002764 break;
2765 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002766 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002767 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002768 DEBUGPC(DNM, " CAUSE=%s\n",
2769 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002770 else
2771 DEBUGPC(DNM, "\n");
2772 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002773 case NM_MT_IPACC_SET_NVATTR_ACK:
2774 DEBUGPC(DNM, "SET NVATTR ACK\n");
2775 /* FIXME: decode and show the actual attributes */
2776 break;
2777 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002778 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002779 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002780 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002781 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2782 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002783 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002784 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002785 case NM_MT_IPACC_GET_NVATTR_ACK:
2786 DEBUGPC(DNM, "GET NVATTR ACK\n");
2787 /* FIXME: decode and show the actual attributes */
2788 break;
2789 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002790 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002791 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002792 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002793 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2794 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002795 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002796 break;
Harald Welte15c44172009-10-08 20:15:24 +02002797 case NM_MT_IPACC_SET_ATTR_ACK:
2798 DEBUGPC(DNM, "SET ATTR ACK\n");
2799 break;
2800 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002801 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002802 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002803 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002804 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2805 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002806 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002807 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002808 default:
2809 DEBUGPC(DNM, "unknown\n");
2810 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002811 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002812
2813 /* signal handling */
2814 switch (foh->msg_type) {
2815 case NM_MT_IPACC_RSL_CONNECT_NACK:
2816 case NM_MT_IPACC_SET_NVATTR_NACK:
2817 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002818 signal.bts = msg->trx->bts;
2819 signal.msg_type = foh->msg_type;
2820 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002821 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002822 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002823 signal.bts = msg->trx->bts;
2824 signal.msg_type = foh->msg_type;
2825 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002826 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002827 default:
2828 break;
2829 }
2830
Harald Welte677c21f2009-02-17 13:22:23 +00002831 return 0;
2832}
2833
Harald Welte193fefc2009-04-30 15:16:27 +00002834/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002835int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2836 u_int8_t obj_class, u_int8_t bts_nr,
2837 u_int8_t trx_nr, u_int8_t ts_nr,
2838 u_int8_t *attr, int attr_len)
2839{
2840 struct msgb *msg = nm_msgb_alloc();
2841 struct abis_om_hdr *oh;
2842 struct abis_om_fom_hdr *foh;
2843 u_int8_t *data;
2844
2845 /* construct the 12.21 OM header, observe the erroneous length */
2846 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2847 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2848 oh->mdisc = ABIS_OM_MDISC_MANUF;
2849
2850 /* add the ip.access magic */
2851 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2852 *data++ = sizeof(ipaccess_magic);
2853 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2854
2855 /* fill the 12.21 FOM header */
2856 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2857 foh->msg_type = msg_type;
2858 foh->obj_class = obj_class;
2859 foh->obj_inst.bts_nr = bts_nr;
2860 foh->obj_inst.trx_nr = trx_nr;
2861 foh->obj_inst.ts_nr = ts_nr;
2862
2863 if (attr && attr_len) {
2864 data = msgb_put(msg, attr_len);
2865 memcpy(data, attr, attr_len);
2866 }
2867
2868 return abis_nm_sendmsg(bts, msg);
2869}
Harald Welte677c21f2009-02-17 13:22:23 +00002870
Harald Welte193fefc2009-04-30 15:16:27 +00002871/* set some attributes in NVRAM */
2872int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2873 int attr_len)
2874{
2875 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2876 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2877 attr_len);
2878}
2879
Harald Welte746d6092009-10-19 22:11:11 +02002880int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2881 u_int32_t ip, u_int16_t port, u_int8_t stream)
2882{
2883 struct in_addr ia;
2884 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2885 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2886 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2887
2888 int attr_len = sizeof(attr);
2889
2890 ia.s_addr = htonl(ip);
2891 attr[1] = stream;
2892 attr[3] = port >> 8;
2893 attr[4] = port & 0xff;
2894 *(u_int32_t *)(attr+6) = ia.s_addr;
2895
2896 /* if ip == 0, we use the default IP */
2897 if (ip == 0)
2898 attr_len -= 5;
2899
2900 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002901 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002902
2903 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2904 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2905 trx->nr, 0xff, attr, attr_len);
2906}
2907
Harald Welte193fefc2009-04-30 15:16:27 +00002908/* restart / reboot an ip.access nanoBTS */
2909int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2910{
2911 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2912}
Harald Weltedaef5212009-10-24 10:20:41 +02002913
2914int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2915 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2916 u_int8_t *attr, u_int8_t attr_len)
2917{
2918 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2919 obj_class, bts_nr, trx_nr, ts_nr,
2920 attr, attr_len);
2921}
Harald Welte0f255852009-11-12 14:48:42 +01002922
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002923void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2924{
2925 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2926
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002927 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002928 if (!trx->bts || !trx->bts->oml_link)
2929 return;
2930
2931 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2932 trx->bts->bts_nr, trx->nr, 0xff,
2933 new_state);
2934}
2935
Harald Welte0f255852009-11-12 14:48:42 +01002936static const char *ipacc_testres_names[] = {
2937 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2938 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2939 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2940 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2941 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2942};
2943
2944const char *ipacc_testres_name(u_int8_t res)
2945{
2946 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2947 ipacc_testres_names[res])
2948 return ipacc_testres_names[res];
2949
2950 return "unknown";
2951}
2952
Harald Welteb40a38f2009-11-13 11:56:05 +01002953void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2954{
2955 cid->mcc = (buf[0] & 0xf) * 100;
2956 cid->mcc += (buf[0] >> 4) * 10;
2957 cid->mcc += (buf[1] & 0xf) * 1;
2958
2959 if (buf[1] >> 4 == 0xf) {
2960 cid->mnc = (buf[2] & 0xf) * 10;
2961 cid->mnc += (buf[2] >> 4) * 1;
2962 } else {
2963 cid->mnc = (buf[2] & 0xf) * 100;
2964 cid->mnc += (buf[2] >> 4) * 10;
2965 cid->mnc += (buf[1] >> 4) * 1;
2966 }
2967
Harald Welteaff237d2009-11-13 14:41:52 +01002968 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2969 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002970}
2971
Harald Welte0f255852009-11-12 14:48:42 +01002972/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2973int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2974{
2975 u_int8_t *cur = buf;
2976 u_int16_t len;
2977
2978 memset(binf, 0, sizeof(binf));
2979
2980 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2981 return -EINVAL;
2982 cur++;
2983
2984 len = ntohs(*(u_int16_t *)cur);
2985 cur += 2;
2986
2987 binf->info_type = ntohs(*(u_int16_t *)cur);
2988 cur += 2;
2989
2990 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2991 binf->freq_qual = *cur >> 2;
2992
2993 binf->arfcn = *cur++ & 3 << 8;
2994 binf->arfcn |= *cur++;
2995
2996 if (binf->info_type & IPAC_BINF_RXLEV)
2997 binf->rx_lev = *cur & 0x3f;
2998 cur++;
2999
3000 if (binf->info_type & IPAC_BINF_RXQUAL)
3001 binf->rx_qual = *cur & 0x7;
3002 cur++;
3003
3004 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3005 binf->freq_err = ntohs(*(u_int16_t *)cur);
3006 cur += 2;
3007
3008 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3009 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3010 cur += 2;
3011
3012 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3013 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3014 cur += 4;
3015
3016 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01003017 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003018 cur++;
3019
Harald Welteb40a38f2009-11-13 11:56:05 +01003020 ipac_parse_cgi(&binf->cgi, cur);
3021 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003022
3023 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3024 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3025 cur += sizeof(binf->ba_list_si2);
3026 }
3027
3028 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3029 memcpy(binf->ba_list_si2bis, cur,
3030 sizeof(binf->ba_list_si2bis));
3031 cur += sizeof(binf->ba_list_si2bis);
3032 }
3033
3034 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3035 memcpy(binf->ba_list_si2ter, cur,
3036 sizeof(binf->ba_list_si2ter));
3037 cur += sizeof(binf->ba_list_si2ter);
3038 }
3039
3040 return 0;
3041}
3042
3043