blob: bb2455d375535289a7d93f4fddfa2fc3158e8ce4 [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
Harald Weltea8bd6d42009-10-20 09:56:18 +0200602static void debugp_foh(struct abis_om_fom_hdr *foh)
603{
604 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
605 obj_class_name(foh->obj_class), foh->obj_class,
606 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
607 foh->obj_inst.ts_nr);
608}
609
Harald Weltee0590df2009-02-15 03:34:15 +0000610/* obtain the gsm_nm_state data structure for a given object instance */
611static struct gsm_nm_state *
612objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
613 struct abis_om_obj_inst *obj_inst)
614{
615 struct gsm_bts_trx *trx;
616 struct gsm_nm_state *nm_state = NULL;
617
618 switch (obj_class) {
619 case NM_OC_BTS:
620 nm_state = &bts->nm_state;
621 break;
622 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100623 if (obj_inst->trx_nr >= bts->num_trx) {
624 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000625 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100626 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200627 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000628 nm_state = &trx->nm_state;
629 break;
630 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100631 if (obj_inst->trx_nr >= bts->num_trx) {
632 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000633 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100634 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200635 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000636 nm_state = &trx->bb_transc.nm_state;
637 break;
638 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100639 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100640 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000641 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100642 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200643 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000644 if (obj_inst->ts_nr >= TRX_NR_TS)
645 return NULL;
646 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
647 break;
648 case NM_OC_SITE_MANAGER:
649 nm_state = &bts->site_mgr.nm_state;
650 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000651 case NM_OC_BS11:
652 switch (obj_inst->bts_nr) {
653 case BS11_OBJ_CCLK:
654 nm_state = &bts->bs11.cclk.nm_state;
655 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000656 case BS11_OBJ_BBSIG:
657 if (obj_inst->ts_nr > bts->num_trx)
658 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200659 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000660 nm_state = &trx->bs11.bbsig.nm_state;
661 break;
662 case BS11_OBJ_PA:
663 if (obj_inst->ts_nr > bts->num_trx)
664 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200665 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000666 nm_state = &trx->bs11.pa.nm_state;
667 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000668 default:
669 return NULL;
670 }
671 case NM_OC_BS11_RACK:
672 nm_state = &bts->bs11.rack.nm_state;
673 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000674 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100675 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000676 return NULL;
677 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
678 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200679 case NM_OC_GPRS_NSE:
680 nm_state = &bts->gprs.nse.nm_state;
681 break;
682 case NM_OC_GPRS_CELL:
683 nm_state = &bts->gprs.cell.nm_state;
684 break;
685 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100686 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200687 return NULL;
688 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
689 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000690 }
691 return nm_state;
692}
693
694/* obtain the in-memory data structure of a given object instance */
695static void *
696objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
697 struct abis_om_obj_inst *obj_inst)
698{
699 struct gsm_bts_trx *trx;
700 void *obj = NULL;
701
702 switch (obj_class) {
703 case NM_OC_BTS:
704 obj = bts;
705 break;
706 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100707 if (obj_inst->trx_nr >= bts->num_trx) {
708 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000709 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100710 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200711 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000712 obj = trx;
713 break;
714 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100715 if (obj_inst->trx_nr >= bts->num_trx) {
716 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000717 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100718 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200719 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000720 obj = &trx->bb_transc;
721 break;
722 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100723 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100724 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000725 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100726 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200727 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000728 if (obj_inst->ts_nr >= TRX_NR_TS)
729 return NULL;
730 obj = &trx->ts[obj_inst->ts_nr];
731 break;
732 case NM_OC_SITE_MANAGER:
733 obj = &bts->site_mgr;
734 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200735 case NM_OC_GPRS_NSE:
736 obj = &bts->gprs.nse;
737 break;
738 case NM_OC_GPRS_CELL:
739 obj = &bts->gprs.cell;
740 break;
741 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100742 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200743 return NULL;
744 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
745 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000746 }
747 return obj;
748}
749
750/* Update the administrative state of a given object in our in-memory data
751 * structures and send an event to the higher layer */
752static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
753 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
754{
Harald Welteaeedeb42009-05-01 13:08:14 +0000755 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000756 void *obj;
757 int rc;
758
Harald Weltee0590df2009-02-15 03:34:15 +0000759 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100760 if (!obj)
761 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000762 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
763 if (!nm_state)
764 return -1;
765
766 new_state = *nm_state;
767 new_state.administrative = adm_state;
768
769 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
770
771 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000772
773 return rc;
774}
775
Harald Welte97ed1e72009-02-06 13:38:02 +0000776static int abis_nm_rx_statechg_rep(struct msgb *mb)
777{
Harald Weltee0590df2009-02-15 03:34:15 +0000778 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000779 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000780 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000781 struct tlv_parsed tp;
782 struct gsm_nm_state *nm_state, new_state;
783 int rc;
784
Harald Welte23897662009-05-01 14:52:51 +0000785 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000786
Harald Welte8b697c72009-06-05 19:18:45 +0000787 memset(&new_state, 0, sizeof(new_state));
788
Harald Weltee0590df2009-02-15 03:34:15 +0000789 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
790 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100791 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000792 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000793 }
Harald Weltee0590df2009-02-15 03:34:15 +0000794
795 new_state = *nm_state;
796
Harald Welte03133942009-02-18 19:51:53 +0000797 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000798 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
799 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000800 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000801 }
802 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000803 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
804 new_state.availability = 0xff;
805 else
806 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000807 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000808 new_state.availability);
809 }
810 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
811 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200812 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000813 }
814 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000815
816 if (memcmp(&new_state, nm_state, sizeof(new_state))) {
817 /* Update the operational state of a given object in our in-memory data
818 * structures and send an event to the higher layer */
819 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
820 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
821 *nm_state = new_state;
822 }
823#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000824 if (op_state == 1) {
825 /* try to enable objects that are disabled */
826 abis_nm_opstart(bts, foh->obj_class,
827 foh->obj_inst.bts_nr,
828 foh->obj_inst.trx_nr,
829 foh->obj_inst.ts_nr);
830 }
Harald Weltee0590df2009-02-15 03:34:15 +0000831#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000832 return 0;
833}
834
Harald Welte0db97b22009-05-01 17:22:47 +0000835static int rx_fail_evt_rep(struct msgb *mb)
836{
837 struct abis_om_hdr *oh = msgb_l2(mb);
838 struct abis_om_fom_hdr *foh = msgb_l3(mb);
839 struct tlv_parsed tp;
840
841 DEBUGPC(DNM, "Failure Event Report ");
842
843 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
844
845 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
846 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
847 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
848 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
849
850 DEBUGPC(DNM, "\n");
851
852 return 0;
853}
854
Harald Welte97ed1e72009-02-06 13:38:02 +0000855static int abis_nm_rcvmsg_report(struct msgb *mb)
856{
857 struct abis_om_fom_hdr *foh = msgb_l3(mb);
858 u_int8_t mt = foh->msg_type;
859
Harald Weltea8bd6d42009-10-20 09:56:18 +0200860 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000861
Harald Welte97ed1e72009-02-06 13:38:02 +0000862 //nmh->cfg->report_cb(mb, foh);
863
864 switch (mt) {
865 case NM_MT_STATECHG_EVENT_REP:
866 return abis_nm_rx_statechg_rep(mb);
867 break;
Harald Welte34a99682009-02-13 02:41:40 +0000868 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000869 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000870 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000871 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000872 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000873 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000874 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000875 break;
Harald Weltec7310382009-08-08 00:02:36 +0200876 case NM_MT_TEST_REP:
877 DEBUGPC(DNM, "Test Report\n");
878 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
879 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000880 default:
Harald Welte23897662009-05-01 14:52:51 +0000881 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000882 break;
883
Harald Welte97ed1e72009-02-06 13:38:02 +0000884 };
885
Harald Welte97ed1e72009-02-06 13:38:02 +0000886 return 0;
887}
888
Harald Welte34a99682009-02-13 02:41:40 +0000889/* Activate the specified software into the BTS */
890static 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 +0200891 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000892{
893 struct abis_om_hdr *oh;
894 struct msgb *msg = nm_msgb_alloc();
895 u_int8_t len = swdesc_len;
896 u_int8_t *trailer;
897
898 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
899 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
900
901 trailer = msgb_put(msg, swdesc_len);
902 memcpy(trailer, sw_desc, swdesc_len);
903
904 return abis_nm_sendmsg(bts, msg);
905}
906
907static int abis_nm_rx_sw_act_req(struct msgb *mb)
908{
909 struct abis_om_hdr *oh = msgb_l2(mb);
910 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200911 struct tlv_parsed tp;
912 const u_int8_t *sw_config;
913 int sw_config_len;
914 int file_id_len;
Harald Welte5c1e4582009-02-15 11:57:29 +0000915 int nack = 0;
Harald Welte34a99682009-02-13 02:41:40 +0000916 int ret;
917
Harald Weltea8bd6d42009-10-20 09:56:18 +0200918 debugp_foh(foh);
919
920 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000921
Harald Welte5c1e4582009-02-15 11:57:29 +0000922 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
923 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
924 nack = 1;
925 } else
926 DEBUGPC(DNM, "ACKing and Activating\n");
927
928 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000929 foh->obj_inst.bts_nr,
930 foh->obj_inst.trx_nr,
Harald Welte5c1e4582009-02-15 11:57:29 +0000931 foh->obj_inst.ts_nr, nack,
Harald Welte34a99682009-02-13 02:41:40 +0000932 foh->data, oh->length-sizeof(*foh));
933
Harald Welte5c1e4582009-02-15 11:57:29 +0000934 if (nack)
935 return ret;
936
Mike Habena03f9772009-10-01 14:56:13 +0200937 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
938 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
939 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
940 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
941 DEBUGP(DNM, "SW config not found! Can't continue.\n");
942 return -EINVAL;
943 } else {
944 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
945 }
946
947 if (sw_config[0] != NM_ATT_SW_DESCR)
948 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
949 if (sw_config[1] != NM_ATT_FILE_ID)
950 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
951 file_id_len = sw_config[2] * 256 + sw_config[3];
952
953 /* Assumes first SW file in list is the one to be activated */
954 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000955 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
956 foh->obj_inst.bts_nr,
957 foh->obj_inst.trx_nr,
958 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200959 sw_config + 4,
960 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000961}
962
Harald Weltee0590df2009-02-15 03:34:15 +0000963/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
964static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
965{
966 struct abis_om_hdr *oh = msgb_l2(mb);
967 struct abis_om_fom_hdr *foh = msgb_l3(mb);
968 struct tlv_parsed tp;
969 u_int8_t adm_state;
970
Harald Welte03133942009-02-18 19:51:53 +0000971 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000972 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
973 return -EINVAL;
974
975 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
976
977 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
978}
979
Harald Welteee670472009-02-22 21:58:49 +0000980static int abis_nm_rx_lmt_event(struct msgb *mb)
981{
982 struct abis_om_hdr *oh = msgb_l2(mb);
983 struct abis_om_fom_hdr *foh = msgb_l3(mb);
984 struct tlv_parsed tp;
985
986 DEBUGP(DNM, "LMT Event ");
987 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
988 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
989 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
990 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
991 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
992 }
993 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
994 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
995 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
996 DEBUGPC(DNM, "Level=%u ", level);
997 }
998 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
999 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
1000 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1001 DEBUGPC(DNM, "Username=%s ", name);
1002 }
1003 DEBUGPC(DNM, "\n");
1004 /* FIXME: parse LMT LOGON TIME */
1005 return 0;
1006}
1007
Harald Welte52b1f982008-12-23 20:25:15 +00001008/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001009static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001010{
Harald Welte6c96ba52009-05-01 13:03:40 +00001011 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001012 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1013 u_int8_t mt = foh->msg_type;
1014
1015 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001016 if (is_report(mt))
1017 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001018
Harald Welte4724f992009-01-18 18:01:49 +00001019 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1020 return abis_nm_rcvmsg_sw(mb);
1021
Harald Welte78fc0d42009-02-19 02:50:57 +00001022 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +00001023 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001024
Harald Weltea8bd6d42009-10-20 09:56:18 +02001025 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001026
Harald Welte78fc0d42009-02-19 02:50:57 +00001027 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +02001028 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +00001029 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +00001030 else
Harald Welte4bd0a982009-10-08 20:18:59 +02001031 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +00001032
1033 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1034 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1035 DEBUGPC(DNM, "CAUSE=%s\n",
1036 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1037 else
1038 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001039
Harald Welted8cfc902009-11-17 06:09:56 +01001040 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001041 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001042 }
Harald Weltead384642008-12-26 10:20:07 +00001043#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001044 /* check if last message is to be acked */
1045 if (is_ack_nack(nmh->last_msgtype)) {
1046 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001047 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001048 /* we got our ACK, continue sending the next msg */
1049 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1050 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001051 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001052 /* FIXME: somehow signal this to the caller */
1053 } else {
1054 /* really strange things happen */
1055 return -EINVAL;
1056 }
1057 }
Harald Weltead384642008-12-26 10:20:07 +00001058#endif
1059
Harald Welte97ed1e72009-02-06 13:38:02 +00001060 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001061 case NM_MT_CHG_ADM_STATE_ACK:
1062 return abis_nm_rx_chg_adm_state_ack(mb);
1063 break;
Harald Welte34a99682009-02-13 02:41:40 +00001064 case NM_MT_SW_ACT_REQ:
1065 return abis_nm_rx_sw_act_req(mb);
1066 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001067 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001068 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001069 break;
Harald Welte1989c082009-08-06 17:58:31 +02001070 case NM_MT_CONN_MDROP_LINK_ACK:
1071 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1072 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001073 case NM_MT_IPACC_RESTART_ACK:
1074 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1075 break;
1076 case NM_MT_IPACC_RESTART_NACK:
1077 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1078 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001079 }
1080
Harald Weltead384642008-12-26 10:20:07 +00001081 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001082}
1083
Harald Welte677c21f2009-02-17 13:22:23 +00001084static int abis_nm_rx_ipacc(struct msgb *mb);
1085
1086static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1087{
1088 int rc;
1089 int bts_type = mb->trx->bts->type;
1090
1091 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001092 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001093 rc = abis_nm_rx_ipacc(mb);
1094 break;
1095 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001096 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1097 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001098 rc = 0;
1099 break;
1100 }
1101
1102 return rc;
1103}
1104
Harald Welte52b1f982008-12-23 20:25:15 +00001105/* High-Level API */
1106/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001107int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001108{
Harald Welte52b1f982008-12-23 20:25:15 +00001109 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001110 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001111
1112 /* Various consistency checks */
1113 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001114 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001115 oh->placement);
1116 return -EINVAL;
1117 }
1118 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001119 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001120 oh->sequence);
1121 return -EINVAL;
1122 }
Harald Welte702d8702008-12-26 20:25:35 +00001123#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001124 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1125 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001126 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001127 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001128 oh->length + sizeof(*oh), l2_len);
1129 return -EINVAL;
1130 }
Harald Welte702d8702008-12-26 20:25:35 +00001131 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001132 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 +00001133#endif
Harald Weltead384642008-12-26 10:20:07 +00001134 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001135
1136 switch (oh->mdisc) {
1137 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001138 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001139 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001140 case ABIS_OM_MDISC_MANUF:
1141 rc = abis_nm_rcvmsg_manuf(msg);
1142 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001143 case ABIS_OM_MDISC_MMI:
1144 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001145 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001146 oh->mdisc);
1147 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001148 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001149 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001150 oh->mdisc);
1151 return -EINVAL;
1152 }
1153
Harald Weltead384642008-12-26 10:20:07 +00001154 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001155 return rc;
1156}
1157
1158#if 0
1159/* initialized all resources */
1160struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1161{
1162 struct abis_nm_h *nmh;
1163
1164 nmh = malloc(sizeof(*nmh));
1165 if (!nmh)
1166 return NULL;
1167
1168 nmh->cfg = cfg;
1169
1170 return nmh;
1171}
1172
1173/* free all resources */
1174void abis_nm_fini(struct abis_nm_h *nmh)
1175{
1176 free(nmh);
1177}
1178#endif
1179
1180/* Here we are trying to define a high-level API that can be used by
1181 * the actual BSC implementation. However, the architecture is currently
1182 * still under design. Ideally the calls to this API would be synchronous,
1183 * while the underlying stack behind the APi runs in a traditional select
1184 * based state machine.
1185 */
1186
Harald Welte4724f992009-01-18 18:01:49 +00001187/* 6.2 Software Load: */
1188enum sw_state {
1189 SW_STATE_NONE,
1190 SW_STATE_WAIT_INITACK,
1191 SW_STATE_WAIT_SEGACK,
1192 SW_STATE_WAIT_ENDACK,
1193 SW_STATE_WAIT_ACTACK,
1194 SW_STATE_ERROR,
1195};
Harald Welte52b1f982008-12-23 20:25:15 +00001196
Harald Welte52b1f982008-12-23 20:25:15 +00001197struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001198 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001199 gsm_cbfn *cbfn;
1200 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001201 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001202
Harald Welte52b1f982008-12-23 20:25:15 +00001203 /* this will become part of the SW LOAD INITIATE */
1204 u_int8_t obj_class;
1205 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001206
1207 u_int8_t file_id[255];
1208 u_int8_t file_id_len;
1209
1210 u_int8_t file_version[255];
1211 u_int8_t file_version_len;
1212
1213 u_int8_t window_size;
1214 u_int8_t seg_in_window;
1215
1216 int fd;
1217 FILE *stream;
1218 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001219 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001220};
1221
Harald Welte4724f992009-01-18 18:01:49 +00001222static struct abis_nm_sw g_sw;
1223
1224/* 6.2.1 / 8.3.1: Load Data Initiate */
1225static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001226{
Harald Welte4724f992009-01-18 18:01:49 +00001227 struct abis_om_hdr *oh;
1228 struct msgb *msg = nm_msgb_alloc();
1229 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1230
1231 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1232 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1233 sw->obj_instance[0], sw->obj_instance[1],
1234 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001235
1236 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1237 msgb_v_put(msg, NM_ATT_SW_DESCR);
1238 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1239 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1240 sw->file_version);
1241 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1242 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1243 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1244 sw->file_version);
1245 } else {
1246 return -1;
1247 }
Harald Welte4724f992009-01-18 18:01:49 +00001248 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1249
1250 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001251}
1252
Harald Welte1602ade2009-01-29 21:12:39 +00001253static int is_last_line(FILE *stream)
1254{
1255 char next_seg_buf[256];
1256 long pos;
1257
1258 /* check if we're sending the last line */
1259 pos = ftell(stream);
1260 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1261 fseek(stream, pos, SEEK_SET);
1262 return 1;
1263 }
1264
1265 fseek(stream, pos, SEEK_SET);
1266 return 0;
1267}
1268
Harald Welte4724f992009-01-18 18:01:49 +00001269/* 6.2.2 / 8.3.2 Load Data Segment */
1270static int sw_load_segment(struct abis_nm_sw *sw)
1271{
1272 struct abis_om_hdr *oh;
1273 struct msgb *msg = nm_msgb_alloc();
1274 char seg_buf[256];
1275 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001276 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001277 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001278
1279 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001280
1281 switch (sw->bts->type) {
1282 case GSM_BTS_TYPE_BS11:
1283 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1284 perror("fgets reading segment");
1285 return -EINVAL;
1286 }
1287 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001288
1289 /* check if we're sending the last line */
1290 sw->last_seg = is_last_line(sw->stream);
1291 if (sw->last_seg)
1292 seg_buf[1] = 0;
1293 else
1294 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001295
1296 len = strlen(line_buf) + 2;
1297 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1298 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1299 /* BS11 wants CR + LF in excess of the TLV length !?! */
1300 tlv[1] -= 2;
1301
1302 /* we only now know the exact length for the OM hdr */
1303 len = strlen(line_buf)+2;
1304 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001305 case GSM_BTS_TYPE_NANOBTS: {
1306 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1307 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1308 if (len < 0) {
1309 perror("read failed");
1310 return -EINVAL;
1311 }
1312
1313 if (len != IPACC_SEGMENT_SIZE)
1314 sw->last_seg = 1;
1315
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001316 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001317 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1318 len += 3;
1319 break;
1320 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001321 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001322 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001323 /* FIXME: Other BTS types */
1324 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001325 }
Harald Welte4724f992009-01-18 18:01:49 +00001326
Harald Welte4724f992009-01-18 18:01:49 +00001327 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1328 sw->obj_instance[0], sw->obj_instance[1],
1329 sw->obj_instance[2]);
1330
1331 return abis_nm_sendmsg(sw->bts, msg);
1332}
1333
1334/* 6.2.4 / 8.3.4 Load Data End */
1335static int sw_load_end(struct abis_nm_sw *sw)
1336{
1337 struct abis_om_hdr *oh;
1338 struct msgb *msg = nm_msgb_alloc();
1339 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1340
1341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1342 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1343 sw->obj_instance[0], sw->obj_instance[1],
1344 sw->obj_instance[2]);
1345
Holger Hans Peter Freyther326a6322009-12-28 11:45:43 +01001346 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1347 msgb_v_put(msg, NM_ATT_SW_DESCR);
1348 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1349 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1350 sw->file_version);
1351 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1352 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1353 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1354 sw->file_version);
1355 } else {
1356 return -1;
1357 }
Harald Welte4724f992009-01-18 18:01:49 +00001358
1359 return abis_nm_sendmsg(sw->bts, msg);
1360}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001361
Harald Welte52b1f982008-12-23 20:25:15 +00001362/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001363static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001364{
Harald Welte4724f992009-01-18 18:01:49 +00001365 struct abis_om_hdr *oh;
1366 struct msgb *msg = nm_msgb_alloc();
1367 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001368
Harald Welte4724f992009-01-18 18:01:49 +00001369 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1370 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1371 sw->obj_instance[0], sw->obj_instance[1],
1372 sw->obj_instance[2]);
1373
1374 /* FIXME: this is BS11 specific format */
1375 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1376 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1377 sw->file_version);
1378
1379 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001380}
Harald Welte4724f992009-01-18 18:01:49 +00001381
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001382struct sdp_firmware {
1383 char magic[4];
1384 char more_magic[4];
1385 unsigned int header_length;
1386 unsigned int file_length;
1387} __attribute__ ((packed));
1388
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001389static int parse_sdp_header(struct abis_nm_sw *sw)
1390{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001391 struct sdp_firmware firmware_header;
1392 int rc;
1393 struct stat stat;
1394
1395 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1396 if (rc != sizeof(firmware_header)) {
1397 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1398 return -1;
1399 }
1400
1401 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1402 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1403 return -1;
1404 }
1405
1406 if (firmware_header.more_magic[0] != 0x10 ||
1407 firmware_header.more_magic[1] != 0x02 ||
1408 firmware_header.more_magic[2] != 0x00 ||
1409 firmware_header.more_magic[3] != 0x00) {
1410 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1411 return -1;
1412 }
1413
1414
1415 if (fstat(sw->fd, &stat) == -1) {
1416 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1417 return -1;
1418 }
1419
1420 if (ntohl(firmware_header.file_length) != stat.st_size) {
1421 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1422 return -1;
1423 }
1424
1425 /* go back to the start as we checked the whole filesize.. */
1426 lseek(sw->fd, 0l, SEEK_SET);
1427 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1428 "There might be checksums in the file that are not\n"
1429 "verified and incomplete firmware might be flashed.\n"
1430 "There is absolutely no WARRANTY that flashing will\n"
1431 "work.\n");
1432 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001433}
1434
Harald Welte4724f992009-01-18 18:01:49 +00001435static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1436{
1437 char file_id[12+1];
1438 char file_version[80+1];
1439 int rc;
1440
1441 sw->fd = open(fname, O_RDONLY);
1442 if (sw->fd < 0)
1443 return sw->fd;
1444
1445 switch (sw->bts->type) {
1446 case GSM_BTS_TYPE_BS11:
1447 sw->stream = fdopen(sw->fd, "r");
1448 if (!sw->stream) {
1449 perror("fdopen");
1450 return -1;
1451 }
1452 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001453 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001454 file_id, file_version);
1455 if (rc != 2) {
1456 perror("parsing header line of software file");
1457 return -1;
1458 }
1459 strcpy((char *)sw->file_id, file_id);
1460 sw->file_id_len = strlen(file_id);
1461 strcpy((char *)sw->file_version, file_version);
1462 sw->file_version_len = strlen(file_version);
1463 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001464 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001465 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001466 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001467 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001468 rc = parse_sdp_header(sw);
1469 if (rc < 0) {
1470 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1471 return -1;
1472 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001473
1474 strcpy((char *)sw->file_id, "id");
1475 sw->file_id_len = 3;
1476 strcpy((char *)sw->file_version, "version");
1477 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001478 break;
Harald Welte4724f992009-01-18 18:01:49 +00001479 default:
1480 /* We don't know how to treat them yet */
1481 close(sw->fd);
1482 return -EINVAL;
1483 }
1484
1485 return 0;
1486}
1487
1488static void sw_close_file(struct abis_nm_sw *sw)
1489{
1490 switch (sw->bts->type) {
1491 case GSM_BTS_TYPE_BS11:
1492 fclose(sw->stream);
1493 break;
1494 default:
1495 close(sw->fd);
1496 break;
1497 }
1498}
1499
1500/* Fill the window */
1501static int sw_fill_window(struct abis_nm_sw *sw)
1502{
1503 int rc;
1504
1505 while (sw->seg_in_window < sw->window_size) {
1506 rc = sw_load_segment(sw);
1507 if (rc < 0)
1508 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001509 if (sw->last_seg)
1510 break;
Harald Welte4724f992009-01-18 18:01:49 +00001511 }
1512 return 0;
1513}
1514
1515/* callback function from abis_nm_rcvmsg() handler */
1516static int abis_nm_rcvmsg_sw(struct msgb *mb)
1517{
1518 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1519 int rc = -1;
1520 struct abis_nm_sw *sw = &g_sw;
1521 enum sw_state old_state = sw->state;
1522
Harald Welte3ffd1372009-02-01 22:15:49 +00001523 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001524
1525 switch (sw->state) {
1526 case SW_STATE_WAIT_INITACK:
1527 switch (foh->msg_type) {
1528 case NM_MT_LOAD_INIT_ACK:
1529 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001530 if (sw->cbfn)
1531 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1532 NM_MT_LOAD_INIT_ACK, mb,
1533 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001534 rc = sw_fill_window(sw);
1535 sw->state = SW_STATE_WAIT_SEGACK;
1536 break;
1537 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001538 if (sw->forced) {
1539 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1540 "Init NACK\n");
1541 if (sw->cbfn)
1542 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1543 NM_MT_LOAD_INIT_ACK, mb,
1544 sw->cb_data, NULL);
1545 rc = sw_fill_window(sw);
1546 sw->state = SW_STATE_WAIT_SEGACK;
1547 } else {
1548 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001549 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001550 if (sw->cbfn)
1551 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1552 NM_MT_LOAD_INIT_NACK, mb,
1553 sw->cb_data, NULL);
1554 sw->state = SW_STATE_ERROR;
1555 }
Harald Welte4724f992009-01-18 18:01:49 +00001556 break;
1557 }
1558 break;
1559 case SW_STATE_WAIT_SEGACK:
1560 switch (foh->msg_type) {
1561 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001562 if (sw->cbfn)
1563 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1564 NM_MT_LOAD_SEG_ACK, mb,
1565 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001566 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001567 if (!sw->last_seg) {
1568 /* fill window with more segments */
1569 rc = sw_fill_window(sw);
1570 sw->state = SW_STATE_WAIT_SEGACK;
1571 } else {
1572 /* end the transfer */
1573 sw->state = SW_STATE_WAIT_ENDACK;
1574 rc = sw_load_end(sw);
1575 }
Harald Welte4724f992009-01-18 18:01:49 +00001576 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001577 case NM_MT_LOAD_ABORT:
1578 if (sw->cbfn)
1579 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1580 NM_MT_LOAD_ABORT, mb,
1581 sw->cb_data, NULL);
1582 break;
Harald Welte4724f992009-01-18 18:01:49 +00001583 }
1584 break;
1585 case SW_STATE_WAIT_ENDACK:
1586 switch (foh->msg_type) {
1587 case NM_MT_LOAD_END_ACK:
1588 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001589 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1590 sw->bts->nr);
1591 sw->state = SW_STATE_NONE;
1592 if (sw->cbfn)
1593 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1594 NM_MT_LOAD_END_ACK, mb,
1595 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001596 rc = 0;
Harald Welte4724f992009-01-18 18:01:49 +00001597 break;
1598 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001599 if (sw->forced) {
1600 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1601 "End NACK\n");
1602 sw->state = SW_STATE_NONE;
1603 if (sw->cbfn)
1604 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1605 NM_MT_LOAD_END_ACK, mb,
1606 sw->cb_data, NULL);
1607 } else {
1608 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001609 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001610 sw->state = SW_STATE_ERROR;
1611 if (sw->cbfn)
1612 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1613 NM_MT_LOAD_END_NACK, mb,
1614 sw->cb_data, NULL);
1615 }
Harald Welte4724f992009-01-18 18:01:49 +00001616 break;
1617 }
1618 case SW_STATE_WAIT_ACTACK:
1619 switch (foh->msg_type) {
1620 case NM_MT_ACTIVATE_SW_ACK:
1621 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001622 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001623 sw->state = SW_STATE_NONE;
1624 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001625 if (sw->cbfn)
1626 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1627 NM_MT_ACTIVATE_SW_ACK, mb,
1628 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001629 break;
1630 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001631 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001632 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001633 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001634 if (sw->cbfn)
1635 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1636 NM_MT_ACTIVATE_SW_NACK, mb,
1637 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001638 break;
1639 }
1640 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001641 switch (foh->msg_type) {
1642 case NM_MT_ACTIVATE_SW_ACK:
1643 rc = 0;
1644 break;
1645 }
1646 break;
Harald Welte4724f992009-01-18 18:01:49 +00001647 case SW_STATE_ERROR:
1648 break;
1649 }
1650
1651 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001652 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001653 foh->msg_type, old_state, sw->state);
1654
1655 return rc;
1656}
1657
1658/* Load the specified software into the BTS */
1659int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001660 u_int8_t win_size, int forced,
1661 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001662{
1663 struct abis_nm_sw *sw = &g_sw;
1664 int rc;
1665
Harald Welte5e4d1b32009-02-01 13:36:56 +00001666 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1667 bts->nr, fname);
1668
Harald Welte4724f992009-01-18 18:01:49 +00001669 if (sw->state != SW_STATE_NONE)
1670 return -EBUSY;
1671
1672 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001673
1674 switch (bts->type) {
1675 case GSM_BTS_TYPE_BS11:
1676 sw->obj_class = NM_OC_SITE_MANAGER;
1677 sw->obj_instance[0] = 0xff;
1678 sw->obj_instance[1] = 0xff;
1679 sw->obj_instance[2] = 0xff;
1680 break;
1681 case GSM_BTS_TYPE_NANOBTS:
1682 sw->obj_class = NM_OC_BASEB_TRANSC;
1683 sw->obj_instance[0] = 0x00;
1684 sw->obj_instance[1] = 0x00;
1685 sw->obj_instance[2] = 0xff;
1686 break;
1687 case GSM_BTS_TYPE_UNKNOWN:
1688 default:
1689 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1690 return -1;
1691 break;
1692 }
Harald Welte4724f992009-01-18 18:01:49 +00001693 sw->window_size = win_size;
1694 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001695 sw->cbfn = cbfn;
1696 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001697 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001698
1699 rc = sw_open_file(sw, fname);
1700 if (rc < 0) {
1701 sw->state = SW_STATE_NONE;
1702 return rc;
1703 }
1704
1705 return sw_load_init(sw);
1706}
Harald Welte52b1f982008-12-23 20:25:15 +00001707
Harald Welte1602ade2009-01-29 21:12:39 +00001708int abis_nm_software_load_status(struct gsm_bts *bts)
1709{
1710 struct abis_nm_sw *sw = &g_sw;
1711 struct stat st;
1712 int rc, percent;
1713
1714 rc = fstat(sw->fd, &st);
1715 if (rc < 0) {
1716 perror("ERROR during stat");
1717 return rc;
1718 }
1719
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001720 if (sw->stream)
1721 percent = (ftell(sw->stream) * 100) / st.st_size;
1722 else
1723 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001724 return percent;
1725}
1726
Harald Welte5e4d1b32009-02-01 13:36:56 +00001727/* Activate the specified software into the BTS */
1728int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1729 gsm_cbfn *cbfn, void *cb_data)
1730{
1731 struct abis_nm_sw *sw = &g_sw;
1732 int rc;
1733
1734 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1735 bts->nr, fname);
1736
1737 if (sw->state != SW_STATE_NONE)
1738 return -EBUSY;
1739
1740 sw->bts = bts;
1741 sw->obj_class = NM_OC_SITE_MANAGER;
1742 sw->obj_instance[0] = 0xff;
1743 sw->obj_instance[1] = 0xff;
1744 sw->obj_instance[2] = 0xff;
1745 sw->state = SW_STATE_WAIT_ACTACK;
1746 sw->cbfn = cbfn;
1747 sw->cb_data = cb_data;
1748
1749 /* Open the file in order to fill some sw struct members */
1750 rc = sw_open_file(sw, fname);
1751 if (rc < 0) {
1752 sw->state = SW_STATE_NONE;
1753 return rc;
1754 }
1755 sw_close_file(sw);
1756
1757 return sw_activate(sw);
1758}
1759
Harald Welte8470bf22008-12-25 23:28:35 +00001760static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001761 u_int8_t ts_nr, u_int8_t subslot_nr)
1762{
Harald Welteadaf08b2009-01-18 11:08:10 +00001763 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001764 ch->bts_port = bts_port;
1765 ch->timeslot = ts_nr;
1766 ch->subslot = subslot_nr;
1767}
1768
1769int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1770 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1771 u_int8_t tei)
1772{
1773 struct abis_om_hdr *oh;
1774 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001775 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001776 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001777
1778 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1779 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1780 bts->bts_nr, trx_nr, 0xff);
1781
Harald Welte8470bf22008-12-25 23:28:35 +00001782 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001783
1784 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1785 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1786
1787 return abis_nm_sendmsg(bts, msg);
1788}
1789
1790/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1791int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1792 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1793{
Harald Welte8470bf22008-12-25 23:28:35 +00001794 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001795 struct abis_om_hdr *oh;
1796 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001797 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001798
1799 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001800 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001801 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1802
1803 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1804 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1805
1806 return abis_nm_sendmsg(bts, msg);
1807}
1808
1809#if 0
1810int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1811 struct abis_nm_abis_channel *chan)
1812{
1813}
1814#endif
1815
1816int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1817 u_int8_t e1_port, u_int8_t e1_timeslot,
1818 u_int8_t e1_subslot)
1819{
1820 struct gsm_bts *bts = ts->trx->bts;
1821 struct abis_om_hdr *oh;
1822 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001823 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001824
1825 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1826 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001827 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001828
1829 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1830 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1831
Harald Weltef325eb42009-02-19 17:07:39 +00001832 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1833 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001834 e1_port, e1_timeslot, e1_subslot);
1835
Harald Welte52b1f982008-12-23 20:25:15 +00001836 return abis_nm_sendmsg(bts, msg);
1837}
1838
1839#if 0
1840int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1841 struct abis_nm_abis_channel *chan,
1842 u_int8_t subchan)
1843{
1844}
1845#endif
1846
Harald Welte22af0db2009-02-14 15:41:08 +00001847/* Chapter 8.6.1 */
1848int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1849{
1850 struct abis_om_hdr *oh;
1851 struct msgb *msg = nm_msgb_alloc();
1852 u_int8_t *cur;
1853
1854 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1855
1856 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001857 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 +00001858 cur = msgb_put(msg, attr_len);
1859 memcpy(cur, attr, attr_len);
1860
1861 return abis_nm_sendmsg(bts, msg);
1862}
1863
1864/* Chapter 8.6.2 */
1865int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1866{
1867 struct abis_om_hdr *oh;
1868 struct msgb *msg = nm_msgb_alloc();
1869 u_int8_t *cur;
1870
1871 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1872
1873 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1874 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001875 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001876 cur = msgb_put(msg, attr_len);
1877 memcpy(cur, attr, attr_len);
1878
1879 return abis_nm_sendmsg(trx->bts, msg);
1880}
1881
Harald Welte39c7deb2009-08-09 21:49:48 +02001882static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1883{
1884 int i;
1885
1886 /* As it turns out, the BS-11 has some very peculiar restrictions
1887 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301888 switch (ts->trx->bts->type) {
1889 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001890 switch (chan_comb) {
1891 case NM_CHANC_TCHHalf:
1892 case NM_CHANC_TCHHalf2:
1893 /* not supported */
1894 return -EINVAL;
1895 case NM_CHANC_SDCCH:
1896 /* only one SDCCH/8 per TRX */
1897 for (i = 0; i < TRX_NR_TS; i++) {
1898 if (i == ts->nr)
1899 continue;
1900 if (ts->trx->ts[i].nm_chan_comb ==
1901 NM_CHANC_SDCCH)
1902 return -EINVAL;
1903 }
1904 /* not allowed for TS0 of BCCH-TRX */
1905 if (ts->trx == ts->trx->bts->c0 &&
1906 ts->nr == 0)
1907 return -EINVAL;
1908 /* not on the same TRX that has a BCCH+SDCCH4
1909 * combination */
1910 if (ts->trx == ts->trx->bts->c0 &&
1911 (ts->trx->ts[0].nm_chan_comb == 5 ||
1912 ts->trx->ts[0].nm_chan_comb == 8))
1913 return -EINVAL;
1914 break;
1915 case NM_CHANC_mainBCCH:
1916 case NM_CHANC_BCCHComb:
1917 /* allowed only for TS0 of C0 */
1918 if (ts->trx != ts->trx->bts->c0 ||
1919 ts->nr != 0)
1920 return -EINVAL;
1921 break;
1922 case NM_CHANC_BCCH:
1923 /* allowed only for TS 2/4/6 of C0 */
1924 if (ts->trx != ts->trx->bts->c0)
1925 return -EINVAL;
1926 if (ts->nr != 2 && ts->nr != 4 &&
1927 ts->nr != 6)
1928 return -EINVAL;
1929 break;
1930 case 8: /* this is not like 08.58, but in fact
1931 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1932 /* FIXME: only one CBCH allowed per cell */
1933 break;
1934 }
Harald Welted6575f92009-12-02 02:45:23 +05301935 break;
1936 case GSM_BTS_TYPE_NANOBTS:
1937 switch (ts->nr) {
1938 case 0:
1939 if (ts->trx->nr == 0) {
1940 /* only on TRX0 */
1941 switch (chan_comb) {
1942 case NM_CHANC_BCCH:
1943 case NM_CHANC_mainBCCH:
1944 case NM_CHANC_BCCHComb:
1945 return 0;
1946 break;
1947 default:
1948 return -EINVAL;
1949 }
1950 } else {
1951 switch (chan_comb) {
1952 case NM_CHANC_TCHFull:
1953 case NM_CHANC_TCHHalf:
1954 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1955 return 0;
1956 default:
1957 return -EINVAL;
1958 }
1959 }
1960 break;
1961 case 1:
1962 if (ts->trx->nr == 0) {
1963 switch (chan_comb) {
1964 case NM_CHANC_SDCCH_CBCH:
1965 if (ts->trx->ts[0].nm_chan_comb ==
1966 NM_CHANC_mainBCCH)
1967 return 0;
1968 return -EINVAL;
1969 case NM_CHANC_SDCCH:
1970 case NM_CHANC_TCHFull:
1971 case NM_CHANC_TCHHalf:
1972 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1973 case NM_CHANC_IPAC_TCHFull_PDCH:
1974 return 0;
1975 }
1976 } else {
1977 switch (chan_comb) {
1978 case NM_CHANC_SDCCH:
1979 case NM_CHANC_TCHFull:
1980 case NM_CHANC_TCHHalf:
1981 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1982 return 0;
1983 default:
1984 return -EINVAL;
1985 }
1986 }
1987 break;
1988 case 2:
1989 case 3:
1990 case 4:
1991 case 5:
1992 case 6:
1993 case 7:
1994 switch (chan_comb) {
1995 case NM_CHANC_TCHFull:
1996 case NM_CHANC_TCHHalf:
1997 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1998 return 0;
1999 case NM_CHANC_IPAC_PDCH:
2000 case NM_CHANC_IPAC_TCHFull_PDCH:
2001 if (ts->trx->nr == 0)
2002 return 0;
2003 else
2004 return -EINVAL;
2005 }
2006 break;
2007 }
2008 return -EINVAL;
2009 default:
2010 /* unknown BTS type */
2011 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002012 }
2013 return 0;
2014}
2015
Harald Welte22af0db2009-02-14 15:41:08 +00002016/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002017int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2018{
2019 struct gsm_bts *bts = ts->trx->bts;
2020 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002021 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002022 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002023 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002024 u_int8_t len = 2 + 2;
2025
2026 if (bts->type == GSM_BTS_TYPE_BS11)
2027 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002028
Harald Weltef325eb42009-02-19 17:07:39 +00002029 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002030 if (verify_chan_comb(ts, chan_comb) < 0) {
2031 msgb_free(msg);
2032 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2033 return -EINVAL;
2034 }
2035 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002036
Harald Welte52b1f982008-12-23 20:25:15 +00002037 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002038 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002039 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002040 ts->trx->nr, ts->nr);
2041 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00002042 if (bts->type == GSM_BTS_TYPE_BS11)
2043 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002044 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00002045 if (bts->type == GSM_BTS_TYPE_BS11) {
2046 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2047 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2048 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002049 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002050 if (bts->type == GSM_BTS_TYPE_BS11)
2051 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002052
2053 return abis_nm_sendmsg(bts, msg);
2054}
2055
Harald Welte34a99682009-02-13 02:41:40 +00002056int 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 +00002057 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002058{
2059 struct abis_om_hdr *oh;
2060 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002061 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2062 u_int8_t len = att_len;
2063
2064 if (nack) {
2065 len += 2;
2066 msgtype = NM_MT_SW_ACT_REQ_NACK;
2067 }
Harald Welte34a99682009-02-13 02:41:40 +00002068
2069 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002070 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2071
Harald Welte34a99682009-02-13 02:41:40 +00002072 if (attr) {
2073 u_int8_t *ptr = msgb_put(msg, att_len);
2074 memcpy(ptr, attr, att_len);
2075 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002076 if (nack)
2077 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002078
2079 return abis_nm_sendmsg(bts, msg);
2080}
2081
Harald Welte8470bf22008-12-25 23:28:35 +00002082int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002083{
Harald Welte8470bf22008-12-25 23:28:35 +00002084 struct msgb *msg = nm_msgb_alloc();
2085 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002086 u_int8_t *data;
2087
2088 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2089 fill_om_hdr(oh, len);
2090 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002091 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002092
2093 return abis_nm_sendmsg(bts, msg);
2094}
2095
2096/* Siemens specific commands */
2097static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2098{
2099 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002100 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002101
2102 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002103 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002104 0xff, 0xff, 0xff);
2105
2106 return abis_nm_sendmsg(bts, msg);
2107}
2108
Harald Welte34a99682009-02-13 02:41:40 +00002109/* Chapter 8.9.2 */
2110int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2111{
2112 struct abis_om_hdr *oh;
2113 struct msgb *msg = nm_msgb_alloc();
2114
2115 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2116 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2117
Harald Weltea8bd6d42009-10-20 09:56:18 +02002118 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2119 DEBUGPC(DNM, "Sending OPSTART\n");
2120
Harald Welte34a99682009-02-13 02:41:40 +00002121 return abis_nm_sendmsg(bts, msg);
2122}
2123
2124/* Chapter 8.8.5 */
2125int 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 +02002126 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002127{
2128 struct abis_om_hdr *oh;
2129 struct msgb *msg = nm_msgb_alloc();
2130
2131 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2132 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2133 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2134
2135 return abis_nm_sendmsg(bts, msg);
2136}
2137
Harald Welte1989c082009-08-06 17:58:31 +02002138int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2139 u_int8_t e1_port1, u_int8_t ts1)
2140{
2141 struct abis_om_hdr *oh;
2142 struct msgb *msg = nm_msgb_alloc();
2143 u_int8_t *attr;
2144
2145 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2146 e1_port0, ts0, e1_port1, ts1);
2147
2148 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2149 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2150 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2151
2152 attr = msgb_put(msg, 3);
2153 attr[0] = NM_ATT_MDROP_LINK;
2154 attr[1] = e1_port0;
2155 attr[2] = ts0;
2156
2157 attr = msgb_put(msg, 3);
2158 attr[0] = NM_ATT_MDROP_NEXT;
2159 attr[1] = e1_port1;
2160 attr[2] = ts1;
2161
2162 return abis_nm_sendmsg(bts, msg);
2163}
Harald Welte34a99682009-02-13 02:41:40 +00002164
Harald Weltec7310382009-08-08 00:02:36 +02002165/* Chapter 8.7.1 */
2166int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2167 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2168 u_int8_t test_nr, u_int8_t auton_report,
2169 u_int8_t *phys_config, u_int16_t phys_config_len)
2170{
2171 struct abis_om_hdr *oh;
2172 struct msgb *msg = nm_msgb_alloc();
2173 int len = 4; /* 2 TV attributes */
2174
2175 DEBUGP(DNM, "PEFORM TEST\n");
2176
2177 if (phys_config_len)
2178 len += 3 + phys_config_len;
2179
2180 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2181 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2182 obj_class, bts_nr, trx_nr, ts_nr);
2183 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2184 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2185 if (phys_config_len)
2186 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2187 phys_config);
2188
2189 return abis_nm_sendmsg(bts, msg);
2190}
2191
Harald Welte52b1f982008-12-23 20:25:15 +00002192int abis_nm_event_reports(struct gsm_bts *bts, int on)
2193{
2194 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002195 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002196 else
Harald Welte227d4072009-01-03 08:16:25 +00002197 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002198}
2199
Harald Welte47d88ae2009-01-04 12:02:08 +00002200/* Siemens (or BS-11) specific commands */
2201
Harald Welte3ffd1372009-02-01 22:15:49 +00002202int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2203{
2204 if (reconnect == 0)
2205 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2206 else
2207 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2208}
2209
Harald Welteb8427972009-02-05 19:27:17 +00002210int abis_nm_bs11_restart(struct gsm_bts *bts)
2211{
2212 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2213}
2214
2215
Harald Welte268bb402009-02-01 19:11:56 +00002216struct bs11_date_time {
2217 u_int16_t year;
2218 u_int8_t month;
2219 u_int8_t day;
2220 u_int8_t hour;
2221 u_int8_t min;
2222 u_int8_t sec;
2223} __attribute__((packed));
2224
2225
2226void get_bs11_date_time(struct bs11_date_time *aet)
2227{
2228 time_t t;
2229 struct tm *tm;
2230
2231 t = time(NULL);
2232 tm = localtime(&t);
2233 aet->sec = tm->tm_sec;
2234 aet->min = tm->tm_min;
2235 aet->hour = tm->tm_hour;
2236 aet->day = tm->tm_mday;
2237 aet->month = tm->tm_mon;
2238 aet->year = htons(1900 + tm->tm_year);
2239}
2240
Harald Welte05188ee2009-01-18 11:39:08 +00002241int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002242{
Harald Welte4668fda2009-01-03 08:19:29 +00002243 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002244}
2245
Harald Welte05188ee2009-01-18 11:39:08 +00002246int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002247{
2248 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002249 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002250 else
Harald Welte4668fda2009-01-03 08:19:29 +00002251 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002252}
Harald Welte47d88ae2009-01-04 12:02:08 +00002253
Harald Welte05188ee2009-01-18 11:39:08 +00002254int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002255 enum abis_bs11_objtype type, u_int8_t idx,
2256 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002257{
2258 struct abis_om_hdr *oh;
2259 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002260 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002261
2262 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002263 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002264 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002265 cur = msgb_put(msg, attr_len);
2266 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002267
2268 return abis_nm_sendmsg(bts, msg);
2269}
2270
Harald Welte78fc0d42009-02-19 02:50:57 +00002271int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2272 enum abis_bs11_objtype type, u_int8_t idx)
2273{
2274 struct abis_om_hdr *oh;
2275 struct msgb *msg = nm_msgb_alloc();
2276
2277 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2278 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2279 NM_OC_BS11, type, 0, idx);
2280
2281 return abis_nm_sendmsg(bts, msg);
2282}
2283
Harald Welte05188ee2009-01-18 11:39:08 +00002284int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002285{
2286 struct abis_om_hdr *oh;
2287 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002288 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002289
2290 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002291 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002292 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2293 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002294
2295 return abis_nm_sendmsg(bts, msg);
2296}
2297
Harald Welte05188ee2009-01-18 11:39:08 +00002298int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002299{
2300 struct abis_om_hdr *oh;
2301 struct msgb *msg = nm_msgb_alloc();
2302
2303 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2304 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002305 idx, 0xff, 0xff);
2306
2307 return abis_nm_sendmsg(bts, msg);
2308}
2309
2310int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2311{
2312 struct abis_om_hdr *oh;
2313 struct msgb *msg = nm_msgb_alloc();
2314
2315 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2316 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2317 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002318
2319 return abis_nm_sendmsg(bts, msg);
2320}
Harald Welte05188ee2009-01-18 11:39:08 +00002321
Harald Welte78fc0d42009-02-19 02:50:57 +00002322static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2323int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2324{
2325 struct abis_om_hdr *oh;
2326 struct msgb *msg = nm_msgb_alloc();
2327
2328 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2329 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2330 0xff, 0xff, 0xff);
2331 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2332
2333 return abis_nm_sendmsg(bts, msg);
2334}
2335
Harald Welteb6c92ae2009-02-21 20:15:32 +00002336/* like abis_nm_conn_terr_traf + set_tei */
2337int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2338 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2339 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002340{
2341 struct abis_om_hdr *oh;
2342 struct abis_nm_channel *ch;
2343 struct msgb *msg = nm_msgb_alloc();
2344
2345 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002346 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002347 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2348
2349 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2350 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002351 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002352
2353 return abis_nm_sendmsg(bts, msg);
2354}
2355
2356int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2357{
2358 struct abis_om_hdr *oh;
2359 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002360
2361 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002362 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002363 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2364 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2365
2366 return abis_nm_sendmsg(trx->bts, msg);
2367}
2368
Harald Welte78fc0d42009-02-19 02:50:57 +00002369int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2370{
2371 struct abis_om_hdr *oh;
2372 struct msgb *msg = nm_msgb_alloc();
2373 u_int8_t attr = NM_ATT_BS11_TXPWR;
2374
2375 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2376 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2377 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2378 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2379
2380 return abis_nm_sendmsg(trx->bts, msg);
2381}
2382
Harald Welteaaf02d92009-04-29 13:25:57 +00002383int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2384{
2385 struct abis_om_hdr *oh;
2386 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002387 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002388
2389 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2390 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2391 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002392 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002393
2394 return abis_nm_sendmsg(bts, msg);
2395}
2396
Harald Welteef061952009-05-17 12:43:42 +00002397int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2398{
2399 struct abis_om_hdr *oh;
2400 struct msgb *msg = nm_msgb_alloc();
2401 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2402 NM_ATT_BS11_CCLK_TYPE };
2403
2404 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2405 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2406 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2407 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2408
2409 return abis_nm_sendmsg(bts, msg);
2410
2411}
Harald Welteaaf02d92009-04-29 13:25:57 +00002412
Harald Welte268bb402009-02-01 19:11:56 +00002413//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +00002414static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +00002415static const u_int8_t bs11_logon_c9[] = "FACTORY";
2416
Harald Welte1bc09062009-01-18 14:17:52 +00002417int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002418{
2419 struct abis_om_hdr *oh;
2420 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002421 struct bs11_date_time bdt;
2422
2423 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002424
2425 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002426 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002427 u_int8_t len = 3*2 + sizeof(bdt)
Harald Welte6f676a32009-01-18 14:27:48 +00002428 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +00002429 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002430 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002431 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002432 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002433 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2434 sizeof(bs11_logon_c8), bs11_logon_c8);
2435 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2436 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +00002437 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002438 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002439 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002440 }
Harald Welte05188ee2009-01-18 11:39:08 +00002441
2442 return abis_nm_sendmsg(bts, msg);
2443}
Harald Welte1bc09062009-01-18 14:17:52 +00002444
2445int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2446{
2447 struct abis_om_hdr *oh;
2448 struct msgb *msg;
2449
2450 if (strlen(password) != 10)
2451 return -EINVAL;
2452
2453 msg = nm_msgb_alloc();
2454 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002455 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002456 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2457 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2458
2459 return abis_nm_sendmsg(bts, msg);
2460}
2461
Harald Weltee69f5fb2009-04-28 16:31:38 +00002462/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2463int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2464{
2465 struct abis_om_hdr *oh;
2466 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002467 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002468
2469 msg = nm_msgb_alloc();
2470 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2471 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2472 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002473
2474 if (locked)
2475 tlv_value = BS11_LI_PLL_LOCKED;
2476 else
2477 tlv_value = BS11_LI_PLL_STANDALONE;
2478
2479 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002480
2481 return abis_nm_sendmsg(bts, msg);
2482}
2483
Harald Welte1bc09062009-01-18 14:17:52 +00002484int abis_nm_bs11_get_state(struct gsm_bts *bts)
2485{
2486 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2487}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002488
2489/* BS11 SWL */
2490
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002491void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002492
Harald Welte5e4d1b32009-02-01 13:36:56 +00002493struct abis_nm_bs11_sw {
2494 struct gsm_bts *bts;
2495 char swl_fname[PATH_MAX];
2496 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002497 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002498 struct llist_head file_list;
2499 gsm_cbfn *user_cb; /* specified by the user */
2500};
2501static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2502
2503struct file_list_entry {
2504 struct llist_head list;
2505 char fname[PATH_MAX];
2506};
2507
2508struct file_list_entry *fl_dequeue(struct llist_head *queue)
2509{
2510 struct llist_head *lh;
2511
2512 if (llist_empty(queue))
2513 return NULL;
2514
2515 lh = queue->next;
2516 llist_del(lh);
2517
2518 return llist_entry(lh, struct file_list_entry, list);
2519}
2520
2521static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2522{
2523 char linebuf[255];
2524 struct llist_head *lh, *lh2;
2525 FILE *swl;
2526 int rc = 0;
2527
2528 swl = fopen(bs11_sw->swl_fname, "r");
2529 if (!swl)
2530 return -ENODEV;
2531
2532 /* zero the stale file list, if any */
2533 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2534 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002535 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002536 }
2537
2538 while (fgets(linebuf, sizeof(linebuf), swl)) {
2539 char file_id[12+1];
2540 char file_version[80+1];
2541 struct file_list_entry *fle;
2542 static char dir[PATH_MAX];
2543
2544 if (strlen(linebuf) < 4)
2545 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002546
Harald Welte5e4d1b32009-02-01 13:36:56 +00002547 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2548 if (rc < 0) {
2549 perror("ERR parsing SWL file");
2550 rc = -EINVAL;
2551 goto out;
2552 }
2553 if (rc < 2)
2554 continue;
2555
Harald Welte470ec292009-06-26 20:25:23 +02002556 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002557 if (!fle) {
2558 rc = -ENOMEM;
2559 goto out;
2560 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002561
2562 /* construct new filename */
2563 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2564 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2565 strcat(fle->fname, "/");
2566 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002567
2568 llist_add_tail(&fle->list, &bs11_sw->file_list);
2569 }
2570
2571out:
2572 fclose(swl);
2573 return rc;
2574}
2575
2576/* bs11 swload specific callback, passed to abis_nm core swload */
2577static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2578 struct msgb *msg, void *data, void *param)
2579{
2580 struct abis_nm_bs11_sw *bs11_sw = data;
2581 struct file_list_entry *fle;
2582 int rc = 0;
2583
Harald Welte5e4d1b32009-02-01 13:36:56 +00002584 switch (event) {
2585 case NM_MT_LOAD_END_ACK:
2586 fle = fl_dequeue(&bs11_sw->file_list);
2587 if (fle) {
2588 /* start download the next file of our file list */
2589 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2590 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002591 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002592 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002593 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002594 } else {
2595 /* activate the SWL */
2596 rc = abis_nm_software_activate(bs11_sw->bts,
2597 bs11_sw->swl_fname,
2598 bs11_swload_cbfn,
2599 bs11_sw);
2600 }
2601 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002602 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002603 case NM_MT_LOAD_END_NACK:
2604 case NM_MT_LOAD_INIT_ACK:
2605 case NM_MT_LOAD_INIT_NACK:
2606 case NM_MT_ACTIVATE_SW_NACK:
2607 case NM_MT_ACTIVATE_SW_ACK:
2608 default:
2609 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002610 if (bs11_sw->user_cb)
2611 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002612 break;
2613 }
2614
2615 return rc;
2616}
2617
2618/* Siemens provides a SWL file that is a mere listing of all the other
2619 * files that are part of a software release. We need to upload first
2620 * the list file, and then each file that is listed in the list file */
2621int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002622 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002623{
2624 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2625 struct file_list_entry *fle;
2626 int rc = 0;
2627
2628 INIT_LLIST_HEAD(&bs11_sw->file_list);
2629 bs11_sw->bts = bts;
2630 bs11_sw->win_size = win_size;
2631 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002632 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002633
2634 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2635 rc = bs11_read_swl_file(bs11_sw);
2636 if (rc < 0)
2637 return rc;
2638
2639 /* dequeue next item in file list */
2640 fle = fl_dequeue(&bs11_sw->file_list);
2641 if (!fle)
2642 return -EINVAL;
2643
2644 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002645 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002646 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002647 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002648 return rc;
2649}
2650
Harald Welte5083b0b2009-02-02 19:20:52 +00002651#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002652static u_int8_t req_attr_btse[] = {
2653 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2654 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2655 NM_ATT_BS11_LMT_USER_NAME,
2656
2657 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2658
2659 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2660
2661 NM_ATT_BS11_SW_LOAD_STORED };
2662
2663static u_int8_t req_attr_btsm[] = {
2664 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2665 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2666 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2667 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002668#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002669
2670static u_int8_t req_attr[] = {
2671 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2672 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002673 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002674
2675int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2676{
2677 struct abis_om_hdr *oh;
2678 struct msgb *msg = nm_msgb_alloc();
2679
2680 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2681 /* SiemensHW CCTRL object */
2682 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2683 0x03, 0x00, 0x00);
2684 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2685
2686 return abis_nm_sendmsg(bts, msg);
2687}
Harald Welte268bb402009-02-01 19:11:56 +00002688
2689int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2690{
2691 struct abis_om_hdr *oh;
2692 struct msgb *msg = nm_msgb_alloc();
2693 struct bs11_date_time aet;
2694
2695 get_bs11_date_time(&aet);
2696 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2697 /* SiemensHW CCTRL object */
2698 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2699 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002700 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002701
2702 return abis_nm_sendmsg(bts, msg);
2703}
Harald Welte5c1e4582009-02-15 11:57:29 +00002704
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002705int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2706{
2707 struct abis_om_hdr *oh;
2708 struct msgb *msg = nm_msgb_alloc();
2709 struct bs11_date_time aet;
2710
2711 get_bs11_date_time(&aet);
2712 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2713 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2714 bport, 0xff, 0x02);
2715 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2716
2717 return abis_nm_sendmsg(bts, msg);
2718}
2719
Harald Welte5c1e4582009-02-15 11:57:29 +00002720/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002721static const char ipaccess_magic[] = "com.ipaccess";
2722
Harald Welte677c21f2009-02-17 13:22:23 +00002723
2724static int abis_nm_rx_ipacc(struct msgb *msg)
2725{
2726 struct abis_om_hdr *oh = msgb_l2(msg);
2727 struct abis_om_fom_hdr *foh;
2728 u_int8_t idstrlen = oh->data[0];
2729 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002730 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002731
2732 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002733 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002734 return -EINVAL;
2735 }
2736
Harald Welte193fefc2009-04-30 15:16:27 +00002737 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002738 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002739
Harald Weltea8bd6d42009-10-20 09:56:18 +02002740 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002741
Harald Welte746d6092009-10-19 22:11:11 +02002742 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002743
Harald Welte677c21f2009-02-17 13:22:23 +00002744 switch (foh->msg_type) {
2745 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002746 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002747 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002748 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002749 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002750 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2751 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002752 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002753 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002754 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002755 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2756 DEBUGPC(DNM, "STREAM=0x%02x ",
2757 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002758 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002759 break;
2760 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002761 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002762 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002763 DEBUGPC(DNM, " CAUSE=%s\n",
2764 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002765 else
2766 DEBUGPC(DNM, "\n");
2767 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002768 case NM_MT_IPACC_SET_NVATTR_ACK:
2769 DEBUGPC(DNM, "SET NVATTR ACK\n");
2770 /* FIXME: decode and show the actual attributes */
2771 break;
2772 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002773 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002774 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002775 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002776 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2777 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002778 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002779 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002780 case NM_MT_IPACC_GET_NVATTR_ACK:
2781 DEBUGPC(DNM, "GET NVATTR ACK\n");
2782 /* FIXME: decode and show the actual attributes */
2783 break;
2784 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002785 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002786 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002787 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002788 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2789 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002790 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002791 break;
Harald Welte15c44172009-10-08 20:15:24 +02002792 case NM_MT_IPACC_SET_ATTR_ACK:
2793 DEBUGPC(DNM, "SET ATTR ACK\n");
2794 break;
2795 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002796 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002797 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002798 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002799 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2800 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002801 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002802 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002803 default:
2804 DEBUGPC(DNM, "unknown\n");
2805 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002806 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002807
2808 /* signal handling */
2809 switch (foh->msg_type) {
2810 case NM_MT_IPACC_RSL_CONNECT_NACK:
2811 case NM_MT_IPACC_SET_NVATTR_NACK:
2812 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002813 signal.bts = msg->trx->bts;
2814 signal.msg_type = foh->msg_type;
2815 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002816 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002817 case NM_MT_IPACC_SET_NVATTR_ACK:
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_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002821 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002822 default:
2823 break;
2824 }
2825
Harald Welte677c21f2009-02-17 13:22:23 +00002826 return 0;
2827}
2828
Harald Welte193fefc2009-04-30 15:16:27 +00002829/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002830int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2831 u_int8_t obj_class, u_int8_t bts_nr,
2832 u_int8_t trx_nr, u_int8_t ts_nr,
2833 u_int8_t *attr, int attr_len)
2834{
2835 struct msgb *msg = nm_msgb_alloc();
2836 struct abis_om_hdr *oh;
2837 struct abis_om_fom_hdr *foh;
2838 u_int8_t *data;
2839
2840 /* construct the 12.21 OM header, observe the erroneous length */
2841 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2842 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2843 oh->mdisc = ABIS_OM_MDISC_MANUF;
2844
2845 /* add the ip.access magic */
2846 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2847 *data++ = sizeof(ipaccess_magic);
2848 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2849
2850 /* fill the 12.21 FOM header */
2851 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2852 foh->msg_type = msg_type;
2853 foh->obj_class = obj_class;
2854 foh->obj_inst.bts_nr = bts_nr;
2855 foh->obj_inst.trx_nr = trx_nr;
2856 foh->obj_inst.ts_nr = ts_nr;
2857
2858 if (attr && attr_len) {
2859 data = msgb_put(msg, attr_len);
2860 memcpy(data, attr, attr_len);
2861 }
2862
2863 return abis_nm_sendmsg(bts, msg);
2864}
Harald Welte677c21f2009-02-17 13:22:23 +00002865
Harald Welte193fefc2009-04-30 15:16:27 +00002866/* set some attributes in NVRAM */
2867int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2868 int attr_len)
2869{
2870 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2871 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2872 attr_len);
2873}
2874
Harald Welte746d6092009-10-19 22:11:11 +02002875int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2876 u_int32_t ip, u_int16_t port, u_int8_t stream)
2877{
2878 struct in_addr ia;
2879 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2880 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2881 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2882
2883 int attr_len = sizeof(attr);
2884
2885 ia.s_addr = htonl(ip);
2886 attr[1] = stream;
2887 attr[3] = port >> 8;
2888 attr[4] = port & 0xff;
2889 *(u_int32_t *)(attr+6) = ia.s_addr;
2890
2891 /* if ip == 0, we use the default IP */
2892 if (ip == 0)
2893 attr_len -= 5;
2894
2895 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002896 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002897
2898 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2899 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2900 trx->nr, 0xff, attr, attr_len);
2901}
2902
Harald Welte193fefc2009-04-30 15:16:27 +00002903/* restart / reboot an ip.access nanoBTS */
2904int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2905{
2906 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2907}
Harald Weltedaef5212009-10-24 10:20:41 +02002908
2909int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2910 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2911 u_int8_t *attr, u_int8_t attr_len)
2912{
2913 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2914 obj_class, bts_nr, trx_nr, ts_nr,
2915 attr, attr_len);
2916}
Harald Welte0f255852009-11-12 14:48:42 +01002917
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002918void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2919{
2920 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2921
2922 trx->rf_locked = locked;
2923 if (!trx->bts || !trx->bts->oml_link)
2924 return;
2925
2926 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2927 trx->bts->bts_nr, trx->nr, 0xff,
2928 new_state);
2929}
2930
Harald Welte0f255852009-11-12 14:48:42 +01002931static const char *ipacc_testres_names[] = {
2932 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2933 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2934 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2935 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2936 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2937};
2938
2939const char *ipacc_testres_name(u_int8_t res)
2940{
2941 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2942 ipacc_testres_names[res])
2943 return ipacc_testres_names[res];
2944
2945 return "unknown";
2946}
2947
Harald Welteb40a38f2009-11-13 11:56:05 +01002948void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2949{
2950 cid->mcc = (buf[0] & 0xf) * 100;
2951 cid->mcc += (buf[0] >> 4) * 10;
2952 cid->mcc += (buf[1] & 0xf) * 1;
2953
2954 if (buf[1] >> 4 == 0xf) {
2955 cid->mnc = (buf[2] & 0xf) * 10;
2956 cid->mnc += (buf[2] >> 4) * 1;
2957 } else {
2958 cid->mnc = (buf[2] & 0xf) * 100;
2959 cid->mnc += (buf[2] >> 4) * 10;
2960 cid->mnc += (buf[1] >> 4) * 1;
2961 }
2962
Harald Welteaff237d2009-11-13 14:41:52 +01002963 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2964 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002965}
2966
Harald Welte0f255852009-11-12 14:48:42 +01002967/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2968int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2969{
2970 u_int8_t *cur = buf;
2971 u_int16_t len;
2972
2973 memset(binf, 0, sizeof(binf));
2974
2975 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2976 return -EINVAL;
2977 cur++;
2978
2979 len = ntohs(*(u_int16_t *)cur);
2980 cur += 2;
2981
2982 binf->info_type = ntohs(*(u_int16_t *)cur);
2983 cur += 2;
2984
2985 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2986 binf->freq_qual = *cur >> 2;
2987
2988 binf->arfcn = *cur++ & 3 << 8;
2989 binf->arfcn |= *cur++;
2990
2991 if (binf->info_type & IPAC_BINF_RXLEV)
2992 binf->rx_lev = *cur & 0x3f;
2993 cur++;
2994
2995 if (binf->info_type & IPAC_BINF_RXQUAL)
2996 binf->rx_qual = *cur & 0x7;
2997 cur++;
2998
2999 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3000 binf->freq_err = ntohs(*(u_int16_t *)cur);
3001 cur += 2;
3002
3003 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3004 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3005 cur += 2;
3006
3007 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3008 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3009 cur += 4;
3010
3011 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01003012 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003013 cur++;
3014
Harald Welteb40a38f2009-11-13 11:56:05 +01003015 ipac_parse_cgi(&binf->cgi, cur);
3016 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003017
3018 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3019 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3020 cur += sizeof(binf->ba_list_si2);
3021 }
3022
3023 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3024 memcpy(binf->ba_list_si2bis, cur,
3025 sizeof(binf->ba_list_si2bis));
3026 cur += sizeof(binf->ba_list_si2bis);
3027 }
3028
3029 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3030 memcpy(binf->ba_list_si2ter, cur,
3031 sizeof(binf->ba_list_si2ter));
3032 cur += sizeof(binf->ba_list_si2ter);
3033 }
3034
3035 return 0;
3036}
3037
3038