blob: 0e7fc8d8c3dd8e3260ee4a0f973e25616389419d [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte52b1f982008-12-23 20:25:15 +000033#include <sys/types.h>
Harald Welte4724f992009-01-18 18:01:49 +000034#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000035#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000036#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000037
Harald Welte8470bf22008-12-25 23:28:35 +000038#include <openbsc/gsm_data.h>
39#include <openbsc/debug.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010040#include <osmocore/msgb.h>
41#include <osmocore/tlv.h>
42#include <osmocore/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#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 Welte52b1f982008-12-23 20:25:15 +000046
Harald Welte8470bf22008-12-25 23:28:35 +000047#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010049#define IPACC_SEGMENT_SIZE 245
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
Harald Welte92b1fe42010-03-25 11:45:30 +0800116static const struct value_string nack_names[] = {
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,
138 "CHANGE ADMINISTRATIVE STATE REQUEST" },
139 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
140 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
141 { NM_MT_OPSTART_NACK, "OPSTART" },
142 { NM_MT_REINIT_NACK, "REINIT" },
143 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
144 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
145 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
146 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
147 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
148 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
149 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
150 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
151 { 0, NULL }
Harald Welte78fc0d42009-02-19 02:50:57 +0000152};
153
Harald Welte6c96ba52009-05-01 13:03:40 +0000154/* Chapter 9.4.36 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800155static const struct value_string nack_cause_names[] = {
Harald Welte6c96ba52009-05-01 13:03:40 +0000156 /* General Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800157 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
158 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
159 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
160 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
161 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
162 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
163 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
164 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
165 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
166 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
167 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
168 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
169 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte6c96ba52009-05-01 13:03:40 +0000170 /* Specific Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800171 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
172 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
173 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
174 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
175 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
176 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
177 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
178 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
179 { NM_NACK_TEST_NOSUCH, "No such test" },
180 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
181 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
182 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
183 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
184 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
185 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
186 { NM_NACK_WAIT, "Wait" },
187 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
188 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
189 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
190 { 0, NULL }
Harald Welte6c96ba52009-05-01 13:03:40 +0000191};
192
Harald Welte6c96ba52009-05-01 13:03:40 +0000193static const char *nack_cause_name(u_int8_t cause)
194{
Harald Welte92b1fe42010-03-25 11:45:30 +0800195 return get_value_string(nack_cause_names, cause);
Harald Welte6c96ba52009-05-01 13:03:40 +0000196}
197
Harald Welte0db97b22009-05-01 17:22:47 +0000198/* Chapter 9.4.16: Event Type */
Harald Welte92b1fe42010-03-25 11:45:30 +0800199static const struct value_string event_type_names[] = {
200 { NM_EVT_COMM_FAIL, "communication failure" },
201 { NM_EVT_QOS_FAIL, "quality of service failure" },
202 { NM_EVT_PROC_FAIL, "processing failure" },
203 { NM_EVT_EQUIP_FAIL, "equipment failure" },
204 { NM_EVT_ENV_FAIL, "environment failure" },
205 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000206};
207
208static const char *event_type_name(u_int8_t cause)
209{
Harald Welte92b1fe42010-03-25 11:45:30 +0800210 return get_value_string(event_type_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000211}
212
213/* Chapter 9.4.63: Perceived Severity */
Harald Welte92b1fe42010-03-25 11:45:30 +0800214static const struct value_string severity_names[] = {
215 { NM_SEVER_CEASED, "failure ceased" },
216 { NM_SEVER_CRITICAL, "critical failure" },
217 { NM_SEVER_MAJOR, "major failure" },
218 { NM_SEVER_MINOR, "minor failure" },
219 { NM_SEVER_WARNING, "warning level failure" },
220 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
221 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000222};
223
224static const char *severity_name(u_int8_t cause)
225{
Harald Welte92b1fe42010-03-25 11:45:30 +0800226 return get_value_string(severity_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000227}
228
Harald Welte52b1f982008-12-23 20:25:15 +0000229/* Attributes that the BSC can set, not only get, according to Section 9.4 */
230static const enum abis_nm_attr nm_att_settable[] = {
231 NM_ATT_ADD_INFO,
232 NM_ATT_ADD_TEXT,
233 NM_ATT_DEST,
234 NM_ATT_EVENT_TYPE,
235 NM_ATT_FILE_DATA,
236 NM_ATT_GET_ARI,
237 NM_ATT_HW_CONF_CHG,
238 NM_ATT_LIST_REQ_ATTR,
239 NM_ATT_MDROP_LINK,
240 NM_ATT_MDROP_NEXT,
241 NM_ATT_NACK_CAUSES,
242 NM_ATT_OUTST_ALARM,
243 NM_ATT_PHYS_CONF,
244 NM_ATT_PROB_CAUSE,
245 NM_ATT_RAD_SUBC,
246 NM_ATT_SOURCE,
247 NM_ATT_SPEC_PROB,
248 NM_ATT_START_TIME,
249 NM_ATT_TEST_DUR,
250 NM_ATT_TEST_NO,
251 NM_ATT_TEST_REPORT,
252 NM_ATT_WINDOW_SIZE,
253 NM_ATT_SEVERITY,
254 NM_ATT_MEAS_RES,
255 NM_ATT_MEAS_TYPE,
256};
257
Harald Welte39315c42010-01-10 18:01:52 +0100258const struct tlv_definition nm_att_tlvdef = {
Harald Weltee0590df2009-02-15 03:34:15 +0000259 .def = {
260 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
261 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
262 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
264 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
265 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
266 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
267 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
268 [NM_ATT_BSIC] = { TLV_TYPE_TV },
269 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
270 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
272 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
273 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
274 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
275 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
276 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
277 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
279 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
280 [NM_ATT_HSN] = { TLV_TYPE_TV },
281 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
282 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
283 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
284 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
285 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
286 [NM_ATT_MAIO] = { TLV_TYPE_TV },
287 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
289 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
290 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
291 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
292 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
294 [NM_ATT_NY1] = { TLV_TYPE_TV },
295 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
297 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
298 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
299 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
300 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
302 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
303 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
304 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
305 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
306 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
308 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
309 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
310 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
311 [NM_ATT_TEI] = { TLV_TYPE_TV },
312 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
313 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
314 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
315 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
316 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
317 [NM_ATT_TSC] = { TLV_TYPE_TV },
318 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
319 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
320 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
321 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
322 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000323 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Weltee0590df2009-02-15 03:34:15 +0000324 },
325};
Harald Welte03133942009-02-18 19:51:53 +0000326
Harald Welte21bd3a52009-08-10 12:21:22 +0200327static const enum abis_nm_chan_comb chcomb4pchan[] = {
328 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
329 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
330 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
331 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
332 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200333 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
334 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200335 /* FIXME: bounds check */
336};
337
338int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
339{
340 if (pchan < ARRAY_SIZE(chcomb4pchan))
341 return chcomb4pchan[pchan];
342
343 return -EINVAL;
344}
345
Harald Welte39315c42010-01-10 18:01:52 +0100346int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +0000347{
Harald Welte39315c42010-01-10 18:01:52 +0100348 if (!bts->model)
349 return -EIO;
350 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000351}
Harald Weltee0590df2009-02-15 03:34:15 +0000352
Harald Welte52b1f982008-12-23 20:25:15 +0000353static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
354{
355 int i;
356
357 for (i = 0; i < size; i++) {
358 if (arr[i] == mt)
359 return 1;
360 }
361
362 return 0;
363}
364
Holger Freytherca362a62009-01-04 21:05:01 +0000365#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000366/* is this msgtype the usual ACK/NACK type ? */
367static int is_ack_nack(enum abis_nm_msgtype mt)
368{
369 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
370}
Holger Freytherca362a62009-01-04 21:05:01 +0000371#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000372
373/* is this msgtype a report ? */
374static int is_report(enum abis_nm_msgtype mt)
375{
Harald Welte8470bf22008-12-25 23:28:35 +0000376 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000377}
378
379#define MT_ACK(x) (x+1)
380#define MT_NACK(x) (x+2)
381
382static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
383{
384 oh->mdisc = ABIS_OM_MDISC_FOM;
385 oh->placement = ABIS_OM_PLACEMENT_ONLY;
386 oh->sequence = 0;
387 oh->length = len;
388}
389
390static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
391 u_int8_t msg_type, u_int8_t obj_class,
392 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
393{
394 struct abis_om_fom_hdr *foh =
395 (struct abis_om_fom_hdr *) oh->data;
396
Harald Welte702d8702008-12-26 20:25:35 +0000397 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000398 foh->msg_type = msg_type;
399 foh->obj_class = obj_class;
400 foh->obj_inst.bts_nr = bts_nr;
401 foh->obj_inst.trx_nr = trx_nr;
402 foh->obj_inst.ts_nr = ts_nr;
403}
404
Harald Welte8470bf22008-12-25 23:28:35 +0000405static struct msgb *nm_msgb_alloc(void)
406{
Harald Welte966636f2009-06-26 19:39:35 +0200407 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
408 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000409}
410
Harald Welte52b1f982008-12-23 20:25:15 +0000411/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100412static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000413{
Holger Freyther59639e82009-02-09 23:09:55 +0000414 msg->trx = bts->c0;
415
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100416 /* queue OML messages */
417 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
418 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100419 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100420 } else {
421 msgb_enqueue(&bts->abis_queue, msg);
422 return 0;
423 }
424
425}
426
427int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
428{
429 OBSC_NM_W_ACK_CB(msg) = 1;
430 return abis_nm_queue_msg(bts, msg);
431}
432
433static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
434{
435 OBSC_NM_W_ACK_CB(msg) = 0;
436 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000437}
438
Harald Welte4724f992009-01-18 18:01:49 +0000439static int abis_nm_rcvmsg_sw(struct msgb *mb);
440
Harald Welte81c9b9c2010-05-31 16:40:40 +0200441const struct value_string abis_nm_obj_class_names[] = {
442 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800443 { NM_OC_BTS, "BTS" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200444 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
445 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800446 { NM_OC_CHANNEL, "CHANNEL" },
447 { NM_OC_BS11_ADJC, "ADJC" },
448 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200449 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800450 { NM_OC_BS11_BTSE, "BTSE" },
451 { NM_OC_BS11_RACK, "RACK" },
452 { NM_OC_BS11_TEST, "TEST" },
453 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
454 { NM_OC_BS11_BPORT, "BPORT" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200455 { NM_OC_GPRS_NSE, "GPRS-NSE" },
456 { NM_OC_GPRS_CELL, "GPRS-CELL" },
457 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800458 { NM_OC_BS11, "SIEMENSHW" },
459 { 0, NULL }
460};
461
Harald Welte34a99682009-02-13 02:41:40 +0000462static const char *obj_class_name(u_int8_t oc)
463{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200464 return get_value_string(abis_nm_obj_class_names, oc);
Harald Welte34a99682009-02-13 02:41:40 +0000465}
466
Harald Welte4d87f242009-03-10 19:43:44 +0000467const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000468{
469 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100470 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000471 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100472 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000473 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100474 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000475 return "NULL";
476 default:
477 return "RFU";
478 }
479}
480
Harald Weltee0590df2009-02-15 03:34:15 +0000481/* Chapter 9.4.7 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800482static const struct value_string avail_names[] = {
483 { 0, "In test" },
484 { 1, "Failed" },
485 { 2, "Power off" },
486 { 3, "Off line" },
487 /* Not used */
488 { 5, "Dependency" },
489 { 6, "Degraded" },
490 { 7, "Not installed" },
491 { 0xff, "OK" },
492 { 0, NULL }
Harald Weltee0590df2009-02-15 03:34:15 +0000493};
494
Harald Welte4d87f242009-03-10 19:43:44 +0000495const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000496{
Harald Welte92b1fe42010-03-25 11:45:30 +0800497 return get_value_string(avail_names, avail);
Harald Weltee0590df2009-02-15 03:34:15 +0000498}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000499
Harald Welte0f255852009-11-12 14:48:42 +0100500static struct value_string test_names[] = {
501 /* FIXME: standard test names */
502 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
503 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
504 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
505 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
506 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
507 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
508 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
509 { 0, NULL }
510};
511
Harald Welte81c9b9c2010-05-31 16:40:40 +0200512const struct value_string abis_nm_adm_state_names[] = {
513 { NM_STATE_LOCKED, "Locked" },
514 { NM_STATE_UNLOCKED, "Unlocked" },
515 { NM_STATE_SHUTDOWN, "Shutdown" },
516 { NM_STATE_NULL, "NULL" },
517 { 0, NULL }
518};
519
Harald Welte7b26bcb2009-05-28 11:39:21 +0000520const char *nm_adm_name(u_int8_t adm)
521{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200522 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte7b26bcb2009-05-28 11:39:21 +0000523}
Harald Weltee0590df2009-02-15 03:34:15 +0000524
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100525int nm_is_running(struct gsm_nm_state *s) {
526 return (s->operational == NM_OPSTATE_ENABLED) && (
527 (s->availability == NM_AVSTATE_OK) ||
528 (s->availability == 0xff)
529 );
530}
531
Harald Weltea8bd6d42009-10-20 09:56:18 +0200532static void debugp_foh(struct abis_om_fom_hdr *foh)
533{
534 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200535 obj_class_name(foh->obj_class), foh->obj_class,
Harald Weltea8bd6d42009-10-20 09:56:18 +0200536 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
537 foh->obj_inst.ts_nr);
538}
539
Harald Weltee0590df2009-02-15 03:34:15 +0000540/* obtain the gsm_nm_state data structure for a given object instance */
541static struct gsm_nm_state *
542objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
543 struct abis_om_obj_inst *obj_inst)
544{
545 struct gsm_bts_trx *trx;
546 struct gsm_nm_state *nm_state = NULL;
547
548 switch (obj_class) {
549 case NM_OC_BTS:
550 nm_state = &bts->nm_state;
551 break;
552 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100553 if (obj_inst->trx_nr >= bts->num_trx) {
554 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000555 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100556 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200557 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000558 nm_state = &trx->nm_state;
559 break;
560 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100561 if (obj_inst->trx_nr >= bts->num_trx) {
562 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000563 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100564 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200565 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000566 nm_state = &trx->bb_transc.nm_state;
567 break;
568 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100569 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100570 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000571 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100572 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200573 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000574 if (obj_inst->ts_nr >= TRX_NR_TS)
575 return NULL;
576 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
577 break;
578 case NM_OC_SITE_MANAGER:
579 nm_state = &bts->site_mgr.nm_state;
580 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000581 case NM_OC_BS11:
582 switch (obj_inst->bts_nr) {
583 case BS11_OBJ_CCLK:
584 nm_state = &bts->bs11.cclk.nm_state;
585 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000586 case BS11_OBJ_BBSIG:
587 if (obj_inst->ts_nr > bts->num_trx)
588 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200589 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000590 nm_state = &trx->bs11.bbsig.nm_state;
591 break;
592 case BS11_OBJ_PA:
593 if (obj_inst->ts_nr > bts->num_trx)
594 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200595 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000596 nm_state = &trx->bs11.pa.nm_state;
597 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000598 default:
599 return NULL;
600 }
601 case NM_OC_BS11_RACK:
602 nm_state = &bts->bs11.rack.nm_state;
603 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000604 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100605 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000606 return NULL;
607 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
608 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200609 case NM_OC_GPRS_NSE:
610 nm_state = &bts->gprs.nse.nm_state;
611 break;
612 case NM_OC_GPRS_CELL:
613 nm_state = &bts->gprs.cell.nm_state;
614 break;
615 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100616 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200617 return NULL;
618 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
619 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000620 }
621 return nm_state;
622}
623
624/* obtain the in-memory data structure of a given object instance */
625static void *
626objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
627 struct abis_om_obj_inst *obj_inst)
628{
629 struct gsm_bts_trx *trx;
630 void *obj = NULL;
631
632 switch (obj_class) {
633 case NM_OC_BTS:
634 obj = bts;
635 break;
636 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100637 if (obj_inst->trx_nr >= bts->num_trx) {
638 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000639 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100640 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200641 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000642 obj = trx;
643 break;
644 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100645 if (obj_inst->trx_nr >= bts->num_trx) {
646 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000647 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100648 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200649 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000650 obj = &trx->bb_transc;
651 break;
652 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100653 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100654 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000655 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100656 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200657 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000658 if (obj_inst->ts_nr >= TRX_NR_TS)
659 return NULL;
660 obj = &trx->ts[obj_inst->ts_nr];
661 break;
662 case NM_OC_SITE_MANAGER:
663 obj = &bts->site_mgr;
664 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200665 case NM_OC_GPRS_NSE:
666 obj = &bts->gprs.nse;
667 break;
668 case NM_OC_GPRS_CELL:
669 obj = &bts->gprs.cell;
670 break;
671 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100672 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200673 return NULL;
674 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
675 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000676 }
677 return obj;
678}
679
680/* Update the administrative state of a given object in our in-memory data
681 * structures and send an event to the higher layer */
682static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
683 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
684{
Harald Welteaeedeb42009-05-01 13:08:14 +0000685 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100686 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000687
Harald Weltef338a032011-01-14 15:55:42 +0100688 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
689 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100690 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000691 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
692 if (!nm_state)
693 return -1;
694
695 new_state = *nm_state;
696 new_state.administrative = adm_state;
697
Harald Weltef338a032011-01-14 15:55:42 +0100698 nsd.obj_class = obj_class;
699 nsd.old_state = nm_state;
700 nsd.new_state = &new_state;
701 nsd.obj_inst = obj_inst;
702 dispatch_signal(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000703
704 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000705
Harald Weltef338a032011-01-14 15:55:42 +0100706 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000707}
708
Harald Welte97ed1e72009-02-06 13:38:02 +0000709static int abis_nm_rx_statechg_rep(struct msgb *mb)
710{
Harald Weltee0590df2009-02-15 03:34:15 +0000711 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000712 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000713 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000714 struct tlv_parsed tp;
715 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000716
Harald Welte23897662009-05-01 14:52:51 +0000717 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000718
Harald Welte8b697c72009-06-05 19:18:45 +0000719 memset(&new_state, 0, sizeof(new_state));
720
Harald Weltee0590df2009-02-15 03:34:15 +0000721 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
722 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100723 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000724 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000725 }
Harald Weltee0590df2009-02-15 03:34:15 +0000726
727 new_state = *nm_state;
728
Harald Welte39315c42010-01-10 18:01:52 +0100729 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000730 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
731 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000732 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000733 }
734 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000735 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
736 new_state.availability = 0xff;
737 else
738 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000739 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000740 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100741 } else
742 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000743 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
744 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200745 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000746 }
747 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000748
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100749 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
750 new_state.operational != nm_state->operational ||
751 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000752 /* Update the operational state of a given object in our in-memory data
753 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100754 struct nm_statechg_signal_data nsd;
755 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
756 nsd.obj_class = foh->obj_class;
757 nsd.old_state = nm_state;
758 nsd.new_state = &new_state;
759 nsd.obj_inst = &foh->obj_inst;
760 dispatch_signal(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100761 nm_state->operational = new_state.operational;
762 nm_state->availability = new_state.availability;
763 if (nm_state->administrative == 0)
764 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000765 }
766#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000767 if (op_state == 1) {
768 /* try to enable objects that are disabled */
769 abis_nm_opstart(bts, foh->obj_class,
770 foh->obj_inst.bts_nr,
771 foh->obj_inst.trx_nr,
772 foh->obj_inst.ts_nr);
773 }
Harald Weltee0590df2009-02-15 03:34:15 +0000774#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000775 return 0;
776}
777
Harald Welte0db97b22009-05-01 17:22:47 +0000778static int rx_fail_evt_rep(struct msgb *mb)
779{
780 struct abis_om_hdr *oh = msgb_l2(mb);
781 struct abis_om_fom_hdr *foh = msgb_l3(mb);
782 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100783 const uint8_t *p_val;
784 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000785
786 DEBUGPC(DNM, "Failure Event Report ");
787
Harald Welte39315c42010-01-10 18:01:52 +0100788 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000789
790 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
791 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
792 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
793 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100794 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
795 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
796 DEBUGPC(DNM, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
797 }
798 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
799 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
800 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
801 if (p_text) {
802 DEBUGPC(DNM, "Additional Text=%s ", p_text);
803 talloc_free(p_text);
804 }
805 }
Harald Welte0db97b22009-05-01 17:22:47 +0000806
807 DEBUGPC(DNM, "\n");
808
809 return 0;
810}
811
Harald Welte97ed1e72009-02-06 13:38:02 +0000812static int abis_nm_rcvmsg_report(struct msgb *mb)
813{
814 struct abis_om_fom_hdr *foh = msgb_l3(mb);
815 u_int8_t mt = foh->msg_type;
816
Harald Weltea8bd6d42009-10-20 09:56:18 +0200817 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000818
Harald Welte97ed1e72009-02-06 13:38:02 +0000819 //nmh->cfg->report_cb(mb, foh);
820
821 switch (mt) {
822 case NM_MT_STATECHG_EVENT_REP:
823 return abis_nm_rx_statechg_rep(mb);
824 break;
Harald Welte34a99682009-02-13 02:41:40 +0000825 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000826 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000827 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000828 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000829 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000830 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000831 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000832 break;
Harald Weltec7310382009-08-08 00:02:36 +0200833 case NM_MT_TEST_REP:
834 DEBUGPC(DNM, "Test Report\n");
835 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
836 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000837 default:
Harald Welte23897662009-05-01 14:52:51 +0000838 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000839 break;
840
Harald Welte97ed1e72009-02-06 13:38:02 +0000841 };
842
Harald Welte97ed1e72009-02-06 13:38:02 +0000843 return 0;
844}
845
Harald Welte34a99682009-02-13 02:41:40 +0000846/* Activate the specified software into the BTS */
847static 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 +0200848 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000849{
850 struct abis_om_hdr *oh;
851 struct msgb *msg = nm_msgb_alloc();
852 u_int8_t len = swdesc_len;
853 u_int8_t *trailer;
854
855 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
856 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
857
858 trailer = msgb_put(msg, swdesc_len);
859 memcpy(trailer, sw_desc, swdesc_len);
860
861 return abis_nm_sendmsg(bts, msg);
862}
863
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100864static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
865{
866 static const struct tlv_definition sw_descr_def = {
867 .def = {
868 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
869 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
870 },
871 };
872
873 u_int8_t tag;
874 u_int16_t tag_len;
875 const u_int8_t *val;
876 int ofs = 0, len;
877
878 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
879 * nested nature and the fact you have to assume it contains only two sub
880 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
881
882 if (sw_descr[0] != NM_ATT_SW_DESCR) {
883 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
884 return -1;
885 }
886 ofs += 1;
887
888 len = tlv_parse_one(&tag, &tag_len, &val,
889 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
890 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
891 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
892 return -2;
893 }
894 ofs += len;
895
896 len = tlv_parse_one(&tag, &tag_len, &val,
897 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
898 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
899 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
900 return -3;
901 }
902 ofs += len;
903
904 return ofs;
905}
906
Harald Welte34a99682009-02-13 02:41:40 +0000907static int abis_nm_rx_sw_act_req(struct msgb *mb)
908{
909 struct abis_om_hdr *oh = msgb_l2(mb);
910 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200911 struct tlv_parsed tp;
912 const u_int8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100913 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000914
Harald Weltea8bd6d42009-10-20 09:56:18 +0200915 debugp_foh(foh);
916
917 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000918
Harald Welte97a282b2010-03-14 15:37:43 +0800919 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000920
921 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000922 foh->obj_inst.bts_nr,
923 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800924 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000925 foh->data, oh->length-sizeof(*foh));
926
Harald Welte39315c42010-01-10 18:01:52 +0100927 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200928 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
929 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
930 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
931 DEBUGP(DNM, "SW config not found! Can't continue.\n");
932 return -EINVAL;
933 } else {
934 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
935 }
936
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100937 /* Use the first SW_DESCR present in SW config */
938 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
939 if (sw_descr_len < 0)
940 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200941
Harald Welte34a99682009-02-13 02:41:40 +0000942 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
943 foh->obj_inst.bts_nr,
944 foh->obj_inst.trx_nr,
945 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100946 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000947}
948
Harald Weltee0590df2009-02-15 03:34:15 +0000949/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
950static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
951{
952 struct abis_om_hdr *oh = msgb_l2(mb);
953 struct abis_om_fom_hdr *foh = msgb_l3(mb);
954 struct tlv_parsed tp;
955 u_int8_t adm_state;
956
Harald Welte39315c42010-01-10 18:01:52 +0100957 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000958 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
959 return -EINVAL;
960
961 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
962
963 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
964}
965
Harald Welteee670472009-02-22 21:58:49 +0000966static int abis_nm_rx_lmt_event(struct msgb *mb)
967{
968 struct abis_om_hdr *oh = msgb_l2(mb);
969 struct abis_om_fom_hdr *foh = msgb_l3(mb);
970 struct tlv_parsed tp;
971
972 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100973 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000974 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
975 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
976 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
977 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
978 }
979 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
980 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
981 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
982 DEBUGPC(DNM, "Level=%u ", level);
983 }
984 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
985 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
986 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
987 DEBUGPC(DNM, "Username=%s ", name);
988 }
989 DEBUGPC(DNM, "\n");
990 /* FIXME: parse LMT LOGON TIME */
991 return 0;
992}
993
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100994static void abis_nm_queue_send_next(struct gsm_bts *bts)
995{
996 int wait = 0;
997 struct msgb *msg;
998 /* the queue is empty */
999 while (!llist_empty(&bts->abis_queue)) {
1000 msg = msgb_dequeue(&bts->abis_queue);
1001 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +01001002 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001003
1004 if (wait)
1005 break;
1006 }
1007
1008 bts->abis_nm_pend = wait;
1009}
1010
Harald Welte52b1f982008-12-23 20:25:15 +00001011/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001012static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001013{
Harald Welte6c96ba52009-05-01 13:03:40 +00001014 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001015 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1016 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001017 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001018
1019 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001020 if (is_report(mt))
1021 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001022
Harald Welte4724f992009-01-18 18:01:49 +00001023 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1024 return abis_nm_rcvmsg_sw(mb);
1025
Harald Welte78fc0d42009-02-19 02:50:57 +00001026 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001027 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +00001028 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001029
Harald Weltea8bd6d42009-10-20 09:56:18 +02001030 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001031
Harald Welte92b1fe42010-03-25 11:45:30 +08001032 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +00001033
Harald Welte39315c42010-01-10 18:01:52 +01001034 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +00001035 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001036 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00001037 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1038 else
1039 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001040
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001041 nack_data.msg = mb;
1042 nack_data.mt = mt;
1043 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001044 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001045 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001046 }
Harald Weltead384642008-12-26 10:20:07 +00001047#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001048 /* check if last message is to be acked */
1049 if (is_ack_nack(nmh->last_msgtype)) {
1050 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001051 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001052 /* we got our ACK, continue sending the next msg */
1053 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1054 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001055 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001056 /* FIXME: somehow signal this to the caller */
1057 } else {
1058 /* really strange things happen */
1059 return -EINVAL;
1060 }
1061 }
Harald Weltead384642008-12-26 10:20:07 +00001062#endif
1063
Harald Welte97ed1e72009-02-06 13:38:02 +00001064 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001065 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001066 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +00001067 break;
Harald Welte34a99682009-02-13 02:41:40 +00001068 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001069 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +00001070 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001071 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001072 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001073 break;
Harald Welte1989c082009-08-06 17:58:31 +02001074 case NM_MT_CONN_MDROP_LINK_ACK:
1075 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1076 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001077 case NM_MT_IPACC_RESTART_ACK:
1078 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1079 break;
1080 case NM_MT_IPACC_RESTART_NACK:
1081 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1082 break;
Harald Weltefd355a32011-03-04 13:41:31 +01001083 case NM_MT_SET_BTS_ATTR_ACK:
1084 /* The HSL wants an OPSTART _after_ the SI has been set */
1085 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
1086 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
1087 }
1088 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001089 }
1090
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001091 abis_nm_queue_send_next(mb->trx->bts);
1092 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001093}
1094
Harald Welte677c21f2009-02-17 13:22:23 +00001095static int abis_nm_rx_ipacc(struct msgb *mb);
1096
1097static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1098{
1099 int rc;
1100 int bts_type = mb->trx->bts->type;
1101
1102 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001103 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001104 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001105 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +00001106 break;
1107 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001108 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1109 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001110 rc = 0;
1111 break;
1112 }
1113
1114 return rc;
1115}
1116
Harald Welte52b1f982008-12-23 20:25:15 +00001117/* High-Level API */
1118/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001119int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001120{
Harald Welte52b1f982008-12-23 20:25:15 +00001121 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001122 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001123
1124 /* Various consistency checks */
1125 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001126 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001127 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001128 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1129 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001130 }
1131 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001132 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001133 oh->sequence);
1134 return -EINVAL;
1135 }
Harald Welte702d8702008-12-26 20:25:35 +00001136#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001137 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1138 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001139 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001140 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001141 oh->length + sizeof(*oh), l2_len);
1142 return -EINVAL;
1143 }
Harald Welte702d8702008-12-26 20:25:35 +00001144 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001145 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 +00001146#endif
Harald Weltead384642008-12-26 10:20:07 +00001147 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001148
1149 switch (oh->mdisc) {
1150 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001151 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001152 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001153 case ABIS_OM_MDISC_MANUF:
1154 rc = abis_nm_rcvmsg_manuf(msg);
1155 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001156 case ABIS_OM_MDISC_MMI:
1157 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001158 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001159 oh->mdisc);
1160 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001161 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001162 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001163 oh->mdisc);
1164 return -EINVAL;
1165 }
1166
Harald Weltead384642008-12-26 10:20:07 +00001167 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001168 return rc;
1169}
1170
1171#if 0
1172/* initialized all resources */
1173struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1174{
1175 struct abis_nm_h *nmh;
1176
1177 nmh = malloc(sizeof(*nmh));
1178 if (!nmh)
1179 return NULL;
1180
1181 nmh->cfg = cfg;
1182
1183 return nmh;
1184}
1185
1186/* free all resources */
1187void abis_nm_fini(struct abis_nm_h *nmh)
1188{
1189 free(nmh);
1190}
1191#endif
1192
1193/* Here we are trying to define a high-level API that can be used by
1194 * the actual BSC implementation. However, the architecture is currently
1195 * still under design. Ideally the calls to this API would be synchronous,
1196 * while the underlying stack behind the APi runs in a traditional select
1197 * based state machine.
1198 */
1199
Harald Welte4724f992009-01-18 18:01:49 +00001200/* 6.2 Software Load: */
1201enum sw_state {
1202 SW_STATE_NONE,
1203 SW_STATE_WAIT_INITACK,
1204 SW_STATE_WAIT_SEGACK,
1205 SW_STATE_WAIT_ENDACK,
1206 SW_STATE_WAIT_ACTACK,
1207 SW_STATE_ERROR,
1208};
Harald Welte52b1f982008-12-23 20:25:15 +00001209
Harald Welte52b1f982008-12-23 20:25:15 +00001210struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001211 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001212 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001213 gsm_cbfn *cbfn;
1214 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001215 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001216
Harald Welte52b1f982008-12-23 20:25:15 +00001217 /* this will become part of the SW LOAD INITIATE */
1218 u_int8_t obj_class;
1219 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001220
1221 u_int8_t file_id[255];
1222 u_int8_t file_id_len;
1223
1224 u_int8_t file_version[255];
1225 u_int8_t file_version_len;
1226
1227 u_int8_t window_size;
1228 u_int8_t seg_in_window;
1229
1230 int fd;
1231 FILE *stream;
1232 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001233 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001234};
1235
Harald Welte4724f992009-01-18 18:01:49 +00001236static struct abis_nm_sw g_sw;
1237
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001238static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1239{
1240 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1241 msgb_v_put(msg, NM_ATT_SW_DESCR);
1242 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1243 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1244 sw->file_version);
1245 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1246 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1247 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1248 sw->file_version);
1249 } else {
1250 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1251 }
1252}
1253
Harald Welte4724f992009-01-18 18:01:49 +00001254/* 6.2.1 / 8.3.1: Load Data Initiate */
1255static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001256{
Harald Welte4724f992009-01-18 18:01:49 +00001257 struct abis_om_hdr *oh;
1258 struct msgb *msg = nm_msgb_alloc();
1259 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1260
1261 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1262 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1263 sw->obj_instance[0], sw->obj_instance[1],
1264 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001265
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001266 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001267 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1268
1269 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001270}
1271
Harald Welte1602ade2009-01-29 21:12:39 +00001272static int is_last_line(FILE *stream)
1273{
1274 char next_seg_buf[256];
1275 long pos;
1276
1277 /* check if we're sending the last line */
1278 pos = ftell(stream);
1279 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1280 fseek(stream, pos, SEEK_SET);
1281 return 1;
1282 }
1283
1284 fseek(stream, pos, SEEK_SET);
1285 return 0;
1286}
1287
Harald Welte4724f992009-01-18 18:01:49 +00001288/* 6.2.2 / 8.3.2 Load Data Segment */
1289static int sw_load_segment(struct abis_nm_sw *sw)
1290{
1291 struct abis_om_hdr *oh;
1292 struct msgb *msg = nm_msgb_alloc();
1293 char seg_buf[256];
1294 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001295 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001296 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001297
1298 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001299
1300 switch (sw->bts->type) {
1301 case GSM_BTS_TYPE_BS11:
1302 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1303 perror("fgets reading segment");
1304 return -EINVAL;
1305 }
1306 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001307
1308 /* check if we're sending the last line */
1309 sw->last_seg = is_last_line(sw->stream);
1310 if (sw->last_seg)
1311 seg_buf[1] = 0;
1312 else
1313 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001314
1315 len = strlen(line_buf) + 2;
1316 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1317 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1318 /* BS11 wants CR + LF in excess of the TLV length !?! */
1319 tlv[1] -= 2;
1320
1321 /* we only now know the exact length for the OM hdr */
1322 len = strlen(line_buf)+2;
1323 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001324 case GSM_BTS_TYPE_NANOBTS: {
1325 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1326 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1327 if (len < 0) {
1328 perror("read failed");
1329 return -EINVAL;
1330 }
1331
1332 if (len != IPACC_SEGMENT_SIZE)
1333 sw->last_seg = 1;
1334
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001335 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001336 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1337 len += 3;
1338 break;
1339 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001340 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001341 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001342 /* FIXME: Other BTS types */
1343 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001344 }
Harald Welte4724f992009-01-18 18:01:49 +00001345
Harald Welte4724f992009-01-18 18:01:49 +00001346 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1347 sw->obj_instance[0], sw->obj_instance[1],
1348 sw->obj_instance[2]);
1349
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001350 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001351}
1352
1353/* 6.2.4 / 8.3.4 Load Data End */
1354static int sw_load_end(struct abis_nm_sw *sw)
1355{
1356 struct abis_om_hdr *oh;
1357 struct msgb *msg = nm_msgb_alloc();
1358 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1359
1360 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1361 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1362 sw->obj_instance[0], sw->obj_instance[1],
1363 sw->obj_instance[2]);
1364
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001365 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001366 return abis_nm_sendmsg(sw->bts, msg);
1367}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001368
Harald Welte52b1f982008-12-23 20:25:15 +00001369/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001370static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001371{
Harald Welte4724f992009-01-18 18:01:49 +00001372 struct abis_om_hdr *oh;
1373 struct msgb *msg = nm_msgb_alloc();
1374 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001375
Harald Welte4724f992009-01-18 18:01:49 +00001376 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1377 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1378 sw->obj_instance[0], sw->obj_instance[1],
1379 sw->obj_instance[2]);
1380
1381 /* FIXME: this is BS11 specific format */
1382 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1383 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1384 sw->file_version);
1385
1386 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001387}
Harald Welte4724f992009-01-18 18:01:49 +00001388
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001389struct sdp_firmware {
1390 char magic[4];
1391 char more_magic[4];
1392 unsigned int header_length;
1393 unsigned int file_length;
1394} __attribute__ ((packed));
1395
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001396static int parse_sdp_header(struct abis_nm_sw *sw)
1397{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001398 struct sdp_firmware firmware_header;
1399 int rc;
1400 struct stat stat;
1401
1402 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1403 if (rc != sizeof(firmware_header)) {
1404 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1405 return -1;
1406 }
1407
1408 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1409 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1410 return -1;
1411 }
1412
1413 if (firmware_header.more_magic[0] != 0x10 ||
1414 firmware_header.more_magic[1] != 0x02 ||
1415 firmware_header.more_magic[2] != 0x00 ||
1416 firmware_header.more_magic[3] != 0x00) {
1417 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1418 return -1;
1419 }
1420
1421
1422 if (fstat(sw->fd, &stat) == -1) {
1423 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1424 return -1;
1425 }
1426
1427 if (ntohl(firmware_header.file_length) != stat.st_size) {
1428 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1429 return -1;
1430 }
1431
1432 /* go back to the start as we checked the whole filesize.. */
1433 lseek(sw->fd, 0l, SEEK_SET);
1434 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1435 "There might be checksums in the file that are not\n"
1436 "verified and incomplete firmware might be flashed.\n"
1437 "There is absolutely no WARRANTY that flashing will\n"
1438 "work.\n");
1439 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001440}
1441
Harald Welte4724f992009-01-18 18:01:49 +00001442static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1443{
1444 char file_id[12+1];
1445 char file_version[80+1];
1446 int rc;
1447
1448 sw->fd = open(fname, O_RDONLY);
1449 if (sw->fd < 0)
1450 return sw->fd;
1451
1452 switch (sw->bts->type) {
1453 case GSM_BTS_TYPE_BS11:
1454 sw->stream = fdopen(sw->fd, "r");
1455 if (!sw->stream) {
1456 perror("fdopen");
1457 return -1;
1458 }
1459 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001460 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001461 file_id, file_version);
1462 if (rc != 2) {
1463 perror("parsing header line of software file");
1464 return -1;
1465 }
1466 strcpy((char *)sw->file_id, file_id);
1467 sw->file_id_len = strlen(file_id);
1468 strcpy((char *)sw->file_version, file_version);
1469 sw->file_version_len = strlen(file_version);
1470 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001471 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001472 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001473 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001474 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001475 rc = parse_sdp_header(sw);
1476 if (rc < 0) {
1477 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1478 return -1;
1479 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001480
1481 strcpy((char *)sw->file_id, "id");
1482 sw->file_id_len = 3;
1483 strcpy((char *)sw->file_version, "version");
1484 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001485 break;
Harald Welte4724f992009-01-18 18:01:49 +00001486 default:
1487 /* We don't know how to treat them yet */
1488 close(sw->fd);
1489 return -EINVAL;
1490 }
1491
1492 return 0;
1493}
1494
1495static void sw_close_file(struct abis_nm_sw *sw)
1496{
1497 switch (sw->bts->type) {
1498 case GSM_BTS_TYPE_BS11:
1499 fclose(sw->stream);
1500 break;
1501 default:
1502 close(sw->fd);
1503 break;
1504 }
1505}
1506
1507/* Fill the window */
1508static int sw_fill_window(struct abis_nm_sw *sw)
1509{
1510 int rc;
1511
1512 while (sw->seg_in_window < sw->window_size) {
1513 rc = sw_load_segment(sw);
1514 if (rc < 0)
1515 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001516 if (sw->last_seg)
1517 break;
Harald Welte4724f992009-01-18 18:01:49 +00001518 }
1519 return 0;
1520}
1521
1522/* callback function from abis_nm_rcvmsg() handler */
1523static int abis_nm_rcvmsg_sw(struct msgb *mb)
1524{
1525 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1526 int rc = -1;
1527 struct abis_nm_sw *sw = &g_sw;
1528 enum sw_state old_state = sw->state;
1529
Harald Welte3ffd1372009-02-01 22:15:49 +00001530 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001531
1532 switch (sw->state) {
1533 case SW_STATE_WAIT_INITACK:
1534 switch (foh->msg_type) {
1535 case NM_MT_LOAD_INIT_ACK:
1536 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001537 if (sw->cbfn)
1538 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1539 NM_MT_LOAD_INIT_ACK, mb,
1540 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001541 rc = sw_fill_window(sw);
1542 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001543 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001544 break;
1545 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001546 if (sw->forced) {
1547 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1548 "Init NACK\n");
1549 if (sw->cbfn)
1550 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1551 NM_MT_LOAD_INIT_ACK, mb,
1552 sw->cb_data, NULL);
1553 rc = sw_fill_window(sw);
1554 sw->state = SW_STATE_WAIT_SEGACK;
1555 } else {
1556 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001557 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001558 if (sw->cbfn)
1559 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1560 NM_MT_LOAD_INIT_NACK, mb,
1561 sw->cb_data, NULL);
1562 sw->state = SW_STATE_ERROR;
1563 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001564 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001565 break;
1566 }
1567 break;
1568 case SW_STATE_WAIT_SEGACK:
1569 switch (foh->msg_type) {
1570 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001571 if (sw->cbfn)
1572 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1573 NM_MT_LOAD_SEG_ACK, mb,
1574 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001575 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001576 if (!sw->last_seg) {
1577 /* fill window with more segments */
1578 rc = sw_fill_window(sw);
1579 sw->state = SW_STATE_WAIT_SEGACK;
1580 } else {
1581 /* end the transfer */
1582 sw->state = SW_STATE_WAIT_ENDACK;
1583 rc = sw_load_end(sw);
1584 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001585 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001586 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001587 case NM_MT_LOAD_ABORT:
1588 if (sw->cbfn)
1589 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1590 NM_MT_LOAD_ABORT, mb,
1591 sw->cb_data, NULL);
1592 break;
Harald Welte4724f992009-01-18 18:01:49 +00001593 }
1594 break;
1595 case SW_STATE_WAIT_ENDACK:
1596 switch (foh->msg_type) {
1597 case NM_MT_LOAD_END_ACK:
1598 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001599 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1600 sw->bts->nr);
1601 sw->state = SW_STATE_NONE;
1602 if (sw->cbfn)
1603 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1604 NM_MT_LOAD_END_ACK, mb,
1605 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001606 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001607 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001608 break;
1609 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001610 if (sw->forced) {
1611 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1612 "End NACK\n");
1613 sw->state = SW_STATE_NONE;
1614 if (sw->cbfn)
1615 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1616 NM_MT_LOAD_END_ACK, mb,
1617 sw->cb_data, NULL);
1618 } else {
1619 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001620 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001621 sw->state = SW_STATE_ERROR;
1622 if (sw->cbfn)
1623 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1624 NM_MT_LOAD_END_NACK, mb,
1625 sw->cb_data, NULL);
1626 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001627 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001628 break;
1629 }
1630 case SW_STATE_WAIT_ACTACK:
1631 switch (foh->msg_type) {
1632 case NM_MT_ACTIVATE_SW_ACK:
1633 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001634 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001635 sw->state = SW_STATE_NONE;
1636 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001637 if (sw->cbfn)
1638 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1639 NM_MT_ACTIVATE_SW_ACK, mb,
1640 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001641 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001642 break;
1643 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001644 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001645 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001646 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001647 if (sw->cbfn)
1648 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1649 NM_MT_ACTIVATE_SW_NACK, mb,
1650 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001651 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001652 break;
1653 }
1654 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001655 switch (foh->msg_type) {
1656 case NM_MT_ACTIVATE_SW_ACK:
1657 rc = 0;
1658 break;
1659 }
1660 break;
Harald Welte4724f992009-01-18 18:01:49 +00001661 case SW_STATE_ERROR:
1662 break;
1663 }
1664
1665 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001666 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001667 foh->msg_type, old_state, sw->state);
1668
1669 return rc;
1670}
1671
1672/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001673int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001674 u_int8_t win_size, int forced,
1675 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001676{
1677 struct abis_nm_sw *sw = &g_sw;
1678 int rc;
1679
Harald Welte5e4d1b32009-02-01 13:36:56 +00001680 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1681 bts->nr, fname);
1682
Harald Welte4724f992009-01-18 18:01:49 +00001683 if (sw->state != SW_STATE_NONE)
1684 return -EBUSY;
1685
1686 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001687 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001688
1689 switch (bts->type) {
1690 case GSM_BTS_TYPE_BS11:
1691 sw->obj_class = NM_OC_SITE_MANAGER;
1692 sw->obj_instance[0] = 0xff;
1693 sw->obj_instance[1] = 0xff;
1694 sw->obj_instance[2] = 0xff;
1695 break;
1696 case GSM_BTS_TYPE_NANOBTS:
1697 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001698 sw->obj_instance[0] = sw->bts->nr;
1699 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001700 sw->obj_instance[2] = 0xff;
1701 break;
1702 case GSM_BTS_TYPE_UNKNOWN:
1703 default:
1704 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1705 return -1;
1706 break;
1707 }
Harald Welte4724f992009-01-18 18:01:49 +00001708 sw->window_size = win_size;
1709 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001710 sw->cbfn = cbfn;
1711 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001712 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001713
1714 rc = sw_open_file(sw, fname);
1715 if (rc < 0) {
1716 sw->state = SW_STATE_NONE;
1717 return rc;
1718 }
1719
1720 return sw_load_init(sw);
1721}
Harald Welte52b1f982008-12-23 20:25:15 +00001722
Harald Welte1602ade2009-01-29 21:12:39 +00001723int abis_nm_software_load_status(struct gsm_bts *bts)
1724{
1725 struct abis_nm_sw *sw = &g_sw;
1726 struct stat st;
1727 int rc, percent;
1728
1729 rc = fstat(sw->fd, &st);
1730 if (rc < 0) {
1731 perror("ERROR during stat");
1732 return rc;
1733 }
1734
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001735 if (sw->stream)
1736 percent = (ftell(sw->stream) * 100) / st.st_size;
1737 else
1738 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001739 return percent;
1740}
1741
Harald Welte5e4d1b32009-02-01 13:36:56 +00001742/* Activate the specified software into the BTS */
1743int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1744 gsm_cbfn *cbfn, void *cb_data)
1745{
1746 struct abis_nm_sw *sw = &g_sw;
1747 int rc;
1748
1749 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1750 bts->nr, fname);
1751
1752 if (sw->state != SW_STATE_NONE)
1753 return -EBUSY;
1754
1755 sw->bts = bts;
1756 sw->obj_class = NM_OC_SITE_MANAGER;
1757 sw->obj_instance[0] = 0xff;
1758 sw->obj_instance[1] = 0xff;
1759 sw->obj_instance[2] = 0xff;
1760 sw->state = SW_STATE_WAIT_ACTACK;
1761 sw->cbfn = cbfn;
1762 sw->cb_data = cb_data;
1763
1764 /* Open the file in order to fill some sw struct members */
1765 rc = sw_open_file(sw, fname);
1766 if (rc < 0) {
1767 sw->state = SW_STATE_NONE;
1768 return rc;
1769 }
1770 sw_close_file(sw);
1771
1772 return sw_activate(sw);
1773}
1774
Harald Welte8470bf22008-12-25 23:28:35 +00001775static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001776 u_int8_t ts_nr, u_int8_t subslot_nr)
1777{
Harald Welteadaf08b2009-01-18 11:08:10 +00001778 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001779 ch->bts_port = bts_port;
1780 ch->timeslot = ts_nr;
1781 ch->subslot = subslot_nr;
1782}
1783
1784int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1785 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1786 u_int8_t tei)
1787{
1788 struct abis_om_hdr *oh;
1789 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001790 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001791 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001792
1793 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1794 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1795 bts->bts_nr, trx_nr, 0xff);
1796
Harald Welte8470bf22008-12-25 23:28:35 +00001797 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001798
1799 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1800 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1801
1802 return abis_nm_sendmsg(bts, msg);
1803}
1804
1805/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1806int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1807 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1808{
Harald Welte8470bf22008-12-25 23:28:35 +00001809 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001810 struct abis_om_hdr *oh;
1811 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001812 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001813
1814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001815 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001816 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1817
1818 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1819 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1820
1821 return abis_nm_sendmsg(bts, msg);
1822}
1823
1824#if 0
1825int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1826 struct abis_nm_abis_channel *chan)
1827{
1828}
1829#endif
1830
1831int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1832 u_int8_t e1_port, u_int8_t e1_timeslot,
1833 u_int8_t e1_subslot)
1834{
1835 struct gsm_bts *bts = ts->trx->bts;
1836 struct abis_om_hdr *oh;
1837 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001838 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001839
1840 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1841 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001842 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001843
1844 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1845 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1846
Harald Weltef325eb42009-02-19 17:07:39 +00001847 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1848 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001849 e1_port, e1_timeslot, e1_subslot);
1850
Harald Welte52b1f982008-12-23 20:25:15 +00001851 return abis_nm_sendmsg(bts, msg);
1852}
1853
1854#if 0
1855int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1856 struct abis_nm_abis_channel *chan,
1857 u_int8_t subchan)
1858{
1859}
1860#endif
1861
Harald Welte22af0db2009-02-14 15:41:08 +00001862/* Chapter 8.6.1 */
1863int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1864{
1865 struct abis_om_hdr *oh;
1866 struct msgb *msg = nm_msgb_alloc();
1867 u_int8_t *cur;
1868
1869 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1870
1871 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001872 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 +00001873 cur = msgb_put(msg, attr_len);
1874 memcpy(cur, attr, attr_len);
1875
1876 return abis_nm_sendmsg(bts, msg);
1877}
1878
1879/* Chapter 8.6.2 */
1880int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1881{
1882 struct abis_om_hdr *oh;
1883 struct msgb *msg = nm_msgb_alloc();
1884 u_int8_t *cur;
1885
1886 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1887
1888 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1889 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001890 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001891 cur = msgb_put(msg, attr_len);
1892 memcpy(cur, attr, attr_len);
1893
1894 return abis_nm_sendmsg(trx->bts, msg);
1895}
1896
Harald Welte39c7deb2009-08-09 21:49:48 +02001897static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1898{
1899 int i;
1900
1901 /* As it turns out, the BS-11 has some very peculiar restrictions
1902 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301903 switch (ts->trx->bts->type) {
1904 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001905 switch (chan_comb) {
1906 case NM_CHANC_TCHHalf:
1907 case NM_CHANC_TCHHalf2:
1908 /* not supported */
1909 return -EINVAL;
1910 case NM_CHANC_SDCCH:
1911 /* only one SDCCH/8 per TRX */
1912 for (i = 0; i < TRX_NR_TS; i++) {
1913 if (i == ts->nr)
1914 continue;
1915 if (ts->trx->ts[i].nm_chan_comb ==
1916 NM_CHANC_SDCCH)
1917 return -EINVAL;
1918 }
1919 /* not allowed for TS0 of BCCH-TRX */
1920 if (ts->trx == ts->trx->bts->c0 &&
1921 ts->nr == 0)
1922 return -EINVAL;
1923 /* not on the same TRX that has a BCCH+SDCCH4
1924 * combination */
1925 if (ts->trx == ts->trx->bts->c0 &&
1926 (ts->trx->ts[0].nm_chan_comb == 5 ||
1927 ts->trx->ts[0].nm_chan_comb == 8))
1928 return -EINVAL;
1929 break;
1930 case NM_CHANC_mainBCCH:
1931 case NM_CHANC_BCCHComb:
1932 /* allowed only for TS0 of C0 */
1933 if (ts->trx != ts->trx->bts->c0 ||
1934 ts->nr != 0)
1935 return -EINVAL;
1936 break;
1937 case NM_CHANC_BCCH:
1938 /* allowed only for TS 2/4/6 of C0 */
1939 if (ts->trx != ts->trx->bts->c0)
1940 return -EINVAL;
1941 if (ts->nr != 2 && ts->nr != 4 &&
1942 ts->nr != 6)
1943 return -EINVAL;
1944 break;
1945 case 8: /* this is not like 08.58, but in fact
1946 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1947 /* FIXME: only one CBCH allowed per cell */
1948 break;
1949 }
Harald Welted6575f92009-12-02 02:45:23 +05301950 break;
1951 case GSM_BTS_TYPE_NANOBTS:
1952 switch (ts->nr) {
1953 case 0:
1954 if (ts->trx->nr == 0) {
1955 /* only on TRX0 */
1956 switch (chan_comb) {
1957 case NM_CHANC_BCCH:
1958 case NM_CHANC_mainBCCH:
1959 case NM_CHANC_BCCHComb:
1960 return 0;
1961 break;
1962 default:
1963 return -EINVAL;
1964 }
1965 } else {
1966 switch (chan_comb) {
1967 case NM_CHANC_TCHFull:
1968 case NM_CHANC_TCHHalf:
1969 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1970 return 0;
1971 default:
1972 return -EINVAL;
1973 }
1974 }
1975 break;
1976 case 1:
1977 if (ts->trx->nr == 0) {
1978 switch (chan_comb) {
1979 case NM_CHANC_SDCCH_CBCH:
1980 if (ts->trx->ts[0].nm_chan_comb ==
1981 NM_CHANC_mainBCCH)
1982 return 0;
1983 return -EINVAL;
1984 case NM_CHANC_SDCCH:
1985 case NM_CHANC_TCHFull:
1986 case NM_CHANC_TCHHalf:
1987 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1988 case NM_CHANC_IPAC_TCHFull_PDCH:
1989 return 0;
1990 }
1991 } else {
1992 switch (chan_comb) {
1993 case NM_CHANC_SDCCH:
1994 case NM_CHANC_TCHFull:
1995 case NM_CHANC_TCHHalf:
1996 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1997 return 0;
1998 default:
1999 return -EINVAL;
2000 }
2001 }
2002 break;
2003 case 2:
2004 case 3:
2005 case 4:
2006 case 5:
2007 case 6:
2008 case 7:
2009 switch (chan_comb) {
2010 case NM_CHANC_TCHFull:
2011 case NM_CHANC_TCHHalf:
2012 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2013 return 0;
2014 case NM_CHANC_IPAC_PDCH:
2015 case NM_CHANC_IPAC_TCHFull_PDCH:
2016 if (ts->trx->nr == 0)
2017 return 0;
2018 else
2019 return -EINVAL;
2020 }
2021 break;
2022 }
2023 return -EINVAL;
2024 default:
2025 /* unknown BTS type */
2026 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002027 }
2028 return 0;
2029}
2030
Harald Welte22af0db2009-02-14 15:41:08 +00002031/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002032int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2033{
2034 struct gsm_bts *bts = ts->trx->bts;
2035 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002036 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002037 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002038 u_int8_t len = 2 + 2;
2039
2040 if (bts->type == GSM_BTS_TYPE_BS11)
2041 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002042
Harald Weltef325eb42009-02-19 17:07:39 +00002043 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002044 if (verify_chan_comb(ts, chan_comb) < 0) {
2045 msgb_free(msg);
2046 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2047 return -EINVAL;
2048 }
2049 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002050
Harald Welte52b1f982008-12-23 20:25:15 +00002051 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002052 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002053 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002054 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002055 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002056 if (ts->hopping.enabled) {
2057 unsigned int i;
2058 uint8_t *len;
2059
Harald Welte6e0cd042009-09-12 13:05:33 +02002060 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2061 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002062
2063 /* build the ARFCN list */
2064 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2065 len = msgb_put(msg, 1);
2066 *len = 0;
2067 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2068 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2069 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002070 /* At least BS-11 wants a TLV16 here */
2071 if (bts->type == GSM_BTS_TYPE_BS11)
2072 *len += 1;
2073 else
2074 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002075 }
2076 }
Harald Weltee0590df2009-02-15 03:34:15 +00002077 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002078 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002079 if (bts->type == GSM_BTS_TYPE_BS11)
2080 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002081
2082 return abis_nm_sendmsg(bts, msg);
2083}
2084
Harald Welte34a99682009-02-13 02:41:40 +00002085int 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 +00002086 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002087{
2088 struct abis_om_hdr *oh;
2089 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002090 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2091 u_int8_t len = att_len;
2092
2093 if (nack) {
2094 len += 2;
2095 msgtype = NM_MT_SW_ACT_REQ_NACK;
2096 }
Harald Welte34a99682009-02-13 02:41:40 +00002097
2098 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002099 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2100
Harald Welte34a99682009-02-13 02:41:40 +00002101 if (attr) {
2102 u_int8_t *ptr = msgb_put(msg, att_len);
2103 memcpy(ptr, attr, att_len);
2104 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002105 if (nack)
2106 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002107
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002108 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002109}
2110
Harald Welte8470bf22008-12-25 23:28:35 +00002111int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002112{
Harald Welte8470bf22008-12-25 23:28:35 +00002113 struct msgb *msg = nm_msgb_alloc();
2114 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002115 u_int8_t *data;
2116
2117 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2118 fill_om_hdr(oh, len);
2119 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002120 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002121
2122 return abis_nm_sendmsg(bts, msg);
2123}
2124
2125/* Siemens specific commands */
2126static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2127{
2128 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002129 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002130
2131 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002132 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002133 0xff, 0xff, 0xff);
2134
2135 return abis_nm_sendmsg(bts, msg);
2136}
2137
Harald Welte34a99682009-02-13 02:41:40 +00002138/* Chapter 8.9.2 */
2139int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2140{
2141 struct abis_om_hdr *oh;
2142 struct msgb *msg = nm_msgb_alloc();
2143
2144 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2145 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2146
Harald Weltea8bd6d42009-10-20 09:56:18 +02002147 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2148 DEBUGPC(DNM, "Sending OPSTART\n");
2149
Harald Welte34a99682009-02-13 02:41:40 +00002150 return abis_nm_sendmsg(bts, msg);
2151}
2152
2153/* Chapter 8.8.5 */
2154int 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 +02002155 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002156{
2157 struct abis_om_hdr *oh;
2158 struct msgb *msg = nm_msgb_alloc();
2159
2160 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2161 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2162 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2163
2164 return abis_nm_sendmsg(bts, msg);
2165}
2166
Harald Welte1989c082009-08-06 17:58:31 +02002167int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2168 u_int8_t e1_port1, u_int8_t ts1)
2169{
2170 struct abis_om_hdr *oh;
2171 struct msgb *msg = nm_msgb_alloc();
2172 u_int8_t *attr;
2173
2174 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2175 e1_port0, ts0, e1_port1, ts1);
2176
2177 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2178 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2179 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2180
2181 attr = msgb_put(msg, 3);
2182 attr[0] = NM_ATT_MDROP_LINK;
2183 attr[1] = e1_port0;
2184 attr[2] = ts0;
2185
2186 attr = msgb_put(msg, 3);
2187 attr[0] = NM_ATT_MDROP_NEXT;
2188 attr[1] = e1_port1;
2189 attr[2] = ts1;
2190
2191 return abis_nm_sendmsg(bts, msg);
2192}
Harald Welte34a99682009-02-13 02:41:40 +00002193
Harald Weltec7310382009-08-08 00:02:36 +02002194/* Chapter 8.7.1 */
2195int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2196 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002197 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002198{
2199 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002200
Harald Welte4d54d0b2011-02-19 16:48:17 +01002201 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002202
2203 if (!msg)
2204 msg = nm_msgb_alloc();
2205
2206 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2207 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2208 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2209 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002210 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002211
2212 return abis_nm_sendmsg(bts, msg);
2213}
2214
Harald Welte52b1f982008-12-23 20:25:15 +00002215int abis_nm_event_reports(struct gsm_bts *bts, int on)
2216{
2217 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002218 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002219 else
Harald Welte227d4072009-01-03 08:16:25 +00002220 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002221}
2222
Harald Welte47d88ae2009-01-04 12:02:08 +00002223/* Siemens (or BS-11) specific commands */
2224
Harald Welte3ffd1372009-02-01 22:15:49 +00002225int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2226{
2227 if (reconnect == 0)
2228 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2229 else
2230 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2231}
2232
Harald Welteb8427972009-02-05 19:27:17 +00002233int abis_nm_bs11_restart(struct gsm_bts *bts)
2234{
2235 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2236}
2237
2238
Harald Welte268bb402009-02-01 19:11:56 +00002239struct bs11_date_time {
2240 u_int16_t year;
2241 u_int8_t month;
2242 u_int8_t day;
2243 u_int8_t hour;
2244 u_int8_t min;
2245 u_int8_t sec;
2246} __attribute__((packed));
2247
2248
2249void get_bs11_date_time(struct bs11_date_time *aet)
2250{
2251 time_t t;
2252 struct tm *tm;
2253
2254 t = time(NULL);
2255 tm = localtime(&t);
2256 aet->sec = tm->tm_sec;
2257 aet->min = tm->tm_min;
2258 aet->hour = tm->tm_hour;
2259 aet->day = tm->tm_mday;
2260 aet->month = tm->tm_mon;
2261 aet->year = htons(1900 + tm->tm_year);
2262}
2263
Harald Welte05188ee2009-01-18 11:39:08 +00002264int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002265{
Harald Welte4668fda2009-01-03 08:19:29 +00002266 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002267}
2268
Harald Welte05188ee2009-01-18 11:39:08 +00002269int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002270{
2271 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002272 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002273 else
Harald Welte4668fda2009-01-03 08:19:29 +00002274 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002275}
Harald Welte47d88ae2009-01-04 12:02:08 +00002276
Harald Welte05188ee2009-01-18 11:39:08 +00002277int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002278 enum abis_bs11_objtype type, u_int8_t idx,
2279 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002280{
2281 struct abis_om_hdr *oh;
2282 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002283 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002284
2285 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002286 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002287 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002288 cur = msgb_put(msg, attr_len);
2289 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002290
2291 return abis_nm_sendmsg(bts, msg);
2292}
2293
Harald Welte78fc0d42009-02-19 02:50:57 +00002294int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2295 enum abis_bs11_objtype type, u_int8_t idx)
2296{
2297 struct abis_om_hdr *oh;
2298 struct msgb *msg = nm_msgb_alloc();
2299
2300 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2301 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2302 NM_OC_BS11, type, 0, idx);
2303
2304 return abis_nm_sendmsg(bts, msg);
2305}
2306
Harald Welte05188ee2009-01-18 11:39:08 +00002307int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002308{
2309 struct abis_om_hdr *oh;
2310 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002311 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002312
2313 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002314 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002315 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2316 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002317
2318 return abis_nm_sendmsg(bts, msg);
2319}
2320
Harald Welte05188ee2009-01-18 11:39:08 +00002321int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002322{
2323 struct abis_om_hdr *oh;
2324 struct msgb *msg = nm_msgb_alloc();
2325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2327 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002328 idx, 0xff, 0xff);
2329
2330 return abis_nm_sendmsg(bts, msg);
2331}
2332
2333int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2334{
2335 struct abis_om_hdr *oh;
2336 struct msgb *msg = nm_msgb_alloc();
2337
2338 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2339 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2340 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002341
2342 return abis_nm_sendmsg(bts, msg);
2343}
Harald Welte05188ee2009-01-18 11:39:08 +00002344
Harald Welte78fc0d42009-02-19 02:50:57 +00002345static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2346int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2347{
2348 struct abis_om_hdr *oh;
2349 struct msgb *msg = nm_msgb_alloc();
2350
2351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2352 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2353 0xff, 0xff, 0xff);
2354 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2355
2356 return abis_nm_sendmsg(bts, msg);
2357}
2358
Harald Welteb6c92ae2009-02-21 20:15:32 +00002359/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002360int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002361 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2362 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002363{
2364 struct abis_om_hdr *oh;
2365 struct abis_nm_channel *ch;
2366 struct msgb *msg = nm_msgb_alloc();
2367
2368 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002369 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002370 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2371
2372 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2373 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002374 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002375
2376 return abis_nm_sendmsg(bts, msg);
2377}
2378
2379int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2380{
2381 struct abis_om_hdr *oh;
2382 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002383
2384 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002385 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002386 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2387 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2388
2389 return abis_nm_sendmsg(trx->bts, msg);
2390}
2391
Harald Welte78fc0d42009-02-19 02:50:57 +00002392int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2393{
2394 struct abis_om_hdr *oh;
2395 struct msgb *msg = nm_msgb_alloc();
2396 u_int8_t attr = NM_ATT_BS11_TXPWR;
2397
2398 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2399 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2400 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2401 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2402
2403 return abis_nm_sendmsg(trx->bts, msg);
2404}
2405
Harald Welteaaf02d92009-04-29 13:25:57 +00002406int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2407{
2408 struct abis_om_hdr *oh;
2409 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002410 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002411
2412 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2413 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2414 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002415 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002416
2417 return abis_nm_sendmsg(bts, msg);
2418}
2419
Harald Welteef061952009-05-17 12:43:42 +00002420int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2421{
2422 struct abis_om_hdr *oh;
2423 struct msgb *msg = nm_msgb_alloc();
2424 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2425 NM_ATT_BS11_CCLK_TYPE };
2426
2427 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2428 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2429 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2430 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2431
2432 return abis_nm_sendmsg(bts, msg);
2433
2434}
Harald Welteaaf02d92009-04-29 13:25:57 +00002435
Harald Welte268bb402009-02-01 19:11:56 +00002436//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002437
Harald Welte1bc09062009-01-18 14:17:52 +00002438int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002439{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002440 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2441}
2442
Daniel Willmann4b054c82010-01-07 00:46:26 +01002443int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2444{
2445 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2446}
2447
Daniel Willmann493db4e2010-01-07 00:43:11 +01002448int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2449{
Harald Welte05188ee2009-01-18 11:39:08 +00002450 struct abis_om_hdr *oh;
2451 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002452 struct bs11_date_time bdt;
2453
2454 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002455
2456 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002457 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002458 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002459 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002460 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002461 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002462 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002463 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002464 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002465 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002466 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002467 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002468 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002469 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002470 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002471 }
Harald Welte05188ee2009-01-18 11:39:08 +00002472
2473 return abis_nm_sendmsg(bts, msg);
2474}
Harald Welte1bc09062009-01-18 14:17:52 +00002475
2476int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2477{
2478 struct abis_om_hdr *oh;
2479 struct msgb *msg;
2480
2481 if (strlen(password) != 10)
2482 return -EINVAL;
2483
2484 msg = nm_msgb_alloc();
2485 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002486 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002487 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2488 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2489
2490 return abis_nm_sendmsg(bts, msg);
2491}
2492
Harald Weltee69f5fb2009-04-28 16:31:38 +00002493/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2494int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2495{
2496 struct abis_om_hdr *oh;
2497 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002498 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002499
2500 msg = nm_msgb_alloc();
2501 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2502 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2503 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002504
2505 if (locked)
2506 tlv_value = BS11_LI_PLL_LOCKED;
2507 else
2508 tlv_value = BS11_LI_PLL_STANDALONE;
2509
2510 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002511
2512 return abis_nm_sendmsg(bts, msg);
2513}
2514
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002515/* Set the calibration value of the PLL (work value/set value)
2516 * It depends on the login which one is changed */
2517int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2518{
2519 struct abis_om_hdr *oh;
2520 struct msgb *msg;
2521 u_int8_t tlv_value[2];
2522
2523 msg = nm_msgb_alloc();
2524 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2525 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2526 BS11_OBJ_TRX1, 0x00, 0x00);
2527
2528 tlv_value[0] = value>>8;
2529 tlv_value[1] = value&0xff;
2530
2531 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2532
2533 return abis_nm_sendmsg(bts, msg);
2534}
2535
Harald Welte1bc09062009-01-18 14:17:52 +00002536int abis_nm_bs11_get_state(struct gsm_bts *bts)
2537{
2538 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2539}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002540
2541/* BS11 SWL */
2542
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002543void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002544
Harald Welte5e4d1b32009-02-01 13:36:56 +00002545struct abis_nm_bs11_sw {
2546 struct gsm_bts *bts;
2547 char swl_fname[PATH_MAX];
2548 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002549 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002550 struct llist_head file_list;
2551 gsm_cbfn *user_cb; /* specified by the user */
2552};
2553static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2554
2555struct file_list_entry {
2556 struct llist_head list;
2557 char fname[PATH_MAX];
2558};
2559
2560struct file_list_entry *fl_dequeue(struct llist_head *queue)
2561{
2562 struct llist_head *lh;
2563
2564 if (llist_empty(queue))
2565 return NULL;
2566
2567 lh = queue->next;
2568 llist_del(lh);
2569
2570 return llist_entry(lh, struct file_list_entry, list);
2571}
2572
2573static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2574{
2575 char linebuf[255];
2576 struct llist_head *lh, *lh2;
2577 FILE *swl;
2578 int rc = 0;
2579
2580 swl = fopen(bs11_sw->swl_fname, "r");
2581 if (!swl)
2582 return -ENODEV;
2583
2584 /* zero the stale file list, if any */
2585 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2586 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002587 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002588 }
2589
2590 while (fgets(linebuf, sizeof(linebuf), swl)) {
2591 char file_id[12+1];
2592 char file_version[80+1];
2593 struct file_list_entry *fle;
2594 static char dir[PATH_MAX];
2595
2596 if (strlen(linebuf) < 4)
2597 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002598
Harald Welte5e4d1b32009-02-01 13:36:56 +00002599 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2600 if (rc < 0) {
2601 perror("ERR parsing SWL file");
2602 rc = -EINVAL;
2603 goto out;
2604 }
2605 if (rc < 2)
2606 continue;
2607
Harald Welte470ec292009-06-26 20:25:23 +02002608 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002609 if (!fle) {
2610 rc = -ENOMEM;
2611 goto out;
2612 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002613
2614 /* construct new filename */
2615 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2616 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2617 strcat(fle->fname, "/");
2618 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002619
2620 llist_add_tail(&fle->list, &bs11_sw->file_list);
2621 }
2622
2623out:
2624 fclose(swl);
2625 return rc;
2626}
2627
2628/* bs11 swload specific callback, passed to abis_nm core swload */
2629static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2630 struct msgb *msg, void *data, void *param)
2631{
2632 struct abis_nm_bs11_sw *bs11_sw = data;
2633 struct file_list_entry *fle;
2634 int rc = 0;
2635
Harald Welte5e4d1b32009-02-01 13:36:56 +00002636 switch (event) {
2637 case NM_MT_LOAD_END_ACK:
2638 fle = fl_dequeue(&bs11_sw->file_list);
2639 if (fle) {
2640 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002641 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002642 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002643 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002644 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002645 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002646 } else {
2647 /* activate the SWL */
2648 rc = abis_nm_software_activate(bs11_sw->bts,
2649 bs11_sw->swl_fname,
2650 bs11_swload_cbfn,
2651 bs11_sw);
2652 }
2653 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002654 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002655 case NM_MT_LOAD_END_NACK:
2656 case NM_MT_LOAD_INIT_ACK:
2657 case NM_MT_LOAD_INIT_NACK:
2658 case NM_MT_ACTIVATE_SW_NACK:
2659 case NM_MT_ACTIVATE_SW_ACK:
2660 default:
2661 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002662 if (bs11_sw->user_cb)
2663 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002664 break;
2665 }
2666
2667 return rc;
2668}
2669
2670/* Siemens provides a SWL file that is a mere listing of all the other
2671 * files that are part of a software release. We need to upload first
2672 * the list file, and then each file that is listed in the list file */
2673int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002674 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002675{
2676 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2677 struct file_list_entry *fle;
2678 int rc = 0;
2679
2680 INIT_LLIST_HEAD(&bs11_sw->file_list);
2681 bs11_sw->bts = bts;
2682 bs11_sw->win_size = win_size;
2683 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002684 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002685
2686 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2687 rc = bs11_read_swl_file(bs11_sw);
2688 if (rc < 0)
2689 return rc;
2690
2691 /* dequeue next item in file list */
2692 fle = fl_dequeue(&bs11_sw->file_list);
2693 if (!fle)
2694 return -EINVAL;
2695
2696 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002697 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002698 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002699 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002700 return rc;
2701}
2702
Harald Welte5083b0b2009-02-02 19:20:52 +00002703#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002704static u_int8_t req_attr_btse[] = {
2705 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2706 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2707 NM_ATT_BS11_LMT_USER_NAME,
2708
2709 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2710
2711 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2712
2713 NM_ATT_BS11_SW_LOAD_STORED };
2714
2715static u_int8_t req_attr_btsm[] = {
2716 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2717 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2718 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2719 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002720#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002721
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002722static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002723 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2724 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002725 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002726
2727int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2728{
2729 struct abis_om_hdr *oh;
2730 struct msgb *msg = nm_msgb_alloc();
2731
2732 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2733 /* SiemensHW CCTRL object */
2734 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2735 0x03, 0x00, 0x00);
2736 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2737
2738 return abis_nm_sendmsg(bts, msg);
2739}
Harald Welte268bb402009-02-01 19:11:56 +00002740
2741int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2742{
2743 struct abis_om_hdr *oh;
2744 struct msgb *msg = nm_msgb_alloc();
2745 struct bs11_date_time aet;
2746
2747 get_bs11_date_time(&aet);
2748 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2749 /* SiemensHW CCTRL object */
2750 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2751 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002752 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002753
2754 return abis_nm_sendmsg(bts, msg);
2755}
Harald Welte5c1e4582009-02-15 11:57:29 +00002756
Harald Weltef751a102010-12-14 12:52:16 +01002757int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2758{
2759 struct abis_om_hdr *oh;
2760 struct msgb *msg = nm_msgb_alloc();
2761 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2762
2763 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2764 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2765 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2766 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2767
2768 return abis_nm_sendmsg(bts, msg);
2769}
2770
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002771int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2772{
2773 struct abis_om_hdr *oh;
2774 struct msgb *msg = nm_msgb_alloc();
2775 struct bs11_date_time aet;
2776
2777 get_bs11_date_time(&aet);
2778 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2779 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2780 bport, 0xff, 0x02);
2781 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2782
2783 return abis_nm_sendmsg(bts, msg);
2784}
2785
Harald Welte5c1e4582009-02-15 11:57:29 +00002786/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002787static const char ipaccess_magic[] = "com.ipaccess";
2788
Harald Welte677c21f2009-02-17 13:22:23 +00002789
2790static int abis_nm_rx_ipacc(struct msgb *msg)
2791{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002792 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002793 struct abis_om_hdr *oh = msgb_l2(msg);
2794 struct abis_om_fom_hdr *foh;
2795 u_int8_t idstrlen = oh->data[0];
2796 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002797 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002798
2799 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002800 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002801 return -EINVAL;
2802 }
2803
Harald Welte193fefc2009-04-30 15:16:27 +00002804 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002805 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002806
Harald Weltea8bd6d42009-10-20 09:56:18 +02002807 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002808
Harald Welte746d6092009-10-19 22:11:11 +02002809 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002810
Harald Welte677c21f2009-02-17 13:22:23 +00002811 switch (foh->msg_type) {
2812 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002813 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002814 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2815 memcpy(&addr,
2816 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2817
2818 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2819 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002820 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002821 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002822 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002823 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002824 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2825 DEBUGPC(DNM, "STREAM=0x%02x ",
2826 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002827 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002828 break;
2829 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002830 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002831 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002832 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002833 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002834 else
2835 DEBUGPC(DNM, "\n");
2836 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002837 case NM_MT_IPACC_SET_NVATTR_ACK:
2838 DEBUGPC(DNM, "SET NVATTR ACK\n");
2839 /* FIXME: decode and show the actual attributes */
2840 break;
2841 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002842 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002843 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002844 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002845 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2846 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002847 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002848 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002849 case NM_MT_IPACC_GET_NVATTR_ACK:
2850 DEBUGPC(DNM, "GET NVATTR ACK\n");
2851 /* FIXME: decode and show the actual attributes */
2852 break;
2853 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002854 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002855 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002856 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002857 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2858 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002859 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002860 break;
Harald Welte15c44172009-10-08 20:15:24 +02002861 case NM_MT_IPACC_SET_ATTR_ACK:
2862 DEBUGPC(DNM, "SET ATTR ACK\n");
2863 break;
2864 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002865 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002866 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002867 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002868 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2869 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002870 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002871 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002872 default:
2873 DEBUGPC(DNM, "unknown\n");
2874 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002875 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002876
2877 /* signal handling */
2878 switch (foh->msg_type) {
2879 case NM_MT_IPACC_RSL_CONNECT_NACK:
2880 case NM_MT_IPACC_SET_NVATTR_NACK:
2881 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002882 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002883 signal.msg_type = foh->msg_type;
2884 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002885 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002886 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002887 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002888 signal.msg_type = foh->msg_type;
2889 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002890 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002891 default:
2892 break;
2893 }
2894
Harald Welte677c21f2009-02-17 13:22:23 +00002895 return 0;
2896}
2897
Harald Welte193fefc2009-04-30 15:16:27 +00002898/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002899int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2900 u_int8_t obj_class, u_int8_t bts_nr,
2901 u_int8_t trx_nr, u_int8_t ts_nr,
2902 u_int8_t *attr, int attr_len)
2903{
2904 struct msgb *msg = nm_msgb_alloc();
2905 struct abis_om_hdr *oh;
2906 struct abis_om_fom_hdr *foh;
2907 u_int8_t *data;
2908
2909 /* construct the 12.21 OM header, observe the erroneous length */
2910 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2911 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2912 oh->mdisc = ABIS_OM_MDISC_MANUF;
2913
2914 /* add the ip.access magic */
2915 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2916 *data++ = sizeof(ipaccess_magic);
2917 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2918
2919 /* fill the 12.21 FOM header */
2920 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2921 foh->msg_type = msg_type;
2922 foh->obj_class = obj_class;
2923 foh->obj_inst.bts_nr = bts_nr;
2924 foh->obj_inst.trx_nr = trx_nr;
2925 foh->obj_inst.ts_nr = ts_nr;
2926
2927 if (attr && attr_len) {
2928 data = msgb_put(msg, attr_len);
2929 memcpy(data, attr, attr_len);
2930 }
2931
2932 return abis_nm_sendmsg(bts, msg);
2933}
Harald Welte677c21f2009-02-17 13:22:23 +00002934
Harald Welte193fefc2009-04-30 15:16:27 +00002935/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002936int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002937 int attr_len)
2938{
Harald Welte2ef156d2010-01-07 20:39:42 +01002939 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2940 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002941 attr_len);
2942}
2943
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002944int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002945 u_int32_t ip, u_int16_t port, u_int8_t stream)
2946{
2947 struct in_addr ia;
2948 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2949 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2950 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2951
2952 int attr_len = sizeof(attr);
2953
2954 ia.s_addr = htonl(ip);
2955 attr[1] = stream;
2956 attr[3] = port >> 8;
2957 attr[4] = port & 0xff;
2958 *(u_int32_t *)(attr+6) = ia.s_addr;
2959
2960 /* if ip == 0, we use the default IP */
2961 if (ip == 0)
2962 attr_len -= 5;
2963
2964 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002965 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002966
2967 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2968 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2969 trx->nr, 0xff, attr, attr_len);
2970}
2971
Harald Welte193fefc2009-04-30 15:16:27 +00002972/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002973int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002974{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002975 struct abis_om_hdr *oh;
2976 struct msgb *msg = nm_msgb_alloc();
2977
2978 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2979 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2980 trx->bts->nr, trx->nr, 0xff);
2981
2982 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002983}
Harald Weltedaef5212009-10-24 10:20:41 +02002984
2985int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2986 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2987 u_int8_t *attr, u_int8_t attr_len)
2988{
2989 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2990 obj_class, bts_nr, trx_nr, ts_nr,
2991 attr, attr_len);
2992}
Harald Welte0f255852009-11-12 14:48:42 +01002993
Harald Welte97a282b2010-03-14 15:37:43 +08002994void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2995{
2996 /* we simply reuse the GSM48 function and overwrite the RAC
2997 * with the Cell ID */
2998 gsm48_ra_id_by_bts(buf, bts);
2999 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
3000}
3001
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003002void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
3003{
3004 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
3005
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01003006 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003007 if (!trx->bts || !trx->bts->oml_link)
3008 return;
3009
3010 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3011 trx->bts->bts_nr, trx->nr, 0xff,
3012 new_state);
3013}
3014
Harald Welte92b1fe42010-03-25 11:45:30 +08003015static const struct value_string ipacc_testres_names[] = {
3016 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3017 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3018 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3019 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3020 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3021 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01003022};
3023
3024const char *ipacc_testres_name(u_int8_t res)
3025{
Harald Welte92b1fe42010-03-25 11:45:30 +08003026 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003027}
3028
Harald Welteb40a38f2009-11-13 11:56:05 +01003029void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3030{
3031 cid->mcc = (buf[0] & 0xf) * 100;
3032 cid->mcc += (buf[0] >> 4) * 10;
3033 cid->mcc += (buf[1] & 0xf) * 1;
3034
3035 if (buf[1] >> 4 == 0xf) {
3036 cid->mnc = (buf[2] & 0xf) * 10;
3037 cid->mnc += (buf[2] >> 4) * 1;
3038 } else {
3039 cid->mnc = (buf[2] & 0xf) * 100;
3040 cid->mnc += (buf[2] >> 4) * 10;
3041 cid->mnc += (buf[1] >> 4) * 1;
3042 }
3043
Harald Welteaff237d2009-11-13 14:41:52 +01003044 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3045 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003046}
3047
Harald Welte0f255852009-11-12 14:48:42 +01003048/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3049int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3050{
3051 u_int8_t *cur = buf;
3052 u_int16_t len;
3053
Harald Welteaf109b92010-07-22 18:14:36 +02003054 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003055
3056 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3057 return -EINVAL;
3058 cur++;
3059
3060 len = ntohs(*(u_int16_t *)cur);
3061 cur += 2;
3062
3063 binf->info_type = ntohs(*(u_int16_t *)cur);
3064 cur += 2;
3065
3066 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3067 binf->freq_qual = *cur >> 2;
3068
Harald Welteaf109b92010-07-22 18:14:36 +02003069 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003070 binf->arfcn |= *cur++;
3071
3072 if (binf->info_type & IPAC_BINF_RXLEV)
3073 binf->rx_lev = *cur & 0x3f;
3074 cur++;
3075
3076 if (binf->info_type & IPAC_BINF_RXQUAL)
3077 binf->rx_qual = *cur & 0x7;
3078 cur++;
3079
3080 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3081 binf->freq_err = ntohs(*(u_int16_t *)cur);
3082 cur += 2;
3083
3084 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3085 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3086 cur += 2;
3087
3088 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3089 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3090 cur += 4;
3091
Harald Weltea780a3d2010-07-30 22:34:42 +02003092#if 0
3093 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003094 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003095#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003096 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003097 cur++;
3098
Harald Welteb40a38f2009-11-13 11:56:05 +01003099 ipac_parse_cgi(&binf->cgi, cur);
3100 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003101
3102 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3103 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3104 cur += sizeof(binf->ba_list_si2);
3105 }
3106
3107 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3108 memcpy(binf->ba_list_si2bis, cur,
3109 sizeof(binf->ba_list_si2bis));
3110 cur += sizeof(binf->ba_list_si2bis);
3111 }
3112
3113 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3114 memcpy(binf->ba_list_si2ter, cur,
3115 sizeof(binf->ba_list_si2ter));
3116 cur += sizeof(binf->ba_list_si2ter);
3117 }
3118
3119 return 0;
3120}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003121
3122void abis_nm_clear_queue(struct gsm_bts *bts)
3123{
3124 struct msgb *msg;
3125
3126 while (!llist_empty(&bts->abis_queue)) {
3127 msg = msgb_dequeue(&bts->abis_queue);
3128 msgb_free(msg);
3129 }
3130
3131 bts->abis_nm_pend = 0;
3132}