blob: 2be71f5ed8e46988e91c6bb6d18d5a9a45de4168 [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
Harald Welte52b1f982008-12-23 20:25:15 +000050
51/* unidirectional messages from BTS to BSC */
52static const enum abis_nm_msgtype reports[] = {
53 NM_MT_SW_ACTIVATED_REP,
54 NM_MT_TEST_REP,
55 NM_MT_STATECHG_EVENT_REP,
56 NM_MT_FAILURE_EVENT_REP,
57};
58
59/* messages without ACK/NACK */
60static const enum abis_nm_msgtype no_ack_nack[] = {
61 NM_MT_MEAS_RES_REQ,
62 NM_MT_STOP_MEAS,
63 NM_MT_START_MEAS,
64};
65
Harald Welte4724f992009-01-18 18:01:49 +000066/* Messages related to software load */
67static const enum abis_nm_msgtype sw_load_msgs[] = {
68 NM_MT_LOAD_INIT_ACK,
69 NM_MT_LOAD_INIT_NACK,
70 NM_MT_LOAD_SEG_ACK,
71 NM_MT_LOAD_ABORT,
72 NM_MT_LOAD_END_ACK,
73 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000074 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000075 NM_MT_ACTIVATE_SW_ACK,
76 NM_MT_ACTIVATE_SW_NACK,
77 NM_MT_SW_ACTIVATED_REP,
78};
79
Harald Weltee0590df2009-02-15 03:34:15 +000080static const enum abis_nm_msgtype nacks[] = {
81 NM_MT_LOAD_INIT_NACK,
82 NM_MT_LOAD_END_NACK,
83 NM_MT_SW_ACT_REQ_NACK,
84 NM_MT_ACTIVATE_SW_NACK,
85 NM_MT_ESTABLISH_TEI_NACK,
86 NM_MT_CONN_TERR_SIGN_NACK,
87 NM_MT_DISC_TERR_SIGN_NACK,
88 NM_MT_CONN_TERR_TRAF_NACK,
89 NM_MT_DISC_TERR_TRAF_NACK,
90 NM_MT_CONN_MDROP_LINK_NACK,
91 NM_MT_DISC_MDROP_LINK_NACK,
92 NM_MT_SET_BTS_ATTR_NACK,
93 NM_MT_SET_RADIO_ATTR_NACK,
94 NM_MT_SET_CHAN_ATTR_NACK,
95 NM_MT_PERF_TEST_NACK,
96 NM_MT_SEND_TEST_REP_NACK,
97 NM_MT_STOP_TEST_NACK,
98 NM_MT_STOP_EVENT_REP_NACK,
99 NM_MT_REST_EVENT_REP_NACK,
100 NM_MT_CHG_ADM_STATE_NACK,
101 NM_MT_CHG_ADM_STATE_REQ_NACK,
102 NM_MT_REP_OUTST_ALARMS_NACK,
103 NM_MT_CHANGEOVER_NACK,
104 NM_MT_OPSTART_NACK,
105 NM_MT_REINIT_NACK,
106 NM_MT_SET_SITE_OUT_NACK,
107 NM_MT_CHG_HW_CONF_NACK,
108 NM_MT_GET_ATTR_NACK,
109 NM_MT_SET_ALARM_THRES_NACK,
110 NM_MT_BS11_BEGIN_DB_TX_NACK,
111 NM_MT_BS11_END_DB_TX_NACK,
112 NM_MT_BS11_CREATE_OBJ_NACK,
113 NM_MT_BS11_DELETE_OBJ_NACK,
114};
Harald Welte78fc0d42009-02-19 02:50:57 +0000115
116static const char *nack_names[0xff] = {
117 [NM_MT_LOAD_INIT_NACK] = "SOFTWARE LOAD INIT",
118 [NM_MT_LOAD_END_NACK] = "SOFTWARE LOAD END",
119 [NM_MT_SW_ACT_REQ_NACK] = "SOFTWARE ACTIVATE REQUEST",
120 [NM_MT_ACTIVATE_SW_NACK] = "ACTIVATE SOFTWARE",
121 [NM_MT_ESTABLISH_TEI_NACK] = "ESTABLISH TEI",
122 [NM_MT_CONN_TERR_SIGN_NACK] = "CONNECT TERRESTRIAL SIGNALLING",
123 [NM_MT_DISC_TERR_SIGN_NACK] = "DISCONNECT TERRESTRIAL SIGNALLING",
124 [NM_MT_CONN_TERR_TRAF_NACK] = "CONNECT TERRESTRIAL TRAFFIC",
125 [NM_MT_DISC_TERR_TRAF_NACK] = "DISCONNECT TERRESTRIAL TRAFFIC",
126 [NM_MT_CONN_MDROP_LINK_NACK] = "CONNECT MULTI-DROP LINK",
127 [NM_MT_DISC_MDROP_LINK_NACK] = "DISCONNECT MULTI-DROP LINK",
128 [NM_MT_SET_BTS_ATTR_NACK] = "SET BTS ATTRIBUTE",
129 [NM_MT_SET_RADIO_ATTR_NACK] = "SET RADIO ATTRIBUTE",
130 [NM_MT_SET_CHAN_ATTR_NACK] = "SET CHANNEL ATTRIBUTE",
131 [NM_MT_PERF_TEST_NACK] = "PERFORM TEST",
132 [NM_MT_SEND_TEST_REP_NACK] = "SEND TEST REPORT",
133 [NM_MT_STOP_TEST_NACK] = "STOP TEST",
134 [NM_MT_STOP_EVENT_REP_NACK] = "STOP EVENT REPORT",
135 [NM_MT_REST_EVENT_REP_NACK] = "RESET EVENT REPORT",
136 [NM_MT_CHG_ADM_STATE_NACK] = "CHANGE ADMINISTRATIVE STATE",
137 [NM_MT_CHG_ADM_STATE_REQ_NACK] = "CHANGE ADMINISTRATIVE STATE REQUEST",
138 [NM_MT_REP_OUTST_ALARMS_NACK] = "REPORT OUTSTANDING ALARMS",
139 [NM_MT_CHANGEOVER_NACK] = "CHANGEOVER",
140 [NM_MT_OPSTART_NACK] = "OPSTART",
141 [NM_MT_REINIT_NACK] = "REINIT",
142 [NM_MT_SET_SITE_OUT_NACK] = "SET SITE OUTPUT",
143 [NM_MT_CHG_HW_CONF_NACK] = "CHANGE HARDWARE CONFIGURATION",
144 [NM_MT_GET_ATTR_NACK] = "GET ATTRIBUTE",
145 [NM_MT_SET_ALARM_THRES_NACK] = "SET ALARM THRESHOLD",
146 [NM_MT_BS11_BEGIN_DB_TX_NACK] = "BS11 BEGIN DATABASE TRANSMISSION",
147 [NM_MT_BS11_END_DB_TX_NACK] = "BS11 END DATABASE TRANSMISSION",
148 [NM_MT_BS11_CREATE_OBJ_NACK] = "BS11 CREATE OBJECT",
149 [NM_MT_BS11_DELETE_OBJ_NACK] = "BS11 DELETE OBJECT",
150};
151
Harald Welte6c96ba52009-05-01 13:03:40 +0000152/* Chapter 9.4.36 */
153static const char *nack_cause_names[] = {
154 /* General Nack Causes */
155 [NM_NACK_INCORR_STRUCT] = "Incorrect message structure",
156 [NM_NACK_MSGTYPE_INVAL] = "Invalid message type value",
157 [NM_NACK_OBJCLASS_INVAL] = "Invalid Object class value",
158 [NM_NACK_OBJCLASS_NOTSUPP] = "Object class not supported",
159 [NM_NACK_BTSNR_UNKN] = "BTS no. unknown",
160 [NM_NACK_TRXNR_UNKN] = "Baseband Transceiver no. unknown",
161 [NM_NACK_OBJINST_UNKN] = "Object Instance unknown",
162 [NM_NACK_ATTRID_INVAL] = "Invalid attribute identifier value",
163 [NM_NACK_ATTRID_NOTSUPP] = "Attribute identifier not supported",
164 [NM_NACK_PARAM_RANGE] = "Parameter value outside permitted range",
165 [NM_NACK_ATTRLIST_INCONSISTENT] = "Inconsistency in attribute list",
166 [NM_NACK_SPEC_IMPL_NOTSUPP] = "Specified implementation not supported",
167 [NM_NACK_CANT_PERFORM] = "Message cannot be performed",
168 /* Specific Nack Causes */
169 [NM_NACK_RES_NOTIMPL] = "Resource not implemented",
170 [NM_NACK_RES_NOTAVAIL] = "Resource not available",
171 [NM_NACK_FREQ_NOTAVAIL] = "Frequency not available",
172 [NM_NACK_TEST_NOTSUPP] = "Test not supported",
173 [NM_NACK_CAPACITY_RESTR] = "Capacity restrictions",
174 [NM_NACK_PHYSCFG_NOTPERFORM] = "Physical configuration cannot be performed",
175 [NM_NACK_TEST_NOTINIT] = "Test not initiated",
176 [NM_NACK_PHYSCFG_NOTRESTORE] = "Physical configuration cannot be restored",
177 [NM_NACK_TEST_NOSUCH] = "No such test",
178 [NM_NACK_TEST_NOSTOP] = "Test cannot be stopped",
179 [NM_NACK_MSGINCONSIST_PHYSCFG] = "Message inconsistent with physical configuration",
180 [NM_NACK_FILE_INCOMPLETE] = "Complete file notreceived",
181 [NM_NACK_FILE_NOTAVAIL] = "File not available at destination",
Harald Welte560982b2009-06-26 13:21:57 +0200182 [NM_NACK_FILE_NOTACTIVATE] = "File cannot be activate",
Harald Welte6c96ba52009-05-01 13:03:40 +0000183 [NM_NACK_REQ_NOT_GRANT] = "Request not granted",
184 [NM_NACK_WAIT] = "Wait",
185 [NM_NACK_NOTH_REPORT_EXIST] = "Nothing reportable existing",
186 [NM_NACK_MEAS_NOTSUPP] = "Measurement not supported",
187 [NM_NACK_MEAS_NOTSTART] = "Measurement not started",
188};
189
190static char namebuf[255];
191static const char *nack_cause_name(u_int8_t cause)
192{
193 if (cause < ARRAY_SIZE(nack_cause_names) && nack_cause_names[cause])
194 return nack_cause_names[cause];
195
196 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
197 return namebuf;
198}
199
Harald Welte0db97b22009-05-01 17:22:47 +0000200/* Chapter 9.4.16: Event Type */
201static const char *event_type_names[] = {
202 [NM_EVT_COMM_FAIL] = "communication failure",
203 [NM_EVT_QOS_FAIL] = "quality of service failure",
204 [NM_EVT_PROC_FAIL] = "processing failure",
205 [NM_EVT_EQUIP_FAIL] = "equipment failure",
206 [NM_EVT_ENV_FAIL] = "environment failure",
207};
208
209static const char *event_type_name(u_int8_t cause)
210{
211 if (cause < ARRAY_SIZE(event_type_names) && event_type_names[cause])
212 return event_type_names[cause];
213
214 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
215 return namebuf;
216}
217
218/* Chapter 9.4.63: Perceived Severity */
219static const char *severity_names[] = {
220 [NM_SEVER_CEASED] = "failure ceased",
221 [NM_SEVER_CRITICAL] = "critical failure",
222 [NM_SEVER_MAJOR] = "major failure",
223 [NM_SEVER_MINOR] = "minor failure",
224 [NM_SEVER_WARNING] = "warning level failure",
225 [NM_SEVER_INDETERMINATE] = "indeterminate failure",
226};
227
228static const char *severity_name(u_int8_t cause)
229{
230 if (cause < ARRAY_SIZE(severity_names) && severity_names[cause])
231 return severity_names[cause];
232
233 snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
234 return namebuf;
235}
236
Harald Welte52b1f982008-12-23 20:25:15 +0000237/* Attributes that the BSC can set, not only get, according to Section 9.4 */
238static const enum abis_nm_attr nm_att_settable[] = {
239 NM_ATT_ADD_INFO,
240 NM_ATT_ADD_TEXT,
241 NM_ATT_DEST,
242 NM_ATT_EVENT_TYPE,
243 NM_ATT_FILE_DATA,
244 NM_ATT_GET_ARI,
245 NM_ATT_HW_CONF_CHG,
246 NM_ATT_LIST_REQ_ATTR,
247 NM_ATT_MDROP_LINK,
248 NM_ATT_MDROP_NEXT,
249 NM_ATT_NACK_CAUSES,
250 NM_ATT_OUTST_ALARM,
251 NM_ATT_PHYS_CONF,
252 NM_ATT_PROB_CAUSE,
253 NM_ATT_RAD_SUBC,
254 NM_ATT_SOURCE,
255 NM_ATT_SPEC_PROB,
256 NM_ATT_START_TIME,
257 NM_ATT_TEST_DUR,
258 NM_ATT_TEST_NO,
259 NM_ATT_TEST_REPORT,
260 NM_ATT_WINDOW_SIZE,
261 NM_ATT_SEVERITY,
262 NM_ATT_MEAS_RES,
263 NM_ATT_MEAS_TYPE,
264};
265
Harald Weltee0590df2009-02-15 03:34:15 +0000266static const struct tlv_definition nm_att_tlvdef = {
267 .def = {
268 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
269 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
270 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
271 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
272 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
273 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
274 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
275 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
276 [NM_ATT_BSIC] = { TLV_TYPE_TV },
277 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
278 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
279 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
280 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
281 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
282 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
283 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
284 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
285 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
286 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
287 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
288 [NM_ATT_HSN] = { TLV_TYPE_TV },
289 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
290 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
291 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
292 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
293 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
294 [NM_ATT_MAIO] = { TLV_TYPE_TV },
295 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
297 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
298 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
299 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
300 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
301 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
302 [NM_ATT_NY1] = { TLV_TYPE_TV },
303 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
304 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
305 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
306 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
307 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
308 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
309 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
310 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
311 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
312 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
313 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
314 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
315 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
316 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
317 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
318 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
319 [NM_ATT_TEI] = { TLV_TYPE_TV },
320 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
321 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
322 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
323 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
324 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
325 [NM_ATT_TSC] = { TLV_TYPE_TV },
326 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
327 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
328 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
329 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
330 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000331 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
332 /* BS11 specifics */
Harald Welte78fc0d42009-02-19 02:50:57 +0000333 [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV },
334 [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV },
335 [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV },
336 [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV },
337 [0xd5] = { TLV_TYPE_TLV },
338 [0xa8] = { TLV_TYPE_TLV },
Harald Weltee0590df2009-02-15 03:34:15 +0000339 [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV },
340 [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV },
341 [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV },
342 [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV },
343 [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV },
344 [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 },
345 [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV },
Harald Welteee670472009-02-22 21:58:49 +0000346 [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },
Harald Weltee0590df2009-02-15 03:34:15 +0000347 [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV },
348 [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
349 [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV },
Harald Welte03133942009-02-18 19:51:53 +0000350 [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV },
351 [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV },
Harald Welteaaf02d92009-04-29 13:25:57 +0000352 [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV },
Harald Weltea7cfa032009-04-29 22:33:02 +0000353 [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV },
Harald Welteef061952009-05-17 12:43:42 +0000354 [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV },
355 [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV },
Harald Welte677c21f2009-02-17 13:22:23 +0000356 /* ip.access specifics */
Harald Welte0efe9b72009-07-12 09:33:54 +0200357 [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
358 [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200359 [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
360 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, },
361 [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
362 [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
363 [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
364 [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
365 [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
366 [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
367 [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
368 [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
369 [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
Harald Welte0efe9b72009-07-12 09:33:54 +0200370 [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200371 [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
372 [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
Harald Welte0efe9b72009-07-12 09:33:54 +0200373 [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200374 [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
375 [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
376 [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
377 [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
378 [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
379 [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
380 [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
381 [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
382 [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
383 [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
384 [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
385 [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
386 [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200387 [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
Harald Welte4fbfd3a2009-08-06 17:57:23 +0200388 [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
389 [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
390 [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
391 [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
392 [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
393 [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
394 [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
395 [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
396 [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
397 [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
398 [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
399 [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
Harald Weltea0c0b572009-07-03 12:46:27 +0200400 //[0x95] = { TLV_TYPE_FIXED, 2 },
Harald Welte677c21f2009-02-17 13:22:23 +0000401 [0x85] = { TLV_TYPE_TV },
402
Harald Weltee0590df2009-02-15 03:34:15 +0000403 },
404};
Harald Welte03133942009-02-18 19:51:53 +0000405
Harald Welte21bd3a52009-08-10 12:21:22 +0200406static const enum abis_nm_chan_comb chcomb4pchan[] = {
407 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
408 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
409 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
410 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
411 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200412 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
413 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200414 /* FIXME: bounds check */
415};
416
417int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
418{
419 if (pchan < ARRAY_SIZE(chcomb4pchan))
420 return chcomb4pchan[pchan];
421
422 return -EINVAL;
423}
424
Harald Welte03133942009-02-18 19:51:53 +0000425int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
426{
Harald Weltea4d49e92009-05-23 06:39:58 +0000427 return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000428}
Harald Weltee0590df2009-02-15 03:34:15 +0000429
Harald Welte52b1f982008-12-23 20:25:15 +0000430static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
431{
432 int i;
433
434 for (i = 0; i < size; i++) {
435 if (arr[i] == mt)
436 return 1;
437 }
438
439 return 0;
440}
441
Holger Freytherca362a62009-01-04 21:05:01 +0000442#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000443/* is this msgtype the usual ACK/NACK type ? */
444static int is_ack_nack(enum abis_nm_msgtype mt)
445{
446 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
447}
Holger Freytherca362a62009-01-04 21:05:01 +0000448#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000449
450/* is this msgtype a report ? */
451static int is_report(enum abis_nm_msgtype mt)
452{
Harald Welte8470bf22008-12-25 23:28:35 +0000453 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000454}
455
456#define MT_ACK(x) (x+1)
457#define MT_NACK(x) (x+2)
458
459static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
460{
461 oh->mdisc = ABIS_OM_MDISC_FOM;
462 oh->placement = ABIS_OM_PLACEMENT_ONLY;
463 oh->sequence = 0;
464 oh->length = len;
465}
466
467static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
468 u_int8_t msg_type, u_int8_t obj_class,
469 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
470{
471 struct abis_om_fom_hdr *foh =
472 (struct abis_om_fom_hdr *) oh->data;
473
Harald Welte702d8702008-12-26 20:25:35 +0000474 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000475 foh->msg_type = msg_type;
476 foh->obj_class = obj_class;
477 foh->obj_inst.bts_nr = bts_nr;
478 foh->obj_inst.trx_nr = trx_nr;
479 foh->obj_inst.ts_nr = ts_nr;
480}
481
Harald Welte8470bf22008-12-25 23:28:35 +0000482static struct msgb *nm_msgb_alloc(void)
483{
Harald Welte966636f2009-06-26 19:39:35 +0200484 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
485 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000486}
487
Harald Welte52b1f982008-12-23 20:25:15 +0000488/* Send a OML NM Message from BSC to BTS */
489int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
490{
Holger Freyther59639e82009-02-09 23:09:55 +0000491 msg->trx = bts->c0;
492
Harald Weltead384642008-12-26 10:20:07 +0000493 return _abis_nm_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000494}
495
Harald Welte4724f992009-01-18 18:01:49 +0000496static int abis_nm_rcvmsg_sw(struct msgb *mb);
497
Harald Welte34a99682009-02-13 02:41:40 +0000498static const char *obj_class_name(u_int8_t oc)
499{
Harald Welte7b26bcb2009-05-28 11:39:21 +0000500 switch (oc) {
501 case NM_OC_SITE_MANAGER:
502 return "SITE MANAGER";
503 case NM_OC_BTS:
504 return "BTS";
505 case NM_OC_RADIO_CARRIER:
506 return "RADIO CARRIER";
507 case NM_OC_BASEB_TRANSC:
508 return "BASEBAND TRANSCEIVER";
509 case NM_OC_CHANNEL:
Harald Weltebd8f7e32009-06-09 20:17:12 +0000510 return "CHANNEL";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000511 case NM_OC_BS11_ADJC:
512 return "ADJC";
513 case NM_OC_BS11_HANDOVER:
514 return "HANDOVER";
515 case NM_OC_BS11_PWR_CTRL:
516 return "POWER CONTROL";
517 case NM_OC_BS11_BTSE:
518 return "BTSE";
519 case NM_OC_BS11_RACK:
520 return "RACK";
521 case NM_OC_BS11_TEST:
522 return "TEST";
523 case NM_OC_BS11_ENVABTSE:
524 return "ENVABTSE";
525 case NM_OC_BS11_BPORT:
526 return "BPORT";
527 case NM_OC_GPRS_NSE:
528 return "GPRS NSE";
529 case NM_OC_GPRS_CELL:
530 return "GPRS CELL";
Harald Welted83a1272009-07-12 10:56:06 +0200531 case NM_OC_GPRS_NSVC:
532 return "GPRS NSVC";
Harald Welte8b697c72009-06-05 19:18:45 +0000533 case NM_OC_BS11:
534 return "SIEMENSHW";
Harald Welte7b26bcb2009-05-28 11:39:21 +0000535 }
536
537 return "UNKNOWN";
Harald Welte34a99682009-02-13 02:41:40 +0000538}
539
Harald Welte4d87f242009-03-10 19:43:44 +0000540const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000541{
542 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100543 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000544 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100545 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000546 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100547 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000548 return "NULL";
549 default:
550 return "RFU";
551 }
552}
553
Harald Weltee0590df2009-02-15 03:34:15 +0000554/* Chapter 9.4.7 */
Harald Welte4d87f242009-03-10 19:43:44 +0000555static const char *avail_names[] = {
Harald Weltee0590df2009-02-15 03:34:15 +0000556 "In test",
557 "Failed",
558 "Power off",
559 "Off line",
560 "<not used>",
561 "Dependency",
562 "Degraded",
563 "Not installed",
564};
565
Harald Welte4d87f242009-03-10 19:43:44 +0000566const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000567{
Harald Welte0b8348d2009-02-18 03:43:01 +0000568 if (avail == 0xff)
569 return "OK";
Harald Weltee0590df2009-02-15 03:34:15 +0000570 if (avail >= ARRAY_SIZE(avail_names))
571 return "UNKNOWN";
572 return avail_names[avail];
573}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000574
Harald Welte0f255852009-11-12 14:48:42 +0100575static struct value_string test_names[] = {
576 /* FIXME: standard test names */
577 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
578 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
579 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
580 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
581 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
582 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
583 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
584 { 0, NULL }
585};
586
Harald Welte7b26bcb2009-05-28 11:39:21 +0000587const char *nm_adm_name(u_int8_t adm)
588{
589 switch (adm) {
590 case 1:
591 return "Locked";
592 case 2:
593 return "Unlocked";
594 case 3:
595 return "Shutdown";
596 default:
597 return "<not used>";
598 }
599}
Harald Weltee0590df2009-02-15 03:34:15 +0000600
Harald Weltea8bd6d42009-10-20 09:56:18 +0200601static void debugp_foh(struct abis_om_fom_hdr *foh)
602{
603 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
604 obj_class_name(foh->obj_class), foh->obj_class,
605 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
606 foh->obj_inst.ts_nr);
607}
608
Harald Weltee0590df2009-02-15 03:34:15 +0000609/* obtain the gsm_nm_state data structure for a given object instance */
610static struct gsm_nm_state *
611objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
612 struct abis_om_obj_inst *obj_inst)
613{
614 struct gsm_bts_trx *trx;
615 struct gsm_nm_state *nm_state = NULL;
616
617 switch (obj_class) {
618 case NM_OC_BTS:
619 nm_state = &bts->nm_state;
620 break;
621 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100622 if (obj_inst->trx_nr >= bts->num_trx) {
623 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000624 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100625 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200626 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000627 nm_state = &trx->nm_state;
628 break;
629 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100630 if (obj_inst->trx_nr >= bts->num_trx) {
631 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000632 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100633 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200634 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000635 nm_state = &trx->bb_transc.nm_state;
636 break;
637 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100638 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100639 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000640 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100641 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200642 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000643 if (obj_inst->ts_nr >= TRX_NR_TS)
644 return NULL;
645 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
646 break;
647 case NM_OC_SITE_MANAGER:
648 nm_state = &bts->site_mgr.nm_state;
649 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000650 case NM_OC_BS11:
651 switch (obj_inst->bts_nr) {
652 case BS11_OBJ_CCLK:
653 nm_state = &bts->bs11.cclk.nm_state;
654 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000655 case BS11_OBJ_BBSIG:
656 if (obj_inst->ts_nr > bts->num_trx)
657 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200658 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000659 nm_state = &trx->bs11.bbsig.nm_state;
660 break;
661 case BS11_OBJ_PA:
662 if (obj_inst->ts_nr > bts->num_trx)
663 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200664 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000665 nm_state = &trx->bs11.pa.nm_state;
666 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000667 default:
668 return NULL;
669 }
670 case NM_OC_BS11_RACK:
671 nm_state = &bts->bs11.rack.nm_state;
672 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000673 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100674 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000675 return NULL;
676 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
677 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200678 case NM_OC_GPRS_NSE:
679 nm_state = &bts->gprs.nse.nm_state;
680 break;
681 case NM_OC_GPRS_CELL:
682 nm_state = &bts->gprs.cell.nm_state;
683 break;
684 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100685 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200686 return NULL;
687 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
688 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000689 }
690 return nm_state;
691}
692
693/* obtain the in-memory data structure of a given object instance */
694static void *
695objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
696 struct abis_om_obj_inst *obj_inst)
697{
698 struct gsm_bts_trx *trx;
699 void *obj = NULL;
700
701 switch (obj_class) {
702 case NM_OC_BTS:
703 obj = bts;
704 break;
705 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100706 if (obj_inst->trx_nr >= bts->num_trx) {
707 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000708 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100709 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200710 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000711 obj = trx;
712 break;
713 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100714 if (obj_inst->trx_nr >= bts->num_trx) {
715 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000716 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100717 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200718 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000719 obj = &trx->bb_transc;
720 break;
721 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100722 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100723 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000724 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100725 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200726 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000727 if (obj_inst->ts_nr >= TRX_NR_TS)
728 return NULL;
729 obj = &trx->ts[obj_inst->ts_nr];
730 break;
731 case NM_OC_SITE_MANAGER:
732 obj = &bts->site_mgr;
733 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200734 case NM_OC_GPRS_NSE:
735 obj = &bts->gprs.nse;
736 break;
737 case NM_OC_GPRS_CELL:
738 obj = &bts->gprs.cell;
739 break;
740 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100741 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200742 return NULL;
743 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
744 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000745 }
746 return obj;
747}
748
749/* Update the administrative state of a given object in our in-memory data
750 * structures and send an event to the higher layer */
751static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
752 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
753{
Harald Welteaeedeb42009-05-01 13:08:14 +0000754 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000755 void *obj;
756 int rc;
757
Harald Weltee0590df2009-02-15 03:34:15 +0000758 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100759 if (!obj)
760 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000761 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
762 if (!nm_state)
763 return -1;
764
765 new_state = *nm_state;
766 new_state.administrative = adm_state;
767
768 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
769
770 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000771
772 return rc;
773}
774
Harald Welte97ed1e72009-02-06 13:38:02 +0000775static int abis_nm_rx_statechg_rep(struct msgb *mb)
776{
Harald Weltee0590df2009-02-15 03:34:15 +0000777 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000778 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000779 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000780 struct tlv_parsed tp;
781 struct gsm_nm_state *nm_state, new_state;
782 int rc;
783
Harald Welte23897662009-05-01 14:52:51 +0000784 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000785
Harald Welte8b697c72009-06-05 19:18:45 +0000786 memset(&new_state, 0, sizeof(new_state));
787
Harald Weltee0590df2009-02-15 03:34:15 +0000788 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
789 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100790 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000791 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000792 }
Harald Weltee0590df2009-02-15 03:34:15 +0000793
794 new_state = *nm_state;
795
Harald Welte03133942009-02-18 19:51:53 +0000796 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000797 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
798 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000799 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000800 }
801 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000802 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
803 new_state.availability = 0xff;
804 else
805 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000806 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000807 new_state.availability);
808 }
809 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
810 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200811 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000812 }
813 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000814
815 if (memcmp(&new_state, nm_state, sizeof(new_state))) {
816 /* Update the operational state of a given object in our in-memory data
817 * structures and send an event to the higher layer */
818 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
819 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
820 *nm_state = new_state;
821 }
822#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000823 if (op_state == 1) {
824 /* try to enable objects that are disabled */
825 abis_nm_opstart(bts, foh->obj_class,
826 foh->obj_inst.bts_nr,
827 foh->obj_inst.trx_nr,
828 foh->obj_inst.ts_nr);
829 }
Harald Weltee0590df2009-02-15 03:34:15 +0000830#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000831 return 0;
832}
833
Harald Welte0db97b22009-05-01 17:22:47 +0000834static int rx_fail_evt_rep(struct msgb *mb)
835{
836 struct abis_om_hdr *oh = msgb_l2(mb);
837 struct abis_om_fom_hdr *foh = msgb_l3(mb);
838 struct tlv_parsed tp;
839
840 DEBUGPC(DNM, "Failure Event Report ");
841
842 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
843
844 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
845 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
846 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
847 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
848
849 DEBUGPC(DNM, "\n");
850
851 return 0;
852}
853
Harald Welte97ed1e72009-02-06 13:38:02 +0000854static int abis_nm_rcvmsg_report(struct msgb *mb)
855{
856 struct abis_om_fom_hdr *foh = msgb_l3(mb);
857 u_int8_t mt = foh->msg_type;
858
Harald Weltea8bd6d42009-10-20 09:56:18 +0200859 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000860
Harald Welte97ed1e72009-02-06 13:38:02 +0000861 //nmh->cfg->report_cb(mb, foh);
862
863 switch (mt) {
864 case NM_MT_STATECHG_EVENT_REP:
865 return abis_nm_rx_statechg_rep(mb);
866 break;
Harald Welte34a99682009-02-13 02:41:40 +0000867 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000868 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000869 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000870 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000871 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000872 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000873 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000874 break;
Harald Weltec7310382009-08-08 00:02:36 +0200875 case NM_MT_TEST_REP:
876 DEBUGPC(DNM, "Test Report\n");
877 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
878 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000879 default:
Harald Welte23897662009-05-01 14:52:51 +0000880 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000881 break;
882
Harald Welte97ed1e72009-02-06 13:38:02 +0000883 };
884
Harald Welte97ed1e72009-02-06 13:38:02 +0000885 return 0;
886}
887
Harald Welte34a99682009-02-13 02:41:40 +0000888/* Activate the specified software into the BTS */
889static 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 +0200890 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000891{
892 struct abis_om_hdr *oh;
893 struct msgb *msg = nm_msgb_alloc();
894 u_int8_t len = swdesc_len;
895 u_int8_t *trailer;
896
897 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
898 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
899
900 trailer = msgb_put(msg, swdesc_len);
901 memcpy(trailer, sw_desc, swdesc_len);
902
903 return abis_nm_sendmsg(bts, msg);
904}
905
906static int abis_nm_rx_sw_act_req(struct msgb *mb)
907{
908 struct abis_om_hdr *oh = msgb_l2(mb);
909 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200910 struct tlv_parsed tp;
911 const u_int8_t *sw_config;
912 int sw_config_len;
913 int file_id_len;
Harald Welte5c1e4582009-02-15 11:57:29 +0000914 int nack = 0;
Harald Welte34a99682009-02-13 02:41:40 +0000915 int ret;
916
Harald Weltea8bd6d42009-10-20 09:56:18 +0200917 debugp_foh(foh);
918
919 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000920
Harald Welte5c1e4582009-02-15 11:57:29 +0000921 if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
922 DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
923 nack = 1;
924 } else
925 DEBUGPC(DNM, "ACKing and Activating\n");
926
927 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000928 foh->obj_inst.bts_nr,
929 foh->obj_inst.trx_nr,
Harald Welte5c1e4582009-02-15 11:57:29 +0000930 foh->obj_inst.ts_nr, nack,
Harald Welte34a99682009-02-13 02:41:40 +0000931 foh->data, oh->length-sizeof(*foh));
932
Harald Welte5c1e4582009-02-15 11:57:29 +0000933 if (nack)
934 return ret;
935
Mike Habena03f9772009-10-01 14:56:13 +0200936 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
937 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
938 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
939 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
940 DEBUGP(DNM, "SW config not found! Can't continue.\n");
941 return -EINVAL;
942 } else {
943 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
944 }
945
946 if (sw_config[0] != NM_ATT_SW_DESCR)
947 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
948 if (sw_config[1] != NM_ATT_FILE_ID)
949 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
950 file_id_len = sw_config[2] * 256 + sw_config[3];
951
952 /* Assumes first SW file in list is the one to be activated */
953 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte34a99682009-02-13 02:41:40 +0000954 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
955 foh->obj_inst.bts_nr,
956 foh->obj_inst.trx_nr,
957 foh->obj_inst.ts_nr,
Mike Habena03f9772009-10-01 14:56:13 +0200958 sw_config + 4,
959 file_id_len);
Harald Welte34a99682009-02-13 02:41:40 +0000960}
961
Harald Weltee0590df2009-02-15 03:34:15 +0000962/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
963static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
964{
965 struct abis_om_hdr *oh = msgb_l2(mb);
966 struct abis_om_fom_hdr *foh = msgb_l3(mb);
967 struct tlv_parsed tp;
968 u_int8_t adm_state;
969
Harald Welte03133942009-02-18 19:51:53 +0000970 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000971 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
972 return -EINVAL;
973
974 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
975
976 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
977}
978
Harald Welteee670472009-02-22 21:58:49 +0000979static int abis_nm_rx_lmt_event(struct msgb *mb)
980{
981 struct abis_om_hdr *oh = msgb_l2(mb);
982 struct abis_om_fom_hdr *foh = msgb_l3(mb);
983 struct tlv_parsed tp;
984
985 DEBUGP(DNM, "LMT Event ");
986 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
987 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
988 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
989 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
990 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
991 }
992 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
993 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
994 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
995 DEBUGPC(DNM, "Level=%u ", level);
996 }
997 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
998 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
999 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
1000 DEBUGPC(DNM, "Username=%s ", name);
1001 }
1002 DEBUGPC(DNM, "\n");
1003 /* FIXME: parse LMT LOGON TIME */
1004 return 0;
1005}
1006
Harald Welte52b1f982008-12-23 20:25:15 +00001007/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001008static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001009{
Harald Welte6c96ba52009-05-01 13:03:40 +00001010 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001011 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1012 u_int8_t mt = foh->msg_type;
1013
1014 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001015 if (is_report(mt))
1016 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001017
Harald Welte4724f992009-01-18 18:01:49 +00001018 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1019 return abis_nm_rcvmsg_sw(mb);
1020
Harald Welte78fc0d42009-02-19 02:50:57 +00001021 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Harald Welte6c96ba52009-05-01 13:03:40 +00001022 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001023
Harald Weltea8bd6d42009-10-20 09:56:18 +02001024 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001025
Harald Welte78fc0d42009-02-19 02:50:57 +00001026 if (nack_names[mt])
Harald Welte4bd0a982009-10-08 20:18:59 +02001027 DEBUGPC(DNM, "%s NACK ", nack_names[mt]);
Harald Welte6c96ba52009-05-01 13:03:40 +00001028 /* FIXME: NACK cause */
Harald Welte78fc0d42009-02-19 02:50:57 +00001029 else
Harald Welte4bd0a982009-10-08 20:18:59 +02001030 DEBUGPC(DNM, "NACK 0x%02x ", mt);
Harald Welte6c96ba52009-05-01 13:03:40 +00001031
1032 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
1033 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1034 DEBUGPC(DNM, "CAUSE=%s\n",
1035 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1036 else
1037 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001038
Harald Welted8cfc902009-11-17 06:09:56 +01001039 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001040 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001041 }
Harald Weltead384642008-12-26 10:20:07 +00001042#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001043 /* check if last message is to be acked */
1044 if (is_ack_nack(nmh->last_msgtype)) {
1045 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001046 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001047 /* we got our ACK, continue sending the next msg */
1048 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1049 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001050 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001051 /* FIXME: somehow signal this to the caller */
1052 } else {
1053 /* really strange things happen */
1054 return -EINVAL;
1055 }
1056 }
Harald Weltead384642008-12-26 10:20:07 +00001057#endif
1058
Harald Welte97ed1e72009-02-06 13:38:02 +00001059 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001060 case NM_MT_CHG_ADM_STATE_ACK:
1061 return abis_nm_rx_chg_adm_state_ack(mb);
1062 break;
Harald Welte34a99682009-02-13 02:41:40 +00001063 case NM_MT_SW_ACT_REQ:
1064 return abis_nm_rx_sw_act_req(mb);
1065 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001066 case NM_MT_BS11_LMT_SESSION:
Harald Welteee670472009-02-22 21:58:49 +00001067 return abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001068 break;
Harald Welte1989c082009-08-06 17:58:31 +02001069 case NM_MT_CONN_MDROP_LINK_ACK:
1070 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1071 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001072 }
1073
Harald Weltead384642008-12-26 10:20:07 +00001074 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001075}
1076
Harald Welte677c21f2009-02-17 13:22:23 +00001077static int abis_nm_rx_ipacc(struct msgb *mb);
1078
1079static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1080{
1081 int rc;
1082 int bts_type = mb->trx->bts->type;
1083
1084 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001085 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001086 rc = abis_nm_rx_ipacc(mb);
1087 break;
1088 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001089 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1090 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001091 rc = 0;
1092 break;
1093 }
1094
1095 return rc;
1096}
1097
Harald Welte52b1f982008-12-23 20:25:15 +00001098/* High-Level API */
1099/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001100int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001101{
Harald Welte52b1f982008-12-23 20:25:15 +00001102 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001103 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001104
1105 /* Various consistency checks */
1106 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001107 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001108 oh->placement);
1109 return -EINVAL;
1110 }
1111 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001112 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001113 oh->sequence);
1114 return -EINVAL;
1115 }
Harald Welte702d8702008-12-26 20:25:35 +00001116#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001117 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1118 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001119 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001120 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001121 oh->length + sizeof(*oh), l2_len);
1122 return -EINVAL;
1123 }
Harald Welte702d8702008-12-26 20:25:35 +00001124 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001125 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 +00001126#endif
Harald Weltead384642008-12-26 10:20:07 +00001127 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001128
1129 switch (oh->mdisc) {
1130 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001131 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001132 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001133 case ABIS_OM_MDISC_MANUF:
1134 rc = abis_nm_rcvmsg_manuf(msg);
1135 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001136 case ABIS_OM_MDISC_MMI:
1137 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001138 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001139 oh->mdisc);
1140 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001141 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001142 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001143 oh->mdisc);
1144 return -EINVAL;
1145 }
1146
Harald Weltead384642008-12-26 10:20:07 +00001147 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001148 return rc;
1149}
1150
1151#if 0
1152/* initialized all resources */
1153struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1154{
1155 struct abis_nm_h *nmh;
1156
1157 nmh = malloc(sizeof(*nmh));
1158 if (!nmh)
1159 return NULL;
1160
1161 nmh->cfg = cfg;
1162
1163 return nmh;
1164}
1165
1166/* free all resources */
1167void abis_nm_fini(struct abis_nm_h *nmh)
1168{
1169 free(nmh);
1170}
1171#endif
1172
1173/* Here we are trying to define a high-level API that can be used by
1174 * the actual BSC implementation. However, the architecture is currently
1175 * still under design. Ideally the calls to this API would be synchronous,
1176 * while the underlying stack behind the APi runs in a traditional select
1177 * based state machine.
1178 */
1179
Harald Welte4724f992009-01-18 18:01:49 +00001180/* 6.2 Software Load: */
1181enum sw_state {
1182 SW_STATE_NONE,
1183 SW_STATE_WAIT_INITACK,
1184 SW_STATE_WAIT_SEGACK,
1185 SW_STATE_WAIT_ENDACK,
1186 SW_STATE_WAIT_ACTACK,
1187 SW_STATE_ERROR,
1188};
Harald Welte52b1f982008-12-23 20:25:15 +00001189
Harald Welte52b1f982008-12-23 20:25:15 +00001190struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001191 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001192 gsm_cbfn *cbfn;
1193 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001194 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001195
Harald Welte52b1f982008-12-23 20:25:15 +00001196 /* this will become part of the SW LOAD INITIATE */
1197 u_int8_t obj_class;
1198 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001199
1200 u_int8_t file_id[255];
1201 u_int8_t file_id_len;
1202
1203 u_int8_t file_version[255];
1204 u_int8_t file_version_len;
1205
1206 u_int8_t window_size;
1207 u_int8_t seg_in_window;
1208
1209 int fd;
1210 FILE *stream;
1211 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001212 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001213};
1214
Harald Welte4724f992009-01-18 18:01:49 +00001215static struct abis_nm_sw g_sw;
1216
1217/* 6.2.1 / 8.3.1: Load Data Initiate */
1218static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001219{
Harald Welte4724f992009-01-18 18:01:49 +00001220 struct abis_om_hdr *oh;
1221 struct msgb *msg = nm_msgb_alloc();
1222 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1223
1224 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1225 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1226 sw->obj_instance[0], sw->obj_instance[1],
1227 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001228
1229 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1230 msgb_v_put(msg, NM_ATT_SW_DESCR);
1231 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1232 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1233 sw->file_version);
1234 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1235 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1236 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1237 sw->file_version);
1238 } else {
1239 return -1;
1240 }
Harald Welte4724f992009-01-18 18:01:49 +00001241 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1242
1243 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001244}
1245
Harald Welte1602ade2009-01-29 21:12:39 +00001246static int is_last_line(FILE *stream)
1247{
1248 char next_seg_buf[256];
1249 long pos;
1250
1251 /* check if we're sending the last line */
1252 pos = ftell(stream);
1253 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1254 fseek(stream, pos, SEEK_SET);
1255 return 1;
1256 }
1257
1258 fseek(stream, pos, SEEK_SET);
1259 return 0;
1260}
1261
Harald Welte4724f992009-01-18 18:01:49 +00001262/* 6.2.2 / 8.3.2 Load Data Segment */
1263static int sw_load_segment(struct abis_nm_sw *sw)
1264{
1265 struct abis_om_hdr *oh;
1266 struct msgb *msg = nm_msgb_alloc();
1267 char seg_buf[256];
1268 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001269 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001270 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001271
1272 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001273
1274 switch (sw->bts->type) {
1275 case GSM_BTS_TYPE_BS11:
1276 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1277 perror("fgets reading segment");
1278 return -EINVAL;
1279 }
1280 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001281
1282 /* check if we're sending the last line */
1283 sw->last_seg = is_last_line(sw->stream);
1284 if (sw->last_seg)
1285 seg_buf[1] = 0;
1286 else
1287 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001288
1289 len = strlen(line_buf) + 2;
1290 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1291 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1292 /* BS11 wants CR + LF in excess of the TLV length !?! */
1293 tlv[1] -= 2;
1294
1295 /* we only now know the exact length for the OM hdr */
1296 len = strlen(line_buf)+2;
1297 break;
1298 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001299 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001300 /* FIXME: Other BTS types */
1301 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001302 }
Harald Welte4724f992009-01-18 18:01:49 +00001303
Harald Welte4724f992009-01-18 18:01:49 +00001304 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1305 sw->obj_instance[0], sw->obj_instance[1],
1306 sw->obj_instance[2]);
1307
1308 return abis_nm_sendmsg(sw->bts, msg);
1309}
1310
1311/* 6.2.4 / 8.3.4 Load Data End */
1312static int sw_load_end(struct abis_nm_sw *sw)
1313{
1314 struct abis_om_hdr *oh;
1315 struct msgb *msg = nm_msgb_alloc();
1316 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1317
1318 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1319 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1320 sw->obj_instance[0], sw->obj_instance[1],
1321 sw->obj_instance[2]);
1322
1323 /* FIXME: this is BS11 specific format */
1324 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1325 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1326 sw->file_version);
1327
1328 return abis_nm_sendmsg(sw->bts, msg);
1329}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001330
Harald Welte52b1f982008-12-23 20:25:15 +00001331/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001332static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001333{
Harald Welte4724f992009-01-18 18:01:49 +00001334 struct abis_om_hdr *oh;
1335 struct msgb *msg = nm_msgb_alloc();
1336 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001337
Harald Welte4724f992009-01-18 18:01:49 +00001338 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1339 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1340 sw->obj_instance[0], sw->obj_instance[1],
1341 sw->obj_instance[2]);
1342
1343 /* FIXME: this is BS11 specific format */
1344 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1345 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1346 sw->file_version);
1347
1348 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001349}
Harald Welte4724f992009-01-18 18:01:49 +00001350
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001351struct sdp_firmware {
1352 char magic[4];
1353 char more_magic[4];
1354 unsigned int header_length;
1355 unsigned int file_length;
1356} __attribute__ ((packed));
1357
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001358static int parse_sdp_header(struct abis_nm_sw *sw)
1359{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001360 struct sdp_firmware firmware_header;
1361 int rc;
1362 struct stat stat;
1363
1364 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1365 if (rc != sizeof(firmware_header)) {
1366 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1367 return -1;
1368 }
1369
1370 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1371 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1372 return -1;
1373 }
1374
1375 if (firmware_header.more_magic[0] != 0x10 ||
1376 firmware_header.more_magic[1] != 0x02 ||
1377 firmware_header.more_magic[2] != 0x00 ||
1378 firmware_header.more_magic[3] != 0x00) {
1379 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1380 return -1;
1381 }
1382
1383
1384 if (fstat(sw->fd, &stat) == -1) {
1385 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1386 return -1;
1387 }
1388
1389 if (ntohl(firmware_header.file_length) != stat.st_size) {
1390 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1391 return -1;
1392 }
1393
1394 /* go back to the start as we checked the whole filesize.. */
1395 lseek(sw->fd, 0l, SEEK_SET);
1396 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1397 "There might be checksums in the file that are not\n"
1398 "verified and incomplete firmware might be flashed.\n"
1399 "There is absolutely no WARRANTY that flashing will\n"
1400 "work.\n");
1401 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001402}
1403
Harald Welte4724f992009-01-18 18:01:49 +00001404static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1405{
1406 char file_id[12+1];
1407 char file_version[80+1];
1408 int rc;
1409
1410 sw->fd = open(fname, O_RDONLY);
1411 if (sw->fd < 0)
1412 return sw->fd;
1413
1414 switch (sw->bts->type) {
1415 case GSM_BTS_TYPE_BS11:
1416 sw->stream = fdopen(sw->fd, "r");
1417 if (!sw->stream) {
1418 perror("fdopen");
1419 return -1;
1420 }
1421 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +00001422 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001423 file_id, file_version);
1424 if (rc != 2) {
1425 perror("parsing header line of software file");
1426 return -1;
1427 }
1428 strcpy((char *)sw->file_id, file_id);
1429 sw->file_id_len = strlen(file_id);
1430 strcpy((char *)sw->file_version, file_version);
1431 sw->file_version_len = strlen(file_version);
1432 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001433 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001434 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001435 case GSM_BTS_TYPE_NANOBTS:
1436 sw->stream = fdopen(sw->fd, "r");
1437 if (!sw->stream) {
1438 perror("fdopen");
1439 return -1;
1440 }
1441
1442 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001443 rc = parse_sdp_header(sw);
1444 if (rc < 0) {
1445 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1446 return -1;
1447 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001448
1449 strcpy((char *)sw->file_id, "id");
1450 sw->file_id_len = 3;
1451 strcpy((char *)sw->file_version, "version");
1452 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001453 break;
Harald Welte4724f992009-01-18 18:01:49 +00001454 default:
1455 /* We don't know how to treat them yet */
1456 close(sw->fd);
1457 return -EINVAL;
1458 }
1459
1460 return 0;
1461}
1462
1463static void sw_close_file(struct abis_nm_sw *sw)
1464{
1465 switch (sw->bts->type) {
1466 case GSM_BTS_TYPE_BS11:
1467 fclose(sw->stream);
1468 break;
1469 default:
1470 close(sw->fd);
1471 break;
1472 }
1473}
1474
1475/* Fill the window */
1476static int sw_fill_window(struct abis_nm_sw *sw)
1477{
1478 int rc;
1479
1480 while (sw->seg_in_window < sw->window_size) {
1481 rc = sw_load_segment(sw);
1482 if (rc < 0)
1483 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001484 if (sw->last_seg)
1485 break;
Harald Welte4724f992009-01-18 18:01:49 +00001486 }
1487 return 0;
1488}
1489
1490/* callback function from abis_nm_rcvmsg() handler */
1491static int abis_nm_rcvmsg_sw(struct msgb *mb)
1492{
1493 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1494 int rc = -1;
1495 struct abis_nm_sw *sw = &g_sw;
1496 enum sw_state old_state = sw->state;
1497
Harald Welte3ffd1372009-02-01 22:15:49 +00001498 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001499
1500 switch (sw->state) {
1501 case SW_STATE_WAIT_INITACK:
1502 switch (foh->msg_type) {
1503 case NM_MT_LOAD_INIT_ACK:
1504 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001505 if (sw->cbfn)
1506 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1507 NM_MT_LOAD_INIT_ACK, mb,
1508 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001509 rc = sw_fill_window(sw);
1510 sw->state = SW_STATE_WAIT_SEGACK;
1511 break;
1512 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001513 if (sw->forced) {
1514 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1515 "Init NACK\n");
1516 if (sw->cbfn)
1517 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1518 NM_MT_LOAD_INIT_ACK, mb,
1519 sw->cb_data, NULL);
1520 rc = sw_fill_window(sw);
1521 sw->state = SW_STATE_WAIT_SEGACK;
1522 } else {
1523 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001524 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001525 if (sw->cbfn)
1526 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1527 NM_MT_LOAD_INIT_NACK, mb,
1528 sw->cb_data, NULL);
1529 sw->state = SW_STATE_ERROR;
1530 }
Harald Welte4724f992009-01-18 18:01:49 +00001531 break;
1532 }
1533 break;
1534 case SW_STATE_WAIT_SEGACK:
1535 switch (foh->msg_type) {
1536 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001537 if (sw->cbfn)
1538 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1539 NM_MT_LOAD_SEG_ACK, mb,
1540 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001541 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001542 if (!sw->last_seg) {
1543 /* fill window with more segments */
1544 rc = sw_fill_window(sw);
1545 sw->state = SW_STATE_WAIT_SEGACK;
1546 } else {
1547 /* end the transfer */
1548 sw->state = SW_STATE_WAIT_ENDACK;
1549 rc = sw_load_end(sw);
1550 }
Harald Welte4724f992009-01-18 18:01:49 +00001551 break;
1552 }
1553 break;
1554 case SW_STATE_WAIT_ENDACK:
1555 switch (foh->msg_type) {
1556 case NM_MT_LOAD_END_ACK:
1557 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001558 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1559 sw->bts->nr);
1560 sw->state = SW_STATE_NONE;
1561 if (sw->cbfn)
1562 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1563 NM_MT_LOAD_END_ACK, mb,
1564 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001565 break;
1566 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001567 if (sw->forced) {
1568 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1569 "End NACK\n");
1570 sw->state = SW_STATE_NONE;
1571 if (sw->cbfn)
1572 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1573 NM_MT_LOAD_END_ACK, mb,
1574 sw->cb_data, NULL);
1575 } else {
1576 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001577 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001578 sw->state = SW_STATE_ERROR;
1579 if (sw->cbfn)
1580 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1581 NM_MT_LOAD_END_NACK, mb,
1582 sw->cb_data, NULL);
1583 }
Harald Welte4724f992009-01-18 18:01:49 +00001584 break;
1585 }
1586 case SW_STATE_WAIT_ACTACK:
1587 switch (foh->msg_type) {
1588 case NM_MT_ACTIVATE_SW_ACK:
1589 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001590 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001591 sw->state = SW_STATE_NONE;
1592 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001593 if (sw->cbfn)
1594 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1595 NM_MT_ACTIVATE_SW_ACK, mb,
1596 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001597 break;
1598 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001599 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001600 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001601 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001602 if (sw->cbfn)
1603 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1604 NM_MT_ACTIVATE_SW_NACK, mb,
1605 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001606 break;
1607 }
1608 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001609 switch (foh->msg_type) {
1610 case NM_MT_ACTIVATE_SW_ACK:
1611 rc = 0;
1612 break;
1613 }
1614 break;
Harald Welte4724f992009-01-18 18:01:49 +00001615 case SW_STATE_ERROR:
1616 break;
1617 }
1618
1619 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001620 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001621 foh->msg_type, old_state, sw->state);
1622
1623 return rc;
1624}
1625
1626/* Load the specified software into the BTS */
1627int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001628 u_int8_t win_size, int forced,
1629 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001630{
1631 struct abis_nm_sw *sw = &g_sw;
1632 int rc;
1633
Harald Welte5e4d1b32009-02-01 13:36:56 +00001634 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1635 bts->nr, fname);
1636
Harald Welte4724f992009-01-18 18:01:49 +00001637 if (sw->state != SW_STATE_NONE)
1638 return -EBUSY;
1639
1640 sw->bts = bts;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001641
1642 switch (bts->type) {
1643 case GSM_BTS_TYPE_BS11:
1644 sw->obj_class = NM_OC_SITE_MANAGER;
1645 sw->obj_instance[0] = 0xff;
1646 sw->obj_instance[1] = 0xff;
1647 sw->obj_instance[2] = 0xff;
1648 break;
1649 case GSM_BTS_TYPE_NANOBTS:
1650 sw->obj_class = NM_OC_BASEB_TRANSC;
1651 sw->obj_instance[0] = 0x00;
1652 sw->obj_instance[1] = 0x00;
1653 sw->obj_instance[2] = 0xff;
1654 break;
1655 case GSM_BTS_TYPE_UNKNOWN:
1656 default:
1657 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1658 return -1;
1659 break;
1660 }
Harald Welte4724f992009-01-18 18:01:49 +00001661 sw->window_size = win_size;
1662 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001663 sw->cbfn = cbfn;
1664 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001665 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001666
1667 rc = sw_open_file(sw, fname);
1668 if (rc < 0) {
1669 sw->state = SW_STATE_NONE;
1670 return rc;
1671 }
1672
1673 return sw_load_init(sw);
1674}
Harald Welte52b1f982008-12-23 20:25:15 +00001675
Harald Welte1602ade2009-01-29 21:12:39 +00001676int abis_nm_software_load_status(struct gsm_bts *bts)
1677{
1678 struct abis_nm_sw *sw = &g_sw;
1679 struct stat st;
1680 int rc, percent;
1681
1682 rc = fstat(sw->fd, &st);
1683 if (rc < 0) {
1684 perror("ERROR during stat");
1685 return rc;
1686 }
1687
1688 percent = (ftell(sw->stream) * 100) / st.st_size;
1689 return percent;
1690}
1691
Harald Welte5e4d1b32009-02-01 13:36:56 +00001692/* Activate the specified software into the BTS */
1693int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1694 gsm_cbfn *cbfn, void *cb_data)
1695{
1696 struct abis_nm_sw *sw = &g_sw;
1697 int rc;
1698
1699 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1700 bts->nr, fname);
1701
1702 if (sw->state != SW_STATE_NONE)
1703 return -EBUSY;
1704
1705 sw->bts = bts;
1706 sw->obj_class = NM_OC_SITE_MANAGER;
1707 sw->obj_instance[0] = 0xff;
1708 sw->obj_instance[1] = 0xff;
1709 sw->obj_instance[2] = 0xff;
1710 sw->state = SW_STATE_WAIT_ACTACK;
1711 sw->cbfn = cbfn;
1712 sw->cb_data = cb_data;
1713
1714 /* Open the file in order to fill some sw struct members */
1715 rc = sw_open_file(sw, fname);
1716 if (rc < 0) {
1717 sw->state = SW_STATE_NONE;
1718 return rc;
1719 }
1720 sw_close_file(sw);
1721
1722 return sw_activate(sw);
1723}
1724
Harald Welte8470bf22008-12-25 23:28:35 +00001725static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001726 u_int8_t ts_nr, u_int8_t subslot_nr)
1727{
Harald Welteadaf08b2009-01-18 11:08:10 +00001728 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001729 ch->bts_port = bts_port;
1730 ch->timeslot = ts_nr;
1731 ch->subslot = subslot_nr;
1732}
1733
1734int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1735 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1736 u_int8_t tei)
1737{
1738 struct abis_om_hdr *oh;
1739 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001740 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001741 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001742
1743 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1744 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1745 bts->bts_nr, trx_nr, 0xff);
1746
Harald Welte8470bf22008-12-25 23:28:35 +00001747 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001748
1749 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1750 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1751
1752 return abis_nm_sendmsg(bts, msg);
1753}
1754
1755/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1756int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1757 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1758{
Harald Welte8470bf22008-12-25 23:28:35 +00001759 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001760 struct abis_om_hdr *oh;
1761 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001762 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001763
1764 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001765 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001766 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1767
1768 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1769 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1770
1771 return abis_nm_sendmsg(bts, msg);
1772}
1773
1774#if 0
1775int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1776 struct abis_nm_abis_channel *chan)
1777{
1778}
1779#endif
1780
1781int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1782 u_int8_t e1_port, u_int8_t e1_timeslot,
1783 u_int8_t e1_subslot)
1784{
1785 struct gsm_bts *bts = ts->trx->bts;
1786 struct abis_om_hdr *oh;
1787 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001788 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001789
1790 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1791 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001792 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001793
1794 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1795 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1796
Harald Weltef325eb42009-02-19 17:07:39 +00001797 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1798 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001799 e1_port, e1_timeslot, e1_subslot);
1800
Harald Welte52b1f982008-12-23 20:25:15 +00001801 return abis_nm_sendmsg(bts, msg);
1802}
1803
1804#if 0
1805int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1806 struct abis_nm_abis_channel *chan,
1807 u_int8_t subchan)
1808{
1809}
1810#endif
1811
Harald Welte22af0db2009-02-14 15:41:08 +00001812/* Chapter 8.6.1 */
1813int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1814{
1815 struct abis_om_hdr *oh;
1816 struct msgb *msg = nm_msgb_alloc();
1817 u_int8_t *cur;
1818
1819 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1820
1821 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001822 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 +00001823 cur = msgb_put(msg, attr_len);
1824 memcpy(cur, attr, attr_len);
1825
1826 return abis_nm_sendmsg(bts, msg);
1827}
1828
1829/* Chapter 8.6.2 */
1830int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1831{
1832 struct abis_om_hdr *oh;
1833 struct msgb *msg = nm_msgb_alloc();
1834 u_int8_t *cur;
1835
1836 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1837
1838 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1839 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001840 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001841 cur = msgb_put(msg, attr_len);
1842 memcpy(cur, attr, attr_len);
1843
1844 return abis_nm_sendmsg(trx->bts, msg);
1845}
1846
Harald Welte39c7deb2009-08-09 21:49:48 +02001847static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1848{
1849 int i;
1850
1851 /* As it turns out, the BS-11 has some very peculiar restrictions
1852 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301853 switch (ts->trx->bts->type) {
1854 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001855 switch (chan_comb) {
1856 case NM_CHANC_TCHHalf:
1857 case NM_CHANC_TCHHalf2:
1858 /* not supported */
1859 return -EINVAL;
1860 case NM_CHANC_SDCCH:
1861 /* only one SDCCH/8 per TRX */
1862 for (i = 0; i < TRX_NR_TS; i++) {
1863 if (i == ts->nr)
1864 continue;
1865 if (ts->trx->ts[i].nm_chan_comb ==
1866 NM_CHANC_SDCCH)
1867 return -EINVAL;
1868 }
1869 /* not allowed for TS0 of BCCH-TRX */
1870 if (ts->trx == ts->trx->bts->c0 &&
1871 ts->nr == 0)
1872 return -EINVAL;
1873 /* not on the same TRX that has a BCCH+SDCCH4
1874 * combination */
1875 if (ts->trx == ts->trx->bts->c0 &&
1876 (ts->trx->ts[0].nm_chan_comb == 5 ||
1877 ts->trx->ts[0].nm_chan_comb == 8))
1878 return -EINVAL;
1879 break;
1880 case NM_CHANC_mainBCCH:
1881 case NM_CHANC_BCCHComb:
1882 /* allowed only for TS0 of C0 */
1883 if (ts->trx != ts->trx->bts->c0 ||
1884 ts->nr != 0)
1885 return -EINVAL;
1886 break;
1887 case NM_CHANC_BCCH:
1888 /* allowed only for TS 2/4/6 of C0 */
1889 if (ts->trx != ts->trx->bts->c0)
1890 return -EINVAL;
1891 if (ts->nr != 2 && ts->nr != 4 &&
1892 ts->nr != 6)
1893 return -EINVAL;
1894 break;
1895 case 8: /* this is not like 08.58, but in fact
1896 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1897 /* FIXME: only one CBCH allowed per cell */
1898 break;
1899 }
Harald Welted6575f92009-12-02 02:45:23 +05301900 break;
1901 case GSM_BTS_TYPE_NANOBTS:
1902 switch (ts->nr) {
1903 case 0:
1904 if (ts->trx->nr == 0) {
1905 /* only on TRX0 */
1906 switch (chan_comb) {
1907 case NM_CHANC_BCCH:
1908 case NM_CHANC_mainBCCH:
1909 case NM_CHANC_BCCHComb:
1910 return 0;
1911 break;
1912 default:
1913 return -EINVAL;
1914 }
1915 } else {
1916 switch (chan_comb) {
1917 case NM_CHANC_TCHFull:
1918 case NM_CHANC_TCHHalf:
1919 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1920 return 0;
1921 default:
1922 return -EINVAL;
1923 }
1924 }
1925 break;
1926 case 1:
1927 if (ts->trx->nr == 0) {
1928 switch (chan_comb) {
1929 case NM_CHANC_SDCCH_CBCH:
1930 if (ts->trx->ts[0].nm_chan_comb ==
1931 NM_CHANC_mainBCCH)
1932 return 0;
1933 return -EINVAL;
1934 case NM_CHANC_SDCCH:
1935 case NM_CHANC_TCHFull:
1936 case NM_CHANC_TCHHalf:
1937 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1938 case NM_CHANC_IPAC_TCHFull_PDCH:
1939 return 0;
1940 }
1941 } else {
1942 switch (chan_comb) {
1943 case NM_CHANC_SDCCH:
1944 case NM_CHANC_TCHFull:
1945 case NM_CHANC_TCHHalf:
1946 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1947 return 0;
1948 default:
1949 return -EINVAL;
1950 }
1951 }
1952 break;
1953 case 2:
1954 case 3:
1955 case 4:
1956 case 5:
1957 case 6:
1958 case 7:
1959 switch (chan_comb) {
1960 case NM_CHANC_TCHFull:
1961 case NM_CHANC_TCHHalf:
1962 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1963 return 0;
1964 case NM_CHANC_IPAC_PDCH:
1965 case NM_CHANC_IPAC_TCHFull_PDCH:
1966 if (ts->trx->nr == 0)
1967 return 0;
1968 else
1969 return -EINVAL;
1970 }
1971 break;
1972 }
1973 return -EINVAL;
1974 default:
1975 /* unknown BTS type */
1976 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001977 }
1978 return 0;
1979}
1980
Harald Welte22af0db2009-02-14 15:41:08 +00001981/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00001982int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1983{
1984 struct gsm_bts *bts = ts->trx->bts;
1985 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001986 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00001987 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001988 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00001989 u_int8_t len = 2 + 2;
1990
1991 if (bts->type == GSM_BTS_TYPE_BS11)
1992 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001993
Harald Weltef325eb42009-02-19 17:07:39 +00001994 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02001995 if (verify_chan_comb(ts, chan_comb) < 0) {
1996 msgb_free(msg);
1997 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1998 return -EINVAL;
1999 }
2000 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002001
Harald Welte52b1f982008-12-23 20:25:15 +00002002 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002003 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002004 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002005 ts->trx->nr, ts->nr);
2006 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
Harald Weltee0590df2009-02-15 03:34:15 +00002007 if (bts->type == GSM_BTS_TYPE_BS11)
2008 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002009 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltee0590df2009-02-15 03:34:15 +00002010 if (bts->type == GSM_BTS_TYPE_BS11) {
2011 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
2012 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
2013 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002014 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002015 if (bts->type == GSM_BTS_TYPE_BS11)
2016 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002017
2018 return abis_nm_sendmsg(bts, msg);
2019}
2020
Harald Welte34a99682009-02-13 02:41:40 +00002021int 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 +00002022 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002023{
2024 struct abis_om_hdr *oh;
2025 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002026 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2027 u_int8_t len = att_len;
2028
2029 if (nack) {
2030 len += 2;
2031 msgtype = NM_MT_SW_ACT_REQ_NACK;
2032 }
Harald Welte34a99682009-02-13 02:41:40 +00002033
2034 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002035 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2036
Harald Welte34a99682009-02-13 02:41:40 +00002037 if (attr) {
2038 u_int8_t *ptr = msgb_put(msg, att_len);
2039 memcpy(ptr, attr, att_len);
2040 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002041 if (nack)
2042 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002043
2044 return abis_nm_sendmsg(bts, msg);
2045}
2046
Harald Welte8470bf22008-12-25 23:28:35 +00002047int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002048{
Harald Welte8470bf22008-12-25 23:28:35 +00002049 struct msgb *msg = nm_msgb_alloc();
2050 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002051 u_int8_t *data;
2052
2053 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2054 fill_om_hdr(oh, len);
2055 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002056 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002057
2058 return abis_nm_sendmsg(bts, msg);
2059}
2060
2061/* Siemens specific commands */
2062static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2063{
2064 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002065 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002066
2067 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002068 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002069 0xff, 0xff, 0xff);
2070
2071 return abis_nm_sendmsg(bts, msg);
2072}
2073
Harald Welte34a99682009-02-13 02:41:40 +00002074/* Chapter 8.9.2 */
2075int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2076{
2077 struct abis_om_hdr *oh;
2078 struct msgb *msg = nm_msgb_alloc();
2079
2080 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2081 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2082
Harald Weltea8bd6d42009-10-20 09:56:18 +02002083 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2084 DEBUGPC(DNM, "Sending OPSTART\n");
2085
Harald Welte34a99682009-02-13 02:41:40 +00002086 return abis_nm_sendmsg(bts, msg);
2087}
2088
2089/* Chapter 8.8.5 */
2090int 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 +02002091 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002092{
2093 struct abis_om_hdr *oh;
2094 struct msgb *msg = nm_msgb_alloc();
2095
2096 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2097 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2098 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2099
2100 return abis_nm_sendmsg(bts, msg);
2101}
2102
Harald Welte1989c082009-08-06 17:58:31 +02002103int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2104 u_int8_t e1_port1, u_int8_t ts1)
2105{
2106 struct abis_om_hdr *oh;
2107 struct msgb *msg = nm_msgb_alloc();
2108 u_int8_t *attr;
2109
2110 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2111 e1_port0, ts0, e1_port1, ts1);
2112
2113 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2114 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2115 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2116
2117 attr = msgb_put(msg, 3);
2118 attr[0] = NM_ATT_MDROP_LINK;
2119 attr[1] = e1_port0;
2120 attr[2] = ts0;
2121
2122 attr = msgb_put(msg, 3);
2123 attr[0] = NM_ATT_MDROP_NEXT;
2124 attr[1] = e1_port1;
2125 attr[2] = ts1;
2126
2127 return abis_nm_sendmsg(bts, msg);
2128}
Harald Welte34a99682009-02-13 02:41:40 +00002129
Harald Weltec7310382009-08-08 00:02:36 +02002130/* Chapter 8.7.1 */
2131int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2132 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2133 u_int8_t test_nr, u_int8_t auton_report,
2134 u_int8_t *phys_config, u_int16_t phys_config_len)
2135{
2136 struct abis_om_hdr *oh;
2137 struct msgb *msg = nm_msgb_alloc();
2138 int len = 4; /* 2 TV attributes */
2139
2140 DEBUGP(DNM, "PEFORM TEST\n");
2141
2142 if (phys_config_len)
2143 len += 3 + phys_config_len;
2144
2145 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2146 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2147 obj_class, bts_nr, trx_nr, ts_nr);
2148 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2149 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2150 if (phys_config_len)
2151 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2152 phys_config);
2153
2154 return abis_nm_sendmsg(bts, msg);
2155}
2156
Harald Welte52b1f982008-12-23 20:25:15 +00002157int abis_nm_event_reports(struct gsm_bts *bts, int on)
2158{
2159 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002160 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002161 else
Harald Welte227d4072009-01-03 08:16:25 +00002162 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002163}
2164
Harald Welte47d88ae2009-01-04 12:02:08 +00002165/* Siemens (or BS-11) specific commands */
2166
Harald Welte3ffd1372009-02-01 22:15:49 +00002167int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2168{
2169 if (reconnect == 0)
2170 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2171 else
2172 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2173}
2174
Harald Welteb8427972009-02-05 19:27:17 +00002175int abis_nm_bs11_restart(struct gsm_bts *bts)
2176{
2177 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2178}
2179
2180
Harald Welte268bb402009-02-01 19:11:56 +00002181struct bs11_date_time {
2182 u_int16_t year;
2183 u_int8_t month;
2184 u_int8_t day;
2185 u_int8_t hour;
2186 u_int8_t min;
2187 u_int8_t sec;
2188} __attribute__((packed));
2189
2190
2191void get_bs11_date_time(struct bs11_date_time *aet)
2192{
2193 time_t t;
2194 struct tm *tm;
2195
2196 t = time(NULL);
2197 tm = localtime(&t);
2198 aet->sec = tm->tm_sec;
2199 aet->min = tm->tm_min;
2200 aet->hour = tm->tm_hour;
2201 aet->day = tm->tm_mday;
2202 aet->month = tm->tm_mon;
2203 aet->year = htons(1900 + tm->tm_year);
2204}
2205
Harald Welte05188ee2009-01-18 11:39:08 +00002206int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002207{
Harald Welte4668fda2009-01-03 08:19:29 +00002208 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002209}
2210
Harald Welte05188ee2009-01-18 11:39:08 +00002211int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002212{
2213 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002214 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002215 else
Harald Welte4668fda2009-01-03 08:19:29 +00002216 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002217}
Harald Welte47d88ae2009-01-04 12:02:08 +00002218
Harald Welte05188ee2009-01-18 11:39:08 +00002219int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002220 enum abis_bs11_objtype type, u_int8_t idx,
2221 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002222{
2223 struct abis_om_hdr *oh;
2224 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002225 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002226
2227 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002228 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002229 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002230 cur = msgb_put(msg, attr_len);
2231 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002232
2233 return abis_nm_sendmsg(bts, msg);
2234}
2235
Harald Welte78fc0d42009-02-19 02:50:57 +00002236int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2237 enum abis_bs11_objtype type, u_int8_t idx)
2238{
2239 struct abis_om_hdr *oh;
2240 struct msgb *msg = nm_msgb_alloc();
2241
2242 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2243 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2244 NM_OC_BS11, type, 0, idx);
2245
2246 return abis_nm_sendmsg(bts, msg);
2247}
2248
Harald Welte05188ee2009-01-18 11:39:08 +00002249int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002250{
2251 struct abis_om_hdr *oh;
2252 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002253 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002254
2255 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002256 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002257 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2258 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002259
2260 return abis_nm_sendmsg(bts, msg);
2261}
2262
Harald Welte05188ee2009-01-18 11:39:08 +00002263int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002264{
2265 struct abis_om_hdr *oh;
2266 struct msgb *msg = nm_msgb_alloc();
2267
2268 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2269 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002270 idx, 0xff, 0xff);
2271
2272 return abis_nm_sendmsg(bts, msg);
2273}
2274
2275int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2276{
2277 struct abis_om_hdr *oh;
2278 struct msgb *msg = nm_msgb_alloc();
2279
2280 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2281 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2282 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002283
2284 return abis_nm_sendmsg(bts, msg);
2285}
Harald Welte05188ee2009-01-18 11:39:08 +00002286
Harald Welte78fc0d42009-02-19 02:50:57 +00002287static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2288int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2289{
2290 struct abis_om_hdr *oh;
2291 struct msgb *msg = nm_msgb_alloc();
2292
2293 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2294 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2295 0xff, 0xff, 0xff);
2296 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2297
2298 return abis_nm_sendmsg(bts, msg);
2299}
2300
Harald Welteb6c92ae2009-02-21 20:15:32 +00002301/* like abis_nm_conn_terr_traf + set_tei */
2302int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2303 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2304 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002305{
2306 struct abis_om_hdr *oh;
2307 struct abis_nm_channel *ch;
2308 struct msgb *msg = nm_msgb_alloc();
2309
2310 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002311 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002312 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2313
2314 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2315 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002316 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002317
2318 return abis_nm_sendmsg(bts, msg);
2319}
2320
2321int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2322{
2323 struct abis_om_hdr *oh;
2324 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002327 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002328 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2329 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2330
2331 return abis_nm_sendmsg(trx->bts, msg);
2332}
2333
Harald Welte78fc0d42009-02-19 02:50:57 +00002334int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2335{
2336 struct abis_om_hdr *oh;
2337 struct msgb *msg = nm_msgb_alloc();
2338 u_int8_t attr = NM_ATT_BS11_TXPWR;
2339
2340 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2341 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2342 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2343 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2344
2345 return abis_nm_sendmsg(trx->bts, msg);
2346}
2347
Harald Welteaaf02d92009-04-29 13:25:57 +00002348int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2349{
2350 struct abis_om_hdr *oh;
2351 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002352 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002353
2354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2355 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2356 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002357 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002358
2359 return abis_nm_sendmsg(bts, msg);
2360}
2361
Harald Welteef061952009-05-17 12:43:42 +00002362int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2363{
2364 struct abis_om_hdr *oh;
2365 struct msgb *msg = nm_msgb_alloc();
2366 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2367 NM_ATT_BS11_CCLK_TYPE };
2368
2369 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2370 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2371 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2372 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2373
2374 return abis_nm_sendmsg(bts, msg);
2375
2376}
Harald Welteaaf02d92009-04-29 13:25:57 +00002377
Harald Welte268bb402009-02-01 19:11:56 +00002378//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +00002379static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +00002380static const u_int8_t bs11_logon_c9[] = "FACTORY";
2381
Harald Welte1bc09062009-01-18 14:17:52 +00002382int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002383{
2384 struct abis_om_hdr *oh;
2385 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002386 struct bs11_date_time bdt;
2387
2388 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002389
2390 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002391 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002392 u_int8_t len = 3*2 + sizeof(bdt)
Harald Welte6f676a32009-01-18 14:27:48 +00002393 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +00002394 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002395 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002396 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002397 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002398 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2399 sizeof(bs11_logon_c8), bs11_logon_c8);
2400 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2401 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +00002402 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002403 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002404 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002405 }
Harald Welte05188ee2009-01-18 11:39:08 +00002406
2407 return abis_nm_sendmsg(bts, msg);
2408}
Harald Welte1bc09062009-01-18 14:17:52 +00002409
2410int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2411{
2412 struct abis_om_hdr *oh;
2413 struct msgb *msg;
2414
2415 if (strlen(password) != 10)
2416 return -EINVAL;
2417
2418 msg = nm_msgb_alloc();
2419 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002420 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002421 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2422 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2423
2424 return abis_nm_sendmsg(bts, msg);
2425}
2426
Harald Weltee69f5fb2009-04-28 16:31:38 +00002427/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2428int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2429{
2430 struct abis_om_hdr *oh;
2431 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002432 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002433
2434 msg = nm_msgb_alloc();
2435 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2436 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2437 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002438
2439 if (locked)
2440 tlv_value = BS11_LI_PLL_LOCKED;
2441 else
2442 tlv_value = BS11_LI_PLL_STANDALONE;
2443
2444 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002445
2446 return abis_nm_sendmsg(bts, msg);
2447}
2448
Harald Welte1bc09062009-01-18 14:17:52 +00002449int abis_nm_bs11_get_state(struct gsm_bts *bts)
2450{
2451 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2452}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002453
2454/* BS11 SWL */
2455
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002456void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002457
Harald Welte5e4d1b32009-02-01 13:36:56 +00002458struct abis_nm_bs11_sw {
2459 struct gsm_bts *bts;
2460 char swl_fname[PATH_MAX];
2461 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002462 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002463 struct llist_head file_list;
2464 gsm_cbfn *user_cb; /* specified by the user */
2465};
2466static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2467
2468struct file_list_entry {
2469 struct llist_head list;
2470 char fname[PATH_MAX];
2471};
2472
2473struct file_list_entry *fl_dequeue(struct llist_head *queue)
2474{
2475 struct llist_head *lh;
2476
2477 if (llist_empty(queue))
2478 return NULL;
2479
2480 lh = queue->next;
2481 llist_del(lh);
2482
2483 return llist_entry(lh, struct file_list_entry, list);
2484}
2485
2486static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2487{
2488 char linebuf[255];
2489 struct llist_head *lh, *lh2;
2490 FILE *swl;
2491 int rc = 0;
2492
2493 swl = fopen(bs11_sw->swl_fname, "r");
2494 if (!swl)
2495 return -ENODEV;
2496
2497 /* zero the stale file list, if any */
2498 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2499 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002500 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002501 }
2502
2503 while (fgets(linebuf, sizeof(linebuf), swl)) {
2504 char file_id[12+1];
2505 char file_version[80+1];
2506 struct file_list_entry *fle;
2507 static char dir[PATH_MAX];
2508
2509 if (strlen(linebuf) < 4)
2510 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002511
Harald Welte5e4d1b32009-02-01 13:36:56 +00002512 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2513 if (rc < 0) {
2514 perror("ERR parsing SWL file");
2515 rc = -EINVAL;
2516 goto out;
2517 }
2518 if (rc < 2)
2519 continue;
2520
Harald Welte470ec292009-06-26 20:25:23 +02002521 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002522 if (!fle) {
2523 rc = -ENOMEM;
2524 goto out;
2525 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002526
2527 /* construct new filename */
2528 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2529 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2530 strcat(fle->fname, "/");
2531 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002532
2533 llist_add_tail(&fle->list, &bs11_sw->file_list);
2534 }
2535
2536out:
2537 fclose(swl);
2538 return rc;
2539}
2540
2541/* bs11 swload specific callback, passed to abis_nm core swload */
2542static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2543 struct msgb *msg, void *data, void *param)
2544{
2545 struct abis_nm_bs11_sw *bs11_sw = data;
2546 struct file_list_entry *fle;
2547 int rc = 0;
2548
Harald Welte5e4d1b32009-02-01 13:36:56 +00002549 switch (event) {
2550 case NM_MT_LOAD_END_ACK:
2551 fle = fl_dequeue(&bs11_sw->file_list);
2552 if (fle) {
2553 /* start download the next file of our file list */
2554 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2555 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002556 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002557 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002558 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002559 } else {
2560 /* activate the SWL */
2561 rc = abis_nm_software_activate(bs11_sw->bts,
2562 bs11_sw->swl_fname,
2563 bs11_swload_cbfn,
2564 bs11_sw);
2565 }
2566 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002567 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002568 case NM_MT_LOAD_END_NACK:
2569 case NM_MT_LOAD_INIT_ACK:
2570 case NM_MT_LOAD_INIT_NACK:
2571 case NM_MT_ACTIVATE_SW_NACK:
2572 case NM_MT_ACTIVATE_SW_ACK:
2573 default:
2574 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002575 if (bs11_sw->user_cb)
2576 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002577 break;
2578 }
2579
2580 return rc;
2581}
2582
2583/* Siemens provides a SWL file that is a mere listing of all the other
2584 * files that are part of a software release. We need to upload first
2585 * the list file, and then each file that is listed in the list file */
2586int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002587 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002588{
2589 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2590 struct file_list_entry *fle;
2591 int rc = 0;
2592
2593 INIT_LLIST_HEAD(&bs11_sw->file_list);
2594 bs11_sw->bts = bts;
2595 bs11_sw->win_size = win_size;
2596 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002597 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002598
2599 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2600 rc = bs11_read_swl_file(bs11_sw);
2601 if (rc < 0)
2602 return rc;
2603
2604 /* dequeue next item in file list */
2605 fle = fl_dequeue(&bs11_sw->file_list);
2606 if (!fle)
2607 return -EINVAL;
2608
2609 /* start download the next file of our file list */
Harald Welte3ffd1372009-02-01 22:15:49 +00002610 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002611 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002612 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002613 return rc;
2614}
2615
Harald Welte5083b0b2009-02-02 19:20:52 +00002616#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002617static u_int8_t req_attr_btse[] = {
2618 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2619 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2620 NM_ATT_BS11_LMT_USER_NAME,
2621
2622 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2623
2624 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2625
2626 NM_ATT_BS11_SW_LOAD_STORED };
2627
2628static u_int8_t req_attr_btsm[] = {
2629 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2630 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2631 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2632 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002633#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002634
2635static u_int8_t req_attr[] = {
2636 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2637 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002638 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002639
2640int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2641{
2642 struct abis_om_hdr *oh;
2643 struct msgb *msg = nm_msgb_alloc();
2644
2645 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2646 /* SiemensHW CCTRL object */
2647 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2648 0x03, 0x00, 0x00);
2649 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2650
2651 return abis_nm_sendmsg(bts, msg);
2652}
Harald Welte268bb402009-02-01 19:11:56 +00002653
2654int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2655{
2656 struct abis_om_hdr *oh;
2657 struct msgb *msg = nm_msgb_alloc();
2658 struct bs11_date_time aet;
2659
2660 get_bs11_date_time(&aet);
2661 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2662 /* SiemensHW CCTRL object */
2663 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2664 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002665 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002666
2667 return abis_nm_sendmsg(bts, msg);
2668}
Harald Welte5c1e4582009-02-15 11:57:29 +00002669
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002670int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2671{
2672 struct abis_om_hdr *oh;
2673 struct msgb *msg = nm_msgb_alloc();
2674 struct bs11_date_time aet;
2675
2676 get_bs11_date_time(&aet);
2677 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2678 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2679 bport, 0xff, 0x02);
2680 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2681
2682 return abis_nm_sendmsg(bts, msg);
2683}
2684
Harald Welte5c1e4582009-02-15 11:57:29 +00002685/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002686static const char ipaccess_magic[] = "com.ipaccess";
2687
Harald Welte677c21f2009-02-17 13:22:23 +00002688
2689static int abis_nm_rx_ipacc(struct msgb *msg)
2690{
2691 struct abis_om_hdr *oh = msgb_l2(msg);
2692 struct abis_om_fom_hdr *foh;
2693 u_int8_t idstrlen = oh->data[0];
2694 struct tlv_parsed tp;
2695
2696 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002697 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002698 return -EINVAL;
2699 }
2700
Harald Welte193fefc2009-04-30 15:16:27 +00002701 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte03133942009-02-18 19:51:53 +00002702 abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002703
Harald Weltea8bd6d42009-10-20 09:56:18 +02002704 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002705
Harald Welte746d6092009-10-19 22:11:11 +02002706 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002707
Harald Welte677c21f2009-02-17 13:22:23 +00002708 switch (foh->msg_type) {
2709 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002710 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte0efe9b72009-07-12 09:33:54 +02002711 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte9de2bf82009-04-30 15:59:55 +00002712 DEBUGPC(DNM, "IP=%s ",
Harald Welte677c21f2009-02-17 13:22:23 +00002713 inet_ntoa(*((struct in_addr *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002714 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2715 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002716 DEBUGPC(DNM, "PORT=%u ",
Harald Welte677c21f2009-02-17 13:22:23 +00002717 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002718 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002719 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2720 DEBUGPC(DNM, "STREAM=0x%02x ",
2721 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002722 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002723 break;
2724 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002725 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002726 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte6c96ba52009-05-01 13:03:40 +00002727 DEBUGPC(DNM, " CAUSE=%s\n",
2728 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002729 else
2730 DEBUGPC(DNM, "\n");
2731 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002732 case NM_MT_IPACC_SET_NVATTR_ACK:
2733 DEBUGPC(DNM, "SET NVATTR ACK\n");
2734 /* FIXME: decode and show the actual attributes */
2735 break;
2736 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002737 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002738 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002739 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002740 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2741 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002742 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002743 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002744 case NM_MT_IPACC_GET_NVATTR_ACK:
2745 DEBUGPC(DNM, "GET NVATTR ACK\n");
2746 /* FIXME: decode and show the actual attributes */
2747 break;
2748 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002749 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002750 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002751 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002752 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2753 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002754 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002755 break;
Harald Welte15c44172009-10-08 20:15:24 +02002756 case NM_MT_IPACC_SET_ATTR_ACK:
2757 DEBUGPC(DNM, "SET ATTR ACK\n");
2758 break;
2759 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002760 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002761 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Harald Welte5b8ed432009-12-24 12:20:20 +01002762 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002763 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2764 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002765 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002766 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002767 default:
2768 DEBUGPC(DNM, "unknown\n");
2769 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002770 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002771
2772 /* signal handling */
2773 switch (foh->msg_type) {
2774 case NM_MT_IPACC_RSL_CONNECT_NACK:
2775 case NM_MT_IPACC_SET_NVATTR_NACK:
2776 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welted8cfc902009-11-17 06:09:56 +01002777 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002778 break;
2779 default:
2780 break;
2781 }
2782
Harald Welte677c21f2009-02-17 13:22:23 +00002783 return 0;
2784}
2785
Harald Welte193fefc2009-04-30 15:16:27 +00002786/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002787int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2788 u_int8_t obj_class, u_int8_t bts_nr,
2789 u_int8_t trx_nr, u_int8_t ts_nr,
2790 u_int8_t *attr, int attr_len)
2791{
2792 struct msgb *msg = nm_msgb_alloc();
2793 struct abis_om_hdr *oh;
2794 struct abis_om_fom_hdr *foh;
2795 u_int8_t *data;
2796
2797 /* construct the 12.21 OM header, observe the erroneous length */
2798 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2799 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2800 oh->mdisc = ABIS_OM_MDISC_MANUF;
2801
2802 /* add the ip.access magic */
2803 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2804 *data++ = sizeof(ipaccess_magic);
2805 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2806
2807 /* fill the 12.21 FOM header */
2808 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2809 foh->msg_type = msg_type;
2810 foh->obj_class = obj_class;
2811 foh->obj_inst.bts_nr = bts_nr;
2812 foh->obj_inst.trx_nr = trx_nr;
2813 foh->obj_inst.ts_nr = ts_nr;
2814
2815 if (attr && attr_len) {
2816 data = msgb_put(msg, attr_len);
2817 memcpy(data, attr, attr_len);
2818 }
2819
2820 return abis_nm_sendmsg(bts, msg);
2821}
Harald Welte677c21f2009-02-17 13:22:23 +00002822
Harald Welte193fefc2009-04-30 15:16:27 +00002823/* set some attributes in NVRAM */
2824int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
2825 int attr_len)
2826{
2827 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
2828 NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
2829 attr_len);
2830}
2831
Harald Welte746d6092009-10-19 22:11:11 +02002832int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2833 u_int32_t ip, u_int16_t port, u_int8_t stream)
2834{
2835 struct in_addr ia;
2836 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2837 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2838 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2839
2840 int attr_len = sizeof(attr);
2841
2842 ia.s_addr = htonl(ip);
2843 attr[1] = stream;
2844 attr[3] = port >> 8;
2845 attr[4] = port & 0xff;
2846 *(u_int32_t *)(attr+6) = ia.s_addr;
2847
2848 /* if ip == 0, we use the default IP */
2849 if (ip == 0)
2850 attr_len -= 5;
2851
2852 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002853 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002854
2855 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2856 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2857 trx->nr, 0xff, attr, attr_len);
2858}
2859
Harald Welte193fefc2009-04-30 15:16:27 +00002860/* restart / reboot an ip.access nanoBTS */
2861int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2862{
2863 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2864}
Harald Weltedaef5212009-10-24 10:20:41 +02002865
2866int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2867 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2868 u_int8_t *attr, u_int8_t attr_len)
2869{
2870 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2871 obj_class, bts_nr, trx_nr, ts_nr,
2872 attr, attr_len);
2873}
Harald Welte0f255852009-11-12 14:48:42 +01002874
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002875void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2876{
2877 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2878
2879 trx->rf_locked = locked;
2880 if (!trx->bts || !trx->bts->oml_link)
2881 return;
2882
2883 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2884 trx->bts->bts_nr, trx->nr, 0xff,
2885 new_state);
2886}
2887
Harald Welte0f255852009-11-12 14:48:42 +01002888static const char *ipacc_testres_names[] = {
2889 [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS",
2890 [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT",
2891 [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS",
2892 [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL",
2893 [NM_IPACC_TESTRES_STOPPED] = "STOPPED",
2894};
2895
2896const char *ipacc_testres_name(u_int8_t res)
2897{
2898 if (res < ARRAY_SIZE(ipacc_testres_names) &&
2899 ipacc_testres_names[res])
2900 return ipacc_testres_names[res];
2901
2902 return "unknown";
2903}
2904
Harald Welteb40a38f2009-11-13 11:56:05 +01002905void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2906{
2907 cid->mcc = (buf[0] & 0xf) * 100;
2908 cid->mcc += (buf[0] >> 4) * 10;
2909 cid->mcc += (buf[1] & 0xf) * 1;
2910
2911 if (buf[1] >> 4 == 0xf) {
2912 cid->mnc = (buf[2] & 0xf) * 10;
2913 cid->mnc += (buf[2] >> 4) * 1;
2914 } else {
2915 cid->mnc = (buf[2] & 0xf) * 100;
2916 cid->mnc += (buf[2] >> 4) * 10;
2917 cid->mnc += (buf[1] >> 4) * 1;
2918 }
2919
Harald Welteaff237d2009-11-13 14:41:52 +01002920 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2921 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002922}
2923
Harald Welte0f255852009-11-12 14:48:42 +01002924/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2925int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2926{
2927 u_int8_t *cur = buf;
2928 u_int16_t len;
2929
2930 memset(binf, 0, sizeof(binf));
2931
2932 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2933 return -EINVAL;
2934 cur++;
2935
2936 len = ntohs(*(u_int16_t *)cur);
2937 cur += 2;
2938
2939 binf->info_type = ntohs(*(u_int16_t *)cur);
2940 cur += 2;
2941
2942 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2943 binf->freq_qual = *cur >> 2;
2944
2945 binf->arfcn = *cur++ & 3 << 8;
2946 binf->arfcn |= *cur++;
2947
2948 if (binf->info_type & IPAC_BINF_RXLEV)
2949 binf->rx_lev = *cur & 0x3f;
2950 cur++;
2951
2952 if (binf->info_type & IPAC_BINF_RXQUAL)
2953 binf->rx_qual = *cur & 0x7;
2954 cur++;
2955
2956 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2957 binf->freq_err = ntohs(*(u_int16_t *)cur);
2958 cur += 2;
2959
2960 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2961 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2962 cur += 2;
2963
2964 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2965 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2966 cur += 4;
2967
2968 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welteaff237d2009-11-13 14:41:52 +01002969 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002970 cur++;
2971
Harald Welteb40a38f2009-11-13 11:56:05 +01002972 ipac_parse_cgi(&binf->cgi, cur);
2973 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002974
2975 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2976 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2977 cur += sizeof(binf->ba_list_si2);
2978 }
2979
2980 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2981 memcpy(binf->ba_list_si2bis, cur,
2982 sizeof(binf->ba_list_si2bis));
2983 cur += sizeof(binf->ba_list_si2bis);
2984 }
2985
2986 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2987 memcpy(binf->ba_list_si2ter, cur,
2988 sizeof(binf->ba_list_si2ter));
2989 cur += sizeof(binf->ba_list_si2ter);
2990 }
2991
2992 return 0;
2993}
2994
2995