blob: 45db8bac59f324f8a6ecea61d87e587749a827ae [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte52b1f982008-12-23 20:25:15 +000033#include <sys/types.h>
Harald Welte4724f992009-01-18 18:01:49 +000034#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000035#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000036#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000037
Harald Welte8470bf22008-12-25 23:28:35 +000038#include <openbsc/gsm_data.h>
39#include <openbsc/debug.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010040#include <osmocore/msgb.h>
41#include <osmocore/tlv.h>
42#include <osmocore/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000043#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000044#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000045#include <openbsc/signal.h>
Harald Welte52b1f982008-12-23 20:25:15 +000046
Harald Welte8470bf22008-12-25 23:28:35 +000047#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010049#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000050
51/* unidirectional messages from BTS to BSC */
52static const enum abis_nm_msgtype reports[] = {
53 NM_MT_SW_ACTIVATED_REP,
54 NM_MT_TEST_REP,
55 NM_MT_STATECHG_EVENT_REP,
56 NM_MT_FAILURE_EVENT_REP,
57};
58
59/* messages without ACK/NACK */
60static const enum abis_nm_msgtype no_ack_nack[] = {
61 NM_MT_MEAS_RES_REQ,
62 NM_MT_STOP_MEAS,
63 NM_MT_START_MEAS,
64};
65
Harald Welte4724f992009-01-18 18:01:49 +000066/* Messages related to software load */
67static const enum abis_nm_msgtype sw_load_msgs[] = {
68 NM_MT_LOAD_INIT_ACK,
69 NM_MT_LOAD_INIT_NACK,
70 NM_MT_LOAD_SEG_ACK,
71 NM_MT_LOAD_ABORT,
72 NM_MT_LOAD_END_ACK,
73 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000074 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000075 NM_MT_ACTIVATE_SW_ACK,
76 NM_MT_ACTIVATE_SW_NACK,
77 NM_MT_SW_ACTIVATED_REP,
78};
79
Harald Weltee0590df2009-02-15 03:34:15 +000080static const enum abis_nm_msgtype nacks[] = {
81 NM_MT_LOAD_INIT_NACK,
82 NM_MT_LOAD_END_NACK,
83 NM_MT_SW_ACT_REQ_NACK,
84 NM_MT_ACTIVATE_SW_NACK,
85 NM_MT_ESTABLISH_TEI_NACK,
86 NM_MT_CONN_TERR_SIGN_NACK,
87 NM_MT_DISC_TERR_SIGN_NACK,
88 NM_MT_CONN_TERR_TRAF_NACK,
89 NM_MT_DISC_TERR_TRAF_NACK,
90 NM_MT_CONN_MDROP_LINK_NACK,
91 NM_MT_DISC_MDROP_LINK_NACK,
92 NM_MT_SET_BTS_ATTR_NACK,
93 NM_MT_SET_RADIO_ATTR_NACK,
94 NM_MT_SET_CHAN_ATTR_NACK,
95 NM_MT_PERF_TEST_NACK,
96 NM_MT_SEND_TEST_REP_NACK,
97 NM_MT_STOP_TEST_NACK,
98 NM_MT_STOP_EVENT_REP_NACK,
99 NM_MT_REST_EVENT_REP_NACK,
100 NM_MT_CHG_ADM_STATE_NACK,
101 NM_MT_CHG_ADM_STATE_REQ_NACK,
102 NM_MT_REP_OUTST_ALARMS_NACK,
103 NM_MT_CHANGEOVER_NACK,
104 NM_MT_OPSTART_NACK,
105 NM_MT_REINIT_NACK,
106 NM_MT_SET_SITE_OUT_NACK,
107 NM_MT_CHG_HW_CONF_NACK,
108 NM_MT_GET_ATTR_NACK,
109 NM_MT_SET_ALARM_THRES_NACK,
110 NM_MT_BS11_BEGIN_DB_TX_NACK,
111 NM_MT_BS11_END_DB_TX_NACK,
112 NM_MT_BS11_CREATE_OBJ_NACK,
113 NM_MT_BS11_DELETE_OBJ_NACK,
114};
Harald Welte78fc0d42009-02-19 02:50:57 +0000115
Harald Welte92b1fe42010-03-25 11:45:30 +0800116static const struct value_string nack_names[] = {
117 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
118 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
119 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
120 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
121 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
122 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
123 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
124 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
125 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
126 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
127 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
128 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
129 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
130 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
131 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
132 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
133 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
134 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
135 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
136 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
137 { NM_MT_CHG_ADM_STATE_REQ_NACK,
138 "CHANGE ADMINISTRATIVE STATE REQUEST" },
139 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
140 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
141 { NM_MT_OPSTART_NACK, "OPSTART" },
142 { NM_MT_REINIT_NACK, "REINIT" },
143 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
144 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
145 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
146 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
147 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
148 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
149 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
150 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
151 { 0, NULL }
Harald Welte78fc0d42009-02-19 02:50:57 +0000152};
153
Harald Welte6c96ba52009-05-01 13:03:40 +0000154/* Chapter 9.4.36 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800155static const struct value_string nack_cause_names[] = {
Harald Welte6c96ba52009-05-01 13:03:40 +0000156 /* General Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800157 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
158 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
159 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
160 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
161 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
162 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
163 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
164 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
165 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
166 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
167 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
168 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
169 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte6c96ba52009-05-01 13:03:40 +0000170 /* Specific Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800171 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
172 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
173 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
174 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
175 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
176 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
177 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
178 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
179 { NM_NACK_TEST_NOSUCH, "No such test" },
180 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
181 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
182 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
183 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
184 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
185 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
186 { NM_NACK_WAIT, "Wait" },
187 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
188 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
189 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
190 { 0, NULL }
Harald Welte6c96ba52009-05-01 13:03:40 +0000191};
192
Harald Welte6c96ba52009-05-01 13:03:40 +0000193static const char *nack_cause_name(u_int8_t cause)
194{
Harald Welte92b1fe42010-03-25 11:45:30 +0800195 return get_value_string(nack_cause_names, cause);
Harald Welte6c96ba52009-05-01 13:03:40 +0000196}
197
Harald Welte0db97b22009-05-01 17:22:47 +0000198/* Chapter 9.4.16: Event Type */
Harald Welte92b1fe42010-03-25 11:45:30 +0800199static const struct value_string event_type_names[] = {
200 { NM_EVT_COMM_FAIL, "communication failure" },
201 { NM_EVT_QOS_FAIL, "quality of service failure" },
202 { NM_EVT_PROC_FAIL, "processing failure" },
203 { NM_EVT_EQUIP_FAIL, "equipment failure" },
204 { NM_EVT_ENV_FAIL, "environment failure" },
205 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000206};
207
208static const char *event_type_name(u_int8_t cause)
209{
Harald Welte92b1fe42010-03-25 11:45:30 +0800210 return get_value_string(event_type_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000211}
212
213/* Chapter 9.4.63: Perceived Severity */
Harald Welte92b1fe42010-03-25 11:45:30 +0800214static const struct value_string severity_names[] = {
215 { NM_SEVER_CEASED, "failure ceased" },
216 { NM_SEVER_CRITICAL, "critical failure" },
217 { NM_SEVER_MAJOR, "major failure" },
218 { NM_SEVER_MINOR, "minor failure" },
219 { NM_SEVER_WARNING, "warning level failure" },
220 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
221 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000222};
223
224static const char *severity_name(u_int8_t cause)
225{
Harald Welte92b1fe42010-03-25 11:45:30 +0800226 return get_value_string(severity_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000227}
228
Harald Welte52b1f982008-12-23 20:25:15 +0000229/* Attributes that the BSC can set, not only get, according to Section 9.4 */
230static const enum abis_nm_attr nm_att_settable[] = {
231 NM_ATT_ADD_INFO,
232 NM_ATT_ADD_TEXT,
233 NM_ATT_DEST,
234 NM_ATT_EVENT_TYPE,
235 NM_ATT_FILE_DATA,
236 NM_ATT_GET_ARI,
237 NM_ATT_HW_CONF_CHG,
238 NM_ATT_LIST_REQ_ATTR,
239 NM_ATT_MDROP_LINK,
240 NM_ATT_MDROP_NEXT,
241 NM_ATT_NACK_CAUSES,
242 NM_ATT_OUTST_ALARM,
243 NM_ATT_PHYS_CONF,
244 NM_ATT_PROB_CAUSE,
245 NM_ATT_RAD_SUBC,
246 NM_ATT_SOURCE,
247 NM_ATT_SPEC_PROB,
248 NM_ATT_START_TIME,
249 NM_ATT_TEST_DUR,
250 NM_ATT_TEST_NO,
251 NM_ATT_TEST_REPORT,
252 NM_ATT_WINDOW_SIZE,
253 NM_ATT_SEVERITY,
254 NM_ATT_MEAS_RES,
255 NM_ATT_MEAS_TYPE,
256};
257
Harald Welte39315c42010-01-10 18:01:52 +0100258const struct tlv_definition nm_att_tlvdef = {
Harald Weltee0590df2009-02-15 03:34:15 +0000259 .def = {
260 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
261 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
262 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
264 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
265 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
266 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
267 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
268 [NM_ATT_BSIC] = { TLV_TYPE_TV },
269 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
270 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
272 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
273 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
274 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
275 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
276 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
277 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
279 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
280 [NM_ATT_HSN] = { TLV_TYPE_TV },
281 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
282 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
283 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
284 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
285 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
286 [NM_ATT_MAIO] = { TLV_TYPE_TV },
287 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
289 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
290 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
291 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
292 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
294 [NM_ATT_NY1] = { TLV_TYPE_TV },
295 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
297 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
298 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
299 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
300 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
302 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
303 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
304 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
305 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
306 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
308 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
309 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
310 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
311 [NM_ATT_TEI] = { TLV_TYPE_TV },
312 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
313 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
314 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
315 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
316 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
317 [NM_ATT_TSC] = { TLV_TYPE_TV },
318 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
319 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
320 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
321 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
322 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000323 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Weltee0590df2009-02-15 03:34:15 +0000324 },
325};
Harald Welte03133942009-02-18 19:51:53 +0000326
Harald Welte21bd3a52009-08-10 12:21:22 +0200327static const enum abis_nm_chan_comb chcomb4pchan[] = {
328 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
329 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
330 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
331 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
332 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200333 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
334 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200335 /* FIXME: bounds check */
336};
337
338int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
339{
340 if (pchan < ARRAY_SIZE(chcomb4pchan))
341 return chcomb4pchan[pchan];
342
343 return -EINVAL;
344}
345
Harald Welte39315c42010-01-10 18:01:52 +0100346int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +0000347{
Harald Welte39315c42010-01-10 18:01:52 +0100348 if (!bts->model)
349 return -EIO;
350 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000351}
Harald Weltee0590df2009-02-15 03:34:15 +0000352
Harald Welte52b1f982008-12-23 20:25:15 +0000353static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
354{
355 int i;
356
357 for (i = 0; i < size; i++) {
358 if (arr[i] == mt)
359 return 1;
360 }
361
362 return 0;
363}
364
Holger Freytherca362a62009-01-04 21:05:01 +0000365#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000366/* is this msgtype the usual ACK/NACK type ? */
367static int is_ack_nack(enum abis_nm_msgtype mt)
368{
369 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
370}
Holger Freytherca362a62009-01-04 21:05:01 +0000371#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000372
373/* is this msgtype a report ? */
374static int is_report(enum abis_nm_msgtype mt)
375{
Harald Welte8470bf22008-12-25 23:28:35 +0000376 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000377}
378
379#define MT_ACK(x) (x+1)
380#define MT_NACK(x) (x+2)
381
382static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
383{
384 oh->mdisc = ABIS_OM_MDISC_FOM;
385 oh->placement = ABIS_OM_PLACEMENT_ONLY;
386 oh->sequence = 0;
387 oh->length = len;
388}
389
390static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
391 u_int8_t msg_type, u_int8_t obj_class,
392 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
393{
394 struct abis_om_fom_hdr *foh =
395 (struct abis_om_fom_hdr *) oh->data;
396
Harald Welte702d8702008-12-26 20:25:35 +0000397 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000398 foh->msg_type = msg_type;
399 foh->obj_class = obj_class;
400 foh->obj_inst.bts_nr = bts_nr;
401 foh->obj_inst.trx_nr = trx_nr;
402 foh->obj_inst.ts_nr = ts_nr;
403}
404
Harald Welte8470bf22008-12-25 23:28:35 +0000405static struct msgb *nm_msgb_alloc(void)
406{
Harald Welte966636f2009-06-26 19:39:35 +0200407 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
408 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000409}
410
Harald Welte52b1f982008-12-23 20:25:15 +0000411/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100412static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000413{
Holger Freyther59639e82009-02-09 23:09:55 +0000414 msg->trx = bts->c0;
415
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100416 /* queue OML messages */
417 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
418 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100419 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100420 } else {
421 msgb_enqueue(&bts->abis_queue, msg);
422 return 0;
423 }
424
425}
426
427int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
428{
429 OBSC_NM_W_ACK_CB(msg) = 1;
430 return abis_nm_queue_msg(bts, msg);
431}
432
433static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
434{
435 OBSC_NM_W_ACK_CB(msg) = 0;
436 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000437}
438
Harald Welte4724f992009-01-18 18:01:49 +0000439static int abis_nm_rcvmsg_sw(struct msgb *mb);
440
Harald Welte81c9b9c2010-05-31 16:40:40 +0200441const struct value_string abis_nm_obj_class_names[] = {
442 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800443 { NM_OC_BTS, "BTS" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200444 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
445 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800446 { NM_OC_CHANNEL, "CHANNEL" },
447 { NM_OC_BS11_ADJC, "ADJC" },
448 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200449 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800450 { NM_OC_BS11_BTSE, "BTSE" },
451 { NM_OC_BS11_RACK, "RACK" },
452 { NM_OC_BS11_TEST, "TEST" },
453 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
454 { NM_OC_BS11_BPORT, "BPORT" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200455 { NM_OC_GPRS_NSE, "GPRS-NSE" },
456 { NM_OC_GPRS_CELL, "GPRS-CELL" },
457 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800458 { NM_OC_BS11, "SIEMENSHW" },
459 { 0, NULL }
460};
461
Harald Welte34a99682009-02-13 02:41:40 +0000462static const char *obj_class_name(u_int8_t oc)
463{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200464 return get_value_string(abis_nm_obj_class_names, oc);
Harald Welte34a99682009-02-13 02:41:40 +0000465}
466
Harald Welte4d87f242009-03-10 19:43:44 +0000467const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000468{
469 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100470 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000471 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100472 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000473 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100474 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000475 return "NULL";
476 default:
477 return "RFU";
478 }
479}
480
Harald Weltee0590df2009-02-15 03:34:15 +0000481/* Chapter 9.4.7 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800482static const struct value_string avail_names[] = {
483 { 0, "In test" },
484 { 1, "Failed" },
485 { 2, "Power off" },
486 { 3, "Off line" },
487 /* Not used */
488 { 5, "Dependency" },
489 { 6, "Degraded" },
490 { 7, "Not installed" },
491 { 0xff, "OK" },
492 { 0, NULL }
Harald Weltee0590df2009-02-15 03:34:15 +0000493};
494
Harald Welte4d87f242009-03-10 19:43:44 +0000495const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000496{
Harald Welte92b1fe42010-03-25 11:45:30 +0800497 return get_value_string(avail_names, avail);
Harald Weltee0590df2009-02-15 03:34:15 +0000498}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000499
Harald Welte0f255852009-11-12 14:48:42 +0100500static struct value_string test_names[] = {
501 /* FIXME: standard test names */
502 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
503 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
504 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
505 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
506 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
507 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
508 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
509 { 0, NULL }
510};
511
Harald Welte81c9b9c2010-05-31 16:40:40 +0200512const struct value_string abis_nm_adm_state_names[] = {
513 { NM_STATE_LOCKED, "Locked" },
514 { NM_STATE_UNLOCKED, "Unlocked" },
515 { NM_STATE_SHUTDOWN, "Shutdown" },
516 { NM_STATE_NULL, "NULL" },
517 { 0, NULL }
518};
519
Harald Welte7b26bcb2009-05-28 11:39:21 +0000520const char *nm_adm_name(u_int8_t adm)
521{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200522 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte7b26bcb2009-05-28 11:39:21 +0000523}
Harald Weltee0590df2009-02-15 03:34:15 +0000524
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100525int nm_is_running(struct gsm_nm_state *s) {
526 return (s->operational == NM_OPSTATE_ENABLED) && (
527 (s->availability == NM_AVSTATE_OK) ||
528 (s->availability == 0xff)
529 );
530}
531
Harald Weltea8bd6d42009-10-20 09:56:18 +0200532static void debugp_foh(struct abis_om_fom_hdr *foh)
533{
534 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200535 obj_class_name(foh->obj_class), foh->obj_class,
Harald Weltea8bd6d42009-10-20 09:56:18 +0200536 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
537 foh->obj_inst.ts_nr);
538}
539
Harald Weltee0590df2009-02-15 03:34:15 +0000540/* obtain the gsm_nm_state data structure for a given object instance */
541static struct gsm_nm_state *
542objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
543 struct abis_om_obj_inst *obj_inst)
544{
545 struct gsm_bts_trx *trx;
546 struct gsm_nm_state *nm_state = NULL;
547
548 switch (obj_class) {
549 case NM_OC_BTS:
550 nm_state = &bts->nm_state;
551 break;
552 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100553 if (obj_inst->trx_nr >= bts->num_trx) {
554 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000555 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100556 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200557 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000558 nm_state = &trx->nm_state;
559 break;
560 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100561 if (obj_inst->trx_nr >= bts->num_trx) {
562 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000563 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100564 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200565 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000566 nm_state = &trx->bb_transc.nm_state;
567 break;
568 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100569 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100570 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000571 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100572 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200573 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000574 if (obj_inst->ts_nr >= TRX_NR_TS)
575 return NULL;
576 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
577 break;
578 case NM_OC_SITE_MANAGER:
579 nm_state = &bts->site_mgr.nm_state;
580 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000581 case NM_OC_BS11:
582 switch (obj_inst->bts_nr) {
583 case BS11_OBJ_CCLK:
584 nm_state = &bts->bs11.cclk.nm_state;
585 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000586 case BS11_OBJ_BBSIG:
587 if (obj_inst->ts_nr > bts->num_trx)
588 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200589 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000590 nm_state = &trx->bs11.bbsig.nm_state;
591 break;
592 case BS11_OBJ_PA:
593 if (obj_inst->ts_nr > bts->num_trx)
594 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200595 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000596 nm_state = &trx->bs11.pa.nm_state;
597 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000598 default:
599 return NULL;
600 }
601 case NM_OC_BS11_RACK:
602 nm_state = &bts->bs11.rack.nm_state;
603 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000604 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100605 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000606 return NULL;
607 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
608 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200609 case NM_OC_GPRS_NSE:
610 nm_state = &bts->gprs.nse.nm_state;
611 break;
612 case NM_OC_GPRS_CELL:
613 nm_state = &bts->gprs.cell.nm_state;
614 break;
615 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100616 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200617 return NULL;
618 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
619 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000620 }
621 return nm_state;
622}
623
624/* obtain the in-memory data structure of a given object instance */
625static void *
626objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
627 struct abis_om_obj_inst *obj_inst)
628{
629 struct gsm_bts_trx *trx;
630 void *obj = NULL;
631
632 switch (obj_class) {
633 case NM_OC_BTS:
634 obj = bts;
635 break;
636 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100637 if (obj_inst->trx_nr >= bts->num_trx) {
638 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000639 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100640 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200641 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000642 obj = trx;
643 break;
644 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100645 if (obj_inst->trx_nr >= bts->num_trx) {
646 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000647 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100648 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200649 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000650 obj = &trx->bb_transc;
651 break;
652 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100653 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100654 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000655 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100656 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200657 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000658 if (obj_inst->ts_nr >= TRX_NR_TS)
659 return NULL;
660 obj = &trx->ts[obj_inst->ts_nr];
661 break;
662 case NM_OC_SITE_MANAGER:
663 obj = &bts->site_mgr;
664 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200665 case NM_OC_GPRS_NSE:
666 obj = &bts->gprs.nse;
667 break;
668 case NM_OC_GPRS_CELL:
669 obj = &bts->gprs.cell;
670 break;
671 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100672 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200673 return NULL;
674 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
675 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000676 }
677 return obj;
678}
679
680/* Update the administrative state of a given object in our in-memory data
681 * structures and send an event to the higher layer */
682static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
683 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
684{
Harald Welteaeedeb42009-05-01 13:08:14 +0000685 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100686 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000687
Harald Weltef338a032011-01-14 15:55:42 +0100688 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
689 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100690 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000691 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
692 if (!nm_state)
693 return -1;
694
695 new_state = *nm_state;
696 new_state.administrative = adm_state;
697
Harald Weltef338a032011-01-14 15:55:42 +0100698 nsd.obj_class = obj_class;
699 nsd.old_state = nm_state;
700 nsd.new_state = &new_state;
701 nsd.obj_inst = obj_inst;
702 dispatch_signal(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000703
704 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000705
Harald Weltef338a032011-01-14 15:55:42 +0100706 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000707}
708
Harald Welte97ed1e72009-02-06 13:38:02 +0000709static int abis_nm_rx_statechg_rep(struct msgb *mb)
710{
Harald Weltee0590df2009-02-15 03:34:15 +0000711 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000712 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000713 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000714 struct tlv_parsed tp;
715 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000716
Harald Welte23897662009-05-01 14:52:51 +0000717 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000718
Harald Welte8b697c72009-06-05 19:18:45 +0000719 memset(&new_state, 0, sizeof(new_state));
720
Harald Weltee0590df2009-02-15 03:34:15 +0000721 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
722 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100723 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000724 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000725 }
Harald Weltee0590df2009-02-15 03:34:15 +0000726
727 new_state = *nm_state;
728
Harald Welte39315c42010-01-10 18:01:52 +0100729 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000730 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
731 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000732 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000733 }
734 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000735 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
736 new_state.availability = 0xff;
737 else
738 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000739 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000740 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100741 } else
742 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000743 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
744 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200745 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000746 }
747 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000748
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100749 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
750 new_state.operational != nm_state->operational ||
751 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000752 /* Update the operational state of a given object in our in-memory data
753 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100754 struct nm_statechg_signal_data nsd;
755 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
756 nsd.obj_class = foh->obj_class;
757 nsd.old_state = nm_state;
758 nsd.new_state = &new_state;
759 nsd.obj_inst = &foh->obj_inst;
760 dispatch_signal(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100761 nm_state->operational = new_state.operational;
762 nm_state->availability = new_state.availability;
763 if (nm_state->administrative == 0)
764 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000765 }
766#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000767 if (op_state == 1) {
768 /* try to enable objects that are disabled */
769 abis_nm_opstart(bts, foh->obj_class,
770 foh->obj_inst.bts_nr,
771 foh->obj_inst.trx_nr,
772 foh->obj_inst.ts_nr);
773 }
Harald Weltee0590df2009-02-15 03:34:15 +0000774#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000775 return 0;
776}
777
Harald Welte0db97b22009-05-01 17:22:47 +0000778static int rx_fail_evt_rep(struct msgb *mb)
779{
780 struct abis_om_hdr *oh = msgb_l2(mb);
781 struct abis_om_fom_hdr *foh = msgb_l3(mb);
782 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100783 const uint8_t *p_val;
784 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000785
786 DEBUGPC(DNM, "Failure Event Report ");
787
Harald Welte39315c42010-01-10 18:01:52 +0100788 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000789
790 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
791 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
792 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
793 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100794 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
795 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
796 DEBUGPC(DNM, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
797 }
798 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
799 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
800 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
801 if (p_text) {
802 DEBUGPC(DNM, "Additional Text=%s ", p_text);
803 talloc_free(p_text);
804 }
805 }
Harald Welte0db97b22009-05-01 17:22:47 +0000806
807 DEBUGPC(DNM, "\n");
808
809 return 0;
810}
811
Harald Welte97ed1e72009-02-06 13:38:02 +0000812static int abis_nm_rcvmsg_report(struct msgb *mb)
813{
814 struct abis_om_fom_hdr *foh = msgb_l3(mb);
815 u_int8_t mt = foh->msg_type;
816
Harald Weltea8bd6d42009-10-20 09:56:18 +0200817 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000818
Harald Welte97ed1e72009-02-06 13:38:02 +0000819 //nmh->cfg->report_cb(mb, foh);
820
821 switch (mt) {
822 case NM_MT_STATECHG_EVENT_REP:
823 return abis_nm_rx_statechg_rep(mb);
824 break;
Harald Welte34a99682009-02-13 02:41:40 +0000825 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000826 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000827 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000828 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000829 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000830 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000831 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000832 break;
Harald Weltec7310382009-08-08 00:02:36 +0200833 case NM_MT_TEST_REP:
834 DEBUGPC(DNM, "Test Report\n");
835 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
836 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000837 default:
Harald Welte23897662009-05-01 14:52:51 +0000838 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000839 break;
840
Harald Welte97ed1e72009-02-06 13:38:02 +0000841 };
842
Harald Welte97ed1e72009-02-06 13:38:02 +0000843 return 0;
844}
845
Harald Welte34a99682009-02-13 02:41:40 +0000846/* Activate the specified software into the BTS */
847static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
Mike Habena03f9772009-10-01 14:56:13 +0200848 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000849{
850 struct abis_om_hdr *oh;
851 struct msgb *msg = nm_msgb_alloc();
852 u_int8_t len = swdesc_len;
853 u_int8_t *trailer;
854
855 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
856 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
857
858 trailer = msgb_put(msg, swdesc_len);
859 memcpy(trailer, sw_desc, swdesc_len);
860
861 return abis_nm_sendmsg(bts, msg);
862}
863
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100864static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
865{
866 static const struct tlv_definition sw_descr_def = {
867 .def = {
868 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
869 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
870 },
871 };
872
873 u_int8_t tag;
874 u_int16_t tag_len;
875 const u_int8_t *val;
876 int ofs = 0, len;
877
878 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
879 * nested nature and the fact you have to assume it contains only two sub
880 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
881
882 if (sw_descr[0] != NM_ATT_SW_DESCR) {
883 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
884 return -1;
885 }
886 ofs += 1;
887
888 len = tlv_parse_one(&tag, &tag_len, &val,
889 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
890 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
891 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
892 return -2;
893 }
894 ofs += len;
895
896 len = tlv_parse_one(&tag, &tag_len, &val,
897 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
898 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
899 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
900 return -3;
901 }
902 ofs += len;
903
904 return ofs;
905}
906
Harald Welte34a99682009-02-13 02:41:40 +0000907static int abis_nm_rx_sw_act_req(struct msgb *mb)
908{
909 struct abis_om_hdr *oh = msgb_l2(mb);
910 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200911 struct tlv_parsed tp;
912 const u_int8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100913 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000914
Harald Weltea8bd6d42009-10-20 09:56:18 +0200915 debugp_foh(foh);
916
917 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000918
Harald Welte97a282b2010-03-14 15:37:43 +0800919 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000920
921 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000922 foh->obj_inst.bts_nr,
923 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800924 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000925 foh->data, oh->length-sizeof(*foh));
926
Harald Welte39315c42010-01-10 18:01:52 +0100927 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200928 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
929 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
930 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
931 DEBUGP(DNM, "SW config not found! Can't continue.\n");
932 return -EINVAL;
933 } else {
934 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
935 }
936
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100937 /* Use the first SW_DESCR present in SW config */
938 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
939 if (sw_descr_len < 0)
940 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200941
Harald Welte34a99682009-02-13 02:41:40 +0000942 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
943 foh->obj_inst.bts_nr,
944 foh->obj_inst.trx_nr,
945 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100946 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000947}
948
Harald Weltee0590df2009-02-15 03:34:15 +0000949/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
950static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
951{
952 struct abis_om_hdr *oh = msgb_l2(mb);
953 struct abis_om_fom_hdr *foh = msgb_l3(mb);
954 struct tlv_parsed tp;
955 u_int8_t adm_state;
956
Harald Welte39315c42010-01-10 18:01:52 +0100957 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000958 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
959 return -EINVAL;
960
961 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
962
963 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
964}
965
Harald Welteee670472009-02-22 21:58:49 +0000966static int abis_nm_rx_lmt_event(struct msgb *mb)
967{
968 struct abis_om_hdr *oh = msgb_l2(mb);
969 struct abis_om_fom_hdr *foh = msgb_l3(mb);
970 struct tlv_parsed tp;
971
972 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100973 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000974 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
975 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
976 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
977 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
978 }
979 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
980 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
981 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
982 DEBUGPC(DNM, "Level=%u ", level);
983 }
984 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
985 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
986 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
987 DEBUGPC(DNM, "Username=%s ", name);
988 }
989 DEBUGPC(DNM, "\n");
990 /* FIXME: parse LMT LOGON TIME */
991 return 0;
992}
993
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100994static void abis_nm_queue_send_next(struct gsm_bts *bts)
995{
996 int wait = 0;
997 struct msgb *msg;
998 /* the queue is empty */
999 while (!llist_empty(&bts->abis_queue)) {
1000 msg = msgb_dequeue(&bts->abis_queue);
1001 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +01001002 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001003
1004 if (wait)
1005 break;
1006 }
1007
1008 bts->abis_nm_pend = wait;
1009}
1010
Harald Welte52b1f982008-12-23 20:25:15 +00001011/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001012static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001013{
Harald Welte6c96ba52009-05-01 13:03:40 +00001014 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001015 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1016 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001017 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001018
1019 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001020 if (is_report(mt))
1021 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001022
Harald Welte4724f992009-01-18 18:01:49 +00001023 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1024 return abis_nm_rcvmsg_sw(mb);
1025
Harald Welte78fc0d42009-02-19 02:50:57 +00001026 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001027 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +00001028 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001029
Harald Weltea8bd6d42009-10-20 09:56:18 +02001030 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001031
Harald Welte92b1fe42010-03-25 11:45:30 +08001032 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +00001033
Harald Welte39315c42010-01-10 18:01:52 +01001034 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +00001035 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001036 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00001037 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1038 else
1039 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001040
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001041 nack_data.msg = mb;
1042 nack_data.mt = mt;
1043 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001044 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001045 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001046 }
Harald Weltead384642008-12-26 10:20:07 +00001047#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001048 /* check if last message is to be acked */
1049 if (is_ack_nack(nmh->last_msgtype)) {
1050 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001051 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001052 /* we got our ACK, continue sending the next msg */
1053 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1054 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001055 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001056 /* FIXME: somehow signal this to the caller */
1057 } else {
1058 /* really strange things happen */
1059 return -EINVAL;
1060 }
1061 }
Harald Weltead384642008-12-26 10:20:07 +00001062#endif
1063
Harald Welte97ed1e72009-02-06 13:38:02 +00001064 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001065 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001066 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +00001067 break;
Harald Welte34a99682009-02-13 02:41:40 +00001068 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001069 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +00001070 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001071 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001072 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001073 break;
Harald Welte1989c082009-08-06 17:58:31 +02001074 case NM_MT_CONN_MDROP_LINK_ACK:
1075 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1076 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001077 case NM_MT_IPACC_RESTART_ACK:
1078 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1079 break;
1080 case NM_MT_IPACC_RESTART_NACK:
1081 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1082 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001083 }
1084
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001085 abis_nm_queue_send_next(mb->trx->bts);
1086 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001087}
1088
Harald Welte677c21f2009-02-17 13:22:23 +00001089static int abis_nm_rx_ipacc(struct msgb *mb);
1090
1091static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1092{
1093 int rc;
1094 int bts_type = mb->trx->bts->type;
1095
1096 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001097 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001098 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001099 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +00001100 break;
1101 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001102 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1103 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001104 rc = 0;
1105 break;
1106 }
1107
1108 return rc;
1109}
1110
Harald Welte52b1f982008-12-23 20:25:15 +00001111/* High-Level API */
1112/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001113int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001114{
Harald Welte52b1f982008-12-23 20:25:15 +00001115 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001116 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001117
1118 /* Various consistency checks */
1119 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001120 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001121 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001122 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1123 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001124 }
1125 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001126 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001127 oh->sequence);
1128 return -EINVAL;
1129 }
Harald Welte702d8702008-12-26 20:25:35 +00001130#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001131 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1132 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001133 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001134 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001135 oh->length + sizeof(*oh), l2_len);
1136 return -EINVAL;
1137 }
Harald Welte702d8702008-12-26 20:25:35 +00001138 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001139 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 +00001140#endif
Harald Weltead384642008-12-26 10:20:07 +00001141 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001142
1143 switch (oh->mdisc) {
1144 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001145 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001146 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001147 case ABIS_OM_MDISC_MANUF:
1148 rc = abis_nm_rcvmsg_manuf(msg);
1149 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001150 case ABIS_OM_MDISC_MMI:
1151 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001152 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001153 oh->mdisc);
1154 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001155 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001156 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001157 oh->mdisc);
1158 return -EINVAL;
1159 }
1160
Harald Weltead384642008-12-26 10:20:07 +00001161 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001162 return rc;
1163}
1164
1165#if 0
1166/* initialized all resources */
1167struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1168{
1169 struct abis_nm_h *nmh;
1170
1171 nmh = malloc(sizeof(*nmh));
1172 if (!nmh)
1173 return NULL;
1174
1175 nmh->cfg = cfg;
1176
1177 return nmh;
1178}
1179
1180/* free all resources */
1181void abis_nm_fini(struct abis_nm_h *nmh)
1182{
1183 free(nmh);
1184}
1185#endif
1186
1187/* Here we are trying to define a high-level API that can be used by
1188 * the actual BSC implementation. However, the architecture is currently
1189 * still under design. Ideally the calls to this API would be synchronous,
1190 * while the underlying stack behind the APi runs in a traditional select
1191 * based state machine.
1192 */
1193
Harald Welte4724f992009-01-18 18:01:49 +00001194/* 6.2 Software Load: */
1195enum sw_state {
1196 SW_STATE_NONE,
1197 SW_STATE_WAIT_INITACK,
1198 SW_STATE_WAIT_SEGACK,
1199 SW_STATE_WAIT_ENDACK,
1200 SW_STATE_WAIT_ACTACK,
1201 SW_STATE_ERROR,
1202};
Harald Welte52b1f982008-12-23 20:25:15 +00001203
Harald Welte52b1f982008-12-23 20:25:15 +00001204struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001205 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001206 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001207 gsm_cbfn *cbfn;
1208 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001209 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001210
Harald Welte52b1f982008-12-23 20:25:15 +00001211 /* this will become part of the SW LOAD INITIATE */
1212 u_int8_t obj_class;
1213 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001214
1215 u_int8_t file_id[255];
1216 u_int8_t file_id_len;
1217
1218 u_int8_t file_version[255];
1219 u_int8_t file_version_len;
1220
1221 u_int8_t window_size;
1222 u_int8_t seg_in_window;
1223
1224 int fd;
1225 FILE *stream;
1226 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001227 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001228};
1229
Harald Welte4724f992009-01-18 18:01:49 +00001230static struct abis_nm_sw g_sw;
1231
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001232static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1233{
1234 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1235 msgb_v_put(msg, NM_ATT_SW_DESCR);
1236 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1237 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1238 sw->file_version);
1239 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1240 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1241 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1242 sw->file_version);
1243 } else {
1244 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1245 }
1246}
1247
Harald Welte4724f992009-01-18 18:01:49 +00001248/* 6.2.1 / 8.3.1: Load Data Initiate */
1249static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001250{
Harald Welte4724f992009-01-18 18:01:49 +00001251 struct abis_om_hdr *oh;
1252 struct msgb *msg = nm_msgb_alloc();
1253 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1254
1255 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1256 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1257 sw->obj_instance[0], sw->obj_instance[1],
1258 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001259
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001260 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001261 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1262
1263 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001264}
1265
Harald Welte1602ade2009-01-29 21:12:39 +00001266static int is_last_line(FILE *stream)
1267{
1268 char next_seg_buf[256];
1269 long pos;
1270
1271 /* check if we're sending the last line */
1272 pos = ftell(stream);
1273 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1274 fseek(stream, pos, SEEK_SET);
1275 return 1;
1276 }
1277
1278 fseek(stream, pos, SEEK_SET);
1279 return 0;
1280}
1281
Harald Welte4724f992009-01-18 18:01:49 +00001282/* 6.2.2 / 8.3.2 Load Data Segment */
1283static int sw_load_segment(struct abis_nm_sw *sw)
1284{
1285 struct abis_om_hdr *oh;
1286 struct msgb *msg = nm_msgb_alloc();
1287 char seg_buf[256];
1288 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001289 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001290 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001291
1292 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001293
1294 switch (sw->bts->type) {
1295 case GSM_BTS_TYPE_BS11:
1296 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1297 perror("fgets reading segment");
1298 return -EINVAL;
1299 }
1300 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001301
1302 /* check if we're sending the last line */
1303 sw->last_seg = is_last_line(sw->stream);
1304 if (sw->last_seg)
1305 seg_buf[1] = 0;
1306 else
1307 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001308
1309 len = strlen(line_buf) + 2;
1310 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1311 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1312 /* BS11 wants CR + LF in excess of the TLV length !?! */
1313 tlv[1] -= 2;
1314
1315 /* we only now know the exact length for the OM hdr */
1316 len = strlen(line_buf)+2;
1317 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001318 case GSM_BTS_TYPE_NANOBTS: {
1319 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1320 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1321 if (len < 0) {
1322 perror("read failed");
1323 return -EINVAL;
1324 }
1325
1326 if (len != IPACC_SEGMENT_SIZE)
1327 sw->last_seg = 1;
1328
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001329 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001330 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1331 len += 3;
1332 break;
1333 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001334 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001335 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001336 /* FIXME: Other BTS types */
1337 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001338 }
Harald Welte4724f992009-01-18 18:01:49 +00001339
Harald Welte4724f992009-01-18 18:01:49 +00001340 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1341 sw->obj_instance[0], sw->obj_instance[1],
1342 sw->obj_instance[2]);
1343
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001344 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001345}
1346
1347/* 6.2.4 / 8.3.4 Load Data End */
1348static int sw_load_end(struct abis_nm_sw *sw)
1349{
1350 struct abis_om_hdr *oh;
1351 struct msgb *msg = nm_msgb_alloc();
1352 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1353
1354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1355 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1356 sw->obj_instance[0], sw->obj_instance[1],
1357 sw->obj_instance[2]);
1358
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001359 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001360 return abis_nm_sendmsg(sw->bts, msg);
1361}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001362
Harald Welte52b1f982008-12-23 20:25:15 +00001363/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001364static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001365{
Harald Welte4724f992009-01-18 18:01:49 +00001366 struct abis_om_hdr *oh;
1367 struct msgb *msg = nm_msgb_alloc();
1368 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001369
Harald Welte4724f992009-01-18 18:01:49 +00001370 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1371 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1372 sw->obj_instance[0], sw->obj_instance[1],
1373 sw->obj_instance[2]);
1374
1375 /* FIXME: this is BS11 specific format */
1376 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1377 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1378 sw->file_version);
1379
1380 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001381}
Harald Welte4724f992009-01-18 18:01:49 +00001382
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001383struct sdp_firmware {
1384 char magic[4];
1385 char more_magic[4];
1386 unsigned int header_length;
1387 unsigned int file_length;
1388} __attribute__ ((packed));
1389
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001390static int parse_sdp_header(struct abis_nm_sw *sw)
1391{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001392 struct sdp_firmware firmware_header;
1393 int rc;
1394 struct stat stat;
1395
1396 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1397 if (rc != sizeof(firmware_header)) {
1398 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1399 return -1;
1400 }
1401
1402 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1403 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1404 return -1;
1405 }
1406
1407 if (firmware_header.more_magic[0] != 0x10 ||
1408 firmware_header.more_magic[1] != 0x02 ||
1409 firmware_header.more_magic[2] != 0x00 ||
1410 firmware_header.more_magic[3] != 0x00) {
1411 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1412 return -1;
1413 }
1414
1415
1416 if (fstat(sw->fd, &stat) == -1) {
1417 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1418 return -1;
1419 }
1420
1421 if (ntohl(firmware_header.file_length) != stat.st_size) {
1422 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1423 return -1;
1424 }
1425
1426 /* go back to the start as we checked the whole filesize.. */
1427 lseek(sw->fd, 0l, SEEK_SET);
1428 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1429 "There might be checksums in the file that are not\n"
1430 "verified and incomplete firmware might be flashed.\n"
1431 "There is absolutely no WARRANTY that flashing will\n"
1432 "work.\n");
1433 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001434}
1435
Harald Welte4724f992009-01-18 18:01:49 +00001436static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1437{
1438 char file_id[12+1];
1439 char file_version[80+1];
1440 int rc;
1441
1442 sw->fd = open(fname, O_RDONLY);
1443 if (sw->fd < 0)
1444 return sw->fd;
1445
1446 switch (sw->bts->type) {
1447 case GSM_BTS_TYPE_BS11:
1448 sw->stream = fdopen(sw->fd, "r");
1449 if (!sw->stream) {
1450 perror("fdopen");
1451 return -1;
1452 }
1453 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001454 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001455 file_id, file_version);
1456 if (rc != 2) {
1457 perror("parsing header line of software file");
1458 return -1;
1459 }
1460 strcpy((char *)sw->file_id, file_id);
1461 sw->file_id_len = strlen(file_id);
1462 strcpy((char *)sw->file_version, file_version);
1463 sw->file_version_len = strlen(file_version);
1464 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001465 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001466 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001467 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001468 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001469 rc = parse_sdp_header(sw);
1470 if (rc < 0) {
1471 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1472 return -1;
1473 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001474
1475 strcpy((char *)sw->file_id, "id");
1476 sw->file_id_len = 3;
1477 strcpy((char *)sw->file_version, "version");
1478 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001479 break;
Harald Welte4724f992009-01-18 18:01:49 +00001480 default:
1481 /* We don't know how to treat them yet */
1482 close(sw->fd);
1483 return -EINVAL;
1484 }
1485
1486 return 0;
1487}
1488
1489static void sw_close_file(struct abis_nm_sw *sw)
1490{
1491 switch (sw->bts->type) {
1492 case GSM_BTS_TYPE_BS11:
1493 fclose(sw->stream);
1494 break;
1495 default:
1496 close(sw->fd);
1497 break;
1498 }
1499}
1500
1501/* Fill the window */
1502static int sw_fill_window(struct abis_nm_sw *sw)
1503{
1504 int rc;
1505
1506 while (sw->seg_in_window < sw->window_size) {
1507 rc = sw_load_segment(sw);
1508 if (rc < 0)
1509 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001510 if (sw->last_seg)
1511 break;
Harald Welte4724f992009-01-18 18:01:49 +00001512 }
1513 return 0;
1514}
1515
1516/* callback function from abis_nm_rcvmsg() handler */
1517static int abis_nm_rcvmsg_sw(struct msgb *mb)
1518{
1519 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1520 int rc = -1;
1521 struct abis_nm_sw *sw = &g_sw;
1522 enum sw_state old_state = sw->state;
1523
Harald Welte3ffd1372009-02-01 22:15:49 +00001524 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001525
1526 switch (sw->state) {
1527 case SW_STATE_WAIT_INITACK:
1528 switch (foh->msg_type) {
1529 case NM_MT_LOAD_INIT_ACK:
1530 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001531 if (sw->cbfn)
1532 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1533 NM_MT_LOAD_INIT_ACK, mb,
1534 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001535 rc = sw_fill_window(sw);
1536 sw->state = SW_STATE_WAIT_SEGACK;
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 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001540 if (sw->forced) {
1541 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1542 "Init NACK\n");
1543 if (sw->cbfn)
1544 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1545 NM_MT_LOAD_INIT_ACK, mb,
1546 sw->cb_data, NULL);
1547 rc = sw_fill_window(sw);
1548 sw->state = SW_STATE_WAIT_SEGACK;
1549 } else {
1550 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001551 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001552 if (sw->cbfn)
1553 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1554 NM_MT_LOAD_INIT_NACK, mb,
1555 sw->cb_data, NULL);
1556 sw->state = SW_STATE_ERROR;
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;
1560 }
1561 break;
1562 case SW_STATE_WAIT_SEGACK:
1563 switch (foh->msg_type) {
1564 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001565 if (sw->cbfn)
1566 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1567 NM_MT_LOAD_SEG_ACK, mb,
1568 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001569 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001570 if (!sw->last_seg) {
1571 /* fill window with more segments */
1572 rc = sw_fill_window(sw);
1573 sw->state = SW_STATE_WAIT_SEGACK;
1574 } else {
1575 /* end the transfer */
1576 sw->state = SW_STATE_WAIT_ENDACK;
1577 rc = sw_load_end(sw);
1578 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001579 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001580 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001581 case NM_MT_LOAD_ABORT:
1582 if (sw->cbfn)
1583 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1584 NM_MT_LOAD_ABORT, mb,
1585 sw->cb_data, NULL);
1586 break;
Harald Welte4724f992009-01-18 18:01:49 +00001587 }
1588 break;
1589 case SW_STATE_WAIT_ENDACK:
1590 switch (foh->msg_type) {
1591 case NM_MT_LOAD_END_ACK:
1592 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001593 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1594 sw->bts->nr);
1595 sw->state = SW_STATE_NONE;
1596 if (sw->cbfn)
1597 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1598 NM_MT_LOAD_END_ACK, mb,
1599 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001600 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001601 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001602 break;
1603 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001604 if (sw->forced) {
1605 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1606 "End NACK\n");
1607 sw->state = SW_STATE_NONE;
1608 if (sw->cbfn)
1609 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1610 NM_MT_LOAD_END_ACK, mb,
1611 sw->cb_data, NULL);
1612 } else {
1613 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001614 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001615 sw->state = SW_STATE_ERROR;
1616 if (sw->cbfn)
1617 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1618 NM_MT_LOAD_END_NACK, mb,
1619 sw->cb_data, NULL);
1620 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001621 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001622 break;
1623 }
1624 case SW_STATE_WAIT_ACTACK:
1625 switch (foh->msg_type) {
1626 case NM_MT_ACTIVATE_SW_ACK:
1627 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001628 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001629 sw->state = SW_STATE_NONE;
1630 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001631 if (sw->cbfn)
1632 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1633 NM_MT_ACTIVATE_SW_ACK, mb,
1634 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001635 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001636 break;
1637 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001638 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001639 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001640 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001641 if (sw->cbfn)
1642 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1643 NM_MT_ACTIVATE_SW_NACK, mb,
1644 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001645 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001646 break;
1647 }
1648 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001649 switch (foh->msg_type) {
1650 case NM_MT_ACTIVATE_SW_ACK:
1651 rc = 0;
1652 break;
1653 }
1654 break;
Harald Welte4724f992009-01-18 18:01:49 +00001655 case SW_STATE_ERROR:
1656 break;
1657 }
1658
1659 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001660 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001661 foh->msg_type, old_state, sw->state);
1662
1663 return rc;
1664}
1665
1666/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001667int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001668 u_int8_t win_size, int forced,
1669 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001670{
1671 struct abis_nm_sw *sw = &g_sw;
1672 int rc;
1673
Harald Welte5e4d1b32009-02-01 13:36:56 +00001674 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1675 bts->nr, fname);
1676
Harald Welte4724f992009-01-18 18:01:49 +00001677 if (sw->state != SW_STATE_NONE)
1678 return -EBUSY;
1679
1680 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001681 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001682
1683 switch (bts->type) {
1684 case GSM_BTS_TYPE_BS11:
1685 sw->obj_class = NM_OC_SITE_MANAGER;
1686 sw->obj_instance[0] = 0xff;
1687 sw->obj_instance[1] = 0xff;
1688 sw->obj_instance[2] = 0xff;
1689 break;
1690 case GSM_BTS_TYPE_NANOBTS:
1691 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001692 sw->obj_instance[0] = sw->bts->nr;
1693 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001694 sw->obj_instance[2] = 0xff;
1695 break;
1696 case GSM_BTS_TYPE_UNKNOWN:
1697 default:
1698 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1699 return -1;
1700 break;
1701 }
Harald Welte4724f992009-01-18 18:01:49 +00001702 sw->window_size = win_size;
1703 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001704 sw->cbfn = cbfn;
1705 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001706 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001707
1708 rc = sw_open_file(sw, fname);
1709 if (rc < 0) {
1710 sw->state = SW_STATE_NONE;
1711 return rc;
1712 }
1713
1714 return sw_load_init(sw);
1715}
Harald Welte52b1f982008-12-23 20:25:15 +00001716
Harald Welte1602ade2009-01-29 21:12:39 +00001717int abis_nm_software_load_status(struct gsm_bts *bts)
1718{
1719 struct abis_nm_sw *sw = &g_sw;
1720 struct stat st;
1721 int rc, percent;
1722
1723 rc = fstat(sw->fd, &st);
1724 if (rc < 0) {
1725 perror("ERROR during stat");
1726 return rc;
1727 }
1728
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001729 if (sw->stream)
1730 percent = (ftell(sw->stream) * 100) / st.st_size;
1731 else
1732 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001733 return percent;
1734}
1735
Harald Welte5e4d1b32009-02-01 13:36:56 +00001736/* Activate the specified software into the BTS */
1737int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1738 gsm_cbfn *cbfn, void *cb_data)
1739{
1740 struct abis_nm_sw *sw = &g_sw;
1741 int rc;
1742
1743 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1744 bts->nr, fname);
1745
1746 if (sw->state != SW_STATE_NONE)
1747 return -EBUSY;
1748
1749 sw->bts = bts;
1750 sw->obj_class = NM_OC_SITE_MANAGER;
1751 sw->obj_instance[0] = 0xff;
1752 sw->obj_instance[1] = 0xff;
1753 sw->obj_instance[2] = 0xff;
1754 sw->state = SW_STATE_WAIT_ACTACK;
1755 sw->cbfn = cbfn;
1756 sw->cb_data = cb_data;
1757
1758 /* Open the file in order to fill some sw struct members */
1759 rc = sw_open_file(sw, fname);
1760 if (rc < 0) {
1761 sw->state = SW_STATE_NONE;
1762 return rc;
1763 }
1764 sw_close_file(sw);
1765
1766 return sw_activate(sw);
1767}
1768
Harald Welte8470bf22008-12-25 23:28:35 +00001769static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001770 u_int8_t ts_nr, u_int8_t subslot_nr)
1771{
Harald Welteadaf08b2009-01-18 11:08:10 +00001772 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001773 ch->bts_port = bts_port;
1774 ch->timeslot = ts_nr;
1775 ch->subslot = subslot_nr;
1776}
1777
1778int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1779 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1780 u_int8_t tei)
1781{
1782 struct abis_om_hdr *oh;
1783 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001784 u_int8_t len = sizeof(*ch) + 2;
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);
1788 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1789 bts->bts_nr, trx_nr, 0xff);
1790
Harald Welte8470bf22008-12-25 23:28:35 +00001791 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001792
1793 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1794 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1795
1796 return abis_nm_sendmsg(bts, msg);
1797}
1798
1799/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1800int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1801 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1802{
Harald Welte8470bf22008-12-25 23:28:35 +00001803 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001804 struct abis_om_hdr *oh;
1805 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001806 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001807
1808 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001809 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001810 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1811
1812 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1813 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1814
1815 return abis_nm_sendmsg(bts, msg);
1816}
1817
1818#if 0
1819int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1820 struct abis_nm_abis_channel *chan)
1821{
1822}
1823#endif
1824
1825int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1826 u_int8_t e1_port, u_int8_t e1_timeslot,
1827 u_int8_t e1_subslot)
1828{
1829 struct gsm_bts *bts = ts->trx->bts;
1830 struct abis_om_hdr *oh;
1831 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001832 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001833
1834 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1835 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001836 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001837
1838 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1839 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1840
Harald Weltef325eb42009-02-19 17:07:39 +00001841 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1842 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001843 e1_port, e1_timeslot, e1_subslot);
1844
Harald Welte52b1f982008-12-23 20:25:15 +00001845 return abis_nm_sendmsg(bts, msg);
1846}
1847
1848#if 0
1849int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1850 struct abis_nm_abis_channel *chan,
1851 u_int8_t subchan)
1852{
1853}
1854#endif
1855
Harald Welte22af0db2009-02-14 15:41:08 +00001856/* Chapter 8.6.1 */
1857int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1858{
1859 struct abis_om_hdr *oh;
1860 struct msgb *msg = nm_msgb_alloc();
1861 u_int8_t *cur;
1862
1863 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1864
1865 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001866 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 +00001867 cur = msgb_put(msg, attr_len);
1868 memcpy(cur, attr, attr_len);
1869
1870 return abis_nm_sendmsg(bts, msg);
1871}
1872
1873/* Chapter 8.6.2 */
1874int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1875{
1876 struct abis_om_hdr *oh;
1877 struct msgb *msg = nm_msgb_alloc();
1878 u_int8_t *cur;
1879
1880 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1881
1882 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1883 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001884 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001885 cur = msgb_put(msg, attr_len);
1886 memcpy(cur, attr, attr_len);
1887
1888 return abis_nm_sendmsg(trx->bts, msg);
1889}
1890
Harald Welte39c7deb2009-08-09 21:49:48 +02001891static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1892{
1893 int i;
1894
1895 /* As it turns out, the BS-11 has some very peculiar restrictions
1896 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301897 switch (ts->trx->bts->type) {
1898 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001899 switch (chan_comb) {
1900 case NM_CHANC_TCHHalf:
1901 case NM_CHANC_TCHHalf2:
1902 /* not supported */
1903 return -EINVAL;
1904 case NM_CHANC_SDCCH:
1905 /* only one SDCCH/8 per TRX */
1906 for (i = 0; i < TRX_NR_TS; i++) {
1907 if (i == ts->nr)
1908 continue;
1909 if (ts->trx->ts[i].nm_chan_comb ==
1910 NM_CHANC_SDCCH)
1911 return -EINVAL;
1912 }
1913 /* not allowed for TS0 of BCCH-TRX */
1914 if (ts->trx == ts->trx->bts->c0 &&
1915 ts->nr == 0)
1916 return -EINVAL;
1917 /* not on the same TRX that has a BCCH+SDCCH4
1918 * combination */
1919 if (ts->trx == ts->trx->bts->c0 &&
1920 (ts->trx->ts[0].nm_chan_comb == 5 ||
1921 ts->trx->ts[0].nm_chan_comb == 8))
1922 return -EINVAL;
1923 break;
1924 case NM_CHANC_mainBCCH:
1925 case NM_CHANC_BCCHComb:
1926 /* allowed only for TS0 of C0 */
1927 if (ts->trx != ts->trx->bts->c0 ||
1928 ts->nr != 0)
1929 return -EINVAL;
1930 break;
1931 case NM_CHANC_BCCH:
1932 /* allowed only for TS 2/4/6 of C0 */
1933 if (ts->trx != ts->trx->bts->c0)
1934 return -EINVAL;
1935 if (ts->nr != 2 && ts->nr != 4 &&
1936 ts->nr != 6)
1937 return -EINVAL;
1938 break;
1939 case 8: /* this is not like 08.58, but in fact
1940 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1941 /* FIXME: only one CBCH allowed per cell */
1942 break;
1943 }
Harald Welted6575f92009-12-02 02:45:23 +05301944 break;
1945 case GSM_BTS_TYPE_NANOBTS:
1946 switch (ts->nr) {
1947 case 0:
1948 if (ts->trx->nr == 0) {
1949 /* only on TRX0 */
1950 switch (chan_comb) {
1951 case NM_CHANC_BCCH:
1952 case NM_CHANC_mainBCCH:
1953 case NM_CHANC_BCCHComb:
1954 return 0;
1955 break;
1956 default:
1957 return -EINVAL;
1958 }
1959 } else {
1960 switch (chan_comb) {
1961 case NM_CHANC_TCHFull:
1962 case NM_CHANC_TCHHalf:
1963 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1964 return 0;
1965 default:
1966 return -EINVAL;
1967 }
1968 }
1969 break;
1970 case 1:
1971 if (ts->trx->nr == 0) {
1972 switch (chan_comb) {
1973 case NM_CHANC_SDCCH_CBCH:
1974 if (ts->trx->ts[0].nm_chan_comb ==
1975 NM_CHANC_mainBCCH)
1976 return 0;
1977 return -EINVAL;
1978 case NM_CHANC_SDCCH:
1979 case NM_CHANC_TCHFull:
1980 case NM_CHANC_TCHHalf:
1981 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1982 case NM_CHANC_IPAC_TCHFull_PDCH:
1983 return 0;
1984 }
1985 } else {
1986 switch (chan_comb) {
1987 case NM_CHANC_SDCCH:
1988 case NM_CHANC_TCHFull:
1989 case NM_CHANC_TCHHalf:
1990 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1991 return 0;
1992 default:
1993 return -EINVAL;
1994 }
1995 }
1996 break;
1997 case 2:
1998 case 3:
1999 case 4:
2000 case 5:
2001 case 6:
2002 case 7:
2003 switch (chan_comb) {
2004 case NM_CHANC_TCHFull:
2005 case NM_CHANC_TCHHalf:
2006 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2007 return 0;
2008 case NM_CHANC_IPAC_PDCH:
2009 case NM_CHANC_IPAC_TCHFull_PDCH:
2010 if (ts->trx->nr == 0)
2011 return 0;
2012 else
2013 return -EINVAL;
2014 }
2015 break;
2016 }
2017 return -EINVAL;
2018 default:
2019 /* unknown BTS type */
2020 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002021 }
2022 return 0;
2023}
2024
Harald Welte22af0db2009-02-14 15:41:08 +00002025/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002026int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2027{
2028 struct gsm_bts *bts = ts->trx->bts;
2029 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002030 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002031 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002032 u_int8_t len = 2 + 2;
2033
2034 if (bts->type == GSM_BTS_TYPE_BS11)
2035 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002036
Harald Weltef325eb42009-02-19 17:07:39 +00002037 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002038 if (verify_chan_comb(ts, chan_comb) < 0) {
2039 msgb_free(msg);
2040 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2041 return -EINVAL;
2042 }
2043 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002044
Harald Welte52b1f982008-12-23 20:25:15 +00002045 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002046 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002047 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002048 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002049 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002050 if (ts->hopping.enabled) {
2051 unsigned int i;
2052 uint8_t *len;
2053
Harald Welte6e0cd042009-09-12 13:05:33 +02002054 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2055 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002056
2057 /* build the ARFCN list */
2058 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2059 len = msgb_put(msg, 1);
2060 *len = 0;
2061 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2062 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2063 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002064 /* At least BS-11 wants a TLV16 here */
2065 if (bts->type == GSM_BTS_TYPE_BS11)
2066 *len += 1;
2067 else
2068 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002069 }
2070 }
Harald Weltee0590df2009-02-15 03:34:15 +00002071 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002072 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002073 if (bts->type == GSM_BTS_TYPE_BS11)
2074 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002075
2076 return abis_nm_sendmsg(bts, msg);
2077}
2078
Harald Welte34a99682009-02-13 02:41:40 +00002079int 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 +00002080 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002081{
2082 struct abis_om_hdr *oh;
2083 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002084 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2085 u_int8_t len = att_len;
2086
2087 if (nack) {
2088 len += 2;
2089 msgtype = NM_MT_SW_ACT_REQ_NACK;
2090 }
Harald Welte34a99682009-02-13 02:41:40 +00002091
2092 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002093 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2094
Harald Welte34a99682009-02-13 02:41:40 +00002095 if (attr) {
2096 u_int8_t *ptr = msgb_put(msg, att_len);
2097 memcpy(ptr, attr, att_len);
2098 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002099 if (nack)
2100 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002101
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002102 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002103}
2104
Harald Welte8470bf22008-12-25 23:28:35 +00002105int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002106{
Harald Welte8470bf22008-12-25 23:28:35 +00002107 struct msgb *msg = nm_msgb_alloc();
2108 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002109 u_int8_t *data;
2110
2111 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2112 fill_om_hdr(oh, len);
2113 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002114 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002115
2116 return abis_nm_sendmsg(bts, msg);
2117}
2118
2119/* Siemens specific commands */
2120static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2121{
2122 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002123 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002124
2125 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002126 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002127 0xff, 0xff, 0xff);
2128
2129 return abis_nm_sendmsg(bts, msg);
2130}
2131
Harald Welte34a99682009-02-13 02:41:40 +00002132/* Chapter 8.9.2 */
2133int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2134{
2135 struct abis_om_hdr *oh;
2136 struct msgb *msg = nm_msgb_alloc();
2137
2138 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2139 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2140
Harald Weltea8bd6d42009-10-20 09:56:18 +02002141 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2142 DEBUGPC(DNM, "Sending OPSTART\n");
2143
Harald Welte34a99682009-02-13 02:41:40 +00002144 return abis_nm_sendmsg(bts, msg);
2145}
2146
2147/* Chapter 8.8.5 */
2148int 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 +02002149 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002150{
2151 struct abis_om_hdr *oh;
2152 struct msgb *msg = nm_msgb_alloc();
2153
2154 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2155 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2156 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2157
2158 return abis_nm_sendmsg(bts, msg);
2159}
2160
Harald Welte1989c082009-08-06 17:58:31 +02002161int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2162 u_int8_t e1_port1, u_int8_t ts1)
2163{
2164 struct abis_om_hdr *oh;
2165 struct msgb *msg = nm_msgb_alloc();
2166 u_int8_t *attr;
2167
2168 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2169 e1_port0, ts0, e1_port1, ts1);
2170
2171 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2172 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2173 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2174
2175 attr = msgb_put(msg, 3);
2176 attr[0] = NM_ATT_MDROP_LINK;
2177 attr[1] = e1_port0;
2178 attr[2] = ts0;
2179
2180 attr = msgb_put(msg, 3);
2181 attr[0] = NM_ATT_MDROP_NEXT;
2182 attr[1] = e1_port1;
2183 attr[2] = ts1;
2184
2185 return abis_nm_sendmsg(bts, msg);
2186}
Harald Welte34a99682009-02-13 02:41:40 +00002187
Harald Weltec7310382009-08-08 00:02:36 +02002188/* Chapter 8.7.1 */
2189int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2190 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002191 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002192{
2193 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002194
Harald Welte4d54d0b2011-02-19 16:48:17 +01002195 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002196
2197 if (!msg)
2198 msg = nm_msgb_alloc();
2199
2200 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2201 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2202 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2203 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002204 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002205
2206 return abis_nm_sendmsg(bts, msg);
2207}
2208
Harald Welte52b1f982008-12-23 20:25:15 +00002209int abis_nm_event_reports(struct gsm_bts *bts, int on)
2210{
2211 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002212 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002213 else
Harald Welte227d4072009-01-03 08:16:25 +00002214 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002215}
2216
Harald Welte47d88ae2009-01-04 12:02:08 +00002217/* Siemens (or BS-11) specific commands */
2218
Harald Welte3ffd1372009-02-01 22:15:49 +00002219int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2220{
2221 if (reconnect == 0)
2222 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2223 else
2224 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2225}
2226
Harald Welteb8427972009-02-05 19:27:17 +00002227int abis_nm_bs11_restart(struct gsm_bts *bts)
2228{
2229 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2230}
2231
2232
Harald Welte268bb402009-02-01 19:11:56 +00002233struct bs11_date_time {
2234 u_int16_t year;
2235 u_int8_t month;
2236 u_int8_t day;
2237 u_int8_t hour;
2238 u_int8_t min;
2239 u_int8_t sec;
2240} __attribute__((packed));
2241
2242
2243void get_bs11_date_time(struct bs11_date_time *aet)
2244{
2245 time_t t;
2246 struct tm *tm;
2247
2248 t = time(NULL);
2249 tm = localtime(&t);
2250 aet->sec = tm->tm_sec;
2251 aet->min = tm->tm_min;
2252 aet->hour = tm->tm_hour;
2253 aet->day = tm->tm_mday;
2254 aet->month = tm->tm_mon;
2255 aet->year = htons(1900 + tm->tm_year);
2256}
2257
Harald Welte05188ee2009-01-18 11:39:08 +00002258int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002259{
Harald Welte4668fda2009-01-03 08:19:29 +00002260 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002261}
2262
Harald Welte05188ee2009-01-18 11:39:08 +00002263int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002264{
2265 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002266 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002267 else
Harald Welte4668fda2009-01-03 08:19:29 +00002268 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002269}
Harald Welte47d88ae2009-01-04 12:02:08 +00002270
Harald Welte05188ee2009-01-18 11:39:08 +00002271int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002272 enum abis_bs11_objtype type, u_int8_t idx,
2273 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002274{
2275 struct abis_om_hdr *oh;
2276 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002277 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002278
2279 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002280 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002281 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002282 cur = msgb_put(msg, attr_len);
2283 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002284
2285 return abis_nm_sendmsg(bts, msg);
2286}
2287
Harald Welte78fc0d42009-02-19 02:50:57 +00002288int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2289 enum abis_bs11_objtype type, u_int8_t idx)
2290{
2291 struct abis_om_hdr *oh;
2292 struct msgb *msg = nm_msgb_alloc();
2293
2294 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2295 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2296 NM_OC_BS11, type, 0, idx);
2297
2298 return abis_nm_sendmsg(bts, msg);
2299}
2300
Harald Welte05188ee2009-01-18 11:39:08 +00002301int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002302{
2303 struct abis_om_hdr *oh;
2304 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002305 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002306
2307 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002308 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002309 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2310 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002311
2312 return abis_nm_sendmsg(bts, msg);
2313}
2314
Harald Welte05188ee2009-01-18 11:39:08 +00002315int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002316{
2317 struct abis_om_hdr *oh;
2318 struct msgb *msg = nm_msgb_alloc();
2319
2320 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2321 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002322 idx, 0xff, 0xff);
2323
2324 return abis_nm_sendmsg(bts, msg);
2325}
2326
2327int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2328{
2329 struct abis_om_hdr *oh;
2330 struct msgb *msg = nm_msgb_alloc();
2331
2332 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2333 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2334 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002335
2336 return abis_nm_sendmsg(bts, msg);
2337}
Harald Welte05188ee2009-01-18 11:39:08 +00002338
Harald Welte78fc0d42009-02-19 02:50:57 +00002339static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2340int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2341{
2342 struct abis_om_hdr *oh;
2343 struct msgb *msg = nm_msgb_alloc();
2344
2345 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2346 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2347 0xff, 0xff, 0xff);
2348 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2349
2350 return abis_nm_sendmsg(bts, msg);
2351}
2352
Harald Welteb6c92ae2009-02-21 20:15:32 +00002353/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002354int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002355 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2356 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002357{
2358 struct abis_om_hdr *oh;
2359 struct abis_nm_channel *ch;
2360 struct msgb *msg = nm_msgb_alloc();
2361
2362 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002363 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002364 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2365
2366 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2367 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002368 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002369
2370 return abis_nm_sendmsg(bts, msg);
2371}
2372
2373int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2374{
2375 struct abis_om_hdr *oh;
2376 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002377
2378 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002379 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002380 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2381 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2382
2383 return abis_nm_sendmsg(trx->bts, msg);
2384}
2385
Harald Welte78fc0d42009-02-19 02:50:57 +00002386int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2387{
2388 struct abis_om_hdr *oh;
2389 struct msgb *msg = nm_msgb_alloc();
2390 u_int8_t attr = NM_ATT_BS11_TXPWR;
2391
2392 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2393 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2394 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2395 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2396
2397 return abis_nm_sendmsg(trx->bts, msg);
2398}
2399
Harald Welteaaf02d92009-04-29 13:25:57 +00002400int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2401{
2402 struct abis_om_hdr *oh;
2403 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002404 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002405
2406 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2407 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2408 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002409 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002410
2411 return abis_nm_sendmsg(bts, msg);
2412}
2413
Harald Welteef061952009-05-17 12:43:42 +00002414int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2415{
2416 struct abis_om_hdr *oh;
2417 struct msgb *msg = nm_msgb_alloc();
2418 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2419 NM_ATT_BS11_CCLK_TYPE };
2420
2421 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2422 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2423 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2424 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2425
2426 return abis_nm_sendmsg(bts, msg);
2427
2428}
Harald Welteaaf02d92009-04-29 13:25:57 +00002429
Harald Welte268bb402009-02-01 19:11:56 +00002430//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002431
Harald Welte1bc09062009-01-18 14:17:52 +00002432int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002433{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002434 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2435}
2436
Daniel Willmann4b054c82010-01-07 00:46:26 +01002437int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2438{
2439 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2440}
2441
Daniel Willmann493db4e2010-01-07 00:43:11 +01002442int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2443{
Harald Welte05188ee2009-01-18 11:39:08 +00002444 struct abis_om_hdr *oh;
2445 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002446 struct bs11_date_time bdt;
2447
2448 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002449
2450 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002451 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002452 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002453 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002454 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002455 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002456 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002457 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002458 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002459 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002460 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002461 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002462 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002463 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002464 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002465 }
Harald Welte05188ee2009-01-18 11:39:08 +00002466
2467 return abis_nm_sendmsg(bts, msg);
2468}
Harald Welte1bc09062009-01-18 14:17:52 +00002469
2470int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2471{
2472 struct abis_om_hdr *oh;
2473 struct msgb *msg;
2474
2475 if (strlen(password) != 10)
2476 return -EINVAL;
2477
2478 msg = nm_msgb_alloc();
2479 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002480 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002481 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2482 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2483
2484 return abis_nm_sendmsg(bts, msg);
2485}
2486
Harald Weltee69f5fb2009-04-28 16:31:38 +00002487/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2488int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2489{
2490 struct abis_om_hdr *oh;
2491 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002492 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002493
2494 msg = nm_msgb_alloc();
2495 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2496 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2497 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002498
2499 if (locked)
2500 tlv_value = BS11_LI_PLL_LOCKED;
2501 else
2502 tlv_value = BS11_LI_PLL_STANDALONE;
2503
2504 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002505
2506 return abis_nm_sendmsg(bts, msg);
2507}
2508
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002509/* Set the calibration value of the PLL (work value/set value)
2510 * It depends on the login which one is changed */
2511int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2512{
2513 struct abis_om_hdr *oh;
2514 struct msgb *msg;
2515 u_int8_t tlv_value[2];
2516
2517 msg = nm_msgb_alloc();
2518 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2519 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2520 BS11_OBJ_TRX1, 0x00, 0x00);
2521
2522 tlv_value[0] = value>>8;
2523 tlv_value[1] = value&0xff;
2524
2525 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2526
2527 return abis_nm_sendmsg(bts, msg);
2528}
2529
Harald Welte1bc09062009-01-18 14:17:52 +00002530int abis_nm_bs11_get_state(struct gsm_bts *bts)
2531{
2532 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2533}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002534
2535/* BS11 SWL */
2536
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002537void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002538
Harald Welte5e4d1b32009-02-01 13:36:56 +00002539struct abis_nm_bs11_sw {
2540 struct gsm_bts *bts;
2541 char swl_fname[PATH_MAX];
2542 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002543 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002544 struct llist_head file_list;
2545 gsm_cbfn *user_cb; /* specified by the user */
2546};
2547static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2548
2549struct file_list_entry {
2550 struct llist_head list;
2551 char fname[PATH_MAX];
2552};
2553
2554struct file_list_entry *fl_dequeue(struct llist_head *queue)
2555{
2556 struct llist_head *lh;
2557
2558 if (llist_empty(queue))
2559 return NULL;
2560
2561 lh = queue->next;
2562 llist_del(lh);
2563
2564 return llist_entry(lh, struct file_list_entry, list);
2565}
2566
2567static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2568{
2569 char linebuf[255];
2570 struct llist_head *lh, *lh2;
2571 FILE *swl;
2572 int rc = 0;
2573
2574 swl = fopen(bs11_sw->swl_fname, "r");
2575 if (!swl)
2576 return -ENODEV;
2577
2578 /* zero the stale file list, if any */
2579 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2580 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002581 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002582 }
2583
2584 while (fgets(linebuf, sizeof(linebuf), swl)) {
2585 char file_id[12+1];
2586 char file_version[80+1];
2587 struct file_list_entry *fle;
2588 static char dir[PATH_MAX];
2589
2590 if (strlen(linebuf) < 4)
2591 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002592
Harald Welte5e4d1b32009-02-01 13:36:56 +00002593 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2594 if (rc < 0) {
2595 perror("ERR parsing SWL file");
2596 rc = -EINVAL;
2597 goto out;
2598 }
2599 if (rc < 2)
2600 continue;
2601
Harald Welte470ec292009-06-26 20:25:23 +02002602 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002603 if (!fle) {
2604 rc = -ENOMEM;
2605 goto out;
2606 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002607
2608 /* construct new filename */
2609 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2610 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2611 strcat(fle->fname, "/");
2612 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002613
2614 llist_add_tail(&fle->list, &bs11_sw->file_list);
2615 }
2616
2617out:
2618 fclose(swl);
2619 return rc;
2620}
2621
2622/* bs11 swload specific callback, passed to abis_nm core swload */
2623static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2624 struct msgb *msg, void *data, void *param)
2625{
2626 struct abis_nm_bs11_sw *bs11_sw = data;
2627 struct file_list_entry *fle;
2628 int rc = 0;
2629
Harald Welte5e4d1b32009-02-01 13:36:56 +00002630 switch (event) {
2631 case NM_MT_LOAD_END_ACK:
2632 fle = fl_dequeue(&bs11_sw->file_list);
2633 if (fle) {
2634 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002635 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002636 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002637 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002638 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002639 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002640 } else {
2641 /* activate the SWL */
2642 rc = abis_nm_software_activate(bs11_sw->bts,
2643 bs11_sw->swl_fname,
2644 bs11_swload_cbfn,
2645 bs11_sw);
2646 }
2647 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002648 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002649 case NM_MT_LOAD_END_NACK:
2650 case NM_MT_LOAD_INIT_ACK:
2651 case NM_MT_LOAD_INIT_NACK:
2652 case NM_MT_ACTIVATE_SW_NACK:
2653 case NM_MT_ACTIVATE_SW_ACK:
2654 default:
2655 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002656 if (bs11_sw->user_cb)
2657 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002658 break;
2659 }
2660
2661 return rc;
2662}
2663
2664/* Siemens provides a SWL file that is a mere listing of all the other
2665 * files that are part of a software release. We need to upload first
2666 * the list file, and then each file that is listed in the list file */
2667int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002668 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002669{
2670 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2671 struct file_list_entry *fle;
2672 int rc = 0;
2673
2674 INIT_LLIST_HEAD(&bs11_sw->file_list);
2675 bs11_sw->bts = bts;
2676 bs11_sw->win_size = win_size;
2677 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002678 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002679
2680 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2681 rc = bs11_read_swl_file(bs11_sw);
2682 if (rc < 0)
2683 return rc;
2684
2685 /* dequeue next item in file list */
2686 fle = fl_dequeue(&bs11_sw->file_list);
2687 if (!fle)
2688 return -EINVAL;
2689
2690 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002691 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002692 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002693 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002694 return rc;
2695}
2696
Harald Welte5083b0b2009-02-02 19:20:52 +00002697#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002698static u_int8_t req_attr_btse[] = {
2699 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2700 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2701 NM_ATT_BS11_LMT_USER_NAME,
2702
2703 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2704
2705 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2706
2707 NM_ATT_BS11_SW_LOAD_STORED };
2708
2709static u_int8_t req_attr_btsm[] = {
2710 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2711 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2712 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2713 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002714#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002715
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002716static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002717 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2718 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002719 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002720
2721int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2722{
2723 struct abis_om_hdr *oh;
2724 struct msgb *msg = nm_msgb_alloc();
2725
2726 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2727 /* SiemensHW CCTRL object */
2728 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2729 0x03, 0x00, 0x00);
2730 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2731
2732 return abis_nm_sendmsg(bts, msg);
2733}
Harald Welte268bb402009-02-01 19:11:56 +00002734
2735int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2736{
2737 struct abis_om_hdr *oh;
2738 struct msgb *msg = nm_msgb_alloc();
2739 struct bs11_date_time aet;
2740
2741 get_bs11_date_time(&aet);
2742 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2743 /* SiemensHW CCTRL object */
2744 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2745 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002746 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002747
2748 return abis_nm_sendmsg(bts, msg);
2749}
Harald Welte5c1e4582009-02-15 11:57:29 +00002750
Harald Weltef751a102010-12-14 12:52:16 +01002751int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2752{
2753 struct abis_om_hdr *oh;
2754 struct msgb *msg = nm_msgb_alloc();
2755 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2756
2757 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2758 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2759 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2760 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2761
2762 return abis_nm_sendmsg(bts, msg);
2763}
2764
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002765int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2766{
2767 struct abis_om_hdr *oh;
2768 struct msgb *msg = nm_msgb_alloc();
2769 struct bs11_date_time aet;
2770
2771 get_bs11_date_time(&aet);
2772 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2773 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2774 bport, 0xff, 0x02);
2775 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2776
2777 return abis_nm_sendmsg(bts, msg);
2778}
2779
Harald Welte5c1e4582009-02-15 11:57:29 +00002780/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002781static const char ipaccess_magic[] = "com.ipaccess";
2782
Harald Welte677c21f2009-02-17 13:22:23 +00002783
2784static int abis_nm_rx_ipacc(struct msgb *msg)
2785{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002786 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002787 struct abis_om_hdr *oh = msgb_l2(msg);
2788 struct abis_om_fom_hdr *foh;
2789 u_int8_t idstrlen = oh->data[0];
2790 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002791 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002792
2793 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002794 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002795 return -EINVAL;
2796 }
2797
Harald Welte193fefc2009-04-30 15:16:27 +00002798 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002799 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002800
Harald Weltea8bd6d42009-10-20 09:56:18 +02002801 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002802
Harald Welte746d6092009-10-19 22:11:11 +02002803 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002804
Harald Welte677c21f2009-02-17 13:22:23 +00002805 switch (foh->msg_type) {
2806 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002807 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002808 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2809 memcpy(&addr,
2810 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2811
2812 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2813 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002814 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002815 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002816 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002817 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002818 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2819 DEBUGPC(DNM, "STREAM=0x%02x ",
2820 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002821 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002822 break;
2823 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002824 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002825 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002826 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002827 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002828 else
2829 DEBUGPC(DNM, "\n");
2830 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002831 case NM_MT_IPACC_SET_NVATTR_ACK:
2832 DEBUGPC(DNM, "SET NVATTR ACK\n");
2833 /* FIXME: decode and show the actual attributes */
2834 break;
2835 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002836 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002837 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002838 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002839 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2840 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002841 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002842 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002843 case NM_MT_IPACC_GET_NVATTR_ACK:
2844 DEBUGPC(DNM, "GET NVATTR ACK\n");
2845 /* FIXME: decode and show the actual attributes */
2846 break;
2847 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002848 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002849 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002850 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002851 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2852 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002853 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002854 break;
Harald Welte15c44172009-10-08 20:15:24 +02002855 case NM_MT_IPACC_SET_ATTR_ACK:
2856 DEBUGPC(DNM, "SET ATTR ACK\n");
2857 break;
2858 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002859 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002860 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002861 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002862 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2863 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002864 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002865 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002866 default:
2867 DEBUGPC(DNM, "unknown\n");
2868 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002869 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002870
2871 /* signal handling */
2872 switch (foh->msg_type) {
2873 case NM_MT_IPACC_RSL_CONNECT_NACK:
2874 case NM_MT_IPACC_SET_NVATTR_NACK:
2875 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002876 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002877 signal.msg_type = foh->msg_type;
2878 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002879 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002880 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002881 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002882 signal.msg_type = foh->msg_type;
2883 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002884 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002885 default:
2886 break;
2887 }
2888
Harald Welte677c21f2009-02-17 13:22:23 +00002889 return 0;
2890}
2891
Harald Welte193fefc2009-04-30 15:16:27 +00002892/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002893int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2894 u_int8_t obj_class, u_int8_t bts_nr,
2895 u_int8_t trx_nr, u_int8_t ts_nr,
2896 u_int8_t *attr, int attr_len)
2897{
2898 struct msgb *msg = nm_msgb_alloc();
2899 struct abis_om_hdr *oh;
2900 struct abis_om_fom_hdr *foh;
2901 u_int8_t *data;
2902
2903 /* construct the 12.21 OM header, observe the erroneous length */
2904 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2905 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2906 oh->mdisc = ABIS_OM_MDISC_MANUF;
2907
2908 /* add the ip.access magic */
2909 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2910 *data++ = sizeof(ipaccess_magic);
2911 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2912
2913 /* fill the 12.21 FOM header */
2914 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2915 foh->msg_type = msg_type;
2916 foh->obj_class = obj_class;
2917 foh->obj_inst.bts_nr = bts_nr;
2918 foh->obj_inst.trx_nr = trx_nr;
2919 foh->obj_inst.ts_nr = ts_nr;
2920
2921 if (attr && attr_len) {
2922 data = msgb_put(msg, attr_len);
2923 memcpy(data, attr, attr_len);
2924 }
2925
2926 return abis_nm_sendmsg(bts, msg);
2927}
Harald Welte677c21f2009-02-17 13:22:23 +00002928
Harald Welte193fefc2009-04-30 15:16:27 +00002929/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002930int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002931 int attr_len)
2932{
Harald Welte2ef156d2010-01-07 20:39:42 +01002933 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2934 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002935 attr_len);
2936}
2937
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002938int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002939 u_int32_t ip, u_int16_t port, u_int8_t stream)
2940{
2941 struct in_addr ia;
2942 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2943 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2944 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2945
2946 int attr_len = sizeof(attr);
2947
2948 ia.s_addr = htonl(ip);
2949 attr[1] = stream;
2950 attr[3] = port >> 8;
2951 attr[4] = port & 0xff;
2952 *(u_int32_t *)(attr+6) = ia.s_addr;
2953
2954 /* if ip == 0, we use the default IP */
2955 if (ip == 0)
2956 attr_len -= 5;
2957
2958 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002959 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002960
2961 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2962 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2963 trx->nr, 0xff, attr, attr_len);
2964}
2965
Harald Welte193fefc2009-04-30 15:16:27 +00002966/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002967int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002968{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002969 struct abis_om_hdr *oh;
2970 struct msgb *msg = nm_msgb_alloc();
2971
2972 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2973 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2974 trx->bts->nr, trx->nr, 0xff);
2975
2976 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002977}
Harald Weltedaef5212009-10-24 10:20:41 +02002978
2979int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2980 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2981 u_int8_t *attr, u_int8_t attr_len)
2982{
2983 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2984 obj_class, bts_nr, trx_nr, ts_nr,
2985 attr, attr_len);
2986}
Harald Welte0f255852009-11-12 14:48:42 +01002987
Harald Welte97a282b2010-03-14 15:37:43 +08002988void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2989{
2990 /* we simply reuse the GSM48 function and overwrite the RAC
2991 * with the Cell ID */
2992 gsm48_ra_id_by_bts(buf, bts);
2993 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2994}
2995
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002996void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2997{
2998 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2999
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01003000 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003001 if (!trx->bts || !trx->bts->oml_link)
3002 return;
3003
3004 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3005 trx->bts->bts_nr, trx->nr, 0xff,
3006 new_state);
3007}
3008
Harald Welte92b1fe42010-03-25 11:45:30 +08003009static const struct value_string ipacc_testres_names[] = {
3010 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3011 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3012 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3013 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3014 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3015 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01003016};
3017
3018const char *ipacc_testres_name(u_int8_t res)
3019{
Harald Welte92b1fe42010-03-25 11:45:30 +08003020 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003021}
3022
Harald Welteb40a38f2009-11-13 11:56:05 +01003023void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3024{
3025 cid->mcc = (buf[0] & 0xf) * 100;
3026 cid->mcc += (buf[0] >> 4) * 10;
3027 cid->mcc += (buf[1] & 0xf) * 1;
3028
3029 if (buf[1] >> 4 == 0xf) {
3030 cid->mnc = (buf[2] & 0xf) * 10;
3031 cid->mnc += (buf[2] >> 4) * 1;
3032 } else {
3033 cid->mnc = (buf[2] & 0xf) * 100;
3034 cid->mnc += (buf[2] >> 4) * 10;
3035 cid->mnc += (buf[1] >> 4) * 1;
3036 }
3037
Harald Welteaff237d2009-11-13 14:41:52 +01003038 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3039 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003040}
3041
Harald Welte0f255852009-11-12 14:48:42 +01003042/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3043int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3044{
3045 u_int8_t *cur = buf;
3046 u_int16_t len;
3047
Harald Welteaf109b92010-07-22 18:14:36 +02003048 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003049
3050 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3051 return -EINVAL;
3052 cur++;
3053
3054 len = ntohs(*(u_int16_t *)cur);
3055 cur += 2;
3056
3057 binf->info_type = ntohs(*(u_int16_t *)cur);
3058 cur += 2;
3059
3060 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3061 binf->freq_qual = *cur >> 2;
3062
Harald Welteaf109b92010-07-22 18:14:36 +02003063 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003064 binf->arfcn |= *cur++;
3065
3066 if (binf->info_type & IPAC_BINF_RXLEV)
3067 binf->rx_lev = *cur & 0x3f;
3068 cur++;
3069
3070 if (binf->info_type & IPAC_BINF_RXQUAL)
3071 binf->rx_qual = *cur & 0x7;
3072 cur++;
3073
3074 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3075 binf->freq_err = ntohs(*(u_int16_t *)cur);
3076 cur += 2;
3077
3078 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3079 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3080 cur += 2;
3081
3082 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3083 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3084 cur += 4;
3085
Harald Weltea780a3d2010-07-30 22:34:42 +02003086#if 0
3087 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003088 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003089#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003090 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003091 cur++;
3092
Harald Welteb40a38f2009-11-13 11:56:05 +01003093 ipac_parse_cgi(&binf->cgi, cur);
3094 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003095
3096 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3097 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3098 cur += sizeof(binf->ba_list_si2);
3099 }
3100
3101 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3102 memcpy(binf->ba_list_si2bis, cur,
3103 sizeof(binf->ba_list_si2bis));
3104 cur += sizeof(binf->ba_list_si2bis);
3105 }
3106
3107 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3108 memcpy(binf->ba_list_si2ter, cur,
3109 sizeof(binf->ba_list_si2ter));
3110 cur += sizeof(binf->ba_list_si2ter);
3111 }
3112
3113 return 0;
3114}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003115
3116void abis_nm_clear_queue(struct gsm_bts *bts)
3117{
3118 struct msgb *msg;
3119
3120 while (!llist_empty(&bts->abis_queue)) {
3121 msg = msgb_dequeue(&bts->abis_queue);
3122 msgb_free(msg);
3123 }
3124
3125 bts->abis_nm_pend = 0;
3126}