blob: c2541dfc5408d1ca4e2fee364bb1b14ff6d5b135 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte52b1f982008-12-23 20:25:15 +000033#include <sys/types.h>
Harald Welte4724f992009-01-18 18:01:49 +000034#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000035#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000036#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000037
Harald Welte8470bf22008-12-25 23:28:35 +000038#include <openbsc/gsm_data.h>
39#include <openbsc/debug.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010040#include <osmocore/msgb.h>
41#include <osmocore/tlv.h>
42#include <osmocore/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Harald Welte52b1f982008-12-23 20:25:15 +000046
Harald Welte8470bf22008-12-25 23:28:35 +000047#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010049#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000050
51/* unidirectional messages from BTS to BSC */
52static const enum abis_nm_msgtype reports[] = {
53 NM_MT_SW_ACTIVATED_REP,
54 NM_MT_TEST_REP,
55 NM_MT_STATECHG_EVENT_REP,
56 NM_MT_FAILURE_EVENT_REP,
57};
58
59/* messages without ACK/NACK */
60static const enum abis_nm_msgtype no_ack_nack[] = {
61 NM_MT_MEAS_RES_REQ,
62 NM_MT_STOP_MEAS,
63 NM_MT_START_MEAS,
64};
65
Harald Welte4724f992009-01-18 18:01:49 +000066/* Messages related to software load */
67static const enum abis_nm_msgtype sw_load_msgs[] = {
68 NM_MT_LOAD_INIT_ACK,
69 NM_MT_LOAD_INIT_NACK,
70 NM_MT_LOAD_SEG_ACK,
71 NM_MT_LOAD_ABORT,
72 NM_MT_LOAD_END_ACK,
73 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000074 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000075 NM_MT_ACTIVATE_SW_ACK,
76 NM_MT_ACTIVATE_SW_NACK,
77 NM_MT_SW_ACTIVATED_REP,
78};
79
Harald Weltee0590df2009-02-15 03:34:15 +000080static const enum abis_nm_msgtype nacks[] = {
81 NM_MT_LOAD_INIT_NACK,
82 NM_MT_LOAD_END_NACK,
83 NM_MT_SW_ACT_REQ_NACK,
84 NM_MT_ACTIVATE_SW_NACK,
85 NM_MT_ESTABLISH_TEI_NACK,
86 NM_MT_CONN_TERR_SIGN_NACK,
87 NM_MT_DISC_TERR_SIGN_NACK,
88 NM_MT_CONN_TERR_TRAF_NACK,
89 NM_MT_DISC_TERR_TRAF_NACK,
90 NM_MT_CONN_MDROP_LINK_NACK,
91 NM_MT_DISC_MDROP_LINK_NACK,
92 NM_MT_SET_BTS_ATTR_NACK,
93 NM_MT_SET_RADIO_ATTR_NACK,
94 NM_MT_SET_CHAN_ATTR_NACK,
95 NM_MT_PERF_TEST_NACK,
96 NM_MT_SEND_TEST_REP_NACK,
97 NM_MT_STOP_TEST_NACK,
98 NM_MT_STOP_EVENT_REP_NACK,
99 NM_MT_REST_EVENT_REP_NACK,
100 NM_MT_CHG_ADM_STATE_NACK,
101 NM_MT_CHG_ADM_STATE_REQ_NACK,
102 NM_MT_REP_OUTST_ALARMS_NACK,
103 NM_MT_CHANGEOVER_NACK,
104 NM_MT_OPSTART_NACK,
105 NM_MT_REINIT_NACK,
106 NM_MT_SET_SITE_OUT_NACK,
107 NM_MT_CHG_HW_CONF_NACK,
108 NM_MT_GET_ATTR_NACK,
109 NM_MT_SET_ALARM_THRES_NACK,
110 NM_MT_BS11_BEGIN_DB_TX_NACK,
111 NM_MT_BS11_END_DB_TX_NACK,
112 NM_MT_BS11_CREATE_OBJ_NACK,
113 NM_MT_BS11_DELETE_OBJ_NACK,
114};
Harald Welte78fc0d42009-02-19 02:50:57 +0000115
Harald Welte92b1fe42010-03-25 11:45:30 +0800116static const struct value_string nack_names[] = {
117 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
118 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
119 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
120 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
121 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
122 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
123 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
124 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
125 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
126 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
127 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
128 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
129 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
130 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
131 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
132 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
133 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
134 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
135 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
136 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
137 { NM_MT_CHG_ADM_STATE_REQ_NACK,
138 "CHANGE ADMINISTRATIVE STATE REQUEST" },
139 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
140 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
141 { NM_MT_OPSTART_NACK, "OPSTART" },
142 { NM_MT_REINIT_NACK, "REINIT" },
143 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
144 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
145 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
146 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
147 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
148 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
149 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
150 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
151 { 0, NULL }
Harald Welte78fc0d42009-02-19 02:50:57 +0000152};
153
Harald Welte6c96ba52009-05-01 13:03:40 +0000154/* Chapter 9.4.36 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800155static const struct value_string nack_cause_names[] = {
Harald Welte6c96ba52009-05-01 13:03:40 +0000156 /* General Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800157 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
158 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
159 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
160 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
161 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
162 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
163 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
164 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
165 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
166 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
167 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
168 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
169 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte6c96ba52009-05-01 13:03:40 +0000170 /* Specific Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800171 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
172 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
173 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
174 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
175 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
176 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
177 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
178 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
179 { NM_NACK_TEST_NOSUCH, "No such test" },
180 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
181 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
182 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
183 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
184 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
185 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
186 { NM_NACK_WAIT, "Wait" },
187 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
188 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
189 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
190 { 0, NULL }
Harald Welte6c96ba52009-05-01 13:03:40 +0000191};
192
Harald Welte6c96ba52009-05-01 13:03:40 +0000193static const char *nack_cause_name(u_int8_t cause)
194{
Harald Welte92b1fe42010-03-25 11:45:30 +0800195 return get_value_string(nack_cause_names, cause);
Harald Welte6c96ba52009-05-01 13:03:40 +0000196}
197
Harald Welte0db97b22009-05-01 17:22:47 +0000198/* Chapter 9.4.16: Event Type */
Harald Welte92b1fe42010-03-25 11:45:30 +0800199static const struct value_string event_type_names[] = {
200 { NM_EVT_COMM_FAIL, "communication failure" },
201 { NM_EVT_QOS_FAIL, "quality of service failure" },
202 { NM_EVT_PROC_FAIL, "processing failure" },
203 { NM_EVT_EQUIP_FAIL, "equipment failure" },
204 { NM_EVT_ENV_FAIL, "environment failure" },
205 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000206};
207
208static const char *event_type_name(u_int8_t cause)
209{
Harald Welte92b1fe42010-03-25 11:45:30 +0800210 return get_value_string(event_type_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000211}
212
213/* Chapter 9.4.63: Perceived Severity */
Harald Welte92b1fe42010-03-25 11:45:30 +0800214static const struct value_string severity_names[] = {
215 { NM_SEVER_CEASED, "failure ceased" },
216 { NM_SEVER_CRITICAL, "critical failure" },
217 { NM_SEVER_MAJOR, "major failure" },
218 { NM_SEVER_MINOR, "minor failure" },
219 { NM_SEVER_WARNING, "warning level failure" },
220 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
221 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000222};
223
224static const char *severity_name(u_int8_t cause)
225{
Harald Welte92b1fe42010-03-25 11:45:30 +0800226 return get_value_string(severity_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000227}
228
Harald Welte52b1f982008-12-23 20:25:15 +0000229/* Attributes that the BSC can set, not only get, according to Section 9.4 */
230static const enum abis_nm_attr nm_att_settable[] = {
231 NM_ATT_ADD_INFO,
232 NM_ATT_ADD_TEXT,
233 NM_ATT_DEST,
234 NM_ATT_EVENT_TYPE,
235 NM_ATT_FILE_DATA,
236 NM_ATT_GET_ARI,
237 NM_ATT_HW_CONF_CHG,
238 NM_ATT_LIST_REQ_ATTR,
239 NM_ATT_MDROP_LINK,
240 NM_ATT_MDROP_NEXT,
241 NM_ATT_NACK_CAUSES,
242 NM_ATT_OUTST_ALARM,
243 NM_ATT_PHYS_CONF,
244 NM_ATT_PROB_CAUSE,
245 NM_ATT_RAD_SUBC,
246 NM_ATT_SOURCE,
247 NM_ATT_SPEC_PROB,
248 NM_ATT_START_TIME,
249 NM_ATT_TEST_DUR,
250 NM_ATT_TEST_NO,
251 NM_ATT_TEST_REPORT,
252 NM_ATT_WINDOW_SIZE,
253 NM_ATT_SEVERITY,
254 NM_ATT_MEAS_RES,
255 NM_ATT_MEAS_TYPE,
256};
257
Harald Welte39315c42010-01-10 18:01:52 +0100258const struct tlv_definition nm_att_tlvdef = {
Harald Weltee0590df2009-02-15 03:34:15 +0000259 .def = {
260 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
261 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
262 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
264 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
265 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
266 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
267 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
268 [NM_ATT_BSIC] = { TLV_TYPE_TV },
269 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
270 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
272 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
273 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
274 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
275 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
276 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
277 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
279 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
280 [NM_ATT_HSN] = { TLV_TYPE_TV },
281 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
282 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
283 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
284 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
285 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
286 [NM_ATT_MAIO] = { TLV_TYPE_TV },
287 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
289 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
290 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
291 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
292 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
294 [NM_ATT_NY1] = { TLV_TYPE_TV },
295 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
297 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
298 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
299 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
300 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
302 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
303 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
304 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
305 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
306 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
308 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
309 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
310 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
311 [NM_ATT_TEI] = { TLV_TYPE_TV },
312 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
313 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
314 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
315 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
316 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
317 [NM_ATT_TSC] = { TLV_TYPE_TV },
318 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
319 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
320 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
321 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
322 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000323 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Weltee0590df2009-02-15 03:34:15 +0000324 },
325};
Harald Welte03133942009-02-18 19:51:53 +0000326
Harald Welte21bd3a52009-08-10 12:21:22 +0200327static const enum abis_nm_chan_comb chcomb4pchan[] = {
328 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
329 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
330 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
331 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
332 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200333 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
334 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200335 /* FIXME: bounds check */
336};
337
338int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
339{
340 if (pchan < ARRAY_SIZE(chcomb4pchan))
341 return chcomb4pchan[pchan];
342
343 return -EINVAL;
344}
345
Harald Welte39315c42010-01-10 18:01:52 +0100346int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +0000347{
Harald Welte39315c42010-01-10 18:01:52 +0100348 if (!bts->model)
349 return -EIO;
350 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000351}
Harald Weltee0590df2009-02-15 03:34:15 +0000352
Harald Welte52b1f982008-12-23 20:25:15 +0000353static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
354{
355 int i;
356
357 for (i = 0; i < size; i++) {
358 if (arr[i] == mt)
359 return 1;
360 }
361
362 return 0;
363}
364
Holger Freytherca362a62009-01-04 21:05:01 +0000365#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000366/* is this msgtype the usual ACK/NACK type ? */
367static int is_ack_nack(enum abis_nm_msgtype mt)
368{
369 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
370}
Holger Freytherca362a62009-01-04 21:05:01 +0000371#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000372
373/* is this msgtype a report ? */
374static int is_report(enum abis_nm_msgtype mt)
375{
Harald Welte8470bf22008-12-25 23:28:35 +0000376 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000377}
378
379#define MT_ACK(x) (x+1)
380#define MT_NACK(x) (x+2)
381
382static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
383{
384 oh->mdisc = ABIS_OM_MDISC_FOM;
385 oh->placement = ABIS_OM_PLACEMENT_ONLY;
386 oh->sequence = 0;
387 oh->length = len;
388}
389
390static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
391 u_int8_t msg_type, u_int8_t obj_class,
392 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
393{
394 struct abis_om_fom_hdr *foh =
395 (struct abis_om_fom_hdr *) oh->data;
396
Harald Welte702d8702008-12-26 20:25:35 +0000397 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000398 foh->msg_type = msg_type;
399 foh->obj_class = obj_class;
400 foh->obj_inst.bts_nr = bts_nr;
401 foh->obj_inst.trx_nr = trx_nr;
402 foh->obj_inst.ts_nr = ts_nr;
403}
404
Harald Welte8470bf22008-12-25 23:28:35 +0000405static struct msgb *nm_msgb_alloc(void)
406{
Harald Welte966636f2009-06-26 19:39:35 +0200407 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
408 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000409}
410
Harald Welte52b1f982008-12-23 20:25:15 +0000411/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100412static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000413{
Holger Freyther59639e82009-02-09 23:09:55 +0000414 msg->trx = bts->c0;
415
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100416 /* queue OML messages */
417 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
418 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
419 return _abis_nm_sendmsg(msg);
420 } else {
421 msgb_enqueue(&bts->abis_queue, msg);
422 return 0;
423 }
424
425}
426
427int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
428{
429 OBSC_NM_W_ACK_CB(msg) = 1;
430 return abis_nm_queue_msg(bts, msg);
431}
432
433static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
434{
435 OBSC_NM_W_ACK_CB(msg) = 0;
436 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000437}
438
Harald Welte4724f992009-01-18 18:01:49 +0000439static int abis_nm_rcvmsg_sw(struct msgb *mb);
440
Harald Welte81c9b9c2010-05-31 16:40:40 +0200441const struct value_string abis_nm_obj_class_names[] = {
442 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800443 { NM_OC_BTS, "BTS" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200444 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
445 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800446 { NM_OC_CHANNEL, "CHANNEL" },
447 { NM_OC_BS11_ADJC, "ADJC" },
448 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200449 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800450 { NM_OC_BS11_BTSE, "BTSE" },
451 { NM_OC_BS11_RACK, "RACK" },
452 { NM_OC_BS11_TEST, "TEST" },
453 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
454 { NM_OC_BS11_BPORT, "BPORT" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200455 { NM_OC_GPRS_NSE, "GPRS-NSE" },
456 { NM_OC_GPRS_CELL, "GPRS-CELL" },
457 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800458 { NM_OC_BS11, "SIEMENSHW" },
459 { 0, NULL }
460};
461
Harald Welte34a99682009-02-13 02:41:40 +0000462static const char *obj_class_name(u_int8_t oc)
463{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200464 return get_value_string(abis_nm_obj_class_names, oc);
Harald Welte34a99682009-02-13 02:41:40 +0000465}
466
Harald Welte4d87f242009-03-10 19:43:44 +0000467const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000468{
469 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100470 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000471 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100472 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000473 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100474 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000475 return "NULL";
476 default:
477 return "RFU";
478 }
479}
480
Harald Weltee0590df2009-02-15 03:34:15 +0000481/* Chapter 9.4.7 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800482static const struct value_string avail_names[] = {
483 { 0, "In test" },
484 { 1, "Failed" },
485 { 2, "Power off" },
486 { 3, "Off line" },
487 /* Not used */
488 { 5, "Dependency" },
489 { 6, "Degraded" },
490 { 7, "Not installed" },
491 { 0xff, "OK" },
492 { 0, NULL }
Harald Weltee0590df2009-02-15 03:34:15 +0000493};
494
Harald Welte4d87f242009-03-10 19:43:44 +0000495const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000496{
Harald Welte92b1fe42010-03-25 11:45:30 +0800497 return get_value_string(avail_names, avail);
Harald Weltee0590df2009-02-15 03:34:15 +0000498}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000499
Harald Welte0f255852009-11-12 14:48:42 +0100500static struct value_string test_names[] = {
501 /* FIXME: standard test names */
502 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
503 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
504 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
505 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
506 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
507 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
508 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
509 { 0, NULL }
510};
511
Harald Welte81c9b9c2010-05-31 16:40:40 +0200512const struct value_string abis_nm_adm_state_names[] = {
513 { NM_STATE_LOCKED, "Locked" },
514 { NM_STATE_UNLOCKED, "Unlocked" },
515 { NM_STATE_SHUTDOWN, "Shutdown" },
516 { NM_STATE_NULL, "NULL" },
517 { 0, NULL }
518};
519
Harald Welte7b26bcb2009-05-28 11:39:21 +0000520const char *nm_adm_name(u_int8_t adm)
521{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200522 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte7b26bcb2009-05-28 11:39:21 +0000523}
Harald Weltee0590df2009-02-15 03:34:15 +0000524
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100525int nm_is_running(struct gsm_nm_state *s) {
526 return (s->operational == NM_OPSTATE_ENABLED) && (
527 (s->availability == NM_AVSTATE_OK) ||
528 (s->availability == 0xff)
529 );
530}
531
Harald Weltea8bd6d42009-10-20 09:56:18 +0200532static void debugp_foh(struct abis_om_fom_hdr *foh)
533{
534 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200535 obj_class_name(foh->obj_class), foh->obj_class,
Harald Weltea8bd6d42009-10-20 09:56:18 +0200536 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
537 foh->obj_inst.ts_nr);
538}
539
Harald Weltee0590df2009-02-15 03:34:15 +0000540/* obtain the gsm_nm_state data structure for a given object instance */
541static struct gsm_nm_state *
542objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
543 struct abis_om_obj_inst *obj_inst)
544{
545 struct gsm_bts_trx *trx;
546 struct gsm_nm_state *nm_state = NULL;
547
548 switch (obj_class) {
549 case NM_OC_BTS:
550 nm_state = &bts->nm_state;
551 break;
552 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100553 if (obj_inst->trx_nr >= bts->num_trx) {
554 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000555 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100556 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200557 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000558 nm_state = &trx->nm_state;
559 break;
560 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100561 if (obj_inst->trx_nr >= bts->num_trx) {
562 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000563 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100564 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200565 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000566 nm_state = &trx->bb_transc.nm_state;
567 break;
568 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100569 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100570 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000571 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100572 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200573 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000574 if (obj_inst->ts_nr >= TRX_NR_TS)
575 return NULL;
576 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
577 break;
578 case NM_OC_SITE_MANAGER:
579 nm_state = &bts->site_mgr.nm_state;
580 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000581 case NM_OC_BS11:
582 switch (obj_inst->bts_nr) {
583 case BS11_OBJ_CCLK:
584 nm_state = &bts->bs11.cclk.nm_state;
585 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000586 case BS11_OBJ_BBSIG:
587 if (obj_inst->ts_nr > bts->num_trx)
588 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200589 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000590 nm_state = &trx->bs11.bbsig.nm_state;
591 break;
592 case BS11_OBJ_PA:
593 if (obj_inst->ts_nr > bts->num_trx)
594 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200595 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000596 nm_state = &trx->bs11.pa.nm_state;
597 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000598 default:
599 return NULL;
600 }
601 case NM_OC_BS11_RACK:
602 nm_state = &bts->bs11.rack.nm_state;
603 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000604 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100605 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000606 return NULL;
607 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
608 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200609 case NM_OC_GPRS_NSE:
610 nm_state = &bts->gprs.nse.nm_state;
611 break;
612 case NM_OC_GPRS_CELL:
613 nm_state = &bts->gprs.cell.nm_state;
614 break;
615 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100616 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200617 return NULL;
618 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
619 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000620 }
621 return nm_state;
622}
623
624/* obtain the in-memory data structure of a given object instance */
625static void *
626objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
627 struct abis_om_obj_inst *obj_inst)
628{
629 struct gsm_bts_trx *trx;
630 void *obj = NULL;
631
632 switch (obj_class) {
633 case NM_OC_BTS:
634 obj = bts;
635 break;
636 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100637 if (obj_inst->trx_nr >= bts->num_trx) {
638 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000639 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100640 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200641 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000642 obj = trx;
643 break;
644 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100645 if (obj_inst->trx_nr >= bts->num_trx) {
646 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000647 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100648 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200649 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000650 obj = &trx->bb_transc;
651 break;
652 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100653 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100654 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000655 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100656 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200657 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000658 if (obj_inst->ts_nr >= TRX_NR_TS)
659 return NULL;
660 obj = &trx->ts[obj_inst->ts_nr];
661 break;
662 case NM_OC_SITE_MANAGER:
663 obj = &bts->site_mgr;
664 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200665 case NM_OC_GPRS_NSE:
666 obj = &bts->gprs.nse;
667 break;
668 case NM_OC_GPRS_CELL:
669 obj = &bts->gprs.cell;
670 break;
671 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100672 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200673 return NULL;
674 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
675 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000676 }
677 return obj;
678}
679
680/* Update the administrative state of a given object in our in-memory data
681 * structures and send an event to the higher layer */
682static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
683 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
684{
Harald Welteaeedeb42009-05-01 13:08:14 +0000685 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000686 void *obj;
687 int rc;
688
Harald Weltee0590df2009-02-15 03:34:15 +0000689 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100690 if (!obj)
691 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000692 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
693 if (!nm_state)
694 return -1;
695
696 new_state = *nm_state;
697 new_state.administrative = adm_state;
698
Holger Hans Peter Freytheraa0db802010-05-13 00:37:48 +0800699 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000700
701 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000702
703 return rc;
704}
705
Harald Welte97ed1e72009-02-06 13:38:02 +0000706static int abis_nm_rx_statechg_rep(struct msgb *mb)
707{
Harald Weltee0590df2009-02-15 03:34:15 +0000708 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000709 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000710 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000711 struct tlv_parsed tp;
712 struct gsm_nm_state *nm_state, new_state;
713 int rc;
714
Harald Welte23897662009-05-01 14:52:51 +0000715 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000716
Harald Welte8b697c72009-06-05 19:18:45 +0000717 memset(&new_state, 0, sizeof(new_state));
718
Harald Weltee0590df2009-02-15 03:34:15 +0000719 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
720 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100721 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000722 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000723 }
Harald Weltee0590df2009-02-15 03:34:15 +0000724
725 new_state = *nm_state;
726
Harald Welte39315c42010-01-10 18:01:52 +0100727 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000728 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
729 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000730 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000731 }
732 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000733 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
734 new_state.availability = 0xff;
735 else
736 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000737 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000738 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100739 } else
740 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000741 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
742 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200743 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000744 }
745 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000746
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100747 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
748 new_state.operational != nm_state->operational ||
749 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000750 /* Update the operational state of a given object in our in-memory data
751 * structures and send an event to the higher layer */
752 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Holger Hans Peter Freytheraa0db802010-05-13 00:37:48 +0800753 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100754 nm_state->operational = new_state.operational;
755 nm_state->availability = new_state.availability;
756 if (nm_state->administrative == 0)
757 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000758 }
759#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000760 if (op_state == 1) {
761 /* try to enable objects that are disabled */
762 abis_nm_opstart(bts, foh->obj_class,
763 foh->obj_inst.bts_nr,
764 foh->obj_inst.trx_nr,
765 foh->obj_inst.ts_nr);
766 }
Harald Weltee0590df2009-02-15 03:34:15 +0000767#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000768 return 0;
769}
770
Harald Welte0db97b22009-05-01 17:22:47 +0000771static int rx_fail_evt_rep(struct msgb *mb)
772{
773 struct abis_om_hdr *oh = msgb_l2(mb);
774 struct abis_om_fom_hdr *foh = msgb_l3(mb);
775 struct tlv_parsed tp;
776
777 DEBUGPC(DNM, "Failure Event Report ");
778
Harald Welte39315c42010-01-10 18:01:52 +0100779 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000780
781 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
782 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
783 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
784 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
785
786 DEBUGPC(DNM, "\n");
787
788 return 0;
789}
790
Harald Welte97ed1e72009-02-06 13:38:02 +0000791static int abis_nm_rcvmsg_report(struct msgb *mb)
792{
793 struct abis_om_fom_hdr *foh = msgb_l3(mb);
794 u_int8_t mt = foh->msg_type;
795
Harald Weltea8bd6d42009-10-20 09:56:18 +0200796 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000797
Harald Welte97ed1e72009-02-06 13:38:02 +0000798 //nmh->cfg->report_cb(mb, foh);
799
800 switch (mt) {
801 case NM_MT_STATECHG_EVENT_REP:
802 return abis_nm_rx_statechg_rep(mb);
803 break;
Harald Welte34a99682009-02-13 02:41:40 +0000804 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000805 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000806 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000807 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000808 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000809 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000810 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000811 break;
Harald Weltec7310382009-08-08 00:02:36 +0200812 case NM_MT_TEST_REP:
813 DEBUGPC(DNM, "Test Report\n");
814 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
815 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000816 default:
Harald Welte23897662009-05-01 14:52:51 +0000817 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000818 break;
819
Harald Welte97ed1e72009-02-06 13:38:02 +0000820 };
821
Harald Welte97ed1e72009-02-06 13:38:02 +0000822 return 0;
823}
824
Harald Welte34a99682009-02-13 02:41:40 +0000825/* Activate the specified software into the BTS */
826static 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 +0200827 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000828{
829 struct abis_om_hdr *oh;
830 struct msgb *msg = nm_msgb_alloc();
831 u_int8_t len = swdesc_len;
832 u_int8_t *trailer;
833
834 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
835 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
836
837 trailer = msgb_put(msg, swdesc_len);
838 memcpy(trailer, sw_desc, swdesc_len);
839
840 return abis_nm_sendmsg(bts, msg);
841}
842
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100843static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
844{
845 static const struct tlv_definition sw_descr_def = {
846 .def = {
847 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
848 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
849 },
850 };
851
852 u_int8_t tag;
853 u_int16_t tag_len;
854 const u_int8_t *val;
855 int ofs = 0, len;
856
857 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
858 * nested nature and the fact you have to assume it contains only two sub
859 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
860
861 if (sw_descr[0] != NM_ATT_SW_DESCR) {
862 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
863 return -1;
864 }
865 ofs += 1;
866
867 len = tlv_parse_one(&tag, &tag_len, &val,
868 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
869 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
870 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
871 return -2;
872 }
873 ofs += len;
874
875 len = tlv_parse_one(&tag, &tag_len, &val,
876 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
877 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
878 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
879 return -3;
880 }
881 ofs += len;
882
883 return ofs;
884}
885
Harald Welte34a99682009-02-13 02:41:40 +0000886static int abis_nm_rx_sw_act_req(struct msgb *mb)
887{
888 struct abis_om_hdr *oh = msgb_l2(mb);
889 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200890 struct tlv_parsed tp;
891 const u_int8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100892 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000893
Harald Weltea8bd6d42009-10-20 09:56:18 +0200894 debugp_foh(foh);
895
896 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000897
Harald Welte97a282b2010-03-14 15:37:43 +0800898 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000899
900 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000901 foh->obj_inst.bts_nr,
902 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800903 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000904 foh->data, oh->length-sizeof(*foh));
905
Harald Welte39315c42010-01-10 18:01:52 +0100906 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200907 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
908 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
909 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
910 DEBUGP(DNM, "SW config not found! Can't continue.\n");
911 return -EINVAL;
912 } else {
913 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
914 }
915
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100916 /* Use the first SW_DESCR present in SW config */
917 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
918 if (sw_descr_len < 0)
919 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200920
Harald Welte34a99682009-02-13 02:41:40 +0000921 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
922 foh->obj_inst.bts_nr,
923 foh->obj_inst.trx_nr,
924 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100925 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000926}
927
Harald Weltee0590df2009-02-15 03:34:15 +0000928/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
929static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
930{
931 struct abis_om_hdr *oh = msgb_l2(mb);
932 struct abis_om_fom_hdr *foh = msgb_l3(mb);
933 struct tlv_parsed tp;
934 u_int8_t adm_state;
935
Harald Welte39315c42010-01-10 18:01:52 +0100936 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000937 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
938 return -EINVAL;
939
940 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
941
942 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
943}
944
Harald Welteee670472009-02-22 21:58:49 +0000945static int abis_nm_rx_lmt_event(struct msgb *mb)
946{
947 struct abis_om_hdr *oh = msgb_l2(mb);
948 struct abis_om_fom_hdr *foh = msgb_l3(mb);
949 struct tlv_parsed tp;
950
951 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100952 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000953 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
954 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
955 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
956 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
957 }
958 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
959 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
960 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
961 DEBUGPC(DNM, "Level=%u ", level);
962 }
963 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
964 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
965 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
966 DEBUGPC(DNM, "Username=%s ", name);
967 }
968 DEBUGPC(DNM, "\n");
969 /* FIXME: parse LMT LOGON TIME */
970 return 0;
971}
972
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100973static void abis_nm_queue_send_next(struct gsm_bts *bts)
974{
975 int wait = 0;
976 struct msgb *msg;
977 /* the queue is empty */
978 while (!llist_empty(&bts->abis_queue)) {
979 msg = msgb_dequeue(&bts->abis_queue);
980 wait = OBSC_NM_W_ACK_CB(msg);
981 _abis_nm_sendmsg(msg);
982
983 if (wait)
984 break;
985 }
986
987 bts->abis_nm_pend = wait;
988}
989
Harald Welte52b1f982008-12-23 20:25:15 +0000990/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000991static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000992{
Harald Welte6c96ba52009-05-01 13:03:40 +0000993 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000994 struct abis_om_fom_hdr *foh = msgb_l3(mb);
995 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100996 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000997
998 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000999 if (is_report(mt))
1000 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001001
Harald Welte4724f992009-01-18 18:01:49 +00001002 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1003 return abis_nm_rcvmsg_sw(mb);
1004
Harald Welte78fc0d42009-02-19 02:50:57 +00001005 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001006 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +00001007 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001008
Harald Weltea8bd6d42009-10-20 09:56:18 +02001009 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001010
Harald Welte92b1fe42010-03-25 11:45:30 +08001011 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +00001012
Harald Welte39315c42010-01-10 18:01:52 +01001013 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +00001014 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001015 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00001016 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1017 else
1018 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001019
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001020 nack_data.msg = mb;
1021 nack_data.mt = mt;
1022 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001023 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001024 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001025 }
Harald Weltead384642008-12-26 10:20:07 +00001026#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001027 /* check if last message is to be acked */
1028 if (is_ack_nack(nmh->last_msgtype)) {
1029 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001030 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001031 /* we got our ACK, continue sending the next msg */
1032 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1033 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001034 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001035 /* FIXME: somehow signal this to the caller */
1036 } else {
1037 /* really strange things happen */
1038 return -EINVAL;
1039 }
1040 }
Harald Weltead384642008-12-26 10:20:07 +00001041#endif
1042
Harald Welte97ed1e72009-02-06 13:38:02 +00001043 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001044 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001045 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +00001046 break;
Harald Welte34a99682009-02-13 02:41:40 +00001047 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001048 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +00001049 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001050 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001051 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001052 break;
Harald Welte1989c082009-08-06 17:58:31 +02001053 case NM_MT_CONN_MDROP_LINK_ACK:
1054 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1055 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001056 case NM_MT_IPACC_RESTART_ACK:
1057 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1058 break;
1059 case NM_MT_IPACC_RESTART_NACK:
1060 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1061 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001062 }
1063
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001064 abis_nm_queue_send_next(mb->trx->bts);
1065 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001066}
1067
Harald Welte677c21f2009-02-17 13:22:23 +00001068static int abis_nm_rx_ipacc(struct msgb *mb);
1069
1070static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1071{
1072 int rc;
1073 int bts_type = mb->trx->bts->type;
1074
1075 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001076 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001077 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001078 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +00001079 break;
1080 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001081 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1082 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001083 rc = 0;
1084 break;
1085 }
1086
1087 return rc;
1088}
1089
Harald Welte52b1f982008-12-23 20:25:15 +00001090/* High-Level API */
1091/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001092int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001093{
Harald Welte52b1f982008-12-23 20:25:15 +00001094 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001095 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001096
1097 /* Various consistency checks */
1098 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001099 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001100 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001101 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1102 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001103 }
1104 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001105 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001106 oh->sequence);
1107 return -EINVAL;
1108 }
Harald Welte702d8702008-12-26 20:25:35 +00001109#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001110 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1111 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001112 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001113 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001114 oh->length + sizeof(*oh), l2_len);
1115 return -EINVAL;
1116 }
Harald Welte702d8702008-12-26 20:25:35 +00001117 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001118 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 +00001119#endif
Harald Weltead384642008-12-26 10:20:07 +00001120 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001121
1122 switch (oh->mdisc) {
1123 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001124 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001125 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001126 case ABIS_OM_MDISC_MANUF:
1127 rc = abis_nm_rcvmsg_manuf(msg);
1128 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001129 case ABIS_OM_MDISC_MMI:
1130 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001131 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001132 oh->mdisc);
1133 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001134 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001135 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001136 oh->mdisc);
1137 return -EINVAL;
1138 }
1139
Harald Weltead384642008-12-26 10:20:07 +00001140 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001141 return rc;
1142}
1143
1144#if 0
1145/* initialized all resources */
1146struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1147{
1148 struct abis_nm_h *nmh;
1149
1150 nmh = malloc(sizeof(*nmh));
1151 if (!nmh)
1152 return NULL;
1153
1154 nmh->cfg = cfg;
1155
1156 return nmh;
1157}
1158
1159/* free all resources */
1160void abis_nm_fini(struct abis_nm_h *nmh)
1161{
1162 free(nmh);
1163}
1164#endif
1165
1166/* Here we are trying to define a high-level API that can be used by
1167 * the actual BSC implementation. However, the architecture is currently
1168 * still under design. Ideally the calls to this API would be synchronous,
1169 * while the underlying stack behind the APi runs in a traditional select
1170 * based state machine.
1171 */
1172
Harald Welte4724f992009-01-18 18:01:49 +00001173/* 6.2 Software Load: */
1174enum sw_state {
1175 SW_STATE_NONE,
1176 SW_STATE_WAIT_INITACK,
1177 SW_STATE_WAIT_SEGACK,
1178 SW_STATE_WAIT_ENDACK,
1179 SW_STATE_WAIT_ACTACK,
1180 SW_STATE_ERROR,
1181};
Harald Welte52b1f982008-12-23 20:25:15 +00001182
Harald Welte52b1f982008-12-23 20:25:15 +00001183struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001184 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001185 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001186 gsm_cbfn *cbfn;
1187 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001188 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001189
Harald Welte52b1f982008-12-23 20:25:15 +00001190 /* this will become part of the SW LOAD INITIATE */
1191 u_int8_t obj_class;
1192 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001193
1194 u_int8_t file_id[255];
1195 u_int8_t file_id_len;
1196
1197 u_int8_t file_version[255];
1198 u_int8_t file_version_len;
1199
1200 u_int8_t window_size;
1201 u_int8_t seg_in_window;
1202
1203 int fd;
1204 FILE *stream;
1205 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001206 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001207};
1208
Harald Welte4724f992009-01-18 18:01:49 +00001209static struct abis_nm_sw g_sw;
1210
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001211static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1212{
1213 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1214 msgb_v_put(msg, NM_ATT_SW_DESCR);
1215 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1216 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1217 sw->file_version);
1218 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1219 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1220 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1221 sw->file_version);
1222 } else {
1223 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1224 }
1225}
1226
Harald Welte4724f992009-01-18 18:01:49 +00001227/* 6.2.1 / 8.3.1: Load Data Initiate */
1228static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001229{
Harald Welte4724f992009-01-18 18:01:49 +00001230 struct abis_om_hdr *oh;
1231 struct msgb *msg = nm_msgb_alloc();
1232 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1233
1234 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1235 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1236 sw->obj_instance[0], sw->obj_instance[1],
1237 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001238
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001239 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001240 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1241
1242 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001243}
1244
Harald Welte1602ade2009-01-29 21:12:39 +00001245static int is_last_line(FILE *stream)
1246{
1247 char next_seg_buf[256];
1248 long pos;
1249
1250 /* check if we're sending the last line */
1251 pos = ftell(stream);
1252 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1253 fseek(stream, pos, SEEK_SET);
1254 return 1;
1255 }
1256
1257 fseek(stream, pos, SEEK_SET);
1258 return 0;
1259}
1260
Harald Welte4724f992009-01-18 18:01:49 +00001261/* 6.2.2 / 8.3.2 Load Data Segment */
1262static int sw_load_segment(struct abis_nm_sw *sw)
1263{
1264 struct abis_om_hdr *oh;
1265 struct msgb *msg = nm_msgb_alloc();
1266 char seg_buf[256];
1267 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001268 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001269 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001270
1271 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001272
1273 switch (sw->bts->type) {
1274 case GSM_BTS_TYPE_BS11:
1275 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1276 perror("fgets reading segment");
1277 return -EINVAL;
1278 }
1279 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001280
1281 /* check if we're sending the last line */
1282 sw->last_seg = is_last_line(sw->stream);
1283 if (sw->last_seg)
1284 seg_buf[1] = 0;
1285 else
1286 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001287
1288 len = strlen(line_buf) + 2;
1289 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1290 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1291 /* BS11 wants CR + LF in excess of the TLV length !?! */
1292 tlv[1] -= 2;
1293
1294 /* we only now know the exact length for the OM hdr */
1295 len = strlen(line_buf)+2;
1296 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001297 case GSM_BTS_TYPE_NANOBTS: {
1298 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1299 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1300 if (len < 0) {
1301 perror("read failed");
1302 return -EINVAL;
1303 }
1304
1305 if (len != IPACC_SEGMENT_SIZE)
1306 sw->last_seg = 1;
1307
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001308 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001309 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1310 len += 3;
1311 break;
1312 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001313 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001314 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001315 /* FIXME: Other BTS types */
1316 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001317 }
Harald Welte4724f992009-01-18 18:01:49 +00001318
Harald Welte4724f992009-01-18 18:01:49 +00001319 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1320 sw->obj_instance[0], sw->obj_instance[1],
1321 sw->obj_instance[2]);
1322
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001323 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001324}
1325
1326/* 6.2.4 / 8.3.4 Load Data End */
1327static int sw_load_end(struct abis_nm_sw *sw)
1328{
1329 struct abis_om_hdr *oh;
1330 struct msgb *msg = nm_msgb_alloc();
1331 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1332
1333 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1334 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1335 sw->obj_instance[0], sw->obj_instance[1],
1336 sw->obj_instance[2]);
1337
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001338 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001339 return abis_nm_sendmsg(sw->bts, msg);
1340}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001341
Harald Welte52b1f982008-12-23 20:25:15 +00001342/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001343static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001344{
Harald Welte4724f992009-01-18 18:01:49 +00001345 struct abis_om_hdr *oh;
1346 struct msgb *msg = nm_msgb_alloc();
1347 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001348
Harald Welte4724f992009-01-18 18:01:49 +00001349 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1350 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1351 sw->obj_instance[0], sw->obj_instance[1],
1352 sw->obj_instance[2]);
1353
1354 /* FIXME: this is BS11 specific format */
1355 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1356 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1357 sw->file_version);
1358
1359 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001360}
Harald Welte4724f992009-01-18 18:01:49 +00001361
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001362struct sdp_firmware {
1363 char magic[4];
1364 char more_magic[4];
1365 unsigned int header_length;
1366 unsigned int file_length;
1367} __attribute__ ((packed));
1368
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001369static int parse_sdp_header(struct abis_nm_sw *sw)
1370{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001371 struct sdp_firmware firmware_header;
1372 int rc;
1373 struct stat stat;
1374
1375 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1376 if (rc != sizeof(firmware_header)) {
1377 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1378 return -1;
1379 }
1380
1381 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1382 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1383 return -1;
1384 }
1385
1386 if (firmware_header.more_magic[0] != 0x10 ||
1387 firmware_header.more_magic[1] != 0x02 ||
1388 firmware_header.more_magic[2] != 0x00 ||
1389 firmware_header.more_magic[3] != 0x00) {
1390 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1391 return -1;
1392 }
1393
1394
1395 if (fstat(sw->fd, &stat) == -1) {
1396 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1397 return -1;
1398 }
1399
1400 if (ntohl(firmware_header.file_length) != stat.st_size) {
1401 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1402 return -1;
1403 }
1404
1405 /* go back to the start as we checked the whole filesize.. */
1406 lseek(sw->fd, 0l, SEEK_SET);
1407 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1408 "There might be checksums in the file that are not\n"
1409 "verified and incomplete firmware might be flashed.\n"
1410 "There is absolutely no WARRANTY that flashing will\n"
1411 "work.\n");
1412 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001413}
1414
Harald Welte4724f992009-01-18 18:01:49 +00001415static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1416{
1417 char file_id[12+1];
1418 char file_version[80+1];
1419 int rc;
1420
1421 sw->fd = open(fname, O_RDONLY);
1422 if (sw->fd < 0)
1423 return sw->fd;
1424
1425 switch (sw->bts->type) {
1426 case GSM_BTS_TYPE_BS11:
1427 sw->stream = fdopen(sw->fd, "r");
1428 if (!sw->stream) {
1429 perror("fdopen");
1430 return -1;
1431 }
1432 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001433 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001434 file_id, file_version);
1435 if (rc != 2) {
1436 perror("parsing header line of software file");
1437 return -1;
1438 }
1439 strcpy((char *)sw->file_id, file_id);
1440 sw->file_id_len = strlen(file_id);
1441 strcpy((char *)sw->file_version, file_version);
1442 sw->file_version_len = strlen(file_version);
1443 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001444 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001445 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001446 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001447 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001448 rc = parse_sdp_header(sw);
1449 if (rc < 0) {
1450 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1451 return -1;
1452 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001453
1454 strcpy((char *)sw->file_id, "id");
1455 sw->file_id_len = 3;
1456 strcpy((char *)sw->file_version, "version");
1457 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001458 break;
Harald Welte4724f992009-01-18 18:01:49 +00001459 default:
1460 /* We don't know how to treat them yet */
1461 close(sw->fd);
1462 return -EINVAL;
1463 }
1464
1465 return 0;
1466}
1467
1468static void sw_close_file(struct abis_nm_sw *sw)
1469{
1470 switch (sw->bts->type) {
1471 case GSM_BTS_TYPE_BS11:
1472 fclose(sw->stream);
1473 break;
1474 default:
1475 close(sw->fd);
1476 break;
1477 }
1478}
1479
1480/* Fill the window */
1481static int sw_fill_window(struct abis_nm_sw *sw)
1482{
1483 int rc;
1484
1485 while (sw->seg_in_window < sw->window_size) {
1486 rc = sw_load_segment(sw);
1487 if (rc < 0)
1488 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001489 if (sw->last_seg)
1490 break;
Harald Welte4724f992009-01-18 18:01:49 +00001491 }
1492 return 0;
1493}
1494
1495/* callback function from abis_nm_rcvmsg() handler */
1496static int abis_nm_rcvmsg_sw(struct msgb *mb)
1497{
1498 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1499 int rc = -1;
1500 struct abis_nm_sw *sw = &g_sw;
1501 enum sw_state old_state = sw->state;
1502
Harald Welte3ffd1372009-02-01 22:15:49 +00001503 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001504
1505 switch (sw->state) {
1506 case SW_STATE_WAIT_INITACK:
1507 switch (foh->msg_type) {
1508 case NM_MT_LOAD_INIT_ACK:
1509 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001510 if (sw->cbfn)
1511 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1512 NM_MT_LOAD_INIT_ACK, mb,
1513 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001514 rc = sw_fill_window(sw);
1515 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001516 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001517 break;
1518 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001519 if (sw->forced) {
1520 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1521 "Init NACK\n");
1522 if (sw->cbfn)
1523 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1524 NM_MT_LOAD_INIT_ACK, mb,
1525 sw->cb_data, NULL);
1526 rc = sw_fill_window(sw);
1527 sw->state = SW_STATE_WAIT_SEGACK;
1528 } else {
1529 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001530 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001531 if (sw->cbfn)
1532 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1533 NM_MT_LOAD_INIT_NACK, mb,
1534 sw->cb_data, NULL);
1535 sw->state = SW_STATE_ERROR;
1536 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001537 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001538 break;
1539 }
1540 break;
1541 case SW_STATE_WAIT_SEGACK:
1542 switch (foh->msg_type) {
1543 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001544 if (sw->cbfn)
1545 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1546 NM_MT_LOAD_SEG_ACK, mb,
1547 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001548 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001549 if (!sw->last_seg) {
1550 /* fill window with more segments */
1551 rc = sw_fill_window(sw);
1552 sw->state = SW_STATE_WAIT_SEGACK;
1553 } else {
1554 /* end the transfer */
1555 sw->state = SW_STATE_WAIT_ENDACK;
1556 rc = sw_load_end(sw);
1557 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001558 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001559 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001560 case NM_MT_LOAD_ABORT:
1561 if (sw->cbfn)
1562 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1563 NM_MT_LOAD_ABORT, mb,
1564 sw->cb_data, NULL);
1565 break;
Harald Welte4724f992009-01-18 18:01:49 +00001566 }
1567 break;
1568 case SW_STATE_WAIT_ENDACK:
1569 switch (foh->msg_type) {
1570 case NM_MT_LOAD_END_ACK:
1571 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001572 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1573 sw->bts->nr);
1574 sw->state = SW_STATE_NONE;
1575 if (sw->cbfn)
1576 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1577 NM_MT_LOAD_END_ACK, mb,
1578 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001579 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001580 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001581 break;
1582 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001583 if (sw->forced) {
1584 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1585 "End NACK\n");
1586 sw->state = SW_STATE_NONE;
1587 if (sw->cbfn)
1588 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1589 NM_MT_LOAD_END_ACK, mb,
1590 sw->cb_data, NULL);
1591 } else {
1592 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001593 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001594 sw->state = SW_STATE_ERROR;
1595 if (sw->cbfn)
1596 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1597 NM_MT_LOAD_END_NACK, mb,
1598 sw->cb_data, NULL);
1599 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001600 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001601 break;
1602 }
1603 case SW_STATE_WAIT_ACTACK:
1604 switch (foh->msg_type) {
1605 case NM_MT_ACTIVATE_SW_ACK:
1606 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001607 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001608 sw->state = SW_STATE_NONE;
1609 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001610 if (sw->cbfn)
1611 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1612 NM_MT_ACTIVATE_SW_ACK, mb,
1613 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001614 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001615 break;
1616 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001617 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001618 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001619 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001620 if (sw->cbfn)
1621 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1622 NM_MT_ACTIVATE_SW_NACK, mb,
1623 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001624 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001625 break;
1626 }
1627 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001628 switch (foh->msg_type) {
1629 case NM_MT_ACTIVATE_SW_ACK:
1630 rc = 0;
1631 break;
1632 }
1633 break;
Harald Welte4724f992009-01-18 18:01:49 +00001634 case SW_STATE_ERROR:
1635 break;
1636 }
1637
1638 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001639 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001640 foh->msg_type, old_state, sw->state);
1641
1642 return rc;
1643}
1644
1645/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001646int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001647 u_int8_t win_size, int forced,
1648 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001649{
1650 struct abis_nm_sw *sw = &g_sw;
1651 int rc;
1652
Harald Welte5e4d1b32009-02-01 13:36:56 +00001653 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1654 bts->nr, fname);
1655
Harald Welte4724f992009-01-18 18:01:49 +00001656 if (sw->state != SW_STATE_NONE)
1657 return -EBUSY;
1658
1659 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001660 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001661
1662 switch (bts->type) {
1663 case GSM_BTS_TYPE_BS11:
1664 sw->obj_class = NM_OC_SITE_MANAGER;
1665 sw->obj_instance[0] = 0xff;
1666 sw->obj_instance[1] = 0xff;
1667 sw->obj_instance[2] = 0xff;
1668 break;
1669 case GSM_BTS_TYPE_NANOBTS:
1670 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001671 sw->obj_instance[0] = sw->bts->nr;
1672 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001673 sw->obj_instance[2] = 0xff;
1674 break;
1675 case GSM_BTS_TYPE_UNKNOWN:
1676 default:
1677 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1678 return -1;
1679 break;
1680 }
Harald Welte4724f992009-01-18 18:01:49 +00001681 sw->window_size = win_size;
1682 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001683 sw->cbfn = cbfn;
1684 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001685 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001686
1687 rc = sw_open_file(sw, fname);
1688 if (rc < 0) {
1689 sw->state = SW_STATE_NONE;
1690 return rc;
1691 }
1692
1693 return sw_load_init(sw);
1694}
Harald Welte52b1f982008-12-23 20:25:15 +00001695
Harald Welte1602ade2009-01-29 21:12:39 +00001696int abis_nm_software_load_status(struct gsm_bts *bts)
1697{
1698 struct abis_nm_sw *sw = &g_sw;
1699 struct stat st;
1700 int rc, percent;
1701
1702 rc = fstat(sw->fd, &st);
1703 if (rc < 0) {
1704 perror("ERROR during stat");
1705 return rc;
1706 }
1707
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001708 if (sw->stream)
1709 percent = (ftell(sw->stream) * 100) / st.st_size;
1710 else
1711 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001712 return percent;
1713}
1714
Harald Welte5e4d1b32009-02-01 13:36:56 +00001715/* Activate the specified software into the BTS */
1716int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1717 gsm_cbfn *cbfn, void *cb_data)
1718{
1719 struct abis_nm_sw *sw = &g_sw;
1720 int rc;
1721
1722 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1723 bts->nr, fname);
1724
1725 if (sw->state != SW_STATE_NONE)
1726 return -EBUSY;
1727
1728 sw->bts = bts;
1729 sw->obj_class = NM_OC_SITE_MANAGER;
1730 sw->obj_instance[0] = 0xff;
1731 sw->obj_instance[1] = 0xff;
1732 sw->obj_instance[2] = 0xff;
1733 sw->state = SW_STATE_WAIT_ACTACK;
1734 sw->cbfn = cbfn;
1735 sw->cb_data = cb_data;
1736
1737 /* Open the file in order to fill some sw struct members */
1738 rc = sw_open_file(sw, fname);
1739 if (rc < 0) {
1740 sw->state = SW_STATE_NONE;
1741 return rc;
1742 }
1743 sw_close_file(sw);
1744
1745 return sw_activate(sw);
1746}
1747
Harald Welte8470bf22008-12-25 23:28:35 +00001748static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001749 u_int8_t ts_nr, u_int8_t subslot_nr)
1750{
Harald Welteadaf08b2009-01-18 11:08:10 +00001751 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001752 ch->bts_port = bts_port;
1753 ch->timeslot = ts_nr;
1754 ch->subslot = subslot_nr;
1755}
1756
1757int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1758 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1759 u_int8_t tei)
1760{
1761 struct abis_om_hdr *oh;
1762 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001763 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001764 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001765
1766 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1767 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1768 bts->bts_nr, trx_nr, 0xff);
1769
Harald Welte8470bf22008-12-25 23:28:35 +00001770 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001771
1772 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1773 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1774
1775 return abis_nm_sendmsg(bts, msg);
1776}
1777
1778/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1779int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1780 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1781{
Harald Welte8470bf22008-12-25 23:28:35 +00001782 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001783 struct abis_om_hdr *oh;
1784 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001785 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001786
1787 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001788 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001789 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1790
1791 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1792 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1793
1794 return abis_nm_sendmsg(bts, msg);
1795}
1796
1797#if 0
1798int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1799 struct abis_nm_abis_channel *chan)
1800{
1801}
1802#endif
1803
1804int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1805 u_int8_t e1_port, u_int8_t e1_timeslot,
1806 u_int8_t e1_subslot)
1807{
1808 struct gsm_bts *bts = ts->trx->bts;
1809 struct abis_om_hdr *oh;
1810 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001811 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001812
1813 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1814 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001815 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001816
1817 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1818 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1819
Harald Weltef325eb42009-02-19 17:07:39 +00001820 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1821 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001822 e1_port, e1_timeslot, e1_subslot);
1823
Harald Welte52b1f982008-12-23 20:25:15 +00001824 return abis_nm_sendmsg(bts, msg);
1825}
1826
1827#if 0
1828int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1829 struct abis_nm_abis_channel *chan,
1830 u_int8_t subchan)
1831{
1832}
1833#endif
1834
Harald Welte22af0db2009-02-14 15:41:08 +00001835/* Chapter 8.6.1 */
1836int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1837{
1838 struct abis_om_hdr *oh;
1839 struct msgb *msg = nm_msgb_alloc();
1840 u_int8_t *cur;
1841
1842 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1843
1844 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001845 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 +00001846 cur = msgb_put(msg, attr_len);
1847 memcpy(cur, attr, attr_len);
1848
1849 return abis_nm_sendmsg(bts, msg);
1850}
1851
1852/* Chapter 8.6.2 */
1853int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1854{
1855 struct abis_om_hdr *oh;
1856 struct msgb *msg = nm_msgb_alloc();
1857 u_int8_t *cur;
1858
1859 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1860
1861 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1862 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001863 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001864 cur = msgb_put(msg, attr_len);
1865 memcpy(cur, attr, attr_len);
1866
1867 return abis_nm_sendmsg(trx->bts, msg);
1868}
1869
Harald Welte39c7deb2009-08-09 21:49:48 +02001870static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1871{
1872 int i;
1873
1874 /* As it turns out, the BS-11 has some very peculiar restrictions
1875 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301876 switch (ts->trx->bts->type) {
1877 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001878 switch (chan_comb) {
1879 case NM_CHANC_TCHHalf:
1880 case NM_CHANC_TCHHalf2:
1881 /* not supported */
1882 return -EINVAL;
1883 case NM_CHANC_SDCCH:
1884 /* only one SDCCH/8 per TRX */
1885 for (i = 0; i < TRX_NR_TS; i++) {
1886 if (i == ts->nr)
1887 continue;
1888 if (ts->trx->ts[i].nm_chan_comb ==
1889 NM_CHANC_SDCCH)
1890 return -EINVAL;
1891 }
1892 /* not allowed for TS0 of BCCH-TRX */
1893 if (ts->trx == ts->trx->bts->c0 &&
1894 ts->nr == 0)
1895 return -EINVAL;
1896 /* not on the same TRX that has a BCCH+SDCCH4
1897 * combination */
1898 if (ts->trx == ts->trx->bts->c0 &&
1899 (ts->trx->ts[0].nm_chan_comb == 5 ||
1900 ts->trx->ts[0].nm_chan_comb == 8))
1901 return -EINVAL;
1902 break;
1903 case NM_CHANC_mainBCCH:
1904 case NM_CHANC_BCCHComb:
1905 /* allowed only for TS0 of C0 */
1906 if (ts->trx != ts->trx->bts->c0 ||
1907 ts->nr != 0)
1908 return -EINVAL;
1909 break;
1910 case NM_CHANC_BCCH:
1911 /* allowed only for TS 2/4/6 of C0 */
1912 if (ts->trx != ts->trx->bts->c0)
1913 return -EINVAL;
1914 if (ts->nr != 2 && ts->nr != 4 &&
1915 ts->nr != 6)
1916 return -EINVAL;
1917 break;
1918 case 8: /* this is not like 08.58, but in fact
1919 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1920 /* FIXME: only one CBCH allowed per cell */
1921 break;
1922 }
Harald Welted6575f92009-12-02 02:45:23 +05301923 break;
1924 case GSM_BTS_TYPE_NANOBTS:
1925 switch (ts->nr) {
1926 case 0:
1927 if (ts->trx->nr == 0) {
1928 /* only on TRX0 */
1929 switch (chan_comb) {
1930 case NM_CHANC_BCCH:
1931 case NM_CHANC_mainBCCH:
1932 case NM_CHANC_BCCHComb:
1933 return 0;
1934 break;
1935 default:
1936 return -EINVAL;
1937 }
1938 } else {
1939 switch (chan_comb) {
1940 case NM_CHANC_TCHFull:
1941 case NM_CHANC_TCHHalf:
1942 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1943 return 0;
1944 default:
1945 return -EINVAL;
1946 }
1947 }
1948 break;
1949 case 1:
1950 if (ts->trx->nr == 0) {
1951 switch (chan_comb) {
1952 case NM_CHANC_SDCCH_CBCH:
1953 if (ts->trx->ts[0].nm_chan_comb ==
1954 NM_CHANC_mainBCCH)
1955 return 0;
1956 return -EINVAL;
1957 case NM_CHANC_SDCCH:
1958 case NM_CHANC_TCHFull:
1959 case NM_CHANC_TCHHalf:
1960 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1961 case NM_CHANC_IPAC_TCHFull_PDCH:
1962 return 0;
1963 }
1964 } else {
1965 switch (chan_comb) {
1966 case NM_CHANC_SDCCH:
1967 case NM_CHANC_TCHFull:
1968 case NM_CHANC_TCHHalf:
1969 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1970 return 0;
1971 default:
1972 return -EINVAL;
1973 }
1974 }
1975 break;
1976 case 2:
1977 case 3:
1978 case 4:
1979 case 5:
1980 case 6:
1981 case 7:
1982 switch (chan_comb) {
1983 case NM_CHANC_TCHFull:
1984 case NM_CHANC_TCHHalf:
1985 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1986 return 0;
1987 case NM_CHANC_IPAC_PDCH:
1988 case NM_CHANC_IPAC_TCHFull_PDCH:
1989 if (ts->trx->nr == 0)
1990 return 0;
1991 else
1992 return -EINVAL;
1993 }
1994 break;
1995 }
1996 return -EINVAL;
1997 default:
1998 /* unknown BTS type */
1999 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002000 }
2001 return 0;
2002}
2003
Harald Welte22af0db2009-02-14 15:41:08 +00002004/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002005int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2006{
2007 struct gsm_bts *bts = ts->trx->bts;
2008 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002009 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002010 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002011 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002012 u_int8_t len = 2 + 2;
2013
2014 if (bts->type == GSM_BTS_TYPE_BS11)
2015 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002016
Harald Weltef325eb42009-02-19 17:07:39 +00002017 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002018 if (verify_chan_comb(ts, chan_comb) < 0) {
2019 msgb_free(msg);
2020 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2021 return -EINVAL;
2022 }
2023 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002024
Harald Welte52b1f982008-12-23 20:25:15 +00002025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002026 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002027 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002028 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002029 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002030 if (ts->hopping.enabled) {
2031 unsigned int i;
2032 uint8_t *len;
2033
Harald Welte6e0cd042009-09-12 13:05:33 +02002034 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2035 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002036
2037 /* build the ARFCN list */
2038 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2039 len = msgb_put(msg, 1);
2040 *len = 0;
2041 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2042 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2043 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002044 /* At least BS-11 wants a TLV16 here */
2045 if (bts->type == GSM_BTS_TYPE_BS11)
2046 *len += 1;
2047 else
2048 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002049 }
2050 }
Harald Weltee0590df2009-02-15 03:34:15 +00002051 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002052 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002053 if (bts->type == GSM_BTS_TYPE_BS11)
2054 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002055
2056 return abis_nm_sendmsg(bts, msg);
2057}
2058
Harald Welte34a99682009-02-13 02:41:40 +00002059int 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 +00002060 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002061{
2062 struct abis_om_hdr *oh;
2063 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002064 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2065 u_int8_t len = att_len;
2066
2067 if (nack) {
2068 len += 2;
2069 msgtype = NM_MT_SW_ACT_REQ_NACK;
2070 }
Harald Welte34a99682009-02-13 02:41:40 +00002071
2072 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002073 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2074
Harald Welte34a99682009-02-13 02:41:40 +00002075 if (attr) {
2076 u_int8_t *ptr = msgb_put(msg, att_len);
2077 memcpy(ptr, attr, att_len);
2078 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002079 if (nack)
2080 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002081
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002082 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002083}
2084
Harald Welte8470bf22008-12-25 23:28:35 +00002085int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002086{
Harald Welte8470bf22008-12-25 23:28:35 +00002087 struct msgb *msg = nm_msgb_alloc();
2088 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002089 u_int8_t *data;
2090
2091 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2092 fill_om_hdr(oh, len);
2093 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002094 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002095
2096 return abis_nm_sendmsg(bts, msg);
2097}
2098
2099/* Siemens specific commands */
2100static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2101{
2102 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002103 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002104
2105 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002106 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002107 0xff, 0xff, 0xff);
2108
2109 return abis_nm_sendmsg(bts, msg);
2110}
2111
Harald Welte34a99682009-02-13 02:41:40 +00002112/* Chapter 8.9.2 */
2113int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2114{
2115 struct abis_om_hdr *oh;
2116 struct msgb *msg = nm_msgb_alloc();
2117
2118 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2119 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2120
Harald Weltea8bd6d42009-10-20 09:56:18 +02002121 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2122 DEBUGPC(DNM, "Sending OPSTART\n");
2123
Harald Welte34a99682009-02-13 02:41:40 +00002124 return abis_nm_sendmsg(bts, msg);
2125}
2126
2127/* Chapter 8.8.5 */
2128int 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 +02002129 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002130{
2131 struct abis_om_hdr *oh;
2132 struct msgb *msg = nm_msgb_alloc();
2133
2134 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2135 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2136 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2137
2138 return abis_nm_sendmsg(bts, msg);
2139}
2140
Harald Welte1989c082009-08-06 17:58:31 +02002141int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2142 u_int8_t e1_port1, u_int8_t ts1)
2143{
2144 struct abis_om_hdr *oh;
2145 struct msgb *msg = nm_msgb_alloc();
2146 u_int8_t *attr;
2147
2148 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2149 e1_port0, ts0, e1_port1, ts1);
2150
2151 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2152 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2153 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2154
2155 attr = msgb_put(msg, 3);
2156 attr[0] = NM_ATT_MDROP_LINK;
2157 attr[1] = e1_port0;
2158 attr[2] = ts0;
2159
2160 attr = msgb_put(msg, 3);
2161 attr[0] = NM_ATT_MDROP_NEXT;
2162 attr[1] = e1_port1;
2163 attr[2] = ts1;
2164
2165 return abis_nm_sendmsg(bts, msg);
2166}
Harald Welte34a99682009-02-13 02:41:40 +00002167
Harald Weltec7310382009-08-08 00:02:36 +02002168/* Chapter 8.7.1 */
2169int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2170 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002171 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002172{
2173 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002174
2175 DEBUGP(DNM, "PEFORM TEST\n");
Harald Welte887deab2010-03-06 11:38:05 +01002176
2177 if (!msg)
2178 msg = nm_msgb_alloc();
2179
2180 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2181 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2182 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2183 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002184 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002185
2186 return abis_nm_sendmsg(bts, msg);
2187}
2188
Harald Welte52b1f982008-12-23 20:25:15 +00002189int abis_nm_event_reports(struct gsm_bts *bts, int on)
2190{
2191 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002192 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002193 else
Harald Welte227d4072009-01-03 08:16:25 +00002194 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002195}
2196
Harald Welte47d88ae2009-01-04 12:02:08 +00002197/* Siemens (or BS-11) specific commands */
2198
Harald Welte3ffd1372009-02-01 22:15:49 +00002199int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2200{
2201 if (reconnect == 0)
2202 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2203 else
2204 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2205}
2206
Harald Welteb8427972009-02-05 19:27:17 +00002207int abis_nm_bs11_restart(struct gsm_bts *bts)
2208{
2209 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2210}
2211
2212
Harald Welte268bb402009-02-01 19:11:56 +00002213struct bs11_date_time {
2214 u_int16_t year;
2215 u_int8_t month;
2216 u_int8_t day;
2217 u_int8_t hour;
2218 u_int8_t min;
2219 u_int8_t sec;
2220} __attribute__((packed));
2221
2222
2223void get_bs11_date_time(struct bs11_date_time *aet)
2224{
2225 time_t t;
2226 struct tm *tm;
2227
2228 t = time(NULL);
2229 tm = localtime(&t);
2230 aet->sec = tm->tm_sec;
2231 aet->min = tm->tm_min;
2232 aet->hour = tm->tm_hour;
2233 aet->day = tm->tm_mday;
2234 aet->month = tm->tm_mon;
2235 aet->year = htons(1900 + tm->tm_year);
2236}
2237
Harald Welte05188ee2009-01-18 11:39:08 +00002238int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002239{
Harald Welte4668fda2009-01-03 08:19:29 +00002240 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002241}
2242
Harald Welte05188ee2009-01-18 11:39:08 +00002243int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002244{
2245 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002246 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002247 else
Harald Welte4668fda2009-01-03 08:19:29 +00002248 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002249}
Harald Welte47d88ae2009-01-04 12:02:08 +00002250
Harald Welte05188ee2009-01-18 11:39:08 +00002251int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002252 enum abis_bs11_objtype type, u_int8_t idx,
2253 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002254{
2255 struct abis_om_hdr *oh;
2256 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002257 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002258
2259 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002260 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002261 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002262 cur = msgb_put(msg, attr_len);
2263 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002264
2265 return abis_nm_sendmsg(bts, msg);
2266}
2267
Harald Welte78fc0d42009-02-19 02:50:57 +00002268int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2269 enum abis_bs11_objtype type, u_int8_t idx)
2270{
2271 struct abis_om_hdr *oh;
2272 struct msgb *msg = nm_msgb_alloc();
2273
2274 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2275 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2276 NM_OC_BS11, type, 0, idx);
2277
2278 return abis_nm_sendmsg(bts, msg);
2279}
2280
Harald Welte05188ee2009-01-18 11:39:08 +00002281int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
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 zero = 0x00;
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, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002289 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2290 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002291
2292 return abis_nm_sendmsg(bts, msg);
2293}
2294
Harald Welte05188ee2009-01-18 11:39:08 +00002295int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002296{
2297 struct abis_om_hdr *oh;
2298 struct msgb *msg = nm_msgb_alloc();
2299
2300 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2301 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002302 idx, 0xff, 0xff);
2303
2304 return abis_nm_sendmsg(bts, msg);
2305}
2306
2307int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2308{
2309 struct abis_om_hdr *oh;
2310 struct msgb *msg = nm_msgb_alloc();
2311
2312 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2313 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2314 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002315
2316 return abis_nm_sendmsg(bts, msg);
2317}
Harald Welte05188ee2009-01-18 11:39:08 +00002318
Harald Welte78fc0d42009-02-19 02:50:57 +00002319static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2320int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2321{
2322 struct abis_om_hdr *oh;
2323 struct msgb *msg = nm_msgb_alloc();
2324
2325 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2326 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2327 0xff, 0xff, 0xff);
2328 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2329
2330 return abis_nm_sendmsg(bts, msg);
2331}
2332
Harald Welteb6c92ae2009-02-21 20:15:32 +00002333/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002334int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002335 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2336 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002337{
2338 struct abis_om_hdr *oh;
2339 struct abis_nm_channel *ch;
2340 struct msgb *msg = nm_msgb_alloc();
2341
2342 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002343 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002344 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2345
2346 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2347 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002348 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002349
2350 return abis_nm_sendmsg(bts, msg);
2351}
2352
2353int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2354{
2355 struct abis_om_hdr *oh;
2356 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002357
2358 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002359 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002360 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2361 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2362
2363 return abis_nm_sendmsg(trx->bts, msg);
2364}
2365
Harald Welte78fc0d42009-02-19 02:50:57 +00002366int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2367{
2368 struct abis_om_hdr *oh;
2369 struct msgb *msg = nm_msgb_alloc();
2370 u_int8_t attr = NM_ATT_BS11_TXPWR;
2371
2372 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2373 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2374 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2375 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2376
2377 return abis_nm_sendmsg(trx->bts, msg);
2378}
2379
Harald Welteaaf02d92009-04-29 13:25:57 +00002380int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2381{
2382 struct abis_om_hdr *oh;
2383 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002384 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002385
2386 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2387 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2388 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002389 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002390
2391 return abis_nm_sendmsg(bts, msg);
2392}
2393
Harald Welteef061952009-05-17 12:43:42 +00002394int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2395{
2396 struct abis_om_hdr *oh;
2397 struct msgb *msg = nm_msgb_alloc();
2398 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2399 NM_ATT_BS11_CCLK_TYPE };
2400
2401 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2402 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2403 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2404 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2405
2406 return abis_nm_sendmsg(bts, msg);
2407
2408}
Harald Welteaaf02d92009-04-29 13:25:57 +00002409
Harald Welte268bb402009-02-01 19:11:56 +00002410//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002411
Harald Welte1bc09062009-01-18 14:17:52 +00002412int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002413{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002414 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2415}
2416
Daniel Willmann4b054c82010-01-07 00:46:26 +01002417int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2418{
2419 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2420}
2421
Daniel Willmann493db4e2010-01-07 00:43:11 +01002422int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2423{
Harald Welte05188ee2009-01-18 11:39:08 +00002424 struct abis_om_hdr *oh;
2425 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002426 struct bs11_date_time bdt;
2427
2428 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002429
2430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002431 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002432 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002433 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002434 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002435 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002436 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002437 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002438 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002439 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002440 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002441 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002442 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002443 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002444 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002445 }
Harald Welte05188ee2009-01-18 11:39:08 +00002446
2447 return abis_nm_sendmsg(bts, msg);
2448}
Harald Welte1bc09062009-01-18 14:17:52 +00002449
2450int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2451{
2452 struct abis_om_hdr *oh;
2453 struct msgb *msg;
2454
2455 if (strlen(password) != 10)
2456 return -EINVAL;
2457
2458 msg = nm_msgb_alloc();
2459 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002460 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002461 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2462 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2463
2464 return abis_nm_sendmsg(bts, msg);
2465}
2466
Harald Weltee69f5fb2009-04-28 16:31:38 +00002467/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2468int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2469{
2470 struct abis_om_hdr *oh;
2471 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002472 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002473
2474 msg = nm_msgb_alloc();
2475 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2476 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2477 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002478
2479 if (locked)
2480 tlv_value = BS11_LI_PLL_LOCKED;
2481 else
2482 tlv_value = BS11_LI_PLL_STANDALONE;
2483
2484 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002485
2486 return abis_nm_sendmsg(bts, msg);
2487}
2488
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002489/* Set the calibration value of the PLL (work value/set value)
2490 * It depends on the login which one is changed */
2491int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2492{
2493 struct abis_om_hdr *oh;
2494 struct msgb *msg;
2495 u_int8_t tlv_value[2];
2496
2497 msg = nm_msgb_alloc();
2498 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2499 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2500 BS11_OBJ_TRX1, 0x00, 0x00);
2501
2502 tlv_value[0] = value>>8;
2503 tlv_value[1] = value&0xff;
2504
2505 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2506
2507 return abis_nm_sendmsg(bts, msg);
2508}
2509
Harald Welte1bc09062009-01-18 14:17:52 +00002510int abis_nm_bs11_get_state(struct gsm_bts *bts)
2511{
2512 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2513}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002514
2515/* BS11 SWL */
2516
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002517void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002518
Harald Welte5e4d1b32009-02-01 13:36:56 +00002519struct abis_nm_bs11_sw {
2520 struct gsm_bts *bts;
2521 char swl_fname[PATH_MAX];
2522 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002523 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002524 struct llist_head file_list;
2525 gsm_cbfn *user_cb; /* specified by the user */
2526};
2527static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2528
2529struct file_list_entry {
2530 struct llist_head list;
2531 char fname[PATH_MAX];
2532};
2533
2534struct file_list_entry *fl_dequeue(struct llist_head *queue)
2535{
2536 struct llist_head *lh;
2537
2538 if (llist_empty(queue))
2539 return NULL;
2540
2541 lh = queue->next;
2542 llist_del(lh);
2543
2544 return llist_entry(lh, struct file_list_entry, list);
2545}
2546
2547static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2548{
2549 char linebuf[255];
2550 struct llist_head *lh, *lh2;
2551 FILE *swl;
2552 int rc = 0;
2553
2554 swl = fopen(bs11_sw->swl_fname, "r");
2555 if (!swl)
2556 return -ENODEV;
2557
2558 /* zero the stale file list, if any */
2559 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2560 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002561 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002562 }
2563
2564 while (fgets(linebuf, sizeof(linebuf), swl)) {
2565 char file_id[12+1];
2566 char file_version[80+1];
2567 struct file_list_entry *fle;
2568 static char dir[PATH_MAX];
2569
2570 if (strlen(linebuf) < 4)
2571 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002572
Harald Welte5e4d1b32009-02-01 13:36:56 +00002573 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2574 if (rc < 0) {
2575 perror("ERR parsing SWL file");
2576 rc = -EINVAL;
2577 goto out;
2578 }
2579 if (rc < 2)
2580 continue;
2581
Harald Welte470ec292009-06-26 20:25:23 +02002582 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002583 if (!fle) {
2584 rc = -ENOMEM;
2585 goto out;
2586 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002587
2588 /* construct new filename */
2589 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2590 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2591 strcat(fle->fname, "/");
2592 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002593
2594 llist_add_tail(&fle->list, &bs11_sw->file_list);
2595 }
2596
2597out:
2598 fclose(swl);
2599 return rc;
2600}
2601
2602/* bs11 swload specific callback, passed to abis_nm core swload */
2603static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2604 struct msgb *msg, void *data, void *param)
2605{
2606 struct abis_nm_bs11_sw *bs11_sw = data;
2607 struct file_list_entry *fle;
2608 int rc = 0;
2609
Harald Welte5e4d1b32009-02-01 13:36:56 +00002610 switch (event) {
2611 case NM_MT_LOAD_END_ACK:
2612 fle = fl_dequeue(&bs11_sw->file_list);
2613 if (fle) {
2614 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002615 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002616 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002617 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002618 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002619 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002620 } else {
2621 /* activate the SWL */
2622 rc = abis_nm_software_activate(bs11_sw->bts,
2623 bs11_sw->swl_fname,
2624 bs11_swload_cbfn,
2625 bs11_sw);
2626 }
2627 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002628 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002629 case NM_MT_LOAD_END_NACK:
2630 case NM_MT_LOAD_INIT_ACK:
2631 case NM_MT_LOAD_INIT_NACK:
2632 case NM_MT_ACTIVATE_SW_NACK:
2633 case NM_MT_ACTIVATE_SW_ACK:
2634 default:
2635 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002636 if (bs11_sw->user_cb)
2637 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002638 break;
2639 }
2640
2641 return rc;
2642}
2643
2644/* Siemens provides a SWL file that is a mere listing of all the other
2645 * files that are part of a software release. We need to upload first
2646 * the list file, and then each file that is listed in the list file */
2647int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002648 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002649{
2650 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2651 struct file_list_entry *fle;
2652 int rc = 0;
2653
2654 INIT_LLIST_HEAD(&bs11_sw->file_list);
2655 bs11_sw->bts = bts;
2656 bs11_sw->win_size = win_size;
2657 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002658 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002659
2660 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2661 rc = bs11_read_swl_file(bs11_sw);
2662 if (rc < 0)
2663 return rc;
2664
2665 /* dequeue next item in file list */
2666 fle = fl_dequeue(&bs11_sw->file_list);
2667 if (!fle)
2668 return -EINVAL;
2669
2670 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002671 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002672 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002673 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002674 return rc;
2675}
2676
Harald Welte5083b0b2009-02-02 19:20:52 +00002677#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002678static u_int8_t req_attr_btse[] = {
2679 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2680 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2681 NM_ATT_BS11_LMT_USER_NAME,
2682
2683 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2684
2685 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2686
2687 NM_ATT_BS11_SW_LOAD_STORED };
2688
2689static u_int8_t req_attr_btsm[] = {
2690 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2691 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2692 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2693 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002694#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002695
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002696static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002697 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2698 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002699 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002700
2701int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2702{
2703 struct abis_om_hdr *oh;
2704 struct msgb *msg = nm_msgb_alloc();
2705
2706 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2707 /* SiemensHW CCTRL object */
2708 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2709 0x03, 0x00, 0x00);
2710 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2711
2712 return abis_nm_sendmsg(bts, msg);
2713}
Harald Welte268bb402009-02-01 19:11:56 +00002714
2715int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2716{
2717 struct abis_om_hdr *oh;
2718 struct msgb *msg = nm_msgb_alloc();
2719 struct bs11_date_time aet;
2720
2721 get_bs11_date_time(&aet);
2722 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2723 /* SiemensHW CCTRL object */
2724 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2725 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002726 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002727
2728 return abis_nm_sendmsg(bts, msg);
2729}
Harald Welte5c1e4582009-02-15 11:57:29 +00002730
Harald Weltef751a102010-12-14 12:52:16 +01002731int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2732{
2733 struct abis_om_hdr *oh;
2734 struct msgb *msg = nm_msgb_alloc();
2735 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2736
2737 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2738 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2739 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2740 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2741
2742 return abis_nm_sendmsg(bts, msg);
2743}
2744
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002745int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2746{
2747 struct abis_om_hdr *oh;
2748 struct msgb *msg = nm_msgb_alloc();
2749 struct bs11_date_time aet;
2750
2751 get_bs11_date_time(&aet);
2752 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2753 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2754 bport, 0xff, 0x02);
2755 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2756
2757 return abis_nm_sendmsg(bts, msg);
2758}
2759
Harald Welte5c1e4582009-02-15 11:57:29 +00002760/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002761static const char ipaccess_magic[] = "com.ipaccess";
2762
Harald Welte677c21f2009-02-17 13:22:23 +00002763
2764static int abis_nm_rx_ipacc(struct msgb *msg)
2765{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002766 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002767 struct abis_om_hdr *oh = msgb_l2(msg);
2768 struct abis_om_fom_hdr *foh;
2769 u_int8_t idstrlen = oh->data[0];
2770 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002771 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002772
2773 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002774 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002775 return -EINVAL;
2776 }
2777
Harald Welte193fefc2009-04-30 15:16:27 +00002778 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002779 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002780
Harald Weltea8bd6d42009-10-20 09:56:18 +02002781 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002782
Harald Welte746d6092009-10-19 22:11:11 +02002783 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002784
Harald Welte677c21f2009-02-17 13:22:23 +00002785 switch (foh->msg_type) {
2786 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002787 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002788 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2789 memcpy(&addr,
2790 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2791
2792 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2793 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002794 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002795 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002796 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002797 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002798 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2799 DEBUGPC(DNM, "STREAM=0x%02x ",
2800 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002801 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002802 break;
2803 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002804 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002805 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002806 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002807 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002808 else
2809 DEBUGPC(DNM, "\n");
2810 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002811 case NM_MT_IPACC_SET_NVATTR_ACK:
2812 DEBUGPC(DNM, "SET NVATTR ACK\n");
2813 /* FIXME: decode and show the actual attributes */
2814 break;
2815 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002816 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002817 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002818 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002819 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2820 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002821 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002822 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002823 case NM_MT_IPACC_GET_NVATTR_ACK:
2824 DEBUGPC(DNM, "GET NVATTR ACK\n");
2825 /* FIXME: decode and show the actual attributes */
2826 break;
2827 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002828 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002829 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002830 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002831 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2832 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002833 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002834 break;
Harald Welte15c44172009-10-08 20:15:24 +02002835 case NM_MT_IPACC_SET_ATTR_ACK:
2836 DEBUGPC(DNM, "SET ATTR ACK\n");
2837 break;
2838 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002839 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002840 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002841 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002842 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2843 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002844 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002845 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002846 default:
2847 DEBUGPC(DNM, "unknown\n");
2848 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002849 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002850
2851 /* signal handling */
2852 switch (foh->msg_type) {
2853 case NM_MT_IPACC_RSL_CONNECT_NACK:
2854 case NM_MT_IPACC_SET_NVATTR_NACK:
2855 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002856 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002857 signal.msg_type = foh->msg_type;
2858 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002859 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002860 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002861 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002862 signal.msg_type = foh->msg_type;
2863 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002864 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002865 default:
2866 break;
2867 }
2868
Harald Welte677c21f2009-02-17 13:22:23 +00002869 return 0;
2870}
2871
Harald Welte193fefc2009-04-30 15:16:27 +00002872/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002873int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2874 u_int8_t obj_class, u_int8_t bts_nr,
2875 u_int8_t trx_nr, u_int8_t ts_nr,
2876 u_int8_t *attr, int attr_len)
2877{
2878 struct msgb *msg = nm_msgb_alloc();
2879 struct abis_om_hdr *oh;
2880 struct abis_om_fom_hdr *foh;
2881 u_int8_t *data;
2882
2883 /* construct the 12.21 OM header, observe the erroneous length */
2884 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2885 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2886 oh->mdisc = ABIS_OM_MDISC_MANUF;
2887
2888 /* add the ip.access magic */
2889 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2890 *data++ = sizeof(ipaccess_magic);
2891 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2892
2893 /* fill the 12.21 FOM header */
2894 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2895 foh->msg_type = msg_type;
2896 foh->obj_class = obj_class;
2897 foh->obj_inst.bts_nr = bts_nr;
2898 foh->obj_inst.trx_nr = trx_nr;
2899 foh->obj_inst.ts_nr = ts_nr;
2900
2901 if (attr && attr_len) {
2902 data = msgb_put(msg, attr_len);
2903 memcpy(data, attr, attr_len);
2904 }
2905
2906 return abis_nm_sendmsg(bts, msg);
2907}
Harald Welte677c21f2009-02-17 13:22:23 +00002908
Harald Welte193fefc2009-04-30 15:16:27 +00002909/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002910int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002911 int attr_len)
2912{
Harald Welte2ef156d2010-01-07 20:39:42 +01002913 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2914 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002915 attr_len);
2916}
2917
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002918int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002919 u_int32_t ip, u_int16_t port, u_int8_t stream)
2920{
2921 struct in_addr ia;
2922 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2923 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2924 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2925
2926 int attr_len = sizeof(attr);
2927
2928 ia.s_addr = htonl(ip);
2929 attr[1] = stream;
2930 attr[3] = port >> 8;
2931 attr[4] = port & 0xff;
2932 *(u_int32_t *)(attr+6) = ia.s_addr;
2933
2934 /* if ip == 0, we use the default IP */
2935 if (ip == 0)
2936 attr_len -= 5;
2937
2938 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002939 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002940
2941 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2942 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2943 trx->nr, 0xff, attr, attr_len);
2944}
2945
Harald Welte193fefc2009-04-30 15:16:27 +00002946/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002947int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002948{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002949 struct abis_om_hdr *oh;
2950 struct msgb *msg = nm_msgb_alloc();
2951
2952 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2953 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2954 trx->bts->nr, trx->nr, 0xff);
2955
2956 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002957}
Harald Weltedaef5212009-10-24 10:20:41 +02002958
2959int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2960 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2961 u_int8_t *attr, u_int8_t attr_len)
2962{
2963 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2964 obj_class, bts_nr, trx_nr, ts_nr,
2965 attr, attr_len);
2966}
Harald Welte0f255852009-11-12 14:48:42 +01002967
Harald Welte97a282b2010-03-14 15:37:43 +08002968void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2969{
2970 /* we simply reuse the GSM48 function and overwrite the RAC
2971 * with the Cell ID */
2972 gsm48_ra_id_by_bts(buf, bts);
2973 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2974}
2975
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002976void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2977{
2978 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2979
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002980 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002981 if (!trx->bts || !trx->bts->oml_link)
2982 return;
2983
2984 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2985 trx->bts->bts_nr, trx->nr, 0xff,
2986 new_state);
2987}
2988
Harald Welte92b1fe42010-03-25 11:45:30 +08002989static const struct value_string ipacc_testres_names[] = {
2990 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2991 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2992 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2993 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2994 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2995 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002996};
2997
2998const char *ipacc_testres_name(u_int8_t res)
2999{
Harald Welte92b1fe42010-03-25 11:45:30 +08003000 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003001}
3002
Harald Welteb40a38f2009-11-13 11:56:05 +01003003void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3004{
3005 cid->mcc = (buf[0] & 0xf) * 100;
3006 cid->mcc += (buf[0] >> 4) * 10;
3007 cid->mcc += (buf[1] & 0xf) * 1;
3008
3009 if (buf[1] >> 4 == 0xf) {
3010 cid->mnc = (buf[2] & 0xf) * 10;
3011 cid->mnc += (buf[2] >> 4) * 1;
3012 } else {
3013 cid->mnc = (buf[2] & 0xf) * 100;
3014 cid->mnc += (buf[2] >> 4) * 10;
3015 cid->mnc += (buf[1] >> 4) * 1;
3016 }
3017
Harald Welteaff237d2009-11-13 14:41:52 +01003018 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3019 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003020}
3021
Harald Welte0f255852009-11-12 14:48:42 +01003022/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3023int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3024{
3025 u_int8_t *cur = buf;
3026 u_int16_t len;
3027
Harald Welteaf109b92010-07-22 18:14:36 +02003028 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003029
3030 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3031 return -EINVAL;
3032 cur++;
3033
3034 len = ntohs(*(u_int16_t *)cur);
3035 cur += 2;
3036
3037 binf->info_type = ntohs(*(u_int16_t *)cur);
3038 cur += 2;
3039
3040 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3041 binf->freq_qual = *cur >> 2;
3042
Harald Welteaf109b92010-07-22 18:14:36 +02003043 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003044 binf->arfcn |= *cur++;
3045
3046 if (binf->info_type & IPAC_BINF_RXLEV)
3047 binf->rx_lev = *cur & 0x3f;
3048 cur++;
3049
3050 if (binf->info_type & IPAC_BINF_RXQUAL)
3051 binf->rx_qual = *cur & 0x7;
3052 cur++;
3053
3054 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3055 binf->freq_err = ntohs(*(u_int16_t *)cur);
3056 cur += 2;
3057
3058 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3059 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3060 cur += 2;
3061
3062 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3063 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3064 cur += 4;
3065
Harald Weltea780a3d2010-07-30 22:34:42 +02003066#if 0
3067 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003068 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003069#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003070 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003071 cur++;
3072
Harald Welteb40a38f2009-11-13 11:56:05 +01003073 ipac_parse_cgi(&binf->cgi, cur);
3074 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003075
3076 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3077 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3078 cur += sizeof(binf->ba_list_si2);
3079 }
3080
3081 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3082 memcpy(binf->ba_list_si2bis, cur,
3083 sizeof(binf->ba_list_si2bis));
3084 cur += sizeof(binf->ba_list_si2bis);
3085 }
3086
3087 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3088 memcpy(binf->ba_list_si2ter, cur,
3089 sizeof(binf->ba_list_si2ter));
3090 cur += sizeof(binf->ba_list_si2ter);
3091 }
3092
3093 return 0;
3094}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003095
3096void abis_nm_clear_queue(struct gsm_bts *bts)
3097{
3098 struct msgb *msg;
3099
3100 while (!llist_empty(&bts->abis_queue)) {
3101 msg = msgb_dequeue(&bts->abis_queue);
3102 msgb_free(msg);
3103 }
3104
3105 bts->abis_nm_pend = 0;
3106}