blob: 788dd4de92414b8029ad20c526a2b23db718ebce [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte52b1f982008-12-23 20:25:15 +000033#include <sys/types.h>
Harald Welte4724f992009-01-18 18:01:49 +000034#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000035#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000036#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000037
Harald Welte8470bf22008-12-25 23:28:35 +000038#include <openbsc/gsm_data.h>
39#include <openbsc/debug.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010040#include <osmocore/msgb.h>
41#include <osmocore/tlv.h>
42#include <osmocore/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Harald Welte52b1f982008-12-23 20:25:15 +000046
Harald Welte8470bf22008-12-25 23:28:35 +000047#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010049#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000050
51/* unidirectional messages from BTS to BSC */
52static const enum abis_nm_msgtype reports[] = {
53 NM_MT_SW_ACTIVATED_REP,
54 NM_MT_TEST_REP,
55 NM_MT_STATECHG_EVENT_REP,
56 NM_MT_FAILURE_EVENT_REP,
57};
58
59/* messages without ACK/NACK */
60static const enum abis_nm_msgtype no_ack_nack[] = {
61 NM_MT_MEAS_RES_REQ,
62 NM_MT_STOP_MEAS,
63 NM_MT_START_MEAS,
64};
65
Harald Welte4724f992009-01-18 18:01:49 +000066/* Messages related to software load */
67static const enum abis_nm_msgtype sw_load_msgs[] = {
68 NM_MT_LOAD_INIT_ACK,
69 NM_MT_LOAD_INIT_NACK,
70 NM_MT_LOAD_SEG_ACK,
71 NM_MT_LOAD_ABORT,
72 NM_MT_LOAD_END_ACK,
73 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000074 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000075 NM_MT_ACTIVATE_SW_ACK,
76 NM_MT_ACTIVATE_SW_NACK,
77 NM_MT_SW_ACTIVATED_REP,
78};
79
Harald Weltee0590df2009-02-15 03:34:15 +000080static const enum abis_nm_msgtype nacks[] = {
81 NM_MT_LOAD_INIT_NACK,
82 NM_MT_LOAD_END_NACK,
83 NM_MT_SW_ACT_REQ_NACK,
84 NM_MT_ACTIVATE_SW_NACK,
85 NM_MT_ESTABLISH_TEI_NACK,
86 NM_MT_CONN_TERR_SIGN_NACK,
87 NM_MT_DISC_TERR_SIGN_NACK,
88 NM_MT_CONN_TERR_TRAF_NACK,
89 NM_MT_DISC_TERR_TRAF_NACK,
90 NM_MT_CONN_MDROP_LINK_NACK,
91 NM_MT_DISC_MDROP_LINK_NACK,
92 NM_MT_SET_BTS_ATTR_NACK,
93 NM_MT_SET_RADIO_ATTR_NACK,
94 NM_MT_SET_CHAN_ATTR_NACK,
95 NM_MT_PERF_TEST_NACK,
96 NM_MT_SEND_TEST_REP_NACK,
97 NM_MT_STOP_TEST_NACK,
98 NM_MT_STOP_EVENT_REP_NACK,
99 NM_MT_REST_EVENT_REP_NACK,
100 NM_MT_CHG_ADM_STATE_NACK,
101 NM_MT_CHG_ADM_STATE_REQ_NACK,
102 NM_MT_REP_OUTST_ALARMS_NACK,
103 NM_MT_CHANGEOVER_NACK,
104 NM_MT_OPSTART_NACK,
105 NM_MT_REINIT_NACK,
106 NM_MT_SET_SITE_OUT_NACK,
107 NM_MT_CHG_HW_CONF_NACK,
108 NM_MT_GET_ATTR_NACK,
109 NM_MT_SET_ALARM_THRES_NACK,
110 NM_MT_BS11_BEGIN_DB_TX_NACK,
111 NM_MT_BS11_END_DB_TX_NACK,
112 NM_MT_BS11_CREATE_OBJ_NACK,
113 NM_MT_BS11_DELETE_OBJ_NACK,
114};
Harald Welte78fc0d42009-02-19 02:50:57 +0000115
Harald Welte92b1fe42010-03-25 11:45:30 +0800116static const struct value_string nack_names[] = {
117 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
118 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
119 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
120 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
121 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
122 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
123 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
124 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
125 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
126 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
127 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
128 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
129 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
130 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
131 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
132 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
133 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
134 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
135 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
136 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
137 { NM_MT_CHG_ADM_STATE_REQ_NACK,
138 "CHANGE ADMINISTRATIVE STATE REQUEST" },
139 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
140 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
141 { NM_MT_OPSTART_NACK, "OPSTART" },
142 { NM_MT_REINIT_NACK, "REINIT" },
143 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
144 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
145 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
146 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
147 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
148 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
149 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
150 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
151 { 0, NULL }
Harald Welte78fc0d42009-02-19 02:50:57 +0000152};
153
Harald Welte6c96ba52009-05-01 13:03:40 +0000154/* Chapter 9.4.36 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800155static const struct value_string nack_cause_names[] = {
Harald Welte6c96ba52009-05-01 13:03:40 +0000156 /* General Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800157 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
158 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
159 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
160 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
161 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
162 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
163 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
164 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
165 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
166 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
167 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
168 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
169 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte6c96ba52009-05-01 13:03:40 +0000170 /* Specific Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800171 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
172 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
173 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
174 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
175 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
176 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
177 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
178 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
179 { NM_NACK_TEST_NOSUCH, "No such test" },
180 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
181 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
182 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
183 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
184 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
185 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
186 { NM_NACK_WAIT, "Wait" },
187 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
188 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
189 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
190 { 0, NULL }
Harald Welte6c96ba52009-05-01 13:03:40 +0000191};
192
Harald Welte6c96ba52009-05-01 13:03:40 +0000193static const char *nack_cause_name(u_int8_t cause)
194{
Harald Welte92b1fe42010-03-25 11:45:30 +0800195 return get_value_string(nack_cause_names, cause);
Harald Welte6c96ba52009-05-01 13:03:40 +0000196}
197
Harald Welte0db97b22009-05-01 17:22:47 +0000198/* Chapter 9.4.16: Event Type */
Harald Welte92b1fe42010-03-25 11:45:30 +0800199static const struct value_string event_type_names[] = {
200 { NM_EVT_COMM_FAIL, "communication failure" },
201 { NM_EVT_QOS_FAIL, "quality of service failure" },
202 { NM_EVT_PROC_FAIL, "processing failure" },
203 { NM_EVT_EQUIP_FAIL, "equipment failure" },
204 { NM_EVT_ENV_FAIL, "environment failure" },
205 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000206};
207
208static const char *event_type_name(u_int8_t cause)
209{
Harald Welte92b1fe42010-03-25 11:45:30 +0800210 return get_value_string(event_type_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000211}
212
213/* Chapter 9.4.63: Perceived Severity */
Harald Welte92b1fe42010-03-25 11:45:30 +0800214static const struct value_string severity_names[] = {
215 { NM_SEVER_CEASED, "failure ceased" },
216 { NM_SEVER_CRITICAL, "critical failure" },
217 { NM_SEVER_MAJOR, "major failure" },
218 { NM_SEVER_MINOR, "minor failure" },
219 { NM_SEVER_WARNING, "warning level failure" },
220 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
221 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000222};
223
224static const char *severity_name(u_int8_t cause)
225{
Harald Welte92b1fe42010-03-25 11:45:30 +0800226 return get_value_string(severity_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000227}
228
Harald Welte52b1f982008-12-23 20:25:15 +0000229/* Attributes that the BSC can set, not only get, according to Section 9.4 */
230static const enum abis_nm_attr nm_att_settable[] = {
231 NM_ATT_ADD_INFO,
232 NM_ATT_ADD_TEXT,
233 NM_ATT_DEST,
234 NM_ATT_EVENT_TYPE,
235 NM_ATT_FILE_DATA,
236 NM_ATT_GET_ARI,
237 NM_ATT_HW_CONF_CHG,
238 NM_ATT_LIST_REQ_ATTR,
239 NM_ATT_MDROP_LINK,
240 NM_ATT_MDROP_NEXT,
241 NM_ATT_NACK_CAUSES,
242 NM_ATT_OUTST_ALARM,
243 NM_ATT_PHYS_CONF,
244 NM_ATT_PROB_CAUSE,
245 NM_ATT_RAD_SUBC,
246 NM_ATT_SOURCE,
247 NM_ATT_SPEC_PROB,
248 NM_ATT_START_TIME,
249 NM_ATT_TEST_DUR,
250 NM_ATT_TEST_NO,
251 NM_ATT_TEST_REPORT,
252 NM_ATT_WINDOW_SIZE,
253 NM_ATT_SEVERITY,
254 NM_ATT_MEAS_RES,
255 NM_ATT_MEAS_TYPE,
256};
257
Harald Welte39315c42010-01-10 18:01:52 +0100258const struct tlv_definition nm_att_tlvdef = {
Harald Weltee0590df2009-02-15 03:34:15 +0000259 .def = {
260 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
261 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
262 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
264 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
265 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
266 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
267 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
268 [NM_ATT_BSIC] = { TLV_TYPE_TV },
269 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
270 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
272 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
273 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
274 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
275 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
276 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
277 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
279 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
280 [NM_ATT_HSN] = { TLV_TYPE_TV },
281 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
282 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
283 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
284 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
285 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
286 [NM_ATT_MAIO] = { TLV_TYPE_TV },
287 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
289 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
290 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
291 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
292 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
294 [NM_ATT_NY1] = { TLV_TYPE_TV },
295 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
297 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
298 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
299 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
300 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
302 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
303 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
304 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
305 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
306 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
308 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
309 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
310 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
311 [NM_ATT_TEI] = { TLV_TYPE_TV },
312 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
313 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
314 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
315 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
316 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
317 [NM_ATT_TSC] = { TLV_TYPE_TV },
318 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
319 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
320 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
321 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
322 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000323 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Weltee0590df2009-02-15 03:34:15 +0000324 },
325};
Harald Welte03133942009-02-18 19:51:53 +0000326
Harald Welte21bd3a52009-08-10 12:21:22 +0200327static const enum abis_nm_chan_comb chcomb4pchan[] = {
328 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
329 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
330 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
331 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
332 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200333 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
334 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200335 /* FIXME: bounds check */
336};
337
338int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
339{
340 if (pchan < ARRAY_SIZE(chcomb4pchan))
341 return chcomb4pchan[pchan];
342
343 return -EINVAL;
344}
345
Harald Welte39315c42010-01-10 18:01:52 +0100346int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +0000347{
Harald Welte39315c42010-01-10 18:01:52 +0100348 if (!bts->model)
349 return -EIO;
350 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000351}
Harald Weltee0590df2009-02-15 03:34:15 +0000352
Harald Welte52b1f982008-12-23 20:25:15 +0000353static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
354{
355 int i;
356
357 for (i = 0; i < size; i++) {
358 if (arr[i] == mt)
359 return 1;
360 }
361
362 return 0;
363}
364
Holger Freytherca362a62009-01-04 21:05:01 +0000365#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000366/* is this msgtype the usual ACK/NACK type ? */
367static int is_ack_nack(enum abis_nm_msgtype mt)
368{
369 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
370}
Holger Freytherca362a62009-01-04 21:05:01 +0000371#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000372
373/* is this msgtype a report ? */
374static int is_report(enum abis_nm_msgtype mt)
375{
Harald Welte8470bf22008-12-25 23:28:35 +0000376 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000377}
378
379#define MT_ACK(x) (x+1)
380#define MT_NACK(x) (x+2)
381
382static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
383{
384 oh->mdisc = ABIS_OM_MDISC_FOM;
385 oh->placement = ABIS_OM_PLACEMENT_ONLY;
386 oh->sequence = 0;
387 oh->length = len;
388}
389
390static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
391 u_int8_t msg_type, u_int8_t obj_class,
392 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
393{
394 struct abis_om_fom_hdr *foh =
395 (struct abis_om_fom_hdr *) oh->data;
396
Harald Welte702d8702008-12-26 20:25:35 +0000397 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000398 foh->msg_type = msg_type;
399 foh->obj_class = obj_class;
400 foh->obj_inst.bts_nr = bts_nr;
401 foh->obj_inst.trx_nr = trx_nr;
402 foh->obj_inst.ts_nr = ts_nr;
403}
404
Harald Welte8470bf22008-12-25 23:28:35 +0000405static struct msgb *nm_msgb_alloc(void)
406{
Harald Welte966636f2009-06-26 19:39:35 +0200407 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
408 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000409}
410
Harald Welte52b1f982008-12-23 20:25:15 +0000411/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100412static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000413{
Holger Freyther59639e82009-02-09 23:09:55 +0000414 msg->trx = bts->c0;
415
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100416 /* queue OML messages */
417 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
418 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100419 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100420 } else {
421 msgb_enqueue(&bts->abis_queue, msg);
422 return 0;
423 }
424
425}
426
427int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
428{
429 OBSC_NM_W_ACK_CB(msg) = 1;
430 return abis_nm_queue_msg(bts, msg);
431}
432
433static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
434{
435 OBSC_NM_W_ACK_CB(msg) = 0;
436 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000437}
438
Harald Welte4724f992009-01-18 18:01:49 +0000439static int abis_nm_rcvmsg_sw(struct msgb *mb);
440
Harald Welte81c9b9c2010-05-31 16:40:40 +0200441const struct value_string abis_nm_obj_class_names[] = {
442 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800443 { NM_OC_BTS, "BTS" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200444 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
445 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800446 { NM_OC_CHANNEL, "CHANNEL" },
447 { NM_OC_BS11_ADJC, "ADJC" },
448 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200449 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800450 { NM_OC_BS11_BTSE, "BTSE" },
451 { NM_OC_BS11_RACK, "RACK" },
452 { NM_OC_BS11_TEST, "TEST" },
453 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
454 { NM_OC_BS11_BPORT, "BPORT" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200455 { NM_OC_GPRS_NSE, "GPRS-NSE" },
456 { NM_OC_GPRS_CELL, "GPRS-CELL" },
457 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800458 { NM_OC_BS11, "SIEMENSHW" },
459 { 0, NULL }
460};
461
Harald Welte34a99682009-02-13 02:41:40 +0000462static const char *obj_class_name(u_int8_t oc)
463{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200464 return get_value_string(abis_nm_obj_class_names, oc);
Harald Welte34a99682009-02-13 02:41:40 +0000465}
466
Harald Welte4d87f242009-03-10 19:43:44 +0000467const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000468{
469 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100470 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000471 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100472 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000473 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100474 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000475 return "NULL";
476 default:
477 return "RFU";
478 }
479}
480
Harald Weltee0590df2009-02-15 03:34:15 +0000481/* Chapter 9.4.7 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800482static const struct value_string avail_names[] = {
483 { 0, "In test" },
484 { 1, "Failed" },
485 { 2, "Power off" },
486 { 3, "Off line" },
487 /* Not used */
488 { 5, "Dependency" },
489 { 6, "Degraded" },
490 { 7, "Not installed" },
491 { 0xff, "OK" },
492 { 0, NULL }
Harald Weltee0590df2009-02-15 03:34:15 +0000493};
494
Harald Welte4d87f242009-03-10 19:43:44 +0000495const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000496{
Harald Welte92b1fe42010-03-25 11:45:30 +0800497 return get_value_string(avail_names, avail);
Harald Weltee0590df2009-02-15 03:34:15 +0000498}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000499
Harald Welte0f255852009-11-12 14:48:42 +0100500static struct value_string test_names[] = {
501 /* FIXME: standard test names */
502 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
503 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
504 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
505 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
506 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
507 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
508 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
509 { 0, NULL }
510};
511
Harald Welte81c9b9c2010-05-31 16:40:40 +0200512const struct value_string abis_nm_adm_state_names[] = {
513 { NM_STATE_LOCKED, "Locked" },
514 { NM_STATE_UNLOCKED, "Unlocked" },
515 { NM_STATE_SHUTDOWN, "Shutdown" },
516 { NM_STATE_NULL, "NULL" },
517 { 0, NULL }
518};
519
Harald Welte7b26bcb2009-05-28 11:39:21 +0000520const char *nm_adm_name(u_int8_t adm)
521{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200522 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte7b26bcb2009-05-28 11:39:21 +0000523}
Harald Weltee0590df2009-02-15 03:34:15 +0000524
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100525int nm_is_running(struct gsm_nm_state *s) {
526 return (s->operational == NM_OPSTATE_ENABLED) && (
527 (s->availability == NM_AVSTATE_OK) ||
528 (s->availability == 0xff)
529 );
530}
531
Harald Weltea8bd6d42009-10-20 09:56:18 +0200532static void debugp_foh(struct abis_om_fom_hdr *foh)
533{
534 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200535 obj_class_name(foh->obj_class), foh->obj_class,
Harald Weltea8bd6d42009-10-20 09:56:18 +0200536 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
537 foh->obj_inst.ts_nr);
538}
539
Harald Weltee0590df2009-02-15 03:34:15 +0000540/* obtain the gsm_nm_state data structure for a given object instance */
541static struct gsm_nm_state *
542objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
543 struct abis_om_obj_inst *obj_inst)
544{
545 struct gsm_bts_trx *trx;
546 struct gsm_nm_state *nm_state = NULL;
547
548 switch (obj_class) {
549 case NM_OC_BTS:
550 nm_state = &bts->nm_state;
551 break;
552 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100553 if (obj_inst->trx_nr >= bts->num_trx) {
554 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000555 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100556 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200557 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000558 nm_state = &trx->nm_state;
559 break;
560 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100561 if (obj_inst->trx_nr >= bts->num_trx) {
562 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000563 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100564 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200565 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000566 nm_state = &trx->bb_transc.nm_state;
567 break;
568 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100569 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100570 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000571 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100572 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200573 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000574 if (obj_inst->ts_nr >= TRX_NR_TS)
575 return NULL;
576 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
577 break;
578 case NM_OC_SITE_MANAGER:
579 nm_state = &bts->site_mgr.nm_state;
580 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000581 case NM_OC_BS11:
582 switch (obj_inst->bts_nr) {
583 case BS11_OBJ_CCLK:
584 nm_state = &bts->bs11.cclk.nm_state;
585 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000586 case BS11_OBJ_BBSIG:
587 if (obj_inst->ts_nr > bts->num_trx)
588 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200589 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000590 nm_state = &trx->bs11.bbsig.nm_state;
591 break;
592 case BS11_OBJ_PA:
593 if (obj_inst->ts_nr > bts->num_trx)
594 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200595 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000596 nm_state = &trx->bs11.pa.nm_state;
597 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000598 default:
599 return NULL;
600 }
601 case NM_OC_BS11_RACK:
602 nm_state = &bts->bs11.rack.nm_state;
603 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000604 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100605 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000606 return NULL;
607 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
608 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200609 case NM_OC_GPRS_NSE:
610 nm_state = &bts->gprs.nse.nm_state;
611 break;
612 case NM_OC_GPRS_CELL:
613 nm_state = &bts->gprs.cell.nm_state;
614 break;
615 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100616 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200617 return NULL;
618 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
619 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000620 }
621 return nm_state;
622}
623
624/* obtain the in-memory data structure of a given object instance */
625static void *
626objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
627 struct abis_om_obj_inst *obj_inst)
628{
629 struct gsm_bts_trx *trx;
630 void *obj = NULL;
631
632 switch (obj_class) {
633 case NM_OC_BTS:
634 obj = bts;
635 break;
636 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100637 if (obj_inst->trx_nr >= bts->num_trx) {
638 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000639 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100640 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200641 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000642 obj = trx;
643 break;
644 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100645 if (obj_inst->trx_nr >= bts->num_trx) {
646 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000647 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100648 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200649 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000650 obj = &trx->bb_transc;
651 break;
652 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100653 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100654 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000655 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100656 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200657 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000658 if (obj_inst->ts_nr >= TRX_NR_TS)
659 return NULL;
660 obj = &trx->ts[obj_inst->ts_nr];
661 break;
662 case NM_OC_SITE_MANAGER:
663 obj = &bts->site_mgr;
664 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200665 case NM_OC_GPRS_NSE:
666 obj = &bts->gprs.nse;
667 break;
668 case NM_OC_GPRS_CELL:
669 obj = &bts->gprs.cell;
670 break;
671 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100672 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200673 return NULL;
674 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
675 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000676 }
677 return obj;
678}
679
680/* Update the administrative state of a given object in our in-memory data
681 * structures and send an event to the higher layer */
682static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
683 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
684{
Harald Welteaeedeb42009-05-01 13:08:14 +0000685 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100686 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000687
Harald Welteaf9b8102011-03-06 21:20:38 +0100688 memset(&nsd, 0, sizeof(nsd));
689
Harald Weltef338a032011-01-14 15:55:42 +0100690 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
691 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100692 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000693 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
694 if (!nm_state)
695 return -1;
696
697 new_state = *nm_state;
698 new_state.administrative = adm_state;
699
Harald Weltef338a032011-01-14 15:55:42 +0100700 nsd.obj_class = obj_class;
701 nsd.old_state = nm_state;
702 nsd.new_state = &new_state;
703 nsd.obj_inst = obj_inst;
704 dispatch_signal(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000705
706 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000707
Harald Weltef338a032011-01-14 15:55:42 +0100708 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000709}
710
Harald Welte97ed1e72009-02-06 13:38:02 +0000711static int abis_nm_rx_statechg_rep(struct msgb *mb)
712{
Harald Weltee0590df2009-02-15 03:34:15 +0000713 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000714 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000715 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000716 struct tlv_parsed tp;
717 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000718
Harald Welte23897662009-05-01 14:52:51 +0000719 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000720
Harald Welte8b697c72009-06-05 19:18:45 +0000721 memset(&new_state, 0, sizeof(new_state));
722
Harald Weltee0590df2009-02-15 03:34:15 +0000723 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
724 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100725 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000726 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000727 }
Harald Weltee0590df2009-02-15 03:34:15 +0000728
729 new_state = *nm_state;
730
Harald Welte39315c42010-01-10 18:01:52 +0100731 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000732 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
733 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000734 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000735 }
736 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000737 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
738 new_state.availability = 0xff;
739 else
740 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000741 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000742 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100743 } else
744 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000745 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
746 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200747 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000748 }
749 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000750
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100751 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
752 new_state.operational != nm_state->operational ||
753 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000754 /* Update the operational state of a given object in our in-memory data
755 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100756 struct nm_statechg_signal_data nsd;
757 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
758 nsd.obj_class = foh->obj_class;
759 nsd.old_state = nm_state;
760 nsd.new_state = &new_state;
761 nsd.obj_inst = &foh->obj_inst;
762 dispatch_signal(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100763 nm_state->operational = new_state.operational;
764 nm_state->availability = new_state.availability;
765 if (nm_state->administrative == 0)
766 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000767 }
768#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000769 if (op_state == 1) {
770 /* try to enable objects that are disabled */
771 abis_nm_opstart(bts, foh->obj_class,
772 foh->obj_inst.bts_nr,
773 foh->obj_inst.trx_nr,
774 foh->obj_inst.ts_nr);
775 }
Harald Weltee0590df2009-02-15 03:34:15 +0000776#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000777 return 0;
778}
779
Harald Welte0db97b22009-05-01 17:22:47 +0000780static int rx_fail_evt_rep(struct msgb *mb)
781{
782 struct abis_om_hdr *oh = msgb_l2(mb);
783 struct abis_om_fom_hdr *foh = msgb_l3(mb);
784 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100785 const uint8_t *p_val;
786 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000787
788 DEBUGPC(DNM, "Failure Event Report ");
789
Harald Welte39315c42010-01-10 18:01:52 +0100790 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000791
792 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
793 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
794 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
795 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100796 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
797 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
798 DEBUGPC(DNM, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
799 }
800 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
801 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
802 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
803 if (p_text) {
804 DEBUGPC(DNM, "Additional Text=%s ", p_text);
805 talloc_free(p_text);
806 }
807 }
Harald Welte0db97b22009-05-01 17:22:47 +0000808
809 DEBUGPC(DNM, "\n");
810
811 return 0;
812}
813
Harald Welte97ed1e72009-02-06 13:38:02 +0000814static int abis_nm_rcvmsg_report(struct msgb *mb)
815{
816 struct abis_om_fom_hdr *foh = msgb_l3(mb);
817 u_int8_t mt = foh->msg_type;
818
Harald Weltea8bd6d42009-10-20 09:56:18 +0200819 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000820
Harald Welte97ed1e72009-02-06 13:38:02 +0000821 //nmh->cfg->report_cb(mb, foh);
822
823 switch (mt) {
824 case NM_MT_STATECHG_EVENT_REP:
825 return abis_nm_rx_statechg_rep(mb);
826 break;
Harald Welte34a99682009-02-13 02:41:40 +0000827 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000828 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000829 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000830 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000831 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000832 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000833 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000834 break;
Harald Weltec7310382009-08-08 00:02:36 +0200835 case NM_MT_TEST_REP:
836 DEBUGPC(DNM, "Test Report\n");
837 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
838 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000839 default:
Harald Welte23897662009-05-01 14:52:51 +0000840 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000841 break;
842
Harald Welte97ed1e72009-02-06 13:38:02 +0000843 };
844
Harald Welte97ed1e72009-02-06 13:38:02 +0000845 return 0;
846}
847
Harald Welte34a99682009-02-13 02:41:40 +0000848/* Activate the specified software into the BTS */
849static 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 +0200850 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000851{
852 struct abis_om_hdr *oh;
853 struct msgb *msg = nm_msgb_alloc();
854 u_int8_t len = swdesc_len;
855 u_int8_t *trailer;
856
857 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
858 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
859
860 trailer = msgb_put(msg, swdesc_len);
861 memcpy(trailer, sw_desc, swdesc_len);
862
863 return abis_nm_sendmsg(bts, msg);
864}
865
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100866static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
867{
868 static const struct tlv_definition sw_descr_def = {
869 .def = {
870 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
871 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
872 },
873 };
874
875 u_int8_t tag;
876 u_int16_t tag_len;
877 const u_int8_t *val;
878 int ofs = 0, len;
879
880 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
881 * nested nature and the fact you have to assume it contains only two sub
882 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
883
884 if (sw_descr[0] != NM_ATT_SW_DESCR) {
885 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
886 return -1;
887 }
888 ofs += 1;
889
890 len = tlv_parse_one(&tag, &tag_len, &val,
891 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
892 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
893 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
894 return -2;
895 }
896 ofs += len;
897
898 len = tlv_parse_one(&tag, &tag_len, &val,
899 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
900 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
901 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
902 return -3;
903 }
904 ofs += len;
905
906 return ofs;
907}
908
Harald Welte34a99682009-02-13 02:41:40 +0000909static int abis_nm_rx_sw_act_req(struct msgb *mb)
910{
911 struct abis_om_hdr *oh = msgb_l2(mb);
912 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200913 struct tlv_parsed tp;
914 const u_int8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100915 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000916
Harald Weltea8bd6d42009-10-20 09:56:18 +0200917 debugp_foh(foh);
918
919 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000920
Harald Welte97a282b2010-03-14 15:37:43 +0800921 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000922
923 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000924 foh->obj_inst.bts_nr,
925 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800926 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000927 foh->data, oh->length-sizeof(*foh));
928
Harald Welte39315c42010-01-10 18:01:52 +0100929 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200930 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
931 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
932 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
933 DEBUGP(DNM, "SW config not found! Can't continue.\n");
934 return -EINVAL;
935 } else {
936 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
937 }
938
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100939 /* Use the first SW_DESCR present in SW config */
940 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
941 if (sw_descr_len < 0)
942 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200943
Harald Welte34a99682009-02-13 02:41:40 +0000944 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
945 foh->obj_inst.bts_nr,
946 foh->obj_inst.trx_nr,
947 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100948 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000949}
950
Harald Weltee0590df2009-02-15 03:34:15 +0000951/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
952static int abis_nm_rx_chg_adm_state_ack(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 u_int8_t adm_state;
958
Harald Welte39315c42010-01-10 18:01:52 +0100959 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000960 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
961 return -EINVAL;
962
963 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
964
965 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
966}
967
Harald Welteee670472009-02-22 21:58:49 +0000968static int abis_nm_rx_lmt_event(struct msgb *mb)
969{
970 struct abis_om_hdr *oh = msgb_l2(mb);
971 struct abis_om_fom_hdr *foh = msgb_l3(mb);
972 struct tlv_parsed tp;
973
974 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100975 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000976 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
977 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
978 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
979 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
980 }
981 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
982 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
983 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
984 DEBUGPC(DNM, "Level=%u ", level);
985 }
986 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
987 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
988 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
989 DEBUGPC(DNM, "Username=%s ", name);
990 }
991 DEBUGPC(DNM, "\n");
992 /* FIXME: parse LMT LOGON TIME */
993 return 0;
994}
995
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100996static void abis_nm_queue_send_next(struct gsm_bts *bts)
997{
998 int wait = 0;
999 struct msgb *msg;
1000 /* the queue is empty */
1001 while (!llist_empty(&bts->abis_queue)) {
1002 msg = msgb_dequeue(&bts->abis_queue);
1003 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +01001004 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001005
1006 if (wait)
1007 break;
1008 }
1009
1010 bts->abis_nm_pend = wait;
1011}
1012
Harald Welte52b1f982008-12-23 20:25:15 +00001013/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001014static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001015{
Harald Welte6c96ba52009-05-01 13:03:40 +00001016 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001017 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1018 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001019 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001020
1021 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001022 if (is_report(mt))
1023 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001024
Harald Welte4724f992009-01-18 18:01:49 +00001025 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1026 return abis_nm_rcvmsg_sw(mb);
1027
Harald Welte78fc0d42009-02-19 02:50:57 +00001028 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001029 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +00001030 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001031
Harald Weltea8bd6d42009-10-20 09:56:18 +02001032 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001033
Harald Welte92b1fe42010-03-25 11:45:30 +08001034 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +00001035
Harald Welte39315c42010-01-10 18:01:52 +01001036 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +00001037 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001038 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00001039 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1040 else
1041 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001042
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001043 nack_data.msg = mb;
1044 nack_data.mt = mt;
1045 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001046 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001047 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001048 }
Harald Weltead384642008-12-26 10:20:07 +00001049#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001050 /* check if last message is to be acked */
1051 if (is_ack_nack(nmh->last_msgtype)) {
1052 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001053 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001054 /* we got our ACK, continue sending the next msg */
1055 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1056 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001057 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001058 /* FIXME: somehow signal this to the caller */
1059 } else {
1060 /* really strange things happen */
1061 return -EINVAL;
1062 }
1063 }
Harald Weltead384642008-12-26 10:20:07 +00001064#endif
1065
Harald Welte97ed1e72009-02-06 13:38:02 +00001066 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001067 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001068 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +00001069 break;
Harald Welte34a99682009-02-13 02:41:40 +00001070 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001071 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +00001072 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001073 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001074 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001075 break;
Harald Welte1989c082009-08-06 17:58:31 +02001076 case NM_MT_CONN_MDROP_LINK_ACK:
1077 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1078 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001079 case NM_MT_IPACC_RESTART_ACK:
1080 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1081 break;
1082 case NM_MT_IPACC_RESTART_NACK:
1083 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1084 break;
Harald Weltefd355a32011-03-04 13:41:31 +01001085 case NM_MT_SET_BTS_ATTR_ACK:
1086 /* The HSL wants an OPSTART _after_ the SI has been set */
1087 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
1088 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
1089 }
1090 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001091 }
1092
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001093 abis_nm_queue_send_next(mb->trx->bts);
1094 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001095}
1096
Harald Welte677c21f2009-02-17 13:22:23 +00001097static int abis_nm_rx_ipacc(struct msgb *mb);
1098
1099static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1100{
1101 int rc;
1102 int bts_type = mb->trx->bts->type;
1103
1104 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001105 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001106 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001107 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +00001108 break;
1109 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001110 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1111 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001112 rc = 0;
1113 break;
1114 }
1115
1116 return rc;
1117}
1118
Harald Welte52b1f982008-12-23 20:25:15 +00001119/* High-Level API */
1120/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001121int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001122{
Harald Welte52b1f982008-12-23 20:25:15 +00001123 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001124 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001125
1126 /* Various consistency checks */
1127 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001128 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001129 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001130 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1131 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001132 }
1133 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001134 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001135 oh->sequence);
1136 return -EINVAL;
1137 }
Harald Welte702d8702008-12-26 20:25:35 +00001138#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001139 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1140 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001141 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001142 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001143 oh->length + sizeof(*oh), l2_len);
1144 return -EINVAL;
1145 }
Harald Welte702d8702008-12-26 20:25:35 +00001146 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001147 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 +00001148#endif
Harald Weltead384642008-12-26 10:20:07 +00001149 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001150
1151 switch (oh->mdisc) {
1152 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001153 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001154 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001155 case ABIS_OM_MDISC_MANUF:
1156 rc = abis_nm_rcvmsg_manuf(msg);
1157 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001158 case ABIS_OM_MDISC_MMI:
1159 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001160 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001161 oh->mdisc);
1162 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001163 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001164 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001165 oh->mdisc);
1166 return -EINVAL;
1167 }
1168
Harald Weltead384642008-12-26 10:20:07 +00001169 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001170 return rc;
1171}
1172
1173#if 0
1174/* initialized all resources */
1175struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1176{
1177 struct abis_nm_h *nmh;
1178
1179 nmh = malloc(sizeof(*nmh));
1180 if (!nmh)
1181 return NULL;
1182
1183 nmh->cfg = cfg;
1184
1185 return nmh;
1186}
1187
1188/* free all resources */
1189void abis_nm_fini(struct abis_nm_h *nmh)
1190{
1191 free(nmh);
1192}
1193#endif
1194
1195/* Here we are trying to define a high-level API that can be used by
1196 * the actual BSC implementation. However, the architecture is currently
1197 * still under design. Ideally the calls to this API would be synchronous,
1198 * while the underlying stack behind the APi runs in a traditional select
1199 * based state machine.
1200 */
1201
Harald Welte4724f992009-01-18 18:01:49 +00001202/* 6.2 Software Load: */
1203enum sw_state {
1204 SW_STATE_NONE,
1205 SW_STATE_WAIT_INITACK,
1206 SW_STATE_WAIT_SEGACK,
1207 SW_STATE_WAIT_ENDACK,
1208 SW_STATE_WAIT_ACTACK,
1209 SW_STATE_ERROR,
1210};
Harald Welte52b1f982008-12-23 20:25:15 +00001211
Harald Welte52b1f982008-12-23 20:25:15 +00001212struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001213 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001214 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001215 gsm_cbfn *cbfn;
1216 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001217 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001218
Harald Welte52b1f982008-12-23 20:25:15 +00001219 /* this will become part of the SW LOAD INITIATE */
1220 u_int8_t obj_class;
1221 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001222
1223 u_int8_t file_id[255];
1224 u_int8_t file_id_len;
1225
1226 u_int8_t file_version[255];
1227 u_int8_t file_version_len;
1228
1229 u_int8_t window_size;
1230 u_int8_t seg_in_window;
1231
1232 int fd;
1233 FILE *stream;
1234 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001235 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001236};
1237
Harald Welte4724f992009-01-18 18:01:49 +00001238static struct abis_nm_sw g_sw;
1239
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001240static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1241{
1242 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1243 msgb_v_put(msg, NM_ATT_SW_DESCR);
1244 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1245 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1246 sw->file_version);
1247 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1248 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1249 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1250 sw->file_version);
1251 } else {
1252 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1253 }
1254}
1255
Harald Welte4724f992009-01-18 18:01:49 +00001256/* 6.2.1 / 8.3.1: Load Data Initiate */
1257static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001258{
Harald Welte4724f992009-01-18 18:01:49 +00001259 struct abis_om_hdr *oh;
1260 struct msgb *msg = nm_msgb_alloc();
1261 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1262
1263 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1264 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1265 sw->obj_instance[0], sw->obj_instance[1],
1266 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001267
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001268 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001269 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1270
1271 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001272}
1273
Harald Welte1602ade2009-01-29 21:12:39 +00001274static int is_last_line(FILE *stream)
1275{
1276 char next_seg_buf[256];
1277 long pos;
1278
1279 /* check if we're sending the last line */
1280 pos = ftell(stream);
1281 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1282 fseek(stream, pos, SEEK_SET);
1283 return 1;
1284 }
1285
1286 fseek(stream, pos, SEEK_SET);
1287 return 0;
1288}
1289
Harald Welte4724f992009-01-18 18:01:49 +00001290/* 6.2.2 / 8.3.2 Load Data Segment */
1291static int sw_load_segment(struct abis_nm_sw *sw)
1292{
1293 struct abis_om_hdr *oh;
1294 struct msgb *msg = nm_msgb_alloc();
1295 char seg_buf[256];
1296 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001297 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001298 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001299
1300 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001301
1302 switch (sw->bts->type) {
1303 case GSM_BTS_TYPE_BS11:
1304 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1305 perror("fgets reading segment");
1306 return -EINVAL;
1307 }
1308 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001309
1310 /* check if we're sending the last line */
1311 sw->last_seg = is_last_line(sw->stream);
1312 if (sw->last_seg)
1313 seg_buf[1] = 0;
1314 else
1315 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001316
1317 len = strlen(line_buf) + 2;
1318 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1319 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1320 /* BS11 wants CR + LF in excess of the TLV length !?! */
1321 tlv[1] -= 2;
1322
1323 /* we only now know the exact length for the OM hdr */
1324 len = strlen(line_buf)+2;
1325 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001326 case GSM_BTS_TYPE_NANOBTS: {
1327 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1328 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1329 if (len < 0) {
1330 perror("read failed");
1331 return -EINVAL;
1332 }
1333
1334 if (len != IPACC_SEGMENT_SIZE)
1335 sw->last_seg = 1;
1336
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001337 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001338 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1339 len += 3;
1340 break;
1341 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001342 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001343 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001344 /* FIXME: Other BTS types */
1345 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001346 }
Harald Welte4724f992009-01-18 18:01:49 +00001347
Harald Welte4724f992009-01-18 18:01:49 +00001348 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1349 sw->obj_instance[0], sw->obj_instance[1],
1350 sw->obj_instance[2]);
1351
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001352 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001353}
1354
1355/* 6.2.4 / 8.3.4 Load Data End */
1356static int sw_load_end(struct abis_nm_sw *sw)
1357{
1358 struct abis_om_hdr *oh;
1359 struct msgb *msg = nm_msgb_alloc();
1360 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1361
1362 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1363 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1364 sw->obj_instance[0], sw->obj_instance[1],
1365 sw->obj_instance[2]);
1366
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001367 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001368 return abis_nm_sendmsg(sw->bts, msg);
1369}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001370
Harald Welte52b1f982008-12-23 20:25:15 +00001371/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001372static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001373{
Harald Welte4724f992009-01-18 18:01:49 +00001374 struct abis_om_hdr *oh;
1375 struct msgb *msg = nm_msgb_alloc();
1376 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001377
Harald Welte4724f992009-01-18 18:01:49 +00001378 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1379 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1380 sw->obj_instance[0], sw->obj_instance[1],
1381 sw->obj_instance[2]);
1382
1383 /* FIXME: this is BS11 specific format */
1384 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1385 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1386 sw->file_version);
1387
1388 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001389}
Harald Welte4724f992009-01-18 18:01:49 +00001390
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001391struct sdp_firmware {
1392 char magic[4];
1393 char more_magic[4];
1394 unsigned int header_length;
1395 unsigned int file_length;
1396} __attribute__ ((packed));
1397
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001398static int parse_sdp_header(struct abis_nm_sw *sw)
1399{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001400 struct sdp_firmware firmware_header;
1401 int rc;
1402 struct stat stat;
1403
1404 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1405 if (rc != sizeof(firmware_header)) {
1406 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1407 return -1;
1408 }
1409
1410 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1411 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1412 return -1;
1413 }
1414
1415 if (firmware_header.more_magic[0] != 0x10 ||
1416 firmware_header.more_magic[1] != 0x02 ||
1417 firmware_header.more_magic[2] != 0x00 ||
1418 firmware_header.more_magic[3] != 0x00) {
1419 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1420 return -1;
1421 }
1422
1423
1424 if (fstat(sw->fd, &stat) == -1) {
1425 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1426 return -1;
1427 }
1428
1429 if (ntohl(firmware_header.file_length) != stat.st_size) {
1430 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1431 return -1;
1432 }
1433
1434 /* go back to the start as we checked the whole filesize.. */
1435 lseek(sw->fd, 0l, SEEK_SET);
1436 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1437 "There might be checksums in the file that are not\n"
1438 "verified and incomplete firmware might be flashed.\n"
1439 "There is absolutely no WARRANTY that flashing will\n"
1440 "work.\n");
1441 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001442}
1443
Harald Welte4724f992009-01-18 18:01:49 +00001444static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1445{
1446 char file_id[12+1];
1447 char file_version[80+1];
1448 int rc;
1449
1450 sw->fd = open(fname, O_RDONLY);
1451 if (sw->fd < 0)
1452 return sw->fd;
1453
1454 switch (sw->bts->type) {
1455 case GSM_BTS_TYPE_BS11:
1456 sw->stream = fdopen(sw->fd, "r");
1457 if (!sw->stream) {
1458 perror("fdopen");
1459 return -1;
1460 }
1461 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001462 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001463 file_id, file_version);
1464 if (rc != 2) {
1465 perror("parsing header line of software file");
1466 return -1;
1467 }
1468 strcpy((char *)sw->file_id, file_id);
1469 sw->file_id_len = strlen(file_id);
1470 strcpy((char *)sw->file_version, file_version);
1471 sw->file_version_len = strlen(file_version);
1472 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001473 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001474 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001475 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001476 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001477 rc = parse_sdp_header(sw);
1478 if (rc < 0) {
1479 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1480 return -1;
1481 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001482
1483 strcpy((char *)sw->file_id, "id");
1484 sw->file_id_len = 3;
1485 strcpy((char *)sw->file_version, "version");
1486 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001487 break;
Harald Welte4724f992009-01-18 18:01:49 +00001488 default:
1489 /* We don't know how to treat them yet */
1490 close(sw->fd);
1491 return -EINVAL;
1492 }
1493
1494 return 0;
1495}
1496
1497static void sw_close_file(struct abis_nm_sw *sw)
1498{
1499 switch (sw->bts->type) {
1500 case GSM_BTS_TYPE_BS11:
1501 fclose(sw->stream);
1502 break;
1503 default:
1504 close(sw->fd);
1505 break;
1506 }
1507}
1508
1509/* Fill the window */
1510static int sw_fill_window(struct abis_nm_sw *sw)
1511{
1512 int rc;
1513
1514 while (sw->seg_in_window < sw->window_size) {
1515 rc = sw_load_segment(sw);
1516 if (rc < 0)
1517 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001518 if (sw->last_seg)
1519 break;
Harald Welte4724f992009-01-18 18:01:49 +00001520 }
1521 return 0;
1522}
1523
1524/* callback function from abis_nm_rcvmsg() handler */
1525static int abis_nm_rcvmsg_sw(struct msgb *mb)
1526{
1527 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1528 int rc = -1;
1529 struct abis_nm_sw *sw = &g_sw;
1530 enum sw_state old_state = sw->state;
1531
Harald Welte3ffd1372009-02-01 22:15:49 +00001532 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001533
1534 switch (sw->state) {
1535 case SW_STATE_WAIT_INITACK:
1536 switch (foh->msg_type) {
1537 case NM_MT_LOAD_INIT_ACK:
1538 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001539 if (sw->cbfn)
1540 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1541 NM_MT_LOAD_INIT_ACK, mb,
1542 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001543 rc = sw_fill_window(sw);
1544 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001545 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001546 break;
1547 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001548 if (sw->forced) {
1549 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1550 "Init NACK\n");
1551 if (sw->cbfn)
1552 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1553 NM_MT_LOAD_INIT_ACK, mb,
1554 sw->cb_data, NULL);
1555 rc = sw_fill_window(sw);
1556 sw->state = SW_STATE_WAIT_SEGACK;
1557 } else {
1558 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001559 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001560 if (sw->cbfn)
1561 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1562 NM_MT_LOAD_INIT_NACK, mb,
1563 sw->cb_data, NULL);
1564 sw->state = SW_STATE_ERROR;
1565 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001566 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001567 break;
1568 }
1569 break;
1570 case SW_STATE_WAIT_SEGACK:
1571 switch (foh->msg_type) {
1572 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001573 if (sw->cbfn)
1574 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1575 NM_MT_LOAD_SEG_ACK, mb,
1576 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001577 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001578 if (!sw->last_seg) {
1579 /* fill window with more segments */
1580 rc = sw_fill_window(sw);
1581 sw->state = SW_STATE_WAIT_SEGACK;
1582 } else {
1583 /* end the transfer */
1584 sw->state = SW_STATE_WAIT_ENDACK;
1585 rc = sw_load_end(sw);
1586 }
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;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001589 case NM_MT_LOAD_ABORT:
1590 if (sw->cbfn)
1591 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1592 NM_MT_LOAD_ABORT, mb,
1593 sw->cb_data, NULL);
1594 break;
Harald Welte4724f992009-01-18 18:01:49 +00001595 }
1596 break;
1597 case SW_STATE_WAIT_ENDACK:
1598 switch (foh->msg_type) {
1599 case NM_MT_LOAD_END_ACK:
1600 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001601 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1602 sw->bts->nr);
1603 sw->state = SW_STATE_NONE;
1604 if (sw->cbfn)
1605 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1606 NM_MT_LOAD_END_ACK, mb,
1607 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001608 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001609 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001610 break;
1611 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001612 if (sw->forced) {
1613 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1614 "End NACK\n");
1615 sw->state = SW_STATE_NONE;
1616 if (sw->cbfn)
1617 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1618 NM_MT_LOAD_END_ACK, mb,
1619 sw->cb_data, NULL);
1620 } else {
1621 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001622 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001623 sw->state = SW_STATE_ERROR;
1624 if (sw->cbfn)
1625 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1626 NM_MT_LOAD_END_NACK, mb,
1627 sw->cb_data, NULL);
1628 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001629 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001630 break;
1631 }
1632 case SW_STATE_WAIT_ACTACK:
1633 switch (foh->msg_type) {
1634 case NM_MT_ACTIVATE_SW_ACK:
1635 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001636 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001637 sw->state = SW_STATE_NONE;
1638 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001639 if (sw->cbfn)
1640 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1641 NM_MT_ACTIVATE_SW_ACK, mb,
1642 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001643 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001644 break;
1645 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001646 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001647 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001648 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001649 if (sw->cbfn)
1650 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1651 NM_MT_ACTIVATE_SW_NACK, mb,
1652 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001653 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001654 break;
1655 }
1656 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001657 switch (foh->msg_type) {
1658 case NM_MT_ACTIVATE_SW_ACK:
1659 rc = 0;
1660 break;
1661 }
1662 break;
Harald Welte4724f992009-01-18 18:01:49 +00001663 case SW_STATE_ERROR:
1664 break;
1665 }
1666
1667 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001668 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001669 foh->msg_type, old_state, sw->state);
1670
1671 return rc;
1672}
1673
1674/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001675int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001676 u_int8_t win_size, int forced,
1677 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001678{
1679 struct abis_nm_sw *sw = &g_sw;
1680 int rc;
1681
Harald Welte5e4d1b32009-02-01 13:36:56 +00001682 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1683 bts->nr, fname);
1684
Harald Welte4724f992009-01-18 18:01:49 +00001685 if (sw->state != SW_STATE_NONE)
1686 return -EBUSY;
1687
1688 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001689 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001690
1691 switch (bts->type) {
1692 case GSM_BTS_TYPE_BS11:
1693 sw->obj_class = NM_OC_SITE_MANAGER;
1694 sw->obj_instance[0] = 0xff;
1695 sw->obj_instance[1] = 0xff;
1696 sw->obj_instance[2] = 0xff;
1697 break;
1698 case GSM_BTS_TYPE_NANOBTS:
1699 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001700 sw->obj_instance[0] = sw->bts->nr;
1701 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001702 sw->obj_instance[2] = 0xff;
1703 break;
1704 case GSM_BTS_TYPE_UNKNOWN:
1705 default:
1706 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1707 return -1;
1708 break;
1709 }
Harald Welte4724f992009-01-18 18:01:49 +00001710 sw->window_size = win_size;
1711 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001712 sw->cbfn = cbfn;
1713 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001714 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001715
1716 rc = sw_open_file(sw, fname);
1717 if (rc < 0) {
1718 sw->state = SW_STATE_NONE;
1719 return rc;
1720 }
1721
1722 return sw_load_init(sw);
1723}
Harald Welte52b1f982008-12-23 20:25:15 +00001724
Harald Welte1602ade2009-01-29 21:12:39 +00001725int abis_nm_software_load_status(struct gsm_bts *bts)
1726{
1727 struct abis_nm_sw *sw = &g_sw;
1728 struct stat st;
1729 int rc, percent;
1730
1731 rc = fstat(sw->fd, &st);
1732 if (rc < 0) {
1733 perror("ERROR during stat");
1734 return rc;
1735 }
1736
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001737 if (sw->stream)
1738 percent = (ftell(sw->stream) * 100) / st.st_size;
1739 else
1740 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001741 return percent;
1742}
1743
Harald Welte5e4d1b32009-02-01 13:36:56 +00001744/* Activate the specified software into the BTS */
1745int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1746 gsm_cbfn *cbfn, void *cb_data)
1747{
1748 struct abis_nm_sw *sw = &g_sw;
1749 int rc;
1750
1751 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1752 bts->nr, fname);
1753
1754 if (sw->state != SW_STATE_NONE)
1755 return -EBUSY;
1756
1757 sw->bts = bts;
1758 sw->obj_class = NM_OC_SITE_MANAGER;
1759 sw->obj_instance[0] = 0xff;
1760 sw->obj_instance[1] = 0xff;
1761 sw->obj_instance[2] = 0xff;
1762 sw->state = SW_STATE_WAIT_ACTACK;
1763 sw->cbfn = cbfn;
1764 sw->cb_data = cb_data;
1765
1766 /* Open the file in order to fill some sw struct members */
1767 rc = sw_open_file(sw, fname);
1768 if (rc < 0) {
1769 sw->state = SW_STATE_NONE;
1770 return rc;
1771 }
1772 sw_close_file(sw);
1773
1774 return sw_activate(sw);
1775}
1776
Harald Welte8470bf22008-12-25 23:28:35 +00001777static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001778 u_int8_t ts_nr, u_int8_t subslot_nr)
1779{
Harald Welteadaf08b2009-01-18 11:08:10 +00001780 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001781 ch->bts_port = bts_port;
1782 ch->timeslot = ts_nr;
1783 ch->subslot = subslot_nr;
1784}
1785
1786int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1787 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1788 u_int8_t tei)
1789{
1790 struct abis_om_hdr *oh;
1791 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001792 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001793 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001794
1795 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1796 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1797 bts->bts_nr, trx_nr, 0xff);
1798
Harald Welte8470bf22008-12-25 23:28:35 +00001799 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001800
1801 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1802 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1803
1804 return abis_nm_sendmsg(bts, msg);
1805}
1806
1807/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1808int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1809 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1810{
Harald Welte8470bf22008-12-25 23:28:35 +00001811 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001812 struct abis_om_hdr *oh;
1813 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001814 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001815
1816 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001817 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001818 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1819
1820 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1821 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1822
1823 return abis_nm_sendmsg(bts, msg);
1824}
1825
1826#if 0
1827int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1828 struct abis_nm_abis_channel *chan)
1829{
1830}
1831#endif
1832
1833int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1834 u_int8_t e1_port, u_int8_t e1_timeslot,
1835 u_int8_t e1_subslot)
1836{
1837 struct gsm_bts *bts = ts->trx->bts;
1838 struct abis_om_hdr *oh;
1839 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001840 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001841
1842 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1843 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001844 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001845
1846 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1847 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1848
Harald Weltef325eb42009-02-19 17:07:39 +00001849 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1850 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001851 e1_port, e1_timeslot, e1_subslot);
1852
Harald Welte52b1f982008-12-23 20:25:15 +00001853 return abis_nm_sendmsg(bts, msg);
1854}
1855
1856#if 0
1857int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1858 struct abis_nm_abis_channel *chan,
1859 u_int8_t subchan)
1860{
1861}
1862#endif
1863
Harald Welte22af0db2009-02-14 15:41:08 +00001864/* Chapter 8.6.1 */
1865int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1866{
1867 struct abis_om_hdr *oh;
1868 struct msgb *msg = nm_msgb_alloc();
1869 u_int8_t *cur;
1870
1871 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1872
1873 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001874 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 +00001875 cur = msgb_put(msg, attr_len);
1876 memcpy(cur, attr, attr_len);
1877
1878 return abis_nm_sendmsg(bts, msg);
1879}
1880
1881/* Chapter 8.6.2 */
1882int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1883{
1884 struct abis_om_hdr *oh;
1885 struct msgb *msg = nm_msgb_alloc();
1886 u_int8_t *cur;
1887
1888 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1889
1890 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1891 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001892 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001893 cur = msgb_put(msg, attr_len);
1894 memcpy(cur, attr, attr_len);
1895
1896 return abis_nm_sendmsg(trx->bts, msg);
1897}
1898
Harald Welte39c7deb2009-08-09 21:49:48 +02001899static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1900{
1901 int i;
1902
1903 /* As it turns out, the BS-11 has some very peculiar restrictions
1904 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301905 switch (ts->trx->bts->type) {
1906 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001907 switch (chan_comb) {
1908 case NM_CHANC_TCHHalf:
1909 case NM_CHANC_TCHHalf2:
1910 /* not supported */
1911 return -EINVAL;
1912 case NM_CHANC_SDCCH:
1913 /* only one SDCCH/8 per TRX */
1914 for (i = 0; i < TRX_NR_TS; i++) {
1915 if (i == ts->nr)
1916 continue;
1917 if (ts->trx->ts[i].nm_chan_comb ==
1918 NM_CHANC_SDCCH)
1919 return -EINVAL;
1920 }
1921 /* not allowed for TS0 of BCCH-TRX */
1922 if (ts->trx == ts->trx->bts->c0 &&
1923 ts->nr == 0)
1924 return -EINVAL;
1925 /* not on the same TRX that has a BCCH+SDCCH4
1926 * combination */
1927 if (ts->trx == ts->trx->bts->c0 &&
1928 (ts->trx->ts[0].nm_chan_comb == 5 ||
1929 ts->trx->ts[0].nm_chan_comb == 8))
1930 return -EINVAL;
1931 break;
1932 case NM_CHANC_mainBCCH:
1933 case NM_CHANC_BCCHComb:
1934 /* allowed only for TS0 of C0 */
1935 if (ts->trx != ts->trx->bts->c0 ||
1936 ts->nr != 0)
1937 return -EINVAL;
1938 break;
1939 case NM_CHANC_BCCH:
1940 /* allowed only for TS 2/4/6 of C0 */
1941 if (ts->trx != ts->trx->bts->c0)
1942 return -EINVAL;
1943 if (ts->nr != 2 && ts->nr != 4 &&
1944 ts->nr != 6)
1945 return -EINVAL;
1946 break;
1947 case 8: /* this is not like 08.58, but in fact
1948 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1949 /* FIXME: only one CBCH allowed per cell */
1950 break;
1951 }
Harald Welted6575f92009-12-02 02:45:23 +05301952 break;
1953 case GSM_BTS_TYPE_NANOBTS:
1954 switch (ts->nr) {
1955 case 0:
1956 if (ts->trx->nr == 0) {
1957 /* only on TRX0 */
1958 switch (chan_comb) {
1959 case NM_CHANC_BCCH:
1960 case NM_CHANC_mainBCCH:
1961 case NM_CHANC_BCCHComb:
1962 return 0;
1963 break;
1964 default:
1965 return -EINVAL;
1966 }
1967 } else {
1968 switch (chan_comb) {
1969 case NM_CHANC_TCHFull:
1970 case NM_CHANC_TCHHalf:
1971 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1972 return 0;
1973 default:
1974 return -EINVAL;
1975 }
1976 }
1977 break;
1978 case 1:
1979 if (ts->trx->nr == 0) {
1980 switch (chan_comb) {
1981 case NM_CHANC_SDCCH_CBCH:
1982 if (ts->trx->ts[0].nm_chan_comb ==
1983 NM_CHANC_mainBCCH)
1984 return 0;
1985 return -EINVAL;
1986 case NM_CHANC_SDCCH:
1987 case NM_CHANC_TCHFull:
1988 case NM_CHANC_TCHHalf:
1989 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1990 case NM_CHANC_IPAC_TCHFull_PDCH:
1991 return 0;
1992 }
1993 } else {
1994 switch (chan_comb) {
1995 case NM_CHANC_SDCCH:
1996 case NM_CHANC_TCHFull:
1997 case NM_CHANC_TCHHalf:
1998 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1999 return 0;
2000 default:
2001 return -EINVAL;
2002 }
2003 }
2004 break;
2005 case 2:
2006 case 3:
2007 case 4:
2008 case 5:
2009 case 6:
2010 case 7:
2011 switch (chan_comb) {
2012 case NM_CHANC_TCHFull:
2013 case NM_CHANC_TCHHalf:
2014 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2015 return 0;
2016 case NM_CHANC_IPAC_PDCH:
2017 case NM_CHANC_IPAC_TCHFull_PDCH:
2018 if (ts->trx->nr == 0)
2019 return 0;
2020 else
2021 return -EINVAL;
2022 }
2023 break;
2024 }
2025 return -EINVAL;
2026 default:
2027 /* unknown BTS type */
2028 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002029 }
2030 return 0;
2031}
2032
Harald Welte22af0db2009-02-14 15:41:08 +00002033/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002034int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2035{
2036 struct gsm_bts *bts = ts->trx->bts;
2037 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002038 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002039 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002040 u_int8_t len = 2 + 2;
2041
2042 if (bts->type == GSM_BTS_TYPE_BS11)
2043 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002044
Harald Weltef325eb42009-02-19 17:07:39 +00002045 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002046 if (verify_chan_comb(ts, chan_comb) < 0) {
2047 msgb_free(msg);
2048 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2049 return -EINVAL;
2050 }
2051 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002052
Harald Welte52b1f982008-12-23 20:25:15 +00002053 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002054 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002055 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002056 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002057 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002058 if (ts->hopping.enabled) {
2059 unsigned int i;
2060 uint8_t *len;
2061
Harald Welte6e0cd042009-09-12 13:05:33 +02002062 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2063 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002064
2065 /* build the ARFCN list */
2066 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2067 len = msgb_put(msg, 1);
2068 *len = 0;
2069 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2070 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2071 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002072 /* At least BS-11 wants a TLV16 here */
2073 if (bts->type == GSM_BTS_TYPE_BS11)
2074 *len += 1;
2075 else
2076 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002077 }
2078 }
Harald Weltee0590df2009-02-15 03:34:15 +00002079 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002080 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002081 if (bts->type == GSM_BTS_TYPE_BS11)
2082 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002083
2084 return abis_nm_sendmsg(bts, msg);
2085}
2086
Harald Welte34a99682009-02-13 02:41:40 +00002087int 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 +00002088 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002089{
2090 struct abis_om_hdr *oh;
2091 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002092 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2093 u_int8_t len = att_len;
2094
2095 if (nack) {
2096 len += 2;
2097 msgtype = NM_MT_SW_ACT_REQ_NACK;
2098 }
Harald Welte34a99682009-02-13 02:41:40 +00002099
2100 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002101 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2102
Harald Welte34a99682009-02-13 02:41:40 +00002103 if (attr) {
2104 u_int8_t *ptr = msgb_put(msg, att_len);
2105 memcpy(ptr, attr, att_len);
2106 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002107 if (nack)
2108 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002109
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002110 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002111}
2112
Harald Welte8470bf22008-12-25 23:28:35 +00002113int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002114{
Harald Welte8470bf22008-12-25 23:28:35 +00002115 struct msgb *msg = nm_msgb_alloc();
2116 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002117 u_int8_t *data;
2118
2119 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2120 fill_om_hdr(oh, len);
2121 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002122 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002123
2124 return abis_nm_sendmsg(bts, msg);
2125}
2126
2127/* Siemens specific commands */
2128static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2129{
2130 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002131 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002132
2133 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002134 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002135 0xff, 0xff, 0xff);
2136
2137 return abis_nm_sendmsg(bts, msg);
2138}
2139
Harald Welte34a99682009-02-13 02:41:40 +00002140/* Chapter 8.9.2 */
2141int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2142{
2143 struct abis_om_hdr *oh;
2144 struct msgb *msg = nm_msgb_alloc();
2145
2146 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2147 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2148
Harald Weltea8bd6d42009-10-20 09:56:18 +02002149 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2150 DEBUGPC(DNM, "Sending OPSTART\n");
2151
Harald Welte34a99682009-02-13 02:41:40 +00002152 return abis_nm_sendmsg(bts, msg);
2153}
2154
2155/* Chapter 8.8.5 */
2156int 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 +02002157 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002158{
2159 struct abis_om_hdr *oh;
2160 struct msgb *msg = nm_msgb_alloc();
2161
2162 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2163 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2164 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2165
2166 return abis_nm_sendmsg(bts, msg);
2167}
2168
Harald Welte1989c082009-08-06 17:58:31 +02002169int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2170 u_int8_t e1_port1, u_int8_t ts1)
2171{
2172 struct abis_om_hdr *oh;
2173 struct msgb *msg = nm_msgb_alloc();
2174 u_int8_t *attr;
2175
2176 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2177 e1_port0, ts0, e1_port1, ts1);
2178
2179 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2180 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2181 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2182
2183 attr = msgb_put(msg, 3);
2184 attr[0] = NM_ATT_MDROP_LINK;
2185 attr[1] = e1_port0;
2186 attr[2] = ts0;
2187
2188 attr = msgb_put(msg, 3);
2189 attr[0] = NM_ATT_MDROP_NEXT;
2190 attr[1] = e1_port1;
2191 attr[2] = ts1;
2192
2193 return abis_nm_sendmsg(bts, msg);
2194}
Harald Welte34a99682009-02-13 02:41:40 +00002195
Harald Weltec7310382009-08-08 00:02:36 +02002196/* Chapter 8.7.1 */
2197int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2198 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002199 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002200{
2201 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002202
Harald Welte4d54d0b2011-02-19 16:48:17 +01002203 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002204
2205 if (!msg)
2206 msg = nm_msgb_alloc();
2207
2208 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2209 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2210 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2211 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002212 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002213
2214 return abis_nm_sendmsg(bts, msg);
2215}
2216
Harald Welte52b1f982008-12-23 20:25:15 +00002217int abis_nm_event_reports(struct gsm_bts *bts, int on)
2218{
2219 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002220 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002221 else
Harald Welte227d4072009-01-03 08:16:25 +00002222 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002223}
2224
Harald Welte47d88ae2009-01-04 12:02:08 +00002225/* Siemens (or BS-11) specific commands */
2226
Harald Welte3ffd1372009-02-01 22:15:49 +00002227int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2228{
2229 if (reconnect == 0)
2230 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2231 else
2232 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2233}
2234
Harald Welteb8427972009-02-05 19:27:17 +00002235int abis_nm_bs11_restart(struct gsm_bts *bts)
2236{
2237 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2238}
2239
2240
Harald Welte268bb402009-02-01 19:11:56 +00002241struct bs11_date_time {
2242 u_int16_t year;
2243 u_int8_t month;
2244 u_int8_t day;
2245 u_int8_t hour;
2246 u_int8_t min;
2247 u_int8_t sec;
2248} __attribute__((packed));
2249
2250
2251void get_bs11_date_time(struct bs11_date_time *aet)
2252{
2253 time_t t;
2254 struct tm *tm;
2255
2256 t = time(NULL);
2257 tm = localtime(&t);
2258 aet->sec = tm->tm_sec;
2259 aet->min = tm->tm_min;
2260 aet->hour = tm->tm_hour;
2261 aet->day = tm->tm_mday;
2262 aet->month = tm->tm_mon;
2263 aet->year = htons(1900 + tm->tm_year);
2264}
2265
Harald Welte05188ee2009-01-18 11:39:08 +00002266int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002267{
Harald Welte4668fda2009-01-03 08:19:29 +00002268 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002269}
2270
Harald Welte05188ee2009-01-18 11:39:08 +00002271int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002272{
2273 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002274 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002275 else
Harald Welte4668fda2009-01-03 08:19:29 +00002276 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002277}
Harald Welte47d88ae2009-01-04 12:02:08 +00002278
Harald Welte05188ee2009-01-18 11:39:08 +00002279int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002280 enum abis_bs11_objtype type, u_int8_t idx,
2281 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002282{
2283 struct abis_om_hdr *oh;
2284 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002285 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002286
2287 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002288 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002289 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002290 cur = msgb_put(msg, attr_len);
2291 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002292
2293 return abis_nm_sendmsg(bts, msg);
2294}
2295
Harald Welte78fc0d42009-02-19 02:50:57 +00002296int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2297 enum abis_bs11_objtype type, u_int8_t idx)
2298{
2299 struct abis_om_hdr *oh;
2300 struct msgb *msg = nm_msgb_alloc();
2301
2302 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2303 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2304 NM_OC_BS11, type, 0, idx);
2305
2306 return abis_nm_sendmsg(bts, msg);
2307}
2308
Harald Welte05188ee2009-01-18 11:39:08 +00002309int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002310{
2311 struct abis_om_hdr *oh;
2312 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002313 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002314
2315 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002316 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002317 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2318 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002319
2320 return abis_nm_sendmsg(bts, msg);
2321}
2322
Harald Welte05188ee2009-01-18 11:39:08 +00002323int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002324{
2325 struct abis_om_hdr *oh;
2326 struct msgb *msg = nm_msgb_alloc();
2327
2328 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2329 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002330 idx, 0xff, 0xff);
2331
2332 return abis_nm_sendmsg(bts, msg);
2333}
2334
2335int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2336{
2337 struct abis_om_hdr *oh;
2338 struct msgb *msg = nm_msgb_alloc();
2339
2340 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2341 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2342 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002343
2344 return abis_nm_sendmsg(bts, msg);
2345}
Harald Welte05188ee2009-01-18 11:39:08 +00002346
Harald Welte78fc0d42009-02-19 02:50:57 +00002347static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2348int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2349{
2350 struct abis_om_hdr *oh;
2351 struct msgb *msg = nm_msgb_alloc();
2352
2353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2354 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2355 0xff, 0xff, 0xff);
2356 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2357
2358 return abis_nm_sendmsg(bts, msg);
2359}
2360
Harald Welteb6c92ae2009-02-21 20:15:32 +00002361/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002362int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002363 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2364 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002365{
2366 struct abis_om_hdr *oh;
2367 struct abis_nm_channel *ch;
2368 struct msgb *msg = nm_msgb_alloc();
2369
2370 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002371 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002372 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2373
2374 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2375 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002376 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002377
2378 return abis_nm_sendmsg(bts, msg);
2379}
2380
2381int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2382{
2383 struct abis_om_hdr *oh;
2384 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002385
2386 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002387 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002388 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2389 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2390
2391 return abis_nm_sendmsg(trx->bts, msg);
2392}
2393
Harald Welte78fc0d42009-02-19 02:50:57 +00002394int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2395{
2396 struct abis_om_hdr *oh;
2397 struct msgb *msg = nm_msgb_alloc();
2398 u_int8_t attr = NM_ATT_BS11_TXPWR;
2399
2400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2401 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2402 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2403 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2404
2405 return abis_nm_sendmsg(trx->bts, msg);
2406}
2407
Harald Welteaaf02d92009-04-29 13:25:57 +00002408int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2409{
2410 struct abis_om_hdr *oh;
2411 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002412 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002413
2414 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2415 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2416 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002417 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002418
2419 return abis_nm_sendmsg(bts, msg);
2420}
2421
Harald Welteef061952009-05-17 12:43:42 +00002422int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2423{
2424 struct abis_om_hdr *oh;
2425 struct msgb *msg = nm_msgb_alloc();
2426 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2427 NM_ATT_BS11_CCLK_TYPE };
2428
2429 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2430 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2431 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2432 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2433
2434 return abis_nm_sendmsg(bts, msg);
2435
2436}
Harald Welteaaf02d92009-04-29 13:25:57 +00002437
Harald Welte268bb402009-02-01 19:11:56 +00002438//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002439
Harald Welte1bc09062009-01-18 14:17:52 +00002440int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002441{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002442 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2443}
2444
Daniel Willmann4b054c82010-01-07 00:46:26 +01002445int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2446{
2447 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2448}
2449
Daniel Willmann493db4e2010-01-07 00:43:11 +01002450int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2451{
Harald Welte05188ee2009-01-18 11:39:08 +00002452 struct abis_om_hdr *oh;
2453 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002454 struct bs11_date_time bdt;
2455
2456 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002457
2458 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002459 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002460 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002461 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002462 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002463 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002464 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002465 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002466 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002467 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002468 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002469 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002470 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002471 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002472 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002473 }
Harald Welte05188ee2009-01-18 11:39:08 +00002474
2475 return abis_nm_sendmsg(bts, msg);
2476}
Harald Welte1bc09062009-01-18 14:17:52 +00002477
2478int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2479{
2480 struct abis_om_hdr *oh;
2481 struct msgb *msg;
2482
2483 if (strlen(password) != 10)
2484 return -EINVAL;
2485
2486 msg = nm_msgb_alloc();
2487 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002488 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002489 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2490 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2491
2492 return abis_nm_sendmsg(bts, msg);
2493}
2494
Harald Weltee69f5fb2009-04-28 16:31:38 +00002495/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2496int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2497{
2498 struct abis_om_hdr *oh;
2499 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002500 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002501
2502 msg = nm_msgb_alloc();
2503 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2504 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2505 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002506
2507 if (locked)
2508 tlv_value = BS11_LI_PLL_LOCKED;
2509 else
2510 tlv_value = BS11_LI_PLL_STANDALONE;
2511
2512 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002513
2514 return abis_nm_sendmsg(bts, msg);
2515}
2516
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002517/* Set the calibration value of the PLL (work value/set value)
2518 * It depends on the login which one is changed */
2519int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2520{
2521 struct abis_om_hdr *oh;
2522 struct msgb *msg;
2523 u_int8_t tlv_value[2];
2524
2525 msg = nm_msgb_alloc();
2526 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2527 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2528 BS11_OBJ_TRX1, 0x00, 0x00);
2529
2530 tlv_value[0] = value>>8;
2531 tlv_value[1] = value&0xff;
2532
2533 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2534
2535 return abis_nm_sendmsg(bts, msg);
2536}
2537
Harald Welte1bc09062009-01-18 14:17:52 +00002538int abis_nm_bs11_get_state(struct gsm_bts *bts)
2539{
2540 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2541}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002542
2543/* BS11 SWL */
2544
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002545void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002546
Harald Welte5e4d1b32009-02-01 13:36:56 +00002547struct abis_nm_bs11_sw {
2548 struct gsm_bts *bts;
2549 char swl_fname[PATH_MAX];
2550 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002551 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002552 struct llist_head file_list;
2553 gsm_cbfn *user_cb; /* specified by the user */
2554};
2555static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2556
2557struct file_list_entry {
2558 struct llist_head list;
2559 char fname[PATH_MAX];
2560};
2561
2562struct file_list_entry *fl_dequeue(struct llist_head *queue)
2563{
2564 struct llist_head *lh;
2565
2566 if (llist_empty(queue))
2567 return NULL;
2568
2569 lh = queue->next;
2570 llist_del(lh);
2571
2572 return llist_entry(lh, struct file_list_entry, list);
2573}
2574
2575static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2576{
2577 char linebuf[255];
2578 struct llist_head *lh, *lh2;
2579 FILE *swl;
2580 int rc = 0;
2581
2582 swl = fopen(bs11_sw->swl_fname, "r");
2583 if (!swl)
2584 return -ENODEV;
2585
2586 /* zero the stale file list, if any */
2587 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2588 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002589 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002590 }
2591
2592 while (fgets(linebuf, sizeof(linebuf), swl)) {
2593 char file_id[12+1];
2594 char file_version[80+1];
2595 struct file_list_entry *fle;
2596 static char dir[PATH_MAX];
2597
2598 if (strlen(linebuf) < 4)
2599 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002600
Harald Welte5e4d1b32009-02-01 13:36:56 +00002601 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2602 if (rc < 0) {
2603 perror("ERR parsing SWL file");
2604 rc = -EINVAL;
2605 goto out;
2606 }
2607 if (rc < 2)
2608 continue;
2609
Harald Welte470ec292009-06-26 20:25:23 +02002610 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002611 if (!fle) {
2612 rc = -ENOMEM;
2613 goto out;
2614 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002615
2616 /* construct new filename */
2617 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2618 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2619 strcat(fle->fname, "/");
2620 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002621
2622 llist_add_tail(&fle->list, &bs11_sw->file_list);
2623 }
2624
2625out:
2626 fclose(swl);
2627 return rc;
2628}
2629
2630/* bs11 swload specific callback, passed to abis_nm core swload */
2631static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2632 struct msgb *msg, void *data, void *param)
2633{
2634 struct abis_nm_bs11_sw *bs11_sw = data;
2635 struct file_list_entry *fle;
2636 int rc = 0;
2637
Harald Welte5e4d1b32009-02-01 13:36:56 +00002638 switch (event) {
2639 case NM_MT_LOAD_END_ACK:
2640 fle = fl_dequeue(&bs11_sw->file_list);
2641 if (fle) {
2642 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002643 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002644 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002645 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002646 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002647 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002648 } else {
2649 /* activate the SWL */
2650 rc = abis_nm_software_activate(bs11_sw->bts,
2651 bs11_sw->swl_fname,
2652 bs11_swload_cbfn,
2653 bs11_sw);
2654 }
2655 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002656 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002657 case NM_MT_LOAD_END_NACK:
2658 case NM_MT_LOAD_INIT_ACK:
2659 case NM_MT_LOAD_INIT_NACK:
2660 case NM_MT_ACTIVATE_SW_NACK:
2661 case NM_MT_ACTIVATE_SW_ACK:
2662 default:
2663 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002664 if (bs11_sw->user_cb)
2665 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002666 break;
2667 }
2668
2669 return rc;
2670}
2671
2672/* Siemens provides a SWL file that is a mere listing of all the other
2673 * files that are part of a software release. We need to upload first
2674 * the list file, and then each file that is listed in the list file */
2675int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002676 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002677{
2678 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2679 struct file_list_entry *fle;
2680 int rc = 0;
2681
2682 INIT_LLIST_HEAD(&bs11_sw->file_list);
2683 bs11_sw->bts = bts;
2684 bs11_sw->win_size = win_size;
2685 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002686 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002687
2688 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2689 rc = bs11_read_swl_file(bs11_sw);
2690 if (rc < 0)
2691 return rc;
2692
2693 /* dequeue next item in file list */
2694 fle = fl_dequeue(&bs11_sw->file_list);
2695 if (!fle)
2696 return -EINVAL;
2697
2698 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002699 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002700 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002701 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002702 return rc;
2703}
2704
Harald Welte5083b0b2009-02-02 19:20:52 +00002705#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002706static u_int8_t req_attr_btse[] = {
2707 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2708 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2709 NM_ATT_BS11_LMT_USER_NAME,
2710
2711 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2712
2713 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2714
2715 NM_ATT_BS11_SW_LOAD_STORED };
2716
2717static u_int8_t req_attr_btsm[] = {
2718 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2719 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2720 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2721 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002722#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002723
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002724static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002725 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2726 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002727 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002728
2729int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2730{
2731 struct abis_om_hdr *oh;
2732 struct msgb *msg = nm_msgb_alloc();
2733
2734 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2735 /* SiemensHW CCTRL object */
2736 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2737 0x03, 0x00, 0x00);
2738 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2739
2740 return abis_nm_sendmsg(bts, msg);
2741}
Harald Welte268bb402009-02-01 19:11:56 +00002742
2743int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2744{
2745 struct abis_om_hdr *oh;
2746 struct msgb *msg = nm_msgb_alloc();
2747 struct bs11_date_time aet;
2748
2749 get_bs11_date_time(&aet);
2750 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2751 /* SiemensHW CCTRL object */
2752 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2753 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002754 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002755
2756 return abis_nm_sendmsg(bts, msg);
2757}
Harald Welte5c1e4582009-02-15 11:57:29 +00002758
Harald Weltef751a102010-12-14 12:52:16 +01002759int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2760{
2761 struct abis_om_hdr *oh;
2762 struct msgb *msg = nm_msgb_alloc();
2763 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2764
2765 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2766 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2767 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2768 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2769
2770 return abis_nm_sendmsg(bts, msg);
2771}
2772
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002773int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2774{
2775 struct abis_om_hdr *oh;
2776 struct msgb *msg = nm_msgb_alloc();
2777 struct bs11_date_time aet;
2778
2779 get_bs11_date_time(&aet);
2780 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2781 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2782 bport, 0xff, 0x02);
2783 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2784
2785 return abis_nm_sendmsg(bts, msg);
2786}
2787
Harald Welte5c1e4582009-02-15 11:57:29 +00002788/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002789static const char ipaccess_magic[] = "com.ipaccess";
2790
Harald Welte677c21f2009-02-17 13:22:23 +00002791
2792static int abis_nm_rx_ipacc(struct msgb *msg)
2793{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002794 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002795 struct abis_om_hdr *oh = msgb_l2(msg);
2796 struct abis_om_fom_hdr *foh;
2797 u_int8_t idstrlen = oh->data[0];
2798 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002799 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002800
2801 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002802 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002803 return -EINVAL;
2804 }
2805
Harald Welte193fefc2009-04-30 15:16:27 +00002806 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002807 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002808
Harald Weltea8bd6d42009-10-20 09:56:18 +02002809 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002810
Harald Welte746d6092009-10-19 22:11:11 +02002811 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002812
Harald Welte677c21f2009-02-17 13:22:23 +00002813 switch (foh->msg_type) {
2814 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002815 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002816 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2817 memcpy(&addr,
2818 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2819
2820 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2821 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002822 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002823 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002824 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002825 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002826 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2827 DEBUGPC(DNM, "STREAM=0x%02x ",
2828 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002829 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002830 break;
2831 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002832 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002833 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002834 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002835 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002836 else
2837 DEBUGPC(DNM, "\n");
2838 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002839 case NM_MT_IPACC_SET_NVATTR_ACK:
2840 DEBUGPC(DNM, "SET NVATTR ACK\n");
2841 /* FIXME: decode and show the actual attributes */
2842 break;
2843 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002844 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002845 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002846 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002847 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2848 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002849 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002850 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002851 case NM_MT_IPACC_GET_NVATTR_ACK:
2852 DEBUGPC(DNM, "GET NVATTR ACK\n");
2853 /* FIXME: decode and show the actual attributes */
2854 break;
2855 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002856 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002857 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002858 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002859 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2860 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002861 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002862 break;
Harald Welte15c44172009-10-08 20:15:24 +02002863 case NM_MT_IPACC_SET_ATTR_ACK:
2864 DEBUGPC(DNM, "SET ATTR ACK\n");
2865 break;
2866 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002867 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002868 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002869 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002870 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2871 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002872 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002873 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002874 default:
2875 DEBUGPC(DNM, "unknown\n");
2876 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002877 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002878
2879 /* signal handling */
2880 switch (foh->msg_type) {
2881 case NM_MT_IPACC_RSL_CONNECT_NACK:
2882 case NM_MT_IPACC_SET_NVATTR_NACK:
2883 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002884 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002885 signal.msg_type = foh->msg_type;
2886 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002887 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002888 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002889 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002890 signal.msg_type = foh->msg_type;
2891 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002892 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002893 default:
2894 break;
2895 }
2896
Harald Welte677c21f2009-02-17 13:22:23 +00002897 return 0;
2898}
2899
Harald Welte193fefc2009-04-30 15:16:27 +00002900/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002901int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2902 u_int8_t obj_class, u_int8_t bts_nr,
2903 u_int8_t trx_nr, u_int8_t ts_nr,
2904 u_int8_t *attr, int attr_len)
2905{
2906 struct msgb *msg = nm_msgb_alloc();
2907 struct abis_om_hdr *oh;
2908 struct abis_om_fom_hdr *foh;
2909 u_int8_t *data;
2910
2911 /* construct the 12.21 OM header, observe the erroneous length */
2912 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2913 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2914 oh->mdisc = ABIS_OM_MDISC_MANUF;
2915
2916 /* add the ip.access magic */
2917 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2918 *data++ = sizeof(ipaccess_magic);
2919 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2920
2921 /* fill the 12.21 FOM header */
2922 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2923 foh->msg_type = msg_type;
2924 foh->obj_class = obj_class;
2925 foh->obj_inst.bts_nr = bts_nr;
2926 foh->obj_inst.trx_nr = trx_nr;
2927 foh->obj_inst.ts_nr = ts_nr;
2928
2929 if (attr && attr_len) {
2930 data = msgb_put(msg, attr_len);
2931 memcpy(data, attr, attr_len);
2932 }
2933
2934 return abis_nm_sendmsg(bts, msg);
2935}
Harald Welte677c21f2009-02-17 13:22:23 +00002936
Harald Welte193fefc2009-04-30 15:16:27 +00002937/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002938int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002939 int attr_len)
2940{
Harald Welte2ef156d2010-01-07 20:39:42 +01002941 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2942 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002943 attr_len);
2944}
2945
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002946int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002947 u_int32_t ip, u_int16_t port, u_int8_t stream)
2948{
2949 struct in_addr ia;
2950 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2951 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2952 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2953
2954 int attr_len = sizeof(attr);
2955
2956 ia.s_addr = htonl(ip);
2957 attr[1] = stream;
2958 attr[3] = port >> 8;
2959 attr[4] = port & 0xff;
2960 *(u_int32_t *)(attr+6) = ia.s_addr;
2961
2962 /* if ip == 0, we use the default IP */
2963 if (ip == 0)
2964 attr_len -= 5;
2965
2966 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002967 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002968
2969 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2970 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2971 trx->nr, 0xff, attr, attr_len);
2972}
2973
Harald Welte193fefc2009-04-30 15:16:27 +00002974/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002975int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002976{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002977 struct abis_om_hdr *oh;
2978 struct msgb *msg = nm_msgb_alloc();
2979
2980 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2981 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2982 trx->bts->nr, trx->nr, 0xff);
2983
2984 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002985}
Harald Weltedaef5212009-10-24 10:20:41 +02002986
2987int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2988 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2989 u_int8_t *attr, u_int8_t attr_len)
2990{
2991 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2992 obj_class, bts_nr, trx_nr, ts_nr,
2993 attr, attr_len);
2994}
Harald Welte0f255852009-11-12 14:48:42 +01002995
Harald Welte97a282b2010-03-14 15:37:43 +08002996void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2997{
2998 /* we simply reuse the GSM48 function and overwrite the RAC
2999 * with the Cell ID */
3000 gsm48_ra_id_by_bts(buf, bts);
3001 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
3002}
3003
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003004void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
3005{
3006 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
3007
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01003008 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003009 if (!trx->bts || !trx->bts->oml_link)
3010 return;
3011
3012 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3013 trx->bts->bts_nr, trx->nr, 0xff,
3014 new_state);
3015}
3016
Harald Welte92b1fe42010-03-25 11:45:30 +08003017static const struct value_string ipacc_testres_names[] = {
3018 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3019 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3020 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3021 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3022 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3023 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01003024};
3025
3026const char *ipacc_testres_name(u_int8_t res)
3027{
Harald Welte92b1fe42010-03-25 11:45:30 +08003028 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003029}
3030
Harald Welteb40a38f2009-11-13 11:56:05 +01003031void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3032{
3033 cid->mcc = (buf[0] & 0xf) * 100;
3034 cid->mcc += (buf[0] >> 4) * 10;
3035 cid->mcc += (buf[1] & 0xf) * 1;
3036
3037 if (buf[1] >> 4 == 0xf) {
3038 cid->mnc = (buf[2] & 0xf) * 10;
3039 cid->mnc += (buf[2] >> 4) * 1;
3040 } else {
3041 cid->mnc = (buf[2] & 0xf) * 100;
3042 cid->mnc += (buf[2] >> 4) * 10;
3043 cid->mnc += (buf[1] >> 4) * 1;
3044 }
3045
Harald Welteaff237d2009-11-13 14:41:52 +01003046 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3047 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003048}
3049
Harald Welte0f255852009-11-12 14:48:42 +01003050/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3051int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3052{
3053 u_int8_t *cur = buf;
3054 u_int16_t len;
3055
Harald Welteaf109b92010-07-22 18:14:36 +02003056 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003057
3058 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3059 return -EINVAL;
3060 cur++;
3061
3062 len = ntohs(*(u_int16_t *)cur);
3063 cur += 2;
3064
3065 binf->info_type = ntohs(*(u_int16_t *)cur);
3066 cur += 2;
3067
3068 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3069 binf->freq_qual = *cur >> 2;
3070
Harald Welteaf109b92010-07-22 18:14:36 +02003071 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003072 binf->arfcn |= *cur++;
3073
3074 if (binf->info_type & IPAC_BINF_RXLEV)
3075 binf->rx_lev = *cur & 0x3f;
3076 cur++;
3077
3078 if (binf->info_type & IPAC_BINF_RXQUAL)
3079 binf->rx_qual = *cur & 0x7;
3080 cur++;
3081
3082 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3083 binf->freq_err = ntohs(*(u_int16_t *)cur);
3084 cur += 2;
3085
3086 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3087 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3088 cur += 2;
3089
3090 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3091 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3092 cur += 4;
3093
Harald Weltea780a3d2010-07-30 22:34:42 +02003094#if 0
3095 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003096 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003097#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003098 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003099 cur++;
3100
Harald Welteb40a38f2009-11-13 11:56:05 +01003101 ipac_parse_cgi(&binf->cgi, cur);
3102 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003103
3104 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3105 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3106 cur += sizeof(binf->ba_list_si2);
3107 }
3108
3109 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3110 memcpy(binf->ba_list_si2bis, cur,
3111 sizeof(binf->ba_list_si2bis));
3112 cur += sizeof(binf->ba_list_si2bis);
3113 }
3114
3115 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3116 memcpy(binf->ba_list_si2ter, cur,
3117 sizeof(binf->ba_list_si2ter));
3118 cur += sizeof(binf->ba_list_si2ter);
3119 }
3120
3121 return 0;
3122}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003123
3124void abis_nm_clear_queue(struct gsm_bts *bts)
3125{
3126 struct msgb *msg;
3127
3128 while (!llist_empty(&bts->abis_queue)) {
3129 msg = msgb_dequeue(&bts->abis_queue);
3130 msgb_free(msg);
3131 }
3132
3133 bts->abis_nm_pend = 0;
3134}