blob: 686421625f7b578ff3e3d2938ddb77305e4a82e3 [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);
419 return _abis_nm_sendmsg(msg);
420 } 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);
988 _abis_nm_sendmsg(msg);
989
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 Welte8470bf22008-12-25 23:28:35 +00002016 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002017 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002018 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002019 u_int8_t len = 2 + 2;
2020
2021 if (bts->type == GSM_BTS_TYPE_BS11)
2022 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002023
Harald Weltef325eb42009-02-19 17:07:39 +00002024 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002025 if (verify_chan_comb(ts, chan_comb) < 0) {
2026 msgb_free(msg);
2027 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2028 return -EINVAL;
2029 }
2030 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002031
Harald Welte52b1f982008-12-23 20:25:15 +00002032 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002033 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002034 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002035 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002036 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002037 if (ts->hopping.enabled) {
2038 unsigned int i;
2039 uint8_t *len;
2040
Harald Welte6e0cd042009-09-12 13:05:33 +02002041 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2042 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002043
2044 /* build the ARFCN list */
2045 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2046 len = msgb_put(msg, 1);
2047 *len = 0;
2048 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2049 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2050 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002051 /* At least BS-11 wants a TLV16 here */
2052 if (bts->type == GSM_BTS_TYPE_BS11)
2053 *len += 1;
2054 else
2055 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002056 }
2057 }
Harald Weltee0590df2009-02-15 03:34:15 +00002058 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002059 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002060 if (bts->type == GSM_BTS_TYPE_BS11)
2061 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002062
2063 return abis_nm_sendmsg(bts, msg);
2064}
2065
Harald Welte34a99682009-02-13 02:41:40 +00002066int 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 +00002067 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002068{
2069 struct abis_om_hdr *oh;
2070 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002071 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2072 u_int8_t len = att_len;
2073
2074 if (nack) {
2075 len += 2;
2076 msgtype = NM_MT_SW_ACT_REQ_NACK;
2077 }
Harald Welte34a99682009-02-13 02:41:40 +00002078
2079 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002080 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2081
Harald Welte34a99682009-02-13 02:41:40 +00002082 if (attr) {
2083 u_int8_t *ptr = msgb_put(msg, att_len);
2084 memcpy(ptr, attr, att_len);
2085 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002086 if (nack)
2087 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002088
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002089 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002090}
2091
Harald Welte8470bf22008-12-25 23:28:35 +00002092int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002093{
Harald Welte8470bf22008-12-25 23:28:35 +00002094 struct msgb *msg = nm_msgb_alloc();
2095 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002096 u_int8_t *data;
2097
2098 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2099 fill_om_hdr(oh, len);
2100 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002101 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002102
2103 return abis_nm_sendmsg(bts, msg);
2104}
2105
2106/* Siemens specific commands */
2107static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2108{
2109 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002110 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002111
2112 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002113 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002114 0xff, 0xff, 0xff);
2115
2116 return abis_nm_sendmsg(bts, msg);
2117}
2118
Harald Welte34a99682009-02-13 02:41:40 +00002119/* Chapter 8.9.2 */
2120int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2121{
2122 struct abis_om_hdr *oh;
2123 struct msgb *msg = nm_msgb_alloc();
2124
2125 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2126 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2127
Harald Weltea8bd6d42009-10-20 09:56:18 +02002128 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2129 DEBUGPC(DNM, "Sending OPSTART\n");
2130
Harald Welte34a99682009-02-13 02:41:40 +00002131 return abis_nm_sendmsg(bts, msg);
2132}
2133
2134/* Chapter 8.8.5 */
2135int 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 +02002136 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002137{
2138 struct abis_om_hdr *oh;
2139 struct msgb *msg = nm_msgb_alloc();
2140
2141 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2142 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2143 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2144
2145 return abis_nm_sendmsg(bts, msg);
2146}
2147
Harald Welte1989c082009-08-06 17:58:31 +02002148int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2149 u_int8_t e1_port1, u_int8_t ts1)
2150{
2151 struct abis_om_hdr *oh;
2152 struct msgb *msg = nm_msgb_alloc();
2153 u_int8_t *attr;
2154
2155 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2156 e1_port0, ts0, e1_port1, ts1);
2157
2158 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2159 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2160 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2161
2162 attr = msgb_put(msg, 3);
2163 attr[0] = NM_ATT_MDROP_LINK;
2164 attr[1] = e1_port0;
2165 attr[2] = ts0;
2166
2167 attr = msgb_put(msg, 3);
2168 attr[0] = NM_ATT_MDROP_NEXT;
2169 attr[1] = e1_port1;
2170 attr[2] = ts1;
2171
2172 return abis_nm_sendmsg(bts, msg);
2173}
Harald Welte34a99682009-02-13 02:41:40 +00002174
Harald Weltec7310382009-08-08 00:02:36 +02002175/* Chapter 8.7.1 */
2176int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2177 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002178 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002179{
2180 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002181
2182 DEBUGP(DNM, "PEFORM TEST\n");
Harald Welte887deab2010-03-06 11:38:05 +01002183
2184 if (!msg)
2185 msg = nm_msgb_alloc();
2186
2187 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2188 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2189 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2190 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002191 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002192
2193 return abis_nm_sendmsg(bts, msg);
2194}
2195
Harald Welte52b1f982008-12-23 20:25:15 +00002196int abis_nm_event_reports(struct gsm_bts *bts, int on)
2197{
2198 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002199 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002200 else
Harald Welte227d4072009-01-03 08:16:25 +00002201 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002202}
2203
Harald Welte47d88ae2009-01-04 12:02:08 +00002204/* Siemens (or BS-11) specific commands */
2205
Harald Welte3ffd1372009-02-01 22:15:49 +00002206int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2207{
2208 if (reconnect == 0)
2209 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2210 else
2211 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2212}
2213
Harald Welteb8427972009-02-05 19:27:17 +00002214int abis_nm_bs11_restart(struct gsm_bts *bts)
2215{
2216 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2217}
2218
2219
Harald Welte268bb402009-02-01 19:11:56 +00002220struct bs11_date_time {
2221 u_int16_t year;
2222 u_int8_t month;
2223 u_int8_t day;
2224 u_int8_t hour;
2225 u_int8_t min;
2226 u_int8_t sec;
2227} __attribute__((packed));
2228
2229
2230void get_bs11_date_time(struct bs11_date_time *aet)
2231{
2232 time_t t;
2233 struct tm *tm;
2234
2235 t = time(NULL);
2236 tm = localtime(&t);
2237 aet->sec = tm->tm_sec;
2238 aet->min = tm->tm_min;
2239 aet->hour = tm->tm_hour;
2240 aet->day = tm->tm_mday;
2241 aet->month = tm->tm_mon;
2242 aet->year = htons(1900 + tm->tm_year);
2243}
2244
Harald Welte05188ee2009-01-18 11:39:08 +00002245int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002246{
Harald Welte4668fda2009-01-03 08:19:29 +00002247 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002248}
2249
Harald Welte05188ee2009-01-18 11:39:08 +00002250int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002251{
2252 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002253 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002254 else
Harald Welte4668fda2009-01-03 08:19:29 +00002255 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002256}
Harald Welte47d88ae2009-01-04 12:02:08 +00002257
Harald Welte05188ee2009-01-18 11:39:08 +00002258int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002259 enum abis_bs11_objtype type, u_int8_t idx,
2260 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002261{
2262 struct abis_om_hdr *oh;
2263 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002264 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002265
2266 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002267 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002268 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002269 cur = msgb_put(msg, attr_len);
2270 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002271
2272 return abis_nm_sendmsg(bts, msg);
2273}
2274
Harald Welte78fc0d42009-02-19 02:50:57 +00002275int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2276 enum abis_bs11_objtype type, u_int8_t idx)
2277{
2278 struct abis_om_hdr *oh;
2279 struct msgb *msg = nm_msgb_alloc();
2280
2281 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2282 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2283 NM_OC_BS11, type, 0, idx);
2284
2285 return abis_nm_sendmsg(bts, msg);
2286}
2287
Harald Welte05188ee2009-01-18 11:39:08 +00002288int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002289{
2290 struct abis_om_hdr *oh;
2291 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002292 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002293
2294 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002295 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002296 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2297 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002298
2299 return abis_nm_sendmsg(bts, msg);
2300}
2301
Harald Welte05188ee2009-01-18 11:39:08 +00002302int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002303{
2304 struct abis_om_hdr *oh;
2305 struct msgb *msg = nm_msgb_alloc();
2306
2307 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2308 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002309 idx, 0xff, 0xff);
2310
2311 return abis_nm_sendmsg(bts, msg);
2312}
2313
2314int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2315{
2316 struct abis_om_hdr *oh;
2317 struct msgb *msg = nm_msgb_alloc();
2318
2319 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2320 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2321 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002322
2323 return abis_nm_sendmsg(bts, msg);
2324}
Harald Welte05188ee2009-01-18 11:39:08 +00002325
Harald Welte78fc0d42009-02-19 02:50:57 +00002326static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2327int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2328{
2329 struct abis_om_hdr *oh;
2330 struct msgb *msg = nm_msgb_alloc();
2331
2332 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2333 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2334 0xff, 0xff, 0xff);
2335 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2336
2337 return abis_nm_sendmsg(bts, msg);
2338}
2339
Harald Welteb6c92ae2009-02-21 20:15:32 +00002340/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002341int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002342 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2343 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002344{
2345 struct abis_om_hdr *oh;
2346 struct abis_nm_channel *ch;
2347 struct msgb *msg = nm_msgb_alloc();
2348
2349 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002350 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002351 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2352
2353 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2354 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002355 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002356
2357 return abis_nm_sendmsg(bts, msg);
2358}
2359
2360int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2361{
2362 struct abis_om_hdr *oh;
2363 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002364
2365 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002366 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002367 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2368 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2369
2370 return abis_nm_sendmsg(trx->bts, msg);
2371}
2372
Harald Welte78fc0d42009-02-19 02:50:57 +00002373int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2374{
2375 struct abis_om_hdr *oh;
2376 struct msgb *msg = nm_msgb_alloc();
2377 u_int8_t attr = NM_ATT_BS11_TXPWR;
2378
2379 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2380 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2381 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2382 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2383
2384 return abis_nm_sendmsg(trx->bts, msg);
2385}
2386
Harald Welteaaf02d92009-04-29 13:25:57 +00002387int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2388{
2389 struct abis_om_hdr *oh;
2390 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002391 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002392
2393 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2394 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2395 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002396 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002397
2398 return abis_nm_sendmsg(bts, msg);
2399}
2400
Harald Welteef061952009-05-17 12:43:42 +00002401int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2402{
2403 struct abis_om_hdr *oh;
2404 struct msgb *msg = nm_msgb_alloc();
2405 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2406 NM_ATT_BS11_CCLK_TYPE };
2407
2408 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2409 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2410 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2411 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2412
2413 return abis_nm_sendmsg(bts, msg);
2414
2415}
Harald Welteaaf02d92009-04-29 13:25:57 +00002416
Harald Welte268bb402009-02-01 19:11:56 +00002417//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002418
Harald Welte1bc09062009-01-18 14:17:52 +00002419int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002420{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002421 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2422}
2423
Daniel Willmann4b054c82010-01-07 00:46:26 +01002424int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2425{
2426 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2427}
2428
Daniel Willmann493db4e2010-01-07 00:43:11 +01002429int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2430{
Harald Welte05188ee2009-01-18 11:39:08 +00002431 struct abis_om_hdr *oh;
2432 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002433 struct bs11_date_time bdt;
2434
2435 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002436
2437 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002438 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002439 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002440 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002441 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002442 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002443 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002444 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002445 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002446 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002447 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002448 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002449 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002450 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002451 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002452 }
Harald Welte05188ee2009-01-18 11:39:08 +00002453
2454 return abis_nm_sendmsg(bts, msg);
2455}
Harald Welte1bc09062009-01-18 14:17:52 +00002456
2457int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2458{
2459 struct abis_om_hdr *oh;
2460 struct msgb *msg;
2461
2462 if (strlen(password) != 10)
2463 return -EINVAL;
2464
2465 msg = nm_msgb_alloc();
2466 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002467 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002468 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2469 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2470
2471 return abis_nm_sendmsg(bts, msg);
2472}
2473
Harald Weltee69f5fb2009-04-28 16:31:38 +00002474/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2475int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2476{
2477 struct abis_om_hdr *oh;
2478 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002479 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002480
2481 msg = nm_msgb_alloc();
2482 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2483 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2484 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002485
2486 if (locked)
2487 tlv_value = BS11_LI_PLL_LOCKED;
2488 else
2489 tlv_value = BS11_LI_PLL_STANDALONE;
2490
2491 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002492
2493 return abis_nm_sendmsg(bts, msg);
2494}
2495
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002496/* Set the calibration value of the PLL (work value/set value)
2497 * It depends on the login which one is changed */
2498int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2499{
2500 struct abis_om_hdr *oh;
2501 struct msgb *msg;
2502 u_int8_t tlv_value[2];
2503
2504 msg = nm_msgb_alloc();
2505 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2506 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2507 BS11_OBJ_TRX1, 0x00, 0x00);
2508
2509 tlv_value[0] = value>>8;
2510 tlv_value[1] = value&0xff;
2511
2512 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2513
2514 return abis_nm_sendmsg(bts, msg);
2515}
2516
Harald Welte1bc09062009-01-18 14:17:52 +00002517int abis_nm_bs11_get_state(struct gsm_bts *bts)
2518{
2519 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2520}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002521
2522/* BS11 SWL */
2523
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002524void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002525
Harald Welte5e4d1b32009-02-01 13:36:56 +00002526struct abis_nm_bs11_sw {
2527 struct gsm_bts *bts;
2528 char swl_fname[PATH_MAX];
2529 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002530 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002531 struct llist_head file_list;
2532 gsm_cbfn *user_cb; /* specified by the user */
2533};
2534static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2535
2536struct file_list_entry {
2537 struct llist_head list;
2538 char fname[PATH_MAX];
2539};
2540
2541struct file_list_entry *fl_dequeue(struct llist_head *queue)
2542{
2543 struct llist_head *lh;
2544
2545 if (llist_empty(queue))
2546 return NULL;
2547
2548 lh = queue->next;
2549 llist_del(lh);
2550
2551 return llist_entry(lh, struct file_list_entry, list);
2552}
2553
2554static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2555{
2556 char linebuf[255];
2557 struct llist_head *lh, *lh2;
2558 FILE *swl;
2559 int rc = 0;
2560
2561 swl = fopen(bs11_sw->swl_fname, "r");
2562 if (!swl)
2563 return -ENODEV;
2564
2565 /* zero the stale file list, if any */
2566 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2567 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002568 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002569 }
2570
2571 while (fgets(linebuf, sizeof(linebuf), swl)) {
2572 char file_id[12+1];
2573 char file_version[80+1];
2574 struct file_list_entry *fle;
2575 static char dir[PATH_MAX];
2576
2577 if (strlen(linebuf) < 4)
2578 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002579
Harald Welte5e4d1b32009-02-01 13:36:56 +00002580 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2581 if (rc < 0) {
2582 perror("ERR parsing SWL file");
2583 rc = -EINVAL;
2584 goto out;
2585 }
2586 if (rc < 2)
2587 continue;
2588
Harald Welte470ec292009-06-26 20:25:23 +02002589 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002590 if (!fle) {
2591 rc = -ENOMEM;
2592 goto out;
2593 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002594
2595 /* construct new filename */
2596 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2597 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2598 strcat(fle->fname, "/");
2599 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002600
2601 llist_add_tail(&fle->list, &bs11_sw->file_list);
2602 }
2603
2604out:
2605 fclose(swl);
2606 return rc;
2607}
2608
2609/* bs11 swload specific callback, passed to abis_nm core swload */
2610static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2611 struct msgb *msg, void *data, void *param)
2612{
2613 struct abis_nm_bs11_sw *bs11_sw = data;
2614 struct file_list_entry *fle;
2615 int rc = 0;
2616
Harald Welte5e4d1b32009-02-01 13:36:56 +00002617 switch (event) {
2618 case NM_MT_LOAD_END_ACK:
2619 fle = fl_dequeue(&bs11_sw->file_list);
2620 if (fle) {
2621 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002622 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002623 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002624 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002625 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002626 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002627 } else {
2628 /* activate the SWL */
2629 rc = abis_nm_software_activate(bs11_sw->bts,
2630 bs11_sw->swl_fname,
2631 bs11_swload_cbfn,
2632 bs11_sw);
2633 }
2634 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002635 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002636 case NM_MT_LOAD_END_NACK:
2637 case NM_MT_LOAD_INIT_ACK:
2638 case NM_MT_LOAD_INIT_NACK:
2639 case NM_MT_ACTIVATE_SW_NACK:
2640 case NM_MT_ACTIVATE_SW_ACK:
2641 default:
2642 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002643 if (bs11_sw->user_cb)
2644 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002645 break;
2646 }
2647
2648 return rc;
2649}
2650
2651/* Siemens provides a SWL file that is a mere listing of all the other
2652 * files that are part of a software release. We need to upload first
2653 * the list file, and then each file that is listed in the list file */
2654int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002655 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002656{
2657 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2658 struct file_list_entry *fle;
2659 int rc = 0;
2660
2661 INIT_LLIST_HEAD(&bs11_sw->file_list);
2662 bs11_sw->bts = bts;
2663 bs11_sw->win_size = win_size;
2664 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002665 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002666
2667 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2668 rc = bs11_read_swl_file(bs11_sw);
2669 if (rc < 0)
2670 return rc;
2671
2672 /* dequeue next item in file list */
2673 fle = fl_dequeue(&bs11_sw->file_list);
2674 if (!fle)
2675 return -EINVAL;
2676
2677 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002678 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002679 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002680 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002681 return rc;
2682}
2683
Harald Welte5083b0b2009-02-02 19:20:52 +00002684#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002685static u_int8_t req_attr_btse[] = {
2686 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2687 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2688 NM_ATT_BS11_LMT_USER_NAME,
2689
2690 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2691
2692 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2693
2694 NM_ATT_BS11_SW_LOAD_STORED };
2695
2696static u_int8_t req_attr_btsm[] = {
2697 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2698 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2699 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2700 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002701#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002702
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002703static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002704 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2705 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002706 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002707
2708int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2709{
2710 struct abis_om_hdr *oh;
2711 struct msgb *msg = nm_msgb_alloc();
2712
2713 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2714 /* SiemensHW CCTRL object */
2715 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2716 0x03, 0x00, 0x00);
2717 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2718
2719 return abis_nm_sendmsg(bts, msg);
2720}
Harald Welte268bb402009-02-01 19:11:56 +00002721
2722int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2723{
2724 struct abis_om_hdr *oh;
2725 struct msgb *msg = nm_msgb_alloc();
2726 struct bs11_date_time aet;
2727
2728 get_bs11_date_time(&aet);
2729 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2730 /* SiemensHW CCTRL object */
2731 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2732 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002733 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002734
2735 return abis_nm_sendmsg(bts, msg);
2736}
Harald Welte5c1e4582009-02-15 11:57:29 +00002737
Harald Weltef751a102010-12-14 12:52:16 +01002738int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2739{
2740 struct abis_om_hdr *oh;
2741 struct msgb *msg = nm_msgb_alloc();
2742 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2743
2744 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2745 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2746 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2747 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2748
2749 return abis_nm_sendmsg(bts, msg);
2750}
2751
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002752int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2753{
2754 struct abis_om_hdr *oh;
2755 struct msgb *msg = nm_msgb_alloc();
2756 struct bs11_date_time aet;
2757
2758 get_bs11_date_time(&aet);
2759 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2760 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2761 bport, 0xff, 0x02);
2762 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2763
2764 return abis_nm_sendmsg(bts, msg);
2765}
2766
Harald Welte5c1e4582009-02-15 11:57:29 +00002767/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002768static const char ipaccess_magic[] = "com.ipaccess";
2769
Harald Welte677c21f2009-02-17 13:22:23 +00002770
2771static int abis_nm_rx_ipacc(struct msgb *msg)
2772{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002773 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002774 struct abis_om_hdr *oh = msgb_l2(msg);
2775 struct abis_om_fom_hdr *foh;
2776 u_int8_t idstrlen = oh->data[0];
2777 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002778 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002779
2780 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002781 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002782 return -EINVAL;
2783 }
2784
Harald Welte193fefc2009-04-30 15:16:27 +00002785 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002786 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002787
Harald Weltea8bd6d42009-10-20 09:56:18 +02002788 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002789
Harald Welte746d6092009-10-19 22:11:11 +02002790 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002791
Harald Welte677c21f2009-02-17 13:22:23 +00002792 switch (foh->msg_type) {
2793 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002794 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002795 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2796 memcpy(&addr,
2797 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2798
2799 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2800 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002801 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002802 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002803 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002804 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002805 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2806 DEBUGPC(DNM, "STREAM=0x%02x ",
2807 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002808 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002809 break;
2810 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002811 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002812 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002813 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002814 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002815 else
2816 DEBUGPC(DNM, "\n");
2817 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002818 case NM_MT_IPACC_SET_NVATTR_ACK:
2819 DEBUGPC(DNM, "SET NVATTR ACK\n");
2820 /* FIXME: decode and show the actual attributes */
2821 break;
2822 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002823 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002824 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002825 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002826 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2827 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002828 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002829 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002830 case NM_MT_IPACC_GET_NVATTR_ACK:
2831 DEBUGPC(DNM, "GET NVATTR ACK\n");
2832 /* FIXME: decode and show the actual attributes */
2833 break;
2834 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002835 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002836 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002837 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002838 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2839 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002840 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002841 break;
Harald Welte15c44172009-10-08 20:15:24 +02002842 case NM_MT_IPACC_SET_ATTR_ACK:
2843 DEBUGPC(DNM, "SET ATTR ACK\n");
2844 break;
2845 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002846 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002847 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002848 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002849 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2850 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002851 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002852 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002853 default:
2854 DEBUGPC(DNM, "unknown\n");
2855 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002856 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002857
2858 /* signal handling */
2859 switch (foh->msg_type) {
2860 case NM_MT_IPACC_RSL_CONNECT_NACK:
2861 case NM_MT_IPACC_SET_NVATTR_NACK:
2862 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002863 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002864 signal.msg_type = foh->msg_type;
2865 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002866 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002867 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002868 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002869 signal.msg_type = foh->msg_type;
2870 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002871 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002872 default:
2873 break;
2874 }
2875
Harald Welte677c21f2009-02-17 13:22:23 +00002876 return 0;
2877}
2878
Harald Welte193fefc2009-04-30 15:16:27 +00002879/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002880int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2881 u_int8_t obj_class, u_int8_t bts_nr,
2882 u_int8_t trx_nr, u_int8_t ts_nr,
2883 u_int8_t *attr, int attr_len)
2884{
2885 struct msgb *msg = nm_msgb_alloc();
2886 struct abis_om_hdr *oh;
2887 struct abis_om_fom_hdr *foh;
2888 u_int8_t *data;
2889
2890 /* construct the 12.21 OM header, observe the erroneous length */
2891 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2892 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2893 oh->mdisc = ABIS_OM_MDISC_MANUF;
2894
2895 /* add the ip.access magic */
2896 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2897 *data++ = sizeof(ipaccess_magic);
2898 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2899
2900 /* fill the 12.21 FOM header */
2901 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2902 foh->msg_type = msg_type;
2903 foh->obj_class = obj_class;
2904 foh->obj_inst.bts_nr = bts_nr;
2905 foh->obj_inst.trx_nr = trx_nr;
2906 foh->obj_inst.ts_nr = ts_nr;
2907
2908 if (attr && attr_len) {
2909 data = msgb_put(msg, attr_len);
2910 memcpy(data, attr, attr_len);
2911 }
2912
2913 return abis_nm_sendmsg(bts, msg);
2914}
Harald Welte677c21f2009-02-17 13:22:23 +00002915
Harald Welte193fefc2009-04-30 15:16:27 +00002916/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002917int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002918 int attr_len)
2919{
Harald Welte2ef156d2010-01-07 20:39:42 +01002920 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2921 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002922 attr_len);
2923}
2924
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002925int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002926 u_int32_t ip, u_int16_t port, u_int8_t stream)
2927{
2928 struct in_addr ia;
2929 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2930 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2931 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2932
2933 int attr_len = sizeof(attr);
2934
2935 ia.s_addr = htonl(ip);
2936 attr[1] = stream;
2937 attr[3] = port >> 8;
2938 attr[4] = port & 0xff;
2939 *(u_int32_t *)(attr+6) = ia.s_addr;
2940
2941 /* if ip == 0, we use the default IP */
2942 if (ip == 0)
2943 attr_len -= 5;
2944
2945 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002946 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002947
2948 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2949 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2950 trx->nr, 0xff, attr, attr_len);
2951}
2952
Harald Welte193fefc2009-04-30 15:16:27 +00002953/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002954int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002955{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002956 struct abis_om_hdr *oh;
2957 struct msgb *msg = nm_msgb_alloc();
2958
2959 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2960 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2961 trx->bts->nr, trx->nr, 0xff);
2962
2963 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002964}
Harald Weltedaef5212009-10-24 10:20:41 +02002965
2966int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2967 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2968 u_int8_t *attr, u_int8_t attr_len)
2969{
2970 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2971 obj_class, bts_nr, trx_nr, ts_nr,
2972 attr, attr_len);
2973}
Harald Welte0f255852009-11-12 14:48:42 +01002974
Harald Welte97a282b2010-03-14 15:37:43 +08002975void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2976{
2977 /* we simply reuse the GSM48 function and overwrite the RAC
2978 * with the Cell ID */
2979 gsm48_ra_id_by_bts(buf, bts);
2980 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2981}
2982
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002983void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2984{
2985 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2986
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002987 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002988 if (!trx->bts || !trx->bts->oml_link)
2989 return;
2990
2991 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2992 trx->bts->bts_nr, trx->nr, 0xff,
2993 new_state);
2994}
2995
Harald Welte92b1fe42010-03-25 11:45:30 +08002996static const struct value_string ipacc_testres_names[] = {
2997 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2998 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2999 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3000 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3001 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3002 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01003003};
3004
3005const char *ipacc_testres_name(u_int8_t res)
3006{
Harald Welte92b1fe42010-03-25 11:45:30 +08003007 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003008}
3009
Harald Welteb40a38f2009-11-13 11:56:05 +01003010void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3011{
3012 cid->mcc = (buf[0] & 0xf) * 100;
3013 cid->mcc += (buf[0] >> 4) * 10;
3014 cid->mcc += (buf[1] & 0xf) * 1;
3015
3016 if (buf[1] >> 4 == 0xf) {
3017 cid->mnc = (buf[2] & 0xf) * 10;
3018 cid->mnc += (buf[2] >> 4) * 1;
3019 } else {
3020 cid->mnc = (buf[2] & 0xf) * 100;
3021 cid->mnc += (buf[2] >> 4) * 10;
3022 cid->mnc += (buf[1] >> 4) * 1;
3023 }
3024
Harald Welteaff237d2009-11-13 14:41:52 +01003025 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3026 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003027}
3028
Harald Welte0f255852009-11-12 14:48:42 +01003029/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3030int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3031{
3032 u_int8_t *cur = buf;
3033 u_int16_t len;
3034
Harald Welteaf109b92010-07-22 18:14:36 +02003035 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003036
3037 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3038 return -EINVAL;
3039 cur++;
3040
3041 len = ntohs(*(u_int16_t *)cur);
3042 cur += 2;
3043
3044 binf->info_type = ntohs(*(u_int16_t *)cur);
3045 cur += 2;
3046
3047 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3048 binf->freq_qual = *cur >> 2;
3049
Harald Welteaf109b92010-07-22 18:14:36 +02003050 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003051 binf->arfcn |= *cur++;
3052
3053 if (binf->info_type & IPAC_BINF_RXLEV)
3054 binf->rx_lev = *cur & 0x3f;
3055 cur++;
3056
3057 if (binf->info_type & IPAC_BINF_RXQUAL)
3058 binf->rx_qual = *cur & 0x7;
3059 cur++;
3060
3061 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3062 binf->freq_err = ntohs(*(u_int16_t *)cur);
3063 cur += 2;
3064
3065 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3066 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3067 cur += 2;
3068
3069 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3070 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3071 cur += 4;
3072
Harald Weltea780a3d2010-07-30 22:34:42 +02003073#if 0
3074 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003075 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003076#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003077 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003078 cur++;
3079
Harald Welteb40a38f2009-11-13 11:56:05 +01003080 ipac_parse_cgi(&binf->cgi, cur);
3081 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003082
3083 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3084 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3085 cur += sizeof(binf->ba_list_si2);
3086 }
3087
3088 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3089 memcpy(binf->ba_list_si2bis, cur,
3090 sizeof(binf->ba_list_si2bis));
3091 cur += sizeof(binf->ba_list_si2bis);
3092 }
3093
3094 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3095 memcpy(binf->ba_list_si2ter, cur,
3096 sizeof(binf->ba_list_si2ter));
3097 cur += sizeof(binf->ba_list_si2ter);
3098 }
3099
3100 return 0;
3101}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003102
3103void abis_nm_clear_queue(struct gsm_bts *bts)
3104{
3105 struct msgb *msg;
3106
3107 while (!llist_empty(&bts->abis_queue)) {
3108 msg = msgb_dequeue(&bts->abis_queue);
3109 msgb_free(msg);
3110 }
3111
3112 bts->abis_nm_pend = 0;
3113}