blob: 1a2e0955f50e5a907ebfeb0c1cbab9d117ab475d [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;
783
784 DEBUGPC(DNM, "Failure Event Report ");
785
Harald Welte39315c42010-01-10 18:01:52 +0100786 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000787
788 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
789 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
790 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
791 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
792
793 DEBUGPC(DNM, "\n");
794
795 return 0;
796}
797
Harald Welte97ed1e72009-02-06 13:38:02 +0000798static int abis_nm_rcvmsg_report(struct msgb *mb)
799{
800 struct abis_om_fom_hdr *foh = msgb_l3(mb);
801 u_int8_t mt = foh->msg_type;
802
Harald Weltea8bd6d42009-10-20 09:56:18 +0200803 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000804
Harald Welte97ed1e72009-02-06 13:38:02 +0000805 //nmh->cfg->report_cb(mb, foh);
806
807 switch (mt) {
808 case NM_MT_STATECHG_EVENT_REP:
809 return abis_nm_rx_statechg_rep(mb);
810 break;
Harald Welte34a99682009-02-13 02:41:40 +0000811 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000812 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000813 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000814 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000815 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000816 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000817 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000818 break;
Harald Weltec7310382009-08-08 00:02:36 +0200819 case NM_MT_TEST_REP:
820 DEBUGPC(DNM, "Test Report\n");
821 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
822 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000823 default:
Harald Welte23897662009-05-01 14:52:51 +0000824 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000825 break;
826
Harald Welte97ed1e72009-02-06 13:38:02 +0000827 };
828
Harald Welte97ed1e72009-02-06 13:38:02 +0000829 return 0;
830}
831
Harald Welte34a99682009-02-13 02:41:40 +0000832/* Activate the specified software into the BTS */
833static 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 +0200834 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000835{
836 struct abis_om_hdr *oh;
837 struct msgb *msg = nm_msgb_alloc();
838 u_int8_t len = swdesc_len;
839 u_int8_t *trailer;
840
841 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
842 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
843
844 trailer = msgb_put(msg, swdesc_len);
845 memcpy(trailer, sw_desc, swdesc_len);
846
847 return abis_nm_sendmsg(bts, msg);
848}
849
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100850static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
851{
852 static const struct tlv_definition sw_descr_def = {
853 .def = {
854 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
855 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
856 },
857 };
858
859 u_int8_t tag;
860 u_int16_t tag_len;
861 const u_int8_t *val;
862 int ofs = 0, len;
863
864 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
865 * nested nature and the fact you have to assume it contains only two sub
866 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
867
868 if (sw_descr[0] != NM_ATT_SW_DESCR) {
869 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
870 return -1;
871 }
872 ofs += 1;
873
874 len = tlv_parse_one(&tag, &tag_len, &val,
875 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
876 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
877 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
878 return -2;
879 }
880 ofs += len;
881
882 len = tlv_parse_one(&tag, &tag_len, &val,
883 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
884 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
885 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
886 return -3;
887 }
888 ofs += len;
889
890 return ofs;
891}
892
Harald Welte34a99682009-02-13 02:41:40 +0000893static int abis_nm_rx_sw_act_req(struct msgb *mb)
894{
895 struct abis_om_hdr *oh = msgb_l2(mb);
896 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200897 struct tlv_parsed tp;
898 const u_int8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100899 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000900
Harald Weltea8bd6d42009-10-20 09:56:18 +0200901 debugp_foh(foh);
902
903 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000904
Harald Welte97a282b2010-03-14 15:37:43 +0800905 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000906
907 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000908 foh->obj_inst.bts_nr,
909 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800910 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000911 foh->data, oh->length-sizeof(*foh));
912
Harald Welte39315c42010-01-10 18:01:52 +0100913 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200914 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
915 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
916 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
917 DEBUGP(DNM, "SW config not found! Can't continue.\n");
918 return -EINVAL;
919 } else {
920 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
921 }
922
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100923 /* Use the first SW_DESCR present in SW config */
924 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
925 if (sw_descr_len < 0)
926 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200927
Harald Welte34a99682009-02-13 02:41:40 +0000928 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
929 foh->obj_inst.bts_nr,
930 foh->obj_inst.trx_nr,
931 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100932 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000933}
934
Harald Weltee0590df2009-02-15 03:34:15 +0000935/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
936static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
937{
938 struct abis_om_hdr *oh = msgb_l2(mb);
939 struct abis_om_fom_hdr *foh = msgb_l3(mb);
940 struct tlv_parsed tp;
941 u_int8_t adm_state;
942
Harald Welte39315c42010-01-10 18:01:52 +0100943 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000944 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
945 return -EINVAL;
946
947 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
948
949 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
950}
951
Harald Welteee670472009-02-22 21:58:49 +0000952static int abis_nm_rx_lmt_event(struct msgb *mb)
953{
954 struct abis_om_hdr *oh = msgb_l2(mb);
955 struct abis_om_fom_hdr *foh = msgb_l3(mb);
956 struct tlv_parsed tp;
957
958 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100959 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000960 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
961 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
962 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
963 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
964 }
965 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
966 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
967 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
968 DEBUGPC(DNM, "Level=%u ", level);
969 }
970 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
971 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
972 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
973 DEBUGPC(DNM, "Username=%s ", name);
974 }
975 DEBUGPC(DNM, "\n");
976 /* FIXME: parse LMT LOGON TIME */
977 return 0;
978}
979
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100980static void abis_nm_queue_send_next(struct gsm_bts *bts)
981{
982 int wait = 0;
983 struct msgb *msg;
984 /* the queue is empty */
985 while (!llist_empty(&bts->abis_queue)) {
986 msg = msgb_dequeue(&bts->abis_queue);
987 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100988 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100989
990 if (wait)
991 break;
992 }
993
994 bts->abis_nm_pend = wait;
995}
996
Harald Welte52b1f982008-12-23 20:25:15 +0000997/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000998static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000999{
Harald Welte6c96ba52009-05-01 13:03:40 +00001000 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001001 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1002 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001003 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001004
1005 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001006 if (is_report(mt))
1007 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001008
Harald Welte4724f992009-01-18 18:01:49 +00001009 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1010 return abis_nm_rcvmsg_sw(mb);
1011
Harald Welte78fc0d42009-02-19 02:50:57 +00001012 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001013 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +00001014 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001015
Harald Weltea8bd6d42009-10-20 09:56:18 +02001016 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001017
Harald Welte92b1fe42010-03-25 11:45:30 +08001018 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +00001019
Harald Welte39315c42010-01-10 18:01:52 +01001020 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +00001021 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001022 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00001023 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1024 else
1025 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001026
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001027 nack_data.msg = mb;
1028 nack_data.mt = mt;
1029 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001030 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001031 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001032 }
Harald Weltead384642008-12-26 10:20:07 +00001033#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001034 /* check if last message is to be acked */
1035 if (is_ack_nack(nmh->last_msgtype)) {
1036 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001037 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001038 /* we got our ACK, continue sending the next msg */
1039 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1040 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001041 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001042 /* FIXME: somehow signal this to the caller */
1043 } else {
1044 /* really strange things happen */
1045 return -EINVAL;
1046 }
1047 }
Harald Weltead384642008-12-26 10:20:07 +00001048#endif
1049
Harald Welte97ed1e72009-02-06 13:38:02 +00001050 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001051 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001052 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +00001053 break;
Harald Welte34a99682009-02-13 02:41:40 +00001054 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001055 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +00001056 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001057 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001058 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001059 break;
Harald Welte1989c082009-08-06 17:58:31 +02001060 case NM_MT_CONN_MDROP_LINK_ACK:
1061 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1062 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001063 case NM_MT_IPACC_RESTART_ACK:
1064 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1065 break;
1066 case NM_MT_IPACC_RESTART_NACK:
1067 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1068 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001069 }
1070
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001071 abis_nm_queue_send_next(mb->trx->bts);
1072 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001073}
1074
Harald Welte677c21f2009-02-17 13:22:23 +00001075static int abis_nm_rx_ipacc(struct msgb *mb);
1076
1077static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1078{
1079 int rc;
1080 int bts_type = mb->trx->bts->type;
1081
1082 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001083 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001084 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001085 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +00001086 break;
1087 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001088 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1089 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001090 rc = 0;
1091 break;
1092 }
1093
1094 return rc;
1095}
1096
Harald Welte52b1f982008-12-23 20:25:15 +00001097/* High-Level API */
1098/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001099int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001100{
Harald Welte52b1f982008-12-23 20:25:15 +00001101 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001102 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001103
1104 /* Various consistency checks */
1105 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001106 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001107 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001108 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1109 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001110 }
1111 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001112 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001113 oh->sequence);
1114 return -EINVAL;
1115 }
Harald Welte702d8702008-12-26 20:25:35 +00001116#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001117 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1118 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001119 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001120 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001121 oh->length + sizeof(*oh), l2_len);
1122 return -EINVAL;
1123 }
Harald Welte702d8702008-12-26 20:25:35 +00001124 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001125 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte702d8702008-12-26 20:25:35 +00001126#endif
Harald Weltead384642008-12-26 10:20:07 +00001127 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001128
1129 switch (oh->mdisc) {
1130 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001131 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001132 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001133 case ABIS_OM_MDISC_MANUF:
1134 rc = abis_nm_rcvmsg_manuf(msg);
1135 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001136 case ABIS_OM_MDISC_MMI:
1137 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001138 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001139 oh->mdisc);
1140 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001141 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001142 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001143 oh->mdisc);
1144 return -EINVAL;
1145 }
1146
Harald Weltead384642008-12-26 10:20:07 +00001147 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001148 return rc;
1149}
1150
1151#if 0
1152/* initialized all resources */
1153struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1154{
1155 struct abis_nm_h *nmh;
1156
1157 nmh = malloc(sizeof(*nmh));
1158 if (!nmh)
1159 return NULL;
1160
1161 nmh->cfg = cfg;
1162
1163 return nmh;
1164}
1165
1166/* free all resources */
1167void abis_nm_fini(struct abis_nm_h *nmh)
1168{
1169 free(nmh);
1170}
1171#endif
1172
1173/* Here we are trying to define a high-level API that can be used by
1174 * the actual BSC implementation. However, the architecture is currently
1175 * still under design. Ideally the calls to this API would be synchronous,
1176 * while the underlying stack behind the APi runs in a traditional select
1177 * based state machine.
1178 */
1179
Harald Welte4724f992009-01-18 18:01:49 +00001180/* 6.2 Software Load: */
1181enum sw_state {
1182 SW_STATE_NONE,
1183 SW_STATE_WAIT_INITACK,
1184 SW_STATE_WAIT_SEGACK,
1185 SW_STATE_WAIT_ENDACK,
1186 SW_STATE_WAIT_ACTACK,
1187 SW_STATE_ERROR,
1188};
Harald Welte52b1f982008-12-23 20:25:15 +00001189
Harald Welte52b1f982008-12-23 20:25:15 +00001190struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001191 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001192 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001193 gsm_cbfn *cbfn;
1194 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001195 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001196
Harald Welte52b1f982008-12-23 20:25:15 +00001197 /* this will become part of the SW LOAD INITIATE */
1198 u_int8_t obj_class;
1199 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001200
1201 u_int8_t file_id[255];
1202 u_int8_t file_id_len;
1203
1204 u_int8_t file_version[255];
1205 u_int8_t file_version_len;
1206
1207 u_int8_t window_size;
1208 u_int8_t seg_in_window;
1209
1210 int fd;
1211 FILE *stream;
1212 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001213 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001214};
1215
Harald Welte4724f992009-01-18 18:01:49 +00001216static struct abis_nm_sw g_sw;
1217
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001218static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1219{
1220 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1221 msgb_v_put(msg, NM_ATT_SW_DESCR);
1222 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1223 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1224 sw->file_version);
1225 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1226 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1227 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1228 sw->file_version);
1229 } else {
1230 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1231 }
1232}
1233
Harald Welte4724f992009-01-18 18:01:49 +00001234/* 6.2.1 / 8.3.1: Load Data Initiate */
1235static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001236{
Harald Welte4724f992009-01-18 18:01:49 +00001237 struct abis_om_hdr *oh;
1238 struct msgb *msg = nm_msgb_alloc();
1239 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1240
1241 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1242 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1243 sw->obj_instance[0], sw->obj_instance[1],
1244 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001245
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001246 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001247 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1248
1249 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001250}
1251
Harald Welte1602ade2009-01-29 21:12:39 +00001252static int is_last_line(FILE *stream)
1253{
1254 char next_seg_buf[256];
1255 long pos;
1256
1257 /* check if we're sending the last line */
1258 pos = ftell(stream);
1259 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1260 fseek(stream, pos, SEEK_SET);
1261 return 1;
1262 }
1263
1264 fseek(stream, pos, SEEK_SET);
1265 return 0;
1266}
1267
Harald Welte4724f992009-01-18 18:01:49 +00001268/* 6.2.2 / 8.3.2 Load Data Segment */
1269static int sw_load_segment(struct abis_nm_sw *sw)
1270{
1271 struct abis_om_hdr *oh;
1272 struct msgb *msg = nm_msgb_alloc();
1273 char seg_buf[256];
1274 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001275 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001276 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001277
1278 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001279
1280 switch (sw->bts->type) {
1281 case GSM_BTS_TYPE_BS11:
1282 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1283 perror("fgets reading segment");
1284 return -EINVAL;
1285 }
1286 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001287
1288 /* check if we're sending the last line */
1289 sw->last_seg = is_last_line(sw->stream);
1290 if (sw->last_seg)
1291 seg_buf[1] = 0;
1292 else
1293 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001294
1295 len = strlen(line_buf) + 2;
1296 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1297 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1298 /* BS11 wants CR + LF in excess of the TLV length !?! */
1299 tlv[1] -= 2;
1300
1301 /* we only now know the exact length for the OM hdr */
1302 len = strlen(line_buf)+2;
1303 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001304 case GSM_BTS_TYPE_NANOBTS: {
1305 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1306 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1307 if (len < 0) {
1308 perror("read failed");
1309 return -EINVAL;
1310 }
1311
1312 if (len != IPACC_SEGMENT_SIZE)
1313 sw->last_seg = 1;
1314
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001315 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001316 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1317 len += 3;
1318 break;
1319 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001320 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001321 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001322 /* FIXME: Other BTS types */
1323 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001324 }
Harald Welte4724f992009-01-18 18:01:49 +00001325
Harald Welte4724f992009-01-18 18:01:49 +00001326 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1327 sw->obj_instance[0], sw->obj_instance[1],
1328 sw->obj_instance[2]);
1329
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001330 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001331}
1332
1333/* 6.2.4 / 8.3.4 Load Data End */
1334static int sw_load_end(struct abis_nm_sw *sw)
1335{
1336 struct abis_om_hdr *oh;
1337 struct msgb *msg = nm_msgb_alloc();
1338 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1339
1340 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1341 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1342 sw->obj_instance[0], sw->obj_instance[1],
1343 sw->obj_instance[2]);
1344
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001345 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001346 return abis_nm_sendmsg(sw->bts, msg);
1347}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001348
Harald Welte52b1f982008-12-23 20:25:15 +00001349/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001350static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001351{
Harald Welte4724f992009-01-18 18:01:49 +00001352 struct abis_om_hdr *oh;
1353 struct msgb *msg = nm_msgb_alloc();
1354 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001355
Harald Welte4724f992009-01-18 18:01:49 +00001356 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1357 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1358 sw->obj_instance[0], sw->obj_instance[1],
1359 sw->obj_instance[2]);
1360
1361 /* FIXME: this is BS11 specific format */
1362 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1363 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1364 sw->file_version);
1365
1366 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001367}
Harald Welte4724f992009-01-18 18:01:49 +00001368
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001369struct sdp_firmware {
1370 char magic[4];
1371 char more_magic[4];
1372 unsigned int header_length;
1373 unsigned int file_length;
1374} __attribute__ ((packed));
1375
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001376static int parse_sdp_header(struct abis_nm_sw *sw)
1377{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001378 struct sdp_firmware firmware_header;
1379 int rc;
1380 struct stat stat;
1381
1382 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1383 if (rc != sizeof(firmware_header)) {
1384 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1385 return -1;
1386 }
1387
1388 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1389 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1390 return -1;
1391 }
1392
1393 if (firmware_header.more_magic[0] != 0x10 ||
1394 firmware_header.more_magic[1] != 0x02 ||
1395 firmware_header.more_magic[2] != 0x00 ||
1396 firmware_header.more_magic[3] != 0x00) {
1397 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1398 return -1;
1399 }
1400
1401
1402 if (fstat(sw->fd, &stat) == -1) {
1403 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1404 return -1;
1405 }
1406
1407 if (ntohl(firmware_header.file_length) != stat.st_size) {
1408 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1409 return -1;
1410 }
1411
1412 /* go back to the start as we checked the whole filesize.. */
1413 lseek(sw->fd, 0l, SEEK_SET);
1414 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1415 "There might be checksums in the file that are not\n"
1416 "verified and incomplete firmware might be flashed.\n"
1417 "There is absolutely no WARRANTY that flashing will\n"
1418 "work.\n");
1419 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001420}
1421
Harald Welte4724f992009-01-18 18:01:49 +00001422static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1423{
1424 char file_id[12+1];
1425 char file_version[80+1];
1426 int rc;
1427
1428 sw->fd = open(fname, O_RDONLY);
1429 if (sw->fd < 0)
1430 return sw->fd;
1431
1432 switch (sw->bts->type) {
1433 case GSM_BTS_TYPE_BS11:
1434 sw->stream = fdopen(sw->fd, "r");
1435 if (!sw->stream) {
1436 perror("fdopen");
1437 return -1;
1438 }
1439 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001440 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001441 file_id, file_version);
1442 if (rc != 2) {
1443 perror("parsing header line of software file");
1444 return -1;
1445 }
1446 strcpy((char *)sw->file_id, file_id);
1447 sw->file_id_len = strlen(file_id);
1448 strcpy((char *)sw->file_version, file_version);
1449 sw->file_version_len = strlen(file_version);
1450 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001451 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001452 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001453 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001454 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001455 rc = parse_sdp_header(sw);
1456 if (rc < 0) {
1457 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1458 return -1;
1459 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001460
1461 strcpy((char *)sw->file_id, "id");
1462 sw->file_id_len = 3;
1463 strcpy((char *)sw->file_version, "version");
1464 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001465 break;
Harald Welte4724f992009-01-18 18:01:49 +00001466 default:
1467 /* We don't know how to treat them yet */
1468 close(sw->fd);
1469 return -EINVAL;
1470 }
1471
1472 return 0;
1473}
1474
1475static void sw_close_file(struct abis_nm_sw *sw)
1476{
1477 switch (sw->bts->type) {
1478 case GSM_BTS_TYPE_BS11:
1479 fclose(sw->stream);
1480 break;
1481 default:
1482 close(sw->fd);
1483 break;
1484 }
1485}
1486
1487/* Fill the window */
1488static int sw_fill_window(struct abis_nm_sw *sw)
1489{
1490 int rc;
1491
1492 while (sw->seg_in_window < sw->window_size) {
1493 rc = sw_load_segment(sw);
1494 if (rc < 0)
1495 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001496 if (sw->last_seg)
1497 break;
Harald Welte4724f992009-01-18 18:01:49 +00001498 }
1499 return 0;
1500}
1501
1502/* callback function from abis_nm_rcvmsg() handler */
1503static int abis_nm_rcvmsg_sw(struct msgb *mb)
1504{
1505 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1506 int rc = -1;
1507 struct abis_nm_sw *sw = &g_sw;
1508 enum sw_state old_state = sw->state;
1509
Harald Welte3ffd1372009-02-01 22:15:49 +00001510 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001511
1512 switch (sw->state) {
1513 case SW_STATE_WAIT_INITACK:
1514 switch (foh->msg_type) {
1515 case NM_MT_LOAD_INIT_ACK:
1516 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001517 if (sw->cbfn)
1518 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1519 NM_MT_LOAD_INIT_ACK, mb,
1520 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001521 rc = sw_fill_window(sw);
1522 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001523 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001524 break;
1525 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001526 if (sw->forced) {
1527 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1528 "Init NACK\n");
1529 if (sw->cbfn)
1530 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1531 NM_MT_LOAD_INIT_ACK, mb,
1532 sw->cb_data, NULL);
1533 rc = sw_fill_window(sw);
1534 sw->state = SW_STATE_WAIT_SEGACK;
1535 } else {
1536 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001537 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001538 if (sw->cbfn)
1539 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1540 NM_MT_LOAD_INIT_NACK, mb,
1541 sw->cb_data, NULL);
1542 sw->state = SW_STATE_ERROR;
1543 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001544 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001545 break;
1546 }
1547 break;
1548 case SW_STATE_WAIT_SEGACK:
1549 switch (foh->msg_type) {
1550 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001551 if (sw->cbfn)
1552 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1553 NM_MT_LOAD_SEG_ACK, mb,
1554 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001555 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001556 if (!sw->last_seg) {
1557 /* fill window with more segments */
1558 rc = sw_fill_window(sw);
1559 sw->state = SW_STATE_WAIT_SEGACK;
1560 } else {
1561 /* end the transfer */
1562 sw->state = SW_STATE_WAIT_ENDACK;
1563 rc = sw_load_end(sw);
1564 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001565 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001566 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001567 case NM_MT_LOAD_ABORT:
1568 if (sw->cbfn)
1569 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1570 NM_MT_LOAD_ABORT, mb,
1571 sw->cb_data, NULL);
1572 break;
Harald Welte4724f992009-01-18 18:01:49 +00001573 }
1574 break;
1575 case SW_STATE_WAIT_ENDACK:
1576 switch (foh->msg_type) {
1577 case NM_MT_LOAD_END_ACK:
1578 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001579 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1580 sw->bts->nr);
1581 sw->state = SW_STATE_NONE;
1582 if (sw->cbfn)
1583 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1584 NM_MT_LOAD_END_ACK, mb,
1585 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001586 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001587 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001588 break;
1589 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001590 if (sw->forced) {
1591 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1592 "End NACK\n");
1593 sw->state = SW_STATE_NONE;
1594 if (sw->cbfn)
1595 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1596 NM_MT_LOAD_END_ACK, mb,
1597 sw->cb_data, NULL);
1598 } else {
1599 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001600 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001601 sw->state = SW_STATE_ERROR;
1602 if (sw->cbfn)
1603 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1604 NM_MT_LOAD_END_NACK, mb,
1605 sw->cb_data, NULL);
1606 }
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 }
1610 case SW_STATE_WAIT_ACTACK:
1611 switch (foh->msg_type) {
1612 case NM_MT_ACTIVATE_SW_ACK:
1613 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001614 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001615 sw->state = SW_STATE_NONE;
1616 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001617 if (sw->cbfn)
1618 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1619 NM_MT_ACTIVATE_SW_ACK, mb,
1620 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001621 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001622 break;
1623 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001624 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001625 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001626 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001627 if (sw->cbfn)
1628 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1629 NM_MT_ACTIVATE_SW_NACK, mb,
1630 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001631 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001632 break;
1633 }
1634 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001635 switch (foh->msg_type) {
1636 case NM_MT_ACTIVATE_SW_ACK:
1637 rc = 0;
1638 break;
1639 }
1640 break;
Harald Welte4724f992009-01-18 18:01:49 +00001641 case SW_STATE_ERROR:
1642 break;
1643 }
1644
1645 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001646 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001647 foh->msg_type, old_state, sw->state);
1648
1649 return rc;
1650}
1651
1652/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001653int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001654 u_int8_t win_size, int forced,
1655 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001656{
1657 struct abis_nm_sw *sw = &g_sw;
1658 int rc;
1659
Harald Welte5e4d1b32009-02-01 13:36:56 +00001660 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1661 bts->nr, fname);
1662
Harald Welte4724f992009-01-18 18:01:49 +00001663 if (sw->state != SW_STATE_NONE)
1664 return -EBUSY;
1665
1666 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001667 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001668
1669 switch (bts->type) {
1670 case GSM_BTS_TYPE_BS11:
1671 sw->obj_class = NM_OC_SITE_MANAGER;
1672 sw->obj_instance[0] = 0xff;
1673 sw->obj_instance[1] = 0xff;
1674 sw->obj_instance[2] = 0xff;
1675 break;
1676 case GSM_BTS_TYPE_NANOBTS:
1677 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001678 sw->obj_instance[0] = sw->bts->nr;
1679 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001680 sw->obj_instance[2] = 0xff;
1681 break;
1682 case GSM_BTS_TYPE_UNKNOWN:
1683 default:
1684 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1685 return -1;
1686 break;
1687 }
Harald Welte4724f992009-01-18 18:01:49 +00001688 sw->window_size = win_size;
1689 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001690 sw->cbfn = cbfn;
1691 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001692 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001693
1694 rc = sw_open_file(sw, fname);
1695 if (rc < 0) {
1696 sw->state = SW_STATE_NONE;
1697 return rc;
1698 }
1699
1700 return sw_load_init(sw);
1701}
Harald Welte52b1f982008-12-23 20:25:15 +00001702
Harald Welte1602ade2009-01-29 21:12:39 +00001703int abis_nm_software_load_status(struct gsm_bts *bts)
1704{
1705 struct abis_nm_sw *sw = &g_sw;
1706 struct stat st;
1707 int rc, percent;
1708
1709 rc = fstat(sw->fd, &st);
1710 if (rc < 0) {
1711 perror("ERROR during stat");
1712 return rc;
1713 }
1714
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001715 if (sw->stream)
1716 percent = (ftell(sw->stream) * 100) / st.st_size;
1717 else
1718 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001719 return percent;
1720}
1721
Harald Welte5e4d1b32009-02-01 13:36:56 +00001722/* Activate the specified software into the BTS */
1723int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1724 gsm_cbfn *cbfn, void *cb_data)
1725{
1726 struct abis_nm_sw *sw = &g_sw;
1727 int rc;
1728
1729 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1730 bts->nr, fname);
1731
1732 if (sw->state != SW_STATE_NONE)
1733 return -EBUSY;
1734
1735 sw->bts = bts;
1736 sw->obj_class = NM_OC_SITE_MANAGER;
1737 sw->obj_instance[0] = 0xff;
1738 sw->obj_instance[1] = 0xff;
1739 sw->obj_instance[2] = 0xff;
1740 sw->state = SW_STATE_WAIT_ACTACK;
1741 sw->cbfn = cbfn;
1742 sw->cb_data = cb_data;
1743
1744 /* Open the file in order to fill some sw struct members */
1745 rc = sw_open_file(sw, fname);
1746 if (rc < 0) {
1747 sw->state = SW_STATE_NONE;
1748 return rc;
1749 }
1750 sw_close_file(sw);
1751
1752 return sw_activate(sw);
1753}
1754
Harald Welte8470bf22008-12-25 23:28:35 +00001755static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001756 u_int8_t ts_nr, u_int8_t subslot_nr)
1757{
Harald Welteadaf08b2009-01-18 11:08:10 +00001758 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001759 ch->bts_port = bts_port;
1760 ch->timeslot = ts_nr;
1761 ch->subslot = subslot_nr;
1762}
1763
1764int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1765 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1766 u_int8_t tei)
1767{
1768 struct abis_om_hdr *oh;
1769 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001770 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001771 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001772
1773 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1774 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1775 bts->bts_nr, trx_nr, 0xff);
1776
Harald Welte8470bf22008-12-25 23:28:35 +00001777 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001778
1779 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1780 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1781
1782 return abis_nm_sendmsg(bts, msg);
1783}
1784
1785/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1786int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1787 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1788{
Harald Welte8470bf22008-12-25 23:28:35 +00001789 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001790 struct abis_om_hdr *oh;
1791 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001792 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001793
1794 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001795 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001796 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1797
1798 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1799 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1800
1801 return abis_nm_sendmsg(bts, msg);
1802}
1803
1804#if 0
1805int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1806 struct abis_nm_abis_channel *chan)
1807{
1808}
1809#endif
1810
1811int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1812 u_int8_t e1_port, u_int8_t e1_timeslot,
1813 u_int8_t e1_subslot)
1814{
1815 struct gsm_bts *bts = ts->trx->bts;
1816 struct abis_om_hdr *oh;
1817 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001818 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001819
1820 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1821 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001822 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001823
1824 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1825 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1826
Harald Weltef325eb42009-02-19 17:07:39 +00001827 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1828 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001829 e1_port, e1_timeslot, e1_subslot);
1830
Harald Welte52b1f982008-12-23 20:25:15 +00001831 return abis_nm_sendmsg(bts, msg);
1832}
1833
1834#if 0
1835int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1836 struct abis_nm_abis_channel *chan,
1837 u_int8_t subchan)
1838{
1839}
1840#endif
1841
Harald Welte22af0db2009-02-14 15:41:08 +00001842/* Chapter 8.6.1 */
1843int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1844{
1845 struct abis_om_hdr *oh;
1846 struct msgb *msg = nm_msgb_alloc();
1847 u_int8_t *cur;
1848
1849 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1850
1851 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001852 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 +00001853 cur = msgb_put(msg, attr_len);
1854 memcpy(cur, attr, attr_len);
1855
1856 return abis_nm_sendmsg(bts, msg);
1857}
1858
1859/* Chapter 8.6.2 */
1860int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1861{
1862 struct abis_om_hdr *oh;
1863 struct msgb *msg = nm_msgb_alloc();
1864 u_int8_t *cur;
1865
1866 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1867
1868 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1869 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001870 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001871 cur = msgb_put(msg, attr_len);
1872 memcpy(cur, attr, attr_len);
1873
1874 return abis_nm_sendmsg(trx->bts, msg);
1875}
1876
Harald Welte39c7deb2009-08-09 21:49:48 +02001877static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1878{
1879 int i;
1880
1881 /* As it turns out, the BS-11 has some very peculiar restrictions
1882 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301883 switch (ts->trx->bts->type) {
1884 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001885 switch (chan_comb) {
1886 case NM_CHANC_TCHHalf:
1887 case NM_CHANC_TCHHalf2:
1888 /* not supported */
1889 return -EINVAL;
1890 case NM_CHANC_SDCCH:
1891 /* only one SDCCH/8 per TRX */
1892 for (i = 0; i < TRX_NR_TS; i++) {
1893 if (i == ts->nr)
1894 continue;
1895 if (ts->trx->ts[i].nm_chan_comb ==
1896 NM_CHANC_SDCCH)
1897 return -EINVAL;
1898 }
1899 /* not allowed for TS0 of BCCH-TRX */
1900 if (ts->trx == ts->trx->bts->c0 &&
1901 ts->nr == 0)
1902 return -EINVAL;
1903 /* not on the same TRX that has a BCCH+SDCCH4
1904 * combination */
1905 if (ts->trx == ts->trx->bts->c0 &&
1906 (ts->trx->ts[0].nm_chan_comb == 5 ||
1907 ts->trx->ts[0].nm_chan_comb == 8))
1908 return -EINVAL;
1909 break;
1910 case NM_CHANC_mainBCCH:
1911 case NM_CHANC_BCCHComb:
1912 /* allowed only for TS0 of C0 */
1913 if (ts->trx != ts->trx->bts->c0 ||
1914 ts->nr != 0)
1915 return -EINVAL;
1916 break;
1917 case NM_CHANC_BCCH:
1918 /* allowed only for TS 2/4/6 of C0 */
1919 if (ts->trx != ts->trx->bts->c0)
1920 return -EINVAL;
1921 if (ts->nr != 2 && ts->nr != 4 &&
1922 ts->nr != 6)
1923 return -EINVAL;
1924 break;
1925 case 8: /* this is not like 08.58, but in fact
1926 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1927 /* FIXME: only one CBCH allowed per cell */
1928 break;
1929 }
Harald Welted6575f92009-12-02 02:45:23 +05301930 break;
1931 case GSM_BTS_TYPE_NANOBTS:
1932 switch (ts->nr) {
1933 case 0:
1934 if (ts->trx->nr == 0) {
1935 /* only on TRX0 */
1936 switch (chan_comb) {
1937 case NM_CHANC_BCCH:
1938 case NM_CHANC_mainBCCH:
1939 case NM_CHANC_BCCHComb:
1940 return 0;
1941 break;
1942 default:
1943 return -EINVAL;
1944 }
1945 } else {
1946 switch (chan_comb) {
1947 case NM_CHANC_TCHFull:
1948 case NM_CHANC_TCHHalf:
1949 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1950 return 0;
1951 default:
1952 return -EINVAL;
1953 }
1954 }
1955 break;
1956 case 1:
1957 if (ts->trx->nr == 0) {
1958 switch (chan_comb) {
1959 case NM_CHANC_SDCCH_CBCH:
1960 if (ts->trx->ts[0].nm_chan_comb ==
1961 NM_CHANC_mainBCCH)
1962 return 0;
1963 return -EINVAL;
1964 case NM_CHANC_SDCCH:
1965 case NM_CHANC_TCHFull:
1966 case NM_CHANC_TCHHalf:
1967 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1968 case NM_CHANC_IPAC_TCHFull_PDCH:
1969 return 0;
1970 }
1971 } else {
1972 switch (chan_comb) {
1973 case NM_CHANC_SDCCH:
1974 case NM_CHANC_TCHFull:
1975 case NM_CHANC_TCHHalf:
1976 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1977 return 0;
1978 default:
1979 return -EINVAL;
1980 }
1981 }
1982 break;
1983 case 2:
1984 case 3:
1985 case 4:
1986 case 5:
1987 case 6:
1988 case 7:
1989 switch (chan_comb) {
1990 case NM_CHANC_TCHFull:
1991 case NM_CHANC_TCHHalf:
1992 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1993 return 0;
1994 case NM_CHANC_IPAC_PDCH:
1995 case NM_CHANC_IPAC_TCHFull_PDCH:
1996 if (ts->trx->nr == 0)
1997 return 0;
1998 else
1999 return -EINVAL;
2000 }
2001 break;
2002 }
2003 return -EINVAL;
2004 default:
2005 /* unknown BTS type */
2006 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002007 }
2008 return 0;
2009}
2010
Harald Welte22af0db2009-02-14 15:41:08 +00002011/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002012int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2013{
2014 struct gsm_bts *bts = ts->trx->bts;
2015 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002016 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002017 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002018 u_int8_t len = 2 + 2;
2019
2020 if (bts->type == GSM_BTS_TYPE_BS11)
2021 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002022
Harald Weltef325eb42009-02-19 17:07:39 +00002023 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002024 if (verify_chan_comb(ts, chan_comb) < 0) {
2025 msgb_free(msg);
2026 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2027 return -EINVAL;
2028 }
2029 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002030
Harald Welte52b1f982008-12-23 20:25:15 +00002031 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002032 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002033 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002034 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002035 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002036 if (ts->hopping.enabled) {
2037 unsigned int i;
2038 uint8_t *len;
2039
Harald Welte6e0cd042009-09-12 13:05:33 +02002040 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2041 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002042
2043 /* build the ARFCN list */
2044 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2045 len = msgb_put(msg, 1);
2046 *len = 0;
2047 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2048 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2049 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002050 /* At least BS-11 wants a TLV16 here */
2051 if (bts->type == GSM_BTS_TYPE_BS11)
2052 *len += 1;
2053 else
2054 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002055 }
2056 }
Harald Weltee0590df2009-02-15 03:34:15 +00002057 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002058 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002059 if (bts->type == GSM_BTS_TYPE_BS11)
2060 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002061
2062 return abis_nm_sendmsg(bts, msg);
2063}
2064
Harald Welte34a99682009-02-13 02:41:40 +00002065int 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 +00002066 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002067{
2068 struct abis_om_hdr *oh;
2069 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002070 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2071 u_int8_t len = att_len;
2072
2073 if (nack) {
2074 len += 2;
2075 msgtype = NM_MT_SW_ACT_REQ_NACK;
2076 }
Harald Welte34a99682009-02-13 02:41:40 +00002077
2078 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002079 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2080
Harald Welte34a99682009-02-13 02:41:40 +00002081 if (attr) {
2082 u_int8_t *ptr = msgb_put(msg, att_len);
2083 memcpy(ptr, attr, att_len);
2084 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002085 if (nack)
2086 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002087
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002088 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002089}
2090
Harald Welte8470bf22008-12-25 23:28:35 +00002091int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002092{
Harald Welte8470bf22008-12-25 23:28:35 +00002093 struct msgb *msg = nm_msgb_alloc();
2094 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002095 u_int8_t *data;
2096
2097 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2098 fill_om_hdr(oh, len);
2099 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002100 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002101
2102 return abis_nm_sendmsg(bts, msg);
2103}
2104
2105/* Siemens specific commands */
2106static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2107{
2108 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002109 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002110
2111 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002112 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002113 0xff, 0xff, 0xff);
2114
2115 return abis_nm_sendmsg(bts, msg);
2116}
2117
Harald Welte34a99682009-02-13 02:41:40 +00002118/* Chapter 8.9.2 */
2119int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2120{
2121 struct abis_om_hdr *oh;
2122 struct msgb *msg = nm_msgb_alloc();
2123
2124 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2125 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2126
Harald Weltea8bd6d42009-10-20 09:56:18 +02002127 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2128 DEBUGPC(DNM, "Sending OPSTART\n");
2129
Harald Welte34a99682009-02-13 02:41:40 +00002130 return abis_nm_sendmsg(bts, msg);
2131}
2132
2133/* Chapter 8.8.5 */
2134int 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 +02002135 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002136{
2137 struct abis_om_hdr *oh;
2138 struct msgb *msg = nm_msgb_alloc();
2139
2140 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2141 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2142 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2143
2144 return abis_nm_sendmsg(bts, msg);
2145}
2146
Harald Welte1989c082009-08-06 17:58:31 +02002147int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2148 u_int8_t e1_port1, u_int8_t ts1)
2149{
2150 struct abis_om_hdr *oh;
2151 struct msgb *msg = nm_msgb_alloc();
2152 u_int8_t *attr;
2153
2154 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2155 e1_port0, ts0, e1_port1, ts1);
2156
2157 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2158 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2159 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2160
2161 attr = msgb_put(msg, 3);
2162 attr[0] = NM_ATT_MDROP_LINK;
2163 attr[1] = e1_port0;
2164 attr[2] = ts0;
2165
2166 attr = msgb_put(msg, 3);
2167 attr[0] = NM_ATT_MDROP_NEXT;
2168 attr[1] = e1_port1;
2169 attr[2] = ts1;
2170
2171 return abis_nm_sendmsg(bts, msg);
2172}
Harald Welte34a99682009-02-13 02:41:40 +00002173
Harald Weltec7310382009-08-08 00:02:36 +02002174/* Chapter 8.7.1 */
2175int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2176 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002177 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002178{
2179 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002180
Harald Welte4d54d0b2011-02-19 16:48:17 +01002181 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002182
2183 if (!msg)
2184 msg = nm_msgb_alloc();
2185
2186 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2187 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2188 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2189 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002190 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002191
2192 return abis_nm_sendmsg(bts, msg);
2193}
2194
Harald Welte52b1f982008-12-23 20:25:15 +00002195int abis_nm_event_reports(struct gsm_bts *bts, int on)
2196{
2197 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002198 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002199 else
Harald Welte227d4072009-01-03 08:16:25 +00002200 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002201}
2202
Harald Welte47d88ae2009-01-04 12:02:08 +00002203/* Siemens (or BS-11) specific commands */
2204
Harald Welte3ffd1372009-02-01 22:15:49 +00002205int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2206{
2207 if (reconnect == 0)
2208 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2209 else
2210 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2211}
2212
Harald Welteb8427972009-02-05 19:27:17 +00002213int abis_nm_bs11_restart(struct gsm_bts *bts)
2214{
2215 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2216}
2217
2218
Harald Welte268bb402009-02-01 19:11:56 +00002219struct bs11_date_time {
2220 u_int16_t year;
2221 u_int8_t month;
2222 u_int8_t day;
2223 u_int8_t hour;
2224 u_int8_t min;
2225 u_int8_t sec;
2226} __attribute__((packed));
2227
2228
2229void get_bs11_date_time(struct bs11_date_time *aet)
2230{
2231 time_t t;
2232 struct tm *tm;
2233
2234 t = time(NULL);
2235 tm = localtime(&t);
2236 aet->sec = tm->tm_sec;
2237 aet->min = tm->tm_min;
2238 aet->hour = tm->tm_hour;
2239 aet->day = tm->tm_mday;
2240 aet->month = tm->tm_mon;
2241 aet->year = htons(1900 + tm->tm_year);
2242}
2243
Harald Welte05188ee2009-01-18 11:39:08 +00002244int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002245{
Harald Welte4668fda2009-01-03 08:19:29 +00002246 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002247}
2248
Harald Welte05188ee2009-01-18 11:39:08 +00002249int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002250{
2251 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002252 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002253 else
Harald Welte4668fda2009-01-03 08:19:29 +00002254 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002255}
Harald Welte47d88ae2009-01-04 12:02:08 +00002256
Harald Welte05188ee2009-01-18 11:39:08 +00002257int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002258 enum abis_bs11_objtype type, u_int8_t idx,
2259 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002260{
2261 struct abis_om_hdr *oh;
2262 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002263 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002264
2265 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002266 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002267 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002268 cur = msgb_put(msg, attr_len);
2269 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002270
2271 return abis_nm_sendmsg(bts, msg);
2272}
2273
Harald Welte78fc0d42009-02-19 02:50:57 +00002274int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2275 enum abis_bs11_objtype type, u_int8_t idx)
2276{
2277 struct abis_om_hdr *oh;
2278 struct msgb *msg = nm_msgb_alloc();
2279
2280 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2281 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2282 NM_OC_BS11, type, 0, idx);
2283
2284 return abis_nm_sendmsg(bts, msg);
2285}
2286
Harald Welte05188ee2009-01-18 11:39:08 +00002287int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002288{
2289 struct abis_om_hdr *oh;
2290 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002291 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002292
2293 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002294 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002295 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2296 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002297
2298 return abis_nm_sendmsg(bts, msg);
2299}
2300
Harald Welte05188ee2009-01-18 11:39:08 +00002301int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002302{
2303 struct abis_om_hdr *oh;
2304 struct msgb *msg = nm_msgb_alloc();
2305
2306 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2307 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002308 idx, 0xff, 0xff);
2309
2310 return abis_nm_sendmsg(bts, msg);
2311}
2312
2313int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2314{
2315 struct abis_om_hdr *oh;
2316 struct msgb *msg = nm_msgb_alloc();
2317
2318 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2319 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2320 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002321
2322 return abis_nm_sendmsg(bts, msg);
2323}
Harald Welte05188ee2009-01-18 11:39:08 +00002324
Harald Welte78fc0d42009-02-19 02:50:57 +00002325static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2326int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2327{
2328 struct abis_om_hdr *oh;
2329 struct msgb *msg = nm_msgb_alloc();
2330
2331 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2332 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2333 0xff, 0xff, 0xff);
2334 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2335
2336 return abis_nm_sendmsg(bts, msg);
2337}
2338
Harald Welteb6c92ae2009-02-21 20:15:32 +00002339/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002340int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002341 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2342 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002343{
2344 struct abis_om_hdr *oh;
2345 struct abis_nm_channel *ch;
2346 struct msgb *msg = nm_msgb_alloc();
2347
2348 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002349 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002350 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2351
2352 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2353 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002354 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002355
2356 return abis_nm_sendmsg(bts, msg);
2357}
2358
2359int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2360{
2361 struct abis_om_hdr *oh;
2362 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002363
2364 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002365 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002366 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2367 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2368
2369 return abis_nm_sendmsg(trx->bts, msg);
2370}
2371
Harald Welte78fc0d42009-02-19 02:50:57 +00002372int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2373{
2374 struct abis_om_hdr *oh;
2375 struct msgb *msg = nm_msgb_alloc();
2376 u_int8_t attr = NM_ATT_BS11_TXPWR;
2377
2378 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2379 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2380 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2381 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2382
2383 return abis_nm_sendmsg(trx->bts, msg);
2384}
2385
Harald Welteaaf02d92009-04-29 13:25:57 +00002386int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2387{
2388 struct abis_om_hdr *oh;
2389 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002390 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002391
2392 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2393 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2394 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002395 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002396
2397 return abis_nm_sendmsg(bts, msg);
2398}
2399
Harald Welteef061952009-05-17 12:43:42 +00002400int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2401{
2402 struct abis_om_hdr *oh;
2403 struct msgb *msg = nm_msgb_alloc();
2404 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2405 NM_ATT_BS11_CCLK_TYPE };
2406
2407 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2408 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2409 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2410 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2411
2412 return abis_nm_sendmsg(bts, msg);
2413
2414}
Harald Welteaaf02d92009-04-29 13:25:57 +00002415
Harald Welte268bb402009-02-01 19:11:56 +00002416//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002417
Harald Welte1bc09062009-01-18 14:17:52 +00002418int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002419{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002420 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2421}
2422
Daniel Willmann4b054c82010-01-07 00:46:26 +01002423int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2424{
2425 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2426}
2427
Daniel Willmann493db4e2010-01-07 00:43:11 +01002428int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2429{
Harald Welte05188ee2009-01-18 11:39:08 +00002430 struct abis_om_hdr *oh;
2431 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002432 struct bs11_date_time bdt;
2433
2434 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002435
2436 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002437 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002438 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002439 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002440 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002441 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002442 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002443 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002444 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002445 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002446 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002447 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002448 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002449 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002450 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002451 }
Harald Welte05188ee2009-01-18 11:39:08 +00002452
2453 return abis_nm_sendmsg(bts, msg);
2454}
Harald Welte1bc09062009-01-18 14:17:52 +00002455
2456int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2457{
2458 struct abis_om_hdr *oh;
2459 struct msgb *msg;
2460
2461 if (strlen(password) != 10)
2462 return -EINVAL;
2463
2464 msg = nm_msgb_alloc();
2465 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002466 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002467 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2468 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2469
2470 return abis_nm_sendmsg(bts, msg);
2471}
2472
Harald Weltee69f5fb2009-04-28 16:31:38 +00002473/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2474int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2475{
2476 struct abis_om_hdr *oh;
2477 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002478 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002479
2480 msg = nm_msgb_alloc();
2481 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2482 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2483 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002484
2485 if (locked)
2486 tlv_value = BS11_LI_PLL_LOCKED;
2487 else
2488 tlv_value = BS11_LI_PLL_STANDALONE;
2489
2490 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002491
2492 return abis_nm_sendmsg(bts, msg);
2493}
2494
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002495/* Set the calibration value of the PLL (work value/set value)
2496 * It depends on the login which one is changed */
2497int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2498{
2499 struct abis_om_hdr *oh;
2500 struct msgb *msg;
2501 u_int8_t tlv_value[2];
2502
2503 msg = nm_msgb_alloc();
2504 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2505 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2506 BS11_OBJ_TRX1, 0x00, 0x00);
2507
2508 tlv_value[0] = value>>8;
2509 tlv_value[1] = value&0xff;
2510
2511 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2512
2513 return abis_nm_sendmsg(bts, msg);
2514}
2515
Harald Welte1bc09062009-01-18 14:17:52 +00002516int abis_nm_bs11_get_state(struct gsm_bts *bts)
2517{
2518 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2519}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002520
2521/* BS11 SWL */
2522
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002523void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002524
Harald Welte5e4d1b32009-02-01 13:36:56 +00002525struct abis_nm_bs11_sw {
2526 struct gsm_bts *bts;
2527 char swl_fname[PATH_MAX];
2528 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002529 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002530 struct llist_head file_list;
2531 gsm_cbfn *user_cb; /* specified by the user */
2532};
2533static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2534
2535struct file_list_entry {
2536 struct llist_head list;
2537 char fname[PATH_MAX];
2538};
2539
2540struct file_list_entry *fl_dequeue(struct llist_head *queue)
2541{
2542 struct llist_head *lh;
2543
2544 if (llist_empty(queue))
2545 return NULL;
2546
2547 lh = queue->next;
2548 llist_del(lh);
2549
2550 return llist_entry(lh, struct file_list_entry, list);
2551}
2552
2553static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2554{
2555 char linebuf[255];
2556 struct llist_head *lh, *lh2;
2557 FILE *swl;
2558 int rc = 0;
2559
2560 swl = fopen(bs11_sw->swl_fname, "r");
2561 if (!swl)
2562 return -ENODEV;
2563
2564 /* zero the stale file list, if any */
2565 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2566 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002567 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002568 }
2569
2570 while (fgets(linebuf, sizeof(linebuf), swl)) {
2571 char file_id[12+1];
2572 char file_version[80+1];
2573 struct file_list_entry *fle;
2574 static char dir[PATH_MAX];
2575
2576 if (strlen(linebuf) < 4)
2577 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002578
Harald Welte5e4d1b32009-02-01 13:36:56 +00002579 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2580 if (rc < 0) {
2581 perror("ERR parsing SWL file");
2582 rc = -EINVAL;
2583 goto out;
2584 }
2585 if (rc < 2)
2586 continue;
2587
Harald Welte470ec292009-06-26 20:25:23 +02002588 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002589 if (!fle) {
2590 rc = -ENOMEM;
2591 goto out;
2592 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002593
2594 /* construct new filename */
2595 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2596 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2597 strcat(fle->fname, "/");
2598 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002599
2600 llist_add_tail(&fle->list, &bs11_sw->file_list);
2601 }
2602
2603out:
2604 fclose(swl);
2605 return rc;
2606}
2607
2608/* bs11 swload specific callback, passed to abis_nm core swload */
2609static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2610 struct msgb *msg, void *data, void *param)
2611{
2612 struct abis_nm_bs11_sw *bs11_sw = data;
2613 struct file_list_entry *fle;
2614 int rc = 0;
2615
Harald Welte5e4d1b32009-02-01 13:36:56 +00002616 switch (event) {
2617 case NM_MT_LOAD_END_ACK:
2618 fle = fl_dequeue(&bs11_sw->file_list);
2619 if (fle) {
2620 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002621 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002622 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002623 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002624 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002625 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002626 } else {
2627 /* activate the SWL */
2628 rc = abis_nm_software_activate(bs11_sw->bts,
2629 bs11_sw->swl_fname,
2630 bs11_swload_cbfn,
2631 bs11_sw);
2632 }
2633 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002634 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002635 case NM_MT_LOAD_END_NACK:
2636 case NM_MT_LOAD_INIT_ACK:
2637 case NM_MT_LOAD_INIT_NACK:
2638 case NM_MT_ACTIVATE_SW_NACK:
2639 case NM_MT_ACTIVATE_SW_ACK:
2640 default:
2641 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002642 if (bs11_sw->user_cb)
2643 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002644 break;
2645 }
2646
2647 return rc;
2648}
2649
2650/* Siemens provides a SWL file that is a mere listing of all the other
2651 * files that are part of a software release. We need to upload first
2652 * the list file, and then each file that is listed in the list file */
2653int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002654 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002655{
2656 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2657 struct file_list_entry *fle;
2658 int rc = 0;
2659
2660 INIT_LLIST_HEAD(&bs11_sw->file_list);
2661 bs11_sw->bts = bts;
2662 bs11_sw->win_size = win_size;
2663 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002664 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002665
2666 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2667 rc = bs11_read_swl_file(bs11_sw);
2668 if (rc < 0)
2669 return rc;
2670
2671 /* dequeue next item in file list */
2672 fle = fl_dequeue(&bs11_sw->file_list);
2673 if (!fle)
2674 return -EINVAL;
2675
2676 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002677 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002678 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002679 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002680 return rc;
2681}
2682
Harald Welte5083b0b2009-02-02 19:20:52 +00002683#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002684static u_int8_t req_attr_btse[] = {
2685 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2686 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2687 NM_ATT_BS11_LMT_USER_NAME,
2688
2689 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2690
2691 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2692
2693 NM_ATT_BS11_SW_LOAD_STORED };
2694
2695static u_int8_t req_attr_btsm[] = {
2696 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2697 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2698 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2699 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002700#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002701
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002702static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002703 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2704 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002705 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002706
2707int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2708{
2709 struct abis_om_hdr *oh;
2710 struct msgb *msg = nm_msgb_alloc();
2711
2712 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2713 /* SiemensHW CCTRL object */
2714 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2715 0x03, 0x00, 0x00);
2716 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2717
2718 return abis_nm_sendmsg(bts, msg);
2719}
Harald Welte268bb402009-02-01 19:11:56 +00002720
2721int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2722{
2723 struct abis_om_hdr *oh;
2724 struct msgb *msg = nm_msgb_alloc();
2725 struct bs11_date_time aet;
2726
2727 get_bs11_date_time(&aet);
2728 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2729 /* SiemensHW CCTRL object */
2730 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2731 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002732 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002733
2734 return abis_nm_sendmsg(bts, msg);
2735}
Harald Welte5c1e4582009-02-15 11:57:29 +00002736
Harald Weltef751a102010-12-14 12:52:16 +01002737int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2738{
2739 struct abis_om_hdr *oh;
2740 struct msgb *msg = nm_msgb_alloc();
2741 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2742
2743 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2744 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2745 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2746 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2747
2748 return abis_nm_sendmsg(bts, msg);
2749}
2750
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002751int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2752{
2753 struct abis_om_hdr *oh;
2754 struct msgb *msg = nm_msgb_alloc();
2755 struct bs11_date_time aet;
2756
2757 get_bs11_date_time(&aet);
2758 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2759 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2760 bport, 0xff, 0x02);
2761 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2762
2763 return abis_nm_sendmsg(bts, msg);
2764}
2765
Harald Welte5c1e4582009-02-15 11:57:29 +00002766/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002767static const char ipaccess_magic[] = "com.ipaccess";
2768
Harald Welte677c21f2009-02-17 13:22:23 +00002769
2770static int abis_nm_rx_ipacc(struct msgb *msg)
2771{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002772 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002773 struct abis_om_hdr *oh = msgb_l2(msg);
2774 struct abis_om_fom_hdr *foh;
2775 u_int8_t idstrlen = oh->data[0];
2776 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002777 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002778
2779 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002780 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002781 return -EINVAL;
2782 }
2783
Harald Welte193fefc2009-04-30 15:16:27 +00002784 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002785 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002786
Harald Weltea8bd6d42009-10-20 09:56:18 +02002787 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002788
Harald Welte746d6092009-10-19 22:11:11 +02002789 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002790
Harald Welte677c21f2009-02-17 13:22:23 +00002791 switch (foh->msg_type) {
2792 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002793 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002794 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2795 memcpy(&addr,
2796 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2797
2798 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2799 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002800 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002801 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002802 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002803 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002804 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2805 DEBUGPC(DNM, "STREAM=0x%02x ",
2806 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002807 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002808 break;
2809 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002810 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002811 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002812 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002813 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002814 else
2815 DEBUGPC(DNM, "\n");
2816 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002817 case NM_MT_IPACC_SET_NVATTR_ACK:
2818 DEBUGPC(DNM, "SET NVATTR ACK\n");
2819 /* FIXME: decode and show the actual attributes */
2820 break;
2821 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002822 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002823 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002824 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002825 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2826 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002827 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002828 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002829 case NM_MT_IPACC_GET_NVATTR_ACK:
2830 DEBUGPC(DNM, "GET NVATTR ACK\n");
2831 /* FIXME: decode and show the actual attributes */
2832 break;
2833 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002834 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002835 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002836 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002837 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2838 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002839 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002840 break;
Harald Welte15c44172009-10-08 20:15:24 +02002841 case NM_MT_IPACC_SET_ATTR_ACK:
2842 DEBUGPC(DNM, "SET ATTR ACK\n");
2843 break;
2844 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002845 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002846 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002847 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002848 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2849 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002850 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002851 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002852 default:
2853 DEBUGPC(DNM, "unknown\n");
2854 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002855 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002856
2857 /* signal handling */
2858 switch (foh->msg_type) {
2859 case NM_MT_IPACC_RSL_CONNECT_NACK:
2860 case NM_MT_IPACC_SET_NVATTR_NACK:
2861 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002862 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002863 signal.msg_type = foh->msg_type;
2864 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002865 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002866 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002867 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002868 signal.msg_type = foh->msg_type;
2869 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002870 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002871 default:
2872 break;
2873 }
2874
Harald Welte677c21f2009-02-17 13:22:23 +00002875 return 0;
2876}
2877
Harald Welte193fefc2009-04-30 15:16:27 +00002878/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002879int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2880 u_int8_t obj_class, u_int8_t bts_nr,
2881 u_int8_t trx_nr, u_int8_t ts_nr,
2882 u_int8_t *attr, int attr_len)
2883{
2884 struct msgb *msg = nm_msgb_alloc();
2885 struct abis_om_hdr *oh;
2886 struct abis_om_fom_hdr *foh;
2887 u_int8_t *data;
2888
2889 /* construct the 12.21 OM header, observe the erroneous length */
2890 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2891 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2892 oh->mdisc = ABIS_OM_MDISC_MANUF;
2893
2894 /* add the ip.access magic */
2895 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2896 *data++ = sizeof(ipaccess_magic);
2897 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2898
2899 /* fill the 12.21 FOM header */
2900 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2901 foh->msg_type = msg_type;
2902 foh->obj_class = obj_class;
2903 foh->obj_inst.bts_nr = bts_nr;
2904 foh->obj_inst.trx_nr = trx_nr;
2905 foh->obj_inst.ts_nr = ts_nr;
2906
2907 if (attr && attr_len) {
2908 data = msgb_put(msg, attr_len);
2909 memcpy(data, attr, attr_len);
2910 }
2911
2912 return abis_nm_sendmsg(bts, msg);
2913}
Harald Welte677c21f2009-02-17 13:22:23 +00002914
Harald Welte193fefc2009-04-30 15:16:27 +00002915/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002916int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002917 int attr_len)
2918{
Harald Welte2ef156d2010-01-07 20:39:42 +01002919 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2920 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002921 attr_len);
2922}
2923
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002924int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002925 u_int32_t ip, u_int16_t port, u_int8_t stream)
2926{
2927 struct in_addr ia;
2928 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2929 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2930 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2931
2932 int attr_len = sizeof(attr);
2933
2934 ia.s_addr = htonl(ip);
2935 attr[1] = stream;
2936 attr[3] = port >> 8;
2937 attr[4] = port & 0xff;
2938 *(u_int32_t *)(attr+6) = ia.s_addr;
2939
2940 /* if ip == 0, we use the default IP */
2941 if (ip == 0)
2942 attr_len -= 5;
2943
2944 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002945 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002946
2947 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2948 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2949 trx->nr, 0xff, attr, attr_len);
2950}
2951
Harald Welte193fefc2009-04-30 15:16:27 +00002952/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002953int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002954{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002955 struct abis_om_hdr *oh;
2956 struct msgb *msg = nm_msgb_alloc();
2957
2958 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2959 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2960 trx->bts->nr, trx->nr, 0xff);
2961
2962 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002963}
Harald Weltedaef5212009-10-24 10:20:41 +02002964
2965int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2966 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2967 u_int8_t *attr, u_int8_t attr_len)
2968{
2969 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2970 obj_class, bts_nr, trx_nr, ts_nr,
2971 attr, attr_len);
2972}
Harald Welte0f255852009-11-12 14:48:42 +01002973
Harald Welte97a282b2010-03-14 15:37:43 +08002974void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2975{
2976 /* we simply reuse the GSM48 function and overwrite the RAC
2977 * with the Cell ID */
2978 gsm48_ra_id_by_bts(buf, bts);
2979 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2980}
2981
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002982void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2983{
2984 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2985
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002986 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002987 if (!trx->bts || !trx->bts->oml_link)
2988 return;
2989
2990 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2991 trx->bts->bts_nr, trx->nr, 0xff,
2992 new_state);
2993}
2994
Harald Welte92b1fe42010-03-25 11:45:30 +08002995static const struct value_string ipacc_testres_names[] = {
2996 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2997 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2998 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2999 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3000 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3001 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01003002};
3003
3004const char *ipacc_testres_name(u_int8_t res)
3005{
Harald Welte92b1fe42010-03-25 11:45:30 +08003006 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003007}
3008
Harald Welteb40a38f2009-11-13 11:56:05 +01003009void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3010{
3011 cid->mcc = (buf[0] & 0xf) * 100;
3012 cid->mcc += (buf[0] >> 4) * 10;
3013 cid->mcc += (buf[1] & 0xf) * 1;
3014
3015 if (buf[1] >> 4 == 0xf) {
3016 cid->mnc = (buf[2] & 0xf) * 10;
3017 cid->mnc += (buf[2] >> 4) * 1;
3018 } else {
3019 cid->mnc = (buf[2] & 0xf) * 100;
3020 cid->mnc += (buf[2] >> 4) * 10;
3021 cid->mnc += (buf[1] >> 4) * 1;
3022 }
3023
Harald Welteaff237d2009-11-13 14:41:52 +01003024 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3025 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003026}
3027
Harald Welte0f255852009-11-12 14:48:42 +01003028/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3029int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3030{
3031 u_int8_t *cur = buf;
3032 u_int16_t len;
3033
Harald Welteaf109b92010-07-22 18:14:36 +02003034 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003035
3036 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3037 return -EINVAL;
3038 cur++;
3039
3040 len = ntohs(*(u_int16_t *)cur);
3041 cur += 2;
3042
3043 binf->info_type = ntohs(*(u_int16_t *)cur);
3044 cur += 2;
3045
3046 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3047 binf->freq_qual = *cur >> 2;
3048
Harald Welteaf109b92010-07-22 18:14:36 +02003049 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003050 binf->arfcn |= *cur++;
3051
3052 if (binf->info_type & IPAC_BINF_RXLEV)
3053 binf->rx_lev = *cur & 0x3f;
3054 cur++;
3055
3056 if (binf->info_type & IPAC_BINF_RXQUAL)
3057 binf->rx_qual = *cur & 0x7;
3058 cur++;
3059
3060 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3061 binf->freq_err = ntohs(*(u_int16_t *)cur);
3062 cur += 2;
3063
3064 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3065 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3066 cur += 2;
3067
3068 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3069 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3070 cur += 4;
3071
Harald Weltea780a3d2010-07-30 22:34:42 +02003072#if 0
3073 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003074 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003075#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003076 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003077 cur++;
3078
Harald Welteb40a38f2009-11-13 11:56:05 +01003079 ipac_parse_cgi(&binf->cgi, cur);
3080 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003081
3082 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3083 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3084 cur += sizeof(binf->ba_list_si2);
3085 }
3086
3087 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3088 memcpy(binf->ba_list_si2bis, cur,
3089 sizeof(binf->ba_list_si2bis));
3090 cur += sizeof(binf->ba_list_si2bis);
3091 }
3092
3093 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3094 memcpy(binf->ba_list_si2ter, cur,
3095 sizeof(binf->ba_list_si2ter));
3096 cur += sizeof(binf->ba_list_si2ter);
3097 }
3098
3099 return 0;
3100}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003101
3102void abis_nm_clear_queue(struct gsm_bts *bts)
3103{
3104 struct msgb *msg;
3105
3106 while (!llist_empty(&bts->abis_queue)) {
3107 msg = msgb_dequeue(&bts->abis_queue);
3108 msgb_free(msg);
3109 }
3110
3111 bts->abis_nm_pend = 0;
3112}