blob: 408d56ea8677e26480eafeab09ce416b09a9cbbd [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>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010040#include <osmocom/core/msgb.h>
41#include <osmocom/gsm/tlv.h>
42#include <osmocom/core/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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200193static const char *nack_cause_name(uint8_t cause)
Harald Welte6c96ba52009-05-01 13:03:40 +0000194{
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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200208static const char *event_type_name(uint8_t cause)
Harald Welte0db97b22009-05-01 17:22:47 +0000209{
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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200224static const char *severity_name(uint8_t cause)
Harald Welte0db97b22009-05-01 17:22:47 +0000225{
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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200346int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200382static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +0000383{
384 oh->mdisc = ABIS_OM_MDISC_FOM;
385 oh->placement = ABIS_OM_PLACEMENT_ONLY;
386 oh->sequence = 0;
387 oh->length = len;
388}
389
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200390static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
391 uint8_t msg_type, uint8_t obj_class,
392 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000393{
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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200462static const char *obj_class_name(uint8_t oc)
Harald Welte34a99682009-02-13 02:41:40 +0000463{
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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200467const char *nm_opstate_name(uint8_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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200495const char *nm_avail_name(uint8_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
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200520const char *nm_adm_name(uint8_t adm)
Harald Welte7b26bcb2009-05-28 11:39:21 +0000521{
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 *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200542objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000543 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 *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200626objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000627 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 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200682static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
683 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000684{
Harald Welteaeedeb42009-05-01 13:08:14 +0000685 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100686 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000687
Harald Welteaf9b8102011-03-06 21:20:38 +0100688 memset(&nsd, 0, sizeof(nsd));
689
Harald Weltef338a032011-01-14 15:55:42 +0100690 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
691 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100692 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000693 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
694 if (!nm_state)
695 return -1;
696
697 new_state = *nm_state;
698 new_state.administrative = adm_state;
699
Harald Weltef38ca9a2011-03-06 22:11:32 +0100700 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100701 nsd.obj_class = obj_class;
702 nsd.old_state = nm_state;
703 nsd.new_state = &new_state;
704 nsd.obj_inst = obj_inst;
705 dispatch_signal(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000706
707 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000708
Harald Weltef338a032011-01-14 15:55:42 +0100709 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000710}
711
Harald Welte97ed1e72009-02-06 13:38:02 +0000712static int abis_nm_rx_statechg_rep(struct msgb *mb)
713{
Harald Weltee0590df2009-02-15 03:34:15 +0000714 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000715 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000716 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000717 struct tlv_parsed tp;
718 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000719
Harald Welte23897662009-05-01 14:52:51 +0000720 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000721
Harald Welte8b697c72009-06-05 19:18:45 +0000722 memset(&new_state, 0, sizeof(new_state));
723
Harald Weltee0590df2009-02-15 03:34:15 +0000724 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
725 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100726 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000727 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000728 }
Harald Weltee0590df2009-02-15 03:34:15 +0000729
730 new_state = *nm_state;
731
Harald Welte39315c42010-01-10 18:01:52 +0100732 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000733 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
734 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000735 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000736 }
737 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000738 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
739 new_state.availability = 0xff;
740 else
741 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000742 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000743 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100744 } else
745 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000746 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
747 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200748 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000749 }
750 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000751
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100752 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
753 new_state.operational != nm_state->operational ||
754 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000755 /* Update the operational state of a given object in our in-memory data
756 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100757 struct nm_statechg_signal_data nsd;
758 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
759 nsd.obj_class = foh->obj_class;
760 nsd.old_state = nm_state;
761 nsd.new_state = &new_state;
762 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100763 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100764 dispatch_signal(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100765 nm_state->operational = new_state.operational;
766 nm_state->availability = new_state.availability;
767 if (nm_state->administrative == 0)
768 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000769 }
770#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000771 if (op_state == 1) {
772 /* try to enable objects that are disabled */
773 abis_nm_opstart(bts, foh->obj_class,
774 foh->obj_inst.bts_nr,
775 foh->obj_inst.trx_nr,
776 foh->obj_inst.ts_nr);
777 }
Harald Weltee0590df2009-02-15 03:34:15 +0000778#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000779 return 0;
780}
781
Harald Welte0db97b22009-05-01 17:22:47 +0000782static int rx_fail_evt_rep(struct msgb *mb)
783{
784 struct abis_om_hdr *oh = msgb_l2(mb);
785 struct abis_om_fom_hdr *foh = msgb_l3(mb);
786 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100787 const uint8_t *p_val;
788 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000789
790 DEBUGPC(DNM, "Failure Event Report ");
791
Harald Welte39315c42010-01-10 18:01:52 +0100792 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000793
794 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
795 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
796 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
797 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100798 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
799 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
800 DEBUGPC(DNM, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
801 }
802 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
803 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
804 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
805 if (p_text) {
806 DEBUGPC(DNM, "Additional Text=%s ", p_text);
807 talloc_free(p_text);
808 }
809 }
Harald Welte0db97b22009-05-01 17:22:47 +0000810
811 DEBUGPC(DNM, "\n");
812
813 return 0;
814}
815
Harald Welte97ed1e72009-02-06 13:38:02 +0000816static int abis_nm_rcvmsg_report(struct msgb *mb)
817{
818 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200819 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000820
Harald Weltea8bd6d42009-10-20 09:56:18 +0200821 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000822
Harald Welte97ed1e72009-02-06 13:38:02 +0000823 //nmh->cfg->report_cb(mb, foh);
824
825 switch (mt) {
826 case NM_MT_STATECHG_EVENT_REP:
827 return abis_nm_rx_statechg_rep(mb);
828 break;
Harald Welte34a99682009-02-13 02:41:40 +0000829 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000830 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000831 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000832 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000833 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000834 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000835 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000836 break;
Harald Weltec7310382009-08-08 00:02:36 +0200837 case NM_MT_TEST_REP:
838 DEBUGPC(DNM, "Test Report\n");
839 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
840 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000841 default:
Harald Welte23897662009-05-01 14:52:51 +0000842 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000843 break;
844
Harald Welte97ed1e72009-02-06 13:38:02 +0000845 };
846
Harald Welte97ed1e72009-02-06 13:38:02 +0000847 return 0;
848}
849
Harald Welte34a99682009-02-13 02:41:40 +0000850/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200851static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
852 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000853{
854 struct abis_om_hdr *oh;
855 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200856 uint8_t len = swdesc_len;
857 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000858
859 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
860 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
861
862 trailer = msgb_put(msg, swdesc_len);
863 memcpy(trailer, sw_desc, swdesc_len);
864
865 return abis_nm_sendmsg(bts, msg);
866}
867
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200868static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100869{
870 static const struct tlv_definition sw_descr_def = {
871 .def = {
872 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
873 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
874 },
875 };
876
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200877 uint8_t tag;
878 uint16_t tag_len;
879 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100880 int ofs = 0, len;
881
882 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
883 * nested nature and the fact you have to assume it contains only two sub
884 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
885
886 if (sw_descr[0] != NM_ATT_SW_DESCR) {
887 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
888 return -1;
889 }
890 ofs += 1;
891
892 len = tlv_parse_one(&tag, &tag_len, &val,
893 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
894 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
895 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
896 return -2;
897 }
898 ofs += len;
899
900 len = tlv_parse_one(&tag, &tag_len, &val,
901 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
902 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
903 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
904 return -3;
905 }
906 ofs += len;
907
908 return ofs;
909}
910
Harald Welte34a99682009-02-13 02:41:40 +0000911static int abis_nm_rx_sw_act_req(struct msgb *mb)
912{
913 struct abis_om_hdr *oh = msgb_l2(mb);
914 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200915 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200916 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100917 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000918
Harald Weltea8bd6d42009-10-20 09:56:18 +0200919 debugp_foh(foh);
920
921 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000922
Harald Welte97a282b2010-03-14 15:37:43 +0800923 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000924
925 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000926 foh->obj_inst.bts_nr,
927 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800928 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000929 foh->data, oh->length-sizeof(*foh));
930
Harald Welte39315c42010-01-10 18:01:52 +0100931 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200932 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
933 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
934 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
935 DEBUGP(DNM, "SW config not found! Can't continue.\n");
936 return -EINVAL;
937 } else {
938 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
939 }
940
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100941 /* Use the first SW_DESCR present in SW config */
942 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
943 if (sw_descr_len < 0)
944 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200945
Harald Welte34a99682009-02-13 02:41:40 +0000946 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
947 foh->obj_inst.bts_nr,
948 foh->obj_inst.trx_nr,
949 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100950 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000951}
952
Harald Weltee0590df2009-02-15 03:34:15 +0000953/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
954static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
955{
956 struct abis_om_hdr *oh = msgb_l2(mb);
957 struct abis_om_fom_hdr *foh = msgb_l3(mb);
958 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200959 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000960
Harald Welte39315c42010-01-10 18:01:52 +0100961 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000962 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
963 return -EINVAL;
964
965 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
966
967 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
968}
969
Harald Welteee670472009-02-22 21:58:49 +0000970static int abis_nm_rx_lmt_event(struct msgb *mb)
971{
972 struct abis_om_hdr *oh = msgb_l2(mb);
973 struct abis_om_fom_hdr *foh = msgb_l3(mb);
974 struct tlv_parsed tp;
975
976 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100977 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000978 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
979 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200980 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000981 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
982 }
983 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
984 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200985 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000986 DEBUGPC(DNM, "Level=%u ", level);
987 }
988 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
989 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
990 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
991 DEBUGPC(DNM, "Username=%s ", name);
992 }
993 DEBUGPC(DNM, "\n");
994 /* FIXME: parse LMT LOGON TIME */
995 return 0;
996}
997
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100998static void abis_nm_queue_send_next(struct gsm_bts *bts)
999{
1000 int wait = 0;
1001 struct msgb *msg;
1002 /* the queue is empty */
1003 while (!llist_empty(&bts->abis_queue)) {
1004 msg = msgb_dequeue(&bts->abis_queue);
1005 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +01001006 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001007
1008 if (wait)
1009 break;
1010 }
1011
1012 bts->abis_nm_pend = wait;
1013}
1014
Harald Welte52b1f982008-12-23 20:25:15 +00001015/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001016static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001017{
Harald Welte6c96ba52009-05-01 13:03:40 +00001018 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001019 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001020 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001021 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001022
1023 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001024 if (is_report(mt))
1025 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001026
Harald Welte4724f992009-01-18 18:01:49 +00001027 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1028 return abis_nm_rcvmsg_sw(mb);
1029
Harald Welte78fc0d42009-02-19 02:50:57 +00001030 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001031 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +00001032 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001033
Harald Weltea8bd6d42009-10-20 09:56:18 +02001034 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001035
Harald Welte92b1fe42010-03-25 11:45:30 +08001036 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +00001037
Harald Welte39315c42010-01-10 18:01:52 +01001038 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +00001039 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001040 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00001041 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1042 else
1043 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001044
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001045 nack_data.msg = mb;
1046 nack_data.mt = mt;
1047 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001048 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001049 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001050 }
Harald Weltead384642008-12-26 10:20:07 +00001051#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001052 /* check if last message is to be acked */
1053 if (is_ack_nack(nmh->last_msgtype)) {
1054 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001055 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001056 /* we got our ACK, continue sending the next msg */
1057 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1058 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001059 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001060 /* FIXME: somehow signal this to the caller */
1061 } else {
1062 /* really strange things happen */
1063 return -EINVAL;
1064 }
1065 }
Harald Weltead384642008-12-26 10:20:07 +00001066#endif
1067
Harald Welte97ed1e72009-02-06 13:38:02 +00001068 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001069 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001070 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +00001071 break;
Harald Welte34a99682009-02-13 02:41:40 +00001072 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001073 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +00001074 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001075 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001076 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001077 break;
Harald Welte1989c082009-08-06 17:58:31 +02001078 case NM_MT_CONN_MDROP_LINK_ACK:
1079 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1080 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001081 case NM_MT_IPACC_RESTART_ACK:
1082 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1083 break;
1084 case NM_MT_IPACC_RESTART_NACK:
1085 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1086 break;
Harald Weltefd355a32011-03-04 13:41:31 +01001087 case NM_MT_SET_BTS_ATTR_ACK:
1088 /* The HSL wants an OPSTART _after_ the SI has been set */
1089 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
1090 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
1091 }
1092 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001093 }
1094
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001095 abis_nm_queue_send_next(mb->trx->bts);
1096 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001097}
1098
Harald Welte677c21f2009-02-17 13:22:23 +00001099static int abis_nm_rx_ipacc(struct msgb *mb);
1100
1101static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1102{
1103 int rc;
1104 int bts_type = mb->trx->bts->type;
1105
1106 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001107 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001108 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001109 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +00001110 break;
1111 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001112 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1113 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001114 rc = 0;
1115 break;
1116 }
1117
1118 return rc;
1119}
1120
Harald Welte52b1f982008-12-23 20:25:15 +00001121/* High-Level API */
1122/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001123int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001124{
Harald Welte52b1f982008-12-23 20:25:15 +00001125 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001126 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001127
1128 /* Various consistency checks */
1129 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001130 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001131 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001132 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1133 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001134 }
1135 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001136 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001137 oh->sequence);
1138 return -EINVAL;
1139 }
Harald Welte702d8702008-12-26 20:25:35 +00001140#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001141 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +00001142 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001143 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001144 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001145 oh->length + sizeof(*oh), l2_len);
1146 return -EINVAL;
1147 }
Harald Welte702d8702008-12-26 20:25:35 +00001148 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001149 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 +00001150#endif
Harald Weltead384642008-12-26 10:20:07 +00001151 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001152
1153 switch (oh->mdisc) {
1154 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001155 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001156 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001157 case ABIS_OM_MDISC_MANUF:
1158 rc = abis_nm_rcvmsg_manuf(msg);
1159 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001160 case ABIS_OM_MDISC_MMI:
1161 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001162 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001163 oh->mdisc);
1164 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001165 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001166 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001167 oh->mdisc);
1168 return -EINVAL;
1169 }
1170
Harald Weltead384642008-12-26 10:20:07 +00001171 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001172 return rc;
1173}
1174
1175#if 0
1176/* initialized all resources */
1177struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1178{
1179 struct abis_nm_h *nmh;
1180
1181 nmh = malloc(sizeof(*nmh));
1182 if (!nmh)
1183 return NULL;
1184
1185 nmh->cfg = cfg;
1186
1187 return nmh;
1188}
1189
1190/* free all resources */
1191void abis_nm_fini(struct abis_nm_h *nmh)
1192{
1193 free(nmh);
1194}
1195#endif
1196
1197/* Here we are trying to define a high-level API that can be used by
1198 * the actual BSC implementation. However, the architecture is currently
1199 * still under design. Ideally the calls to this API would be synchronous,
1200 * while the underlying stack behind the APi runs in a traditional select
1201 * based state machine.
1202 */
1203
Harald Welte4724f992009-01-18 18:01:49 +00001204/* 6.2 Software Load: */
1205enum sw_state {
1206 SW_STATE_NONE,
1207 SW_STATE_WAIT_INITACK,
1208 SW_STATE_WAIT_SEGACK,
1209 SW_STATE_WAIT_ENDACK,
1210 SW_STATE_WAIT_ACTACK,
1211 SW_STATE_ERROR,
1212};
Harald Welte52b1f982008-12-23 20:25:15 +00001213
Harald Welte52b1f982008-12-23 20:25:15 +00001214struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001215 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001216 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001217 gsm_cbfn *cbfn;
1218 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001219 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001220
Harald Welte52b1f982008-12-23 20:25:15 +00001221 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001222 uint8_t obj_class;
1223 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001224
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001225 uint8_t file_id[255];
1226 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +00001227
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001228 uint8_t file_version[255];
1229 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001230
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001231 uint8_t window_size;
1232 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +00001233
1234 int fd;
1235 FILE *stream;
1236 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001237 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001238};
1239
Harald Welte4724f992009-01-18 18:01:49 +00001240static struct abis_nm_sw g_sw;
1241
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001242static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1243{
1244 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1245 msgb_v_put(msg, NM_ATT_SW_DESCR);
1246 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1247 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1248 sw->file_version);
1249 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1250 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1251 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1252 sw->file_version);
1253 } else {
1254 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1255 }
1256}
1257
Harald Welte4724f992009-01-18 18:01:49 +00001258/* 6.2.1 / 8.3.1: Load Data Initiate */
1259static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001260{
Harald Welte4724f992009-01-18 18:01:49 +00001261 struct abis_om_hdr *oh;
1262 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001263 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001264
1265 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1266 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1267 sw->obj_instance[0], sw->obj_instance[1],
1268 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001269
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001270 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001271 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1272
1273 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001274}
1275
Harald Welte1602ade2009-01-29 21:12:39 +00001276static int is_last_line(FILE *stream)
1277{
1278 char next_seg_buf[256];
1279 long pos;
1280
1281 /* check if we're sending the last line */
1282 pos = ftell(stream);
1283 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1284 fseek(stream, pos, SEEK_SET);
1285 return 1;
1286 }
1287
1288 fseek(stream, pos, SEEK_SET);
1289 return 0;
1290}
1291
Harald Welte4724f992009-01-18 18:01:49 +00001292/* 6.2.2 / 8.3.2 Load Data Segment */
1293static int sw_load_segment(struct abis_nm_sw *sw)
1294{
1295 struct abis_om_hdr *oh;
1296 struct msgb *msg = nm_msgb_alloc();
1297 char seg_buf[256];
1298 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001299 unsigned char *tlv;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001300 uint8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001301
1302 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001303
1304 switch (sw->bts->type) {
1305 case GSM_BTS_TYPE_BS11:
1306 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1307 perror("fgets reading segment");
1308 return -EINVAL;
1309 }
1310 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001311
1312 /* check if we're sending the last line */
1313 sw->last_seg = is_last_line(sw->stream);
1314 if (sw->last_seg)
1315 seg_buf[1] = 0;
1316 else
1317 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001318
1319 len = strlen(line_buf) + 2;
1320 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001321 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001322 /* BS11 wants CR + LF in excess of the TLV length !?! */
1323 tlv[1] -= 2;
1324
1325 /* we only now know the exact length for the OM hdr */
1326 len = strlen(line_buf)+2;
1327 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001328 case GSM_BTS_TYPE_NANOBTS: {
1329 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1330 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1331 if (len < 0) {
1332 perror("read failed");
1333 return -EINVAL;
1334 }
1335
1336 if (len != IPACC_SEGMENT_SIZE)
1337 sw->last_seg = 1;
1338
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001339 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001340 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001341 len += 3;
1342 break;
1343 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001344 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001345 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001346 /* FIXME: Other BTS types */
1347 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001348 }
Harald Welte4724f992009-01-18 18:01:49 +00001349
Harald Welte4724f992009-01-18 18:01:49 +00001350 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1351 sw->obj_instance[0], sw->obj_instance[1],
1352 sw->obj_instance[2]);
1353
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001354 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001355}
1356
1357/* 6.2.4 / 8.3.4 Load Data End */
1358static int sw_load_end(struct abis_nm_sw *sw)
1359{
1360 struct abis_om_hdr *oh;
1361 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001362 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001363
1364 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1365 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1366 sw->obj_instance[0], sw->obj_instance[1],
1367 sw->obj_instance[2]);
1368
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001369 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001370 return abis_nm_sendmsg(sw->bts, msg);
1371}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001372
Harald Welte52b1f982008-12-23 20:25:15 +00001373/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001374static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001375{
Harald Welte4724f992009-01-18 18:01:49 +00001376 struct abis_om_hdr *oh;
1377 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001378 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001379
Harald Welte4724f992009-01-18 18:01:49 +00001380 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1381 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1382 sw->obj_instance[0], sw->obj_instance[1],
1383 sw->obj_instance[2]);
1384
1385 /* FIXME: this is BS11 specific format */
1386 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1387 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1388 sw->file_version);
1389
1390 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001391}
Harald Welte4724f992009-01-18 18:01:49 +00001392
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001393struct sdp_firmware {
1394 char magic[4];
1395 char more_magic[4];
1396 unsigned int header_length;
1397 unsigned int file_length;
1398} __attribute__ ((packed));
1399
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001400static int parse_sdp_header(struct abis_nm_sw *sw)
1401{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001402 struct sdp_firmware firmware_header;
1403 int rc;
1404 struct stat stat;
1405
1406 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1407 if (rc != sizeof(firmware_header)) {
1408 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1409 return -1;
1410 }
1411
1412 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1413 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1414 return -1;
1415 }
1416
1417 if (firmware_header.more_magic[0] != 0x10 ||
1418 firmware_header.more_magic[1] != 0x02 ||
1419 firmware_header.more_magic[2] != 0x00 ||
1420 firmware_header.more_magic[3] != 0x00) {
1421 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1422 return -1;
1423 }
1424
1425
1426 if (fstat(sw->fd, &stat) == -1) {
1427 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1428 return -1;
1429 }
1430
1431 if (ntohl(firmware_header.file_length) != stat.st_size) {
1432 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1433 return -1;
1434 }
1435
1436 /* go back to the start as we checked the whole filesize.. */
1437 lseek(sw->fd, 0l, SEEK_SET);
1438 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1439 "There might be checksums in the file that are not\n"
1440 "verified and incomplete firmware might be flashed.\n"
1441 "There is absolutely no WARRANTY that flashing will\n"
1442 "work.\n");
1443 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001444}
1445
Harald Welte4724f992009-01-18 18:01:49 +00001446static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1447{
1448 char file_id[12+1];
1449 char file_version[80+1];
1450 int rc;
1451
1452 sw->fd = open(fname, O_RDONLY);
1453 if (sw->fd < 0)
1454 return sw->fd;
1455
1456 switch (sw->bts->type) {
1457 case GSM_BTS_TYPE_BS11:
1458 sw->stream = fdopen(sw->fd, "r");
1459 if (!sw->stream) {
1460 perror("fdopen");
1461 return -1;
1462 }
1463 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001464 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001465 file_id, file_version);
1466 if (rc != 2) {
1467 perror("parsing header line of software file");
1468 return -1;
1469 }
1470 strcpy((char *)sw->file_id, file_id);
1471 sw->file_id_len = strlen(file_id);
1472 strcpy((char *)sw->file_version, file_version);
1473 sw->file_version_len = strlen(file_version);
1474 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001475 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001476 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001477 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001478 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001479 rc = parse_sdp_header(sw);
1480 if (rc < 0) {
1481 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1482 return -1;
1483 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001484
1485 strcpy((char *)sw->file_id, "id");
1486 sw->file_id_len = 3;
1487 strcpy((char *)sw->file_version, "version");
1488 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001489 break;
Harald Welte4724f992009-01-18 18:01:49 +00001490 default:
1491 /* We don't know how to treat them yet */
1492 close(sw->fd);
1493 return -EINVAL;
1494 }
1495
1496 return 0;
1497}
1498
1499static void sw_close_file(struct abis_nm_sw *sw)
1500{
1501 switch (sw->bts->type) {
1502 case GSM_BTS_TYPE_BS11:
1503 fclose(sw->stream);
1504 break;
1505 default:
1506 close(sw->fd);
1507 break;
1508 }
1509}
1510
1511/* Fill the window */
1512static int sw_fill_window(struct abis_nm_sw *sw)
1513{
1514 int rc;
1515
1516 while (sw->seg_in_window < sw->window_size) {
1517 rc = sw_load_segment(sw);
1518 if (rc < 0)
1519 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001520 if (sw->last_seg)
1521 break;
Harald Welte4724f992009-01-18 18:01:49 +00001522 }
1523 return 0;
1524}
1525
1526/* callback function from abis_nm_rcvmsg() handler */
1527static int abis_nm_rcvmsg_sw(struct msgb *mb)
1528{
1529 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1530 int rc = -1;
1531 struct abis_nm_sw *sw = &g_sw;
1532 enum sw_state old_state = sw->state;
1533
Harald Welte3ffd1372009-02-01 22:15:49 +00001534 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001535
1536 switch (sw->state) {
1537 case SW_STATE_WAIT_INITACK:
1538 switch (foh->msg_type) {
1539 case NM_MT_LOAD_INIT_ACK:
1540 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001541 if (sw->cbfn)
1542 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1543 NM_MT_LOAD_INIT_ACK, mb,
1544 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001545 rc = sw_fill_window(sw);
1546 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001547 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001548 break;
1549 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001550 if (sw->forced) {
1551 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1552 "Init NACK\n");
1553 if (sw->cbfn)
1554 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1555 NM_MT_LOAD_INIT_ACK, mb,
1556 sw->cb_data, NULL);
1557 rc = sw_fill_window(sw);
1558 sw->state = SW_STATE_WAIT_SEGACK;
1559 } else {
1560 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001561 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001562 if (sw->cbfn)
1563 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1564 NM_MT_LOAD_INIT_NACK, mb,
1565 sw->cb_data, NULL);
1566 sw->state = SW_STATE_ERROR;
1567 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001568 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001569 break;
1570 }
1571 break;
1572 case SW_STATE_WAIT_SEGACK:
1573 switch (foh->msg_type) {
1574 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001575 if (sw->cbfn)
1576 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1577 NM_MT_LOAD_SEG_ACK, mb,
1578 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001579 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001580 if (!sw->last_seg) {
1581 /* fill window with more segments */
1582 rc = sw_fill_window(sw);
1583 sw->state = SW_STATE_WAIT_SEGACK;
1584 } else {
1585 /* end the transfer */
1586 sw->state = SW_STATE_WAIT_ENDACK;
1587 rc = sw_load_end(sw);
1588 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001589 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001590 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001591 case NM_MT_LOAD_ABORT:
1592 if (sw->cbfn)
1593 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1594 NM_MT_LOAD_ABORT, mb,
1595 sw->cb_data, NULL);
1596 break;
Harald Welte4724f992009-01-18 18:01:49 +00001597 }
1598 break;
1599 case SW_STATE_WAIT_ENDACK:
1600 switch (foh->msg_type) {
1601 case NM_MT_LOAD_END_ACK:
1602 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001603 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1604 sw->bts->nr);
1605 sw->state = SW_STATE_NONE;
1606 if (sw->cbfn)
1607 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1608 NM_MT_LOAD_END_ACK, mb,
1609 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001610 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001611 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001612 break;
1613 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001614 if (sw->forced) {
1615 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1616 "End NACK\n");
1617 sw->state = SW_STATE_NONE;
1618 if (sw->cbfn)
1619 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1620 NM_MT_LOAD_END_ACK, mb,
1621 sw->cb_data, NULL);
1622 } else {
1623 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001624 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001625 sw->state = SW_STATE_ERROR;
1626 if (sw->cbfn)
1627 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1628 NM_MT_LOAD_END_NACK, mb,
1629 sw->cb_data, NULL);
1630 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001631 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001632 break;
1633 }
1634 case SW_STATE_WAIT_ACTACK:
1635 switch (foh->msg_type) {
1636 case NM_MT_ACTIVATE_SW_ACK:
1637 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001638 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001639 sw->state = SW_STATE_NONE;
1640 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001641 if (sw->cbfn)
1642 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1643 NM_MT_ACTIVATE_SW_ACK, 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 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001648 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001649 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001650 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001651 if (sw->cbfn)
1652 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1653 NM_MT_ACTIVATE_SW_NACK, mb,
1654 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001655 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001656 break;
1657 }
1658 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001659 switch (foh->msg_type) {
1660 case NM_MT_ACTIVATE_SW_ACK:
1661 rc = 0;
1662 break;
1663 }
1664 break;
Harald Welte4724f992009-01-18 18:01:49 +00001665 case SW_STATE_ERROR:
1666 break;
1667 }
1668
1669 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001670 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001671 foh->msg_type, old_state, sw->state);
1672
1673 return rc;
1674}
1675
1676/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001677int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001678 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001679 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001680{
1681 struct abis_nm_sw *sw = &g_sw;
1682 int rc;
1683
Harald Welte5e4d1b32009-02-01 13:36:56 +00001684 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1685 bts->nr, fname);
1686
Harald Welte4724f992009-01-18 18:01:49 +00001687 if (sw->state != SW_STATE_NONE)
1688 return -EBUSY;
1689
1690 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001691 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001692
1693 switch (bts->type) {
1694 case GSM_BTS_TYPE_BS11:
1695 sw->obj_class = NM_OC_SITE_MANAGER;
1696 sw->obj_instance[0] = 0xff;
1697 sw->obj_instance[1] = 0xff;
1698 sw->obj_instance[2] = 0xff;
1699 break;
1700 case GSM_BTS_TYPE_NANOBTS:
1701 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001702 sw->obj_instance[0] = sw->bts->nr;
1703 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001704 sw->obj_instance[2] = 0xff;
1705 break;
1706 case GSM_BTS_TYPE_UNKNOWN:
1707 default:
1708 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1709 return -1;
1710 break;
1711 }
Harald Welte4724f992009-01-18 18:01:49 +00001712 sw->window_size = win_size;
1713 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001714 sw->cbfn = cbfn;
1715 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001716 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001717
1718 rc = sw_open_file(sw, fname);
1719 if (rc < 0) {
1720 sw->state = SW_STATE_NONE;
1721 return rc;
1722 }
1723
1724 return sw_load_init(sw);
1725}
Harald Welte52b1f982008-12-23 20:25:15 +00001726
Harald Welte1602ade2009-01-29 21:12:39 +00001727int abis_nm_software_load_status(struct gsm_bts *bts)
1728{
1729 struct abis_nm_sw *sw = &g_sw;
1730 struct stat st;
1731 int rc, percent;
1732
1733 rc = fstat(sw->fd, &st);
1734 if (rc < 0) {
1735 perror("ERROR during stat");
1736 return rc;
1737 }
1738
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001739 if (sw->stream)
1740 percent = (ftell(sw->stream) * 100) / st.st_size;
1741 else
1742 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001743 return percent;
1744}
1745
Harald Welte5e4d1b32009-02-01 13:36:56 +00001746/* Activate the specified software into the BTS */
1747int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1748 gsm_cbfn *cbfn, void *cb_data)
1749{
1750 struct abis_nm_sw *sw = &g_sw;
1751 int rc;
1752
1753 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1754 bts->nr, fname);
1755
1756 if (sw->state != SW_STATE_NONE)
1757 return -EBUSY;
1758
1759 sw->bts = bts;
1760 sw->obj_class = NM_OC_SITE_MANAGER;
1761 sw->obj_instance[0] = 0xff;
1762 sw->obj_instance[1] = 0xff;
1763 sw->obj_instance[2] = 0xff;
1764 sw->state = SW_STATE_WAIT_ACTACK;
1765 sw->cbfn = cbfn;
1766 sw->cb_data = cb_data;
1767
1768 /* Open the file in order to fill some sw struct members */
1769 rc = sw_open_file(sw, fname);
1770 if (rc < 0) {
1771 sw->state = SW_STATE_NONE;
1772 return rc;
1773 }
1774 sw_close_file(sw);
1775
1776 return sw_activate(sw);
1777}
1778
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001779static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1780 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001781{
Harald Welteadaf08b2009-01-18 11:08:10 +00001782 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001783 ch->bts_port = bts_port;
1784 ch->timeslot = ts_nr;
1785 ch->subslot = subslot_nr;
1786}
1787
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001788int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1789 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1790 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001791{
1792 struct abis_om_hdr *oh;
1793 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001794 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001795 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001796
1797 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1798 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1799 bts->bts_nr, trx_nr, 0xff);
1800
Harald Welte8470bf22008-12-25 23:28:35 +00001801 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001802
1803 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1804 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1805
1806 return abis_nm_sendmsg(bts, msg);
1807}
1808
1809/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1810int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001811 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001812{
Harald Welte8470bf22008-12-25 23:28:35 +00001813 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001814 struct abis_om_hdr *oh;
1815 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001816 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001817
1818 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001819 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001820 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1821
1822 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1823 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1824
1825 return abis_nm_sendmsg(bts, msg);
1826}
1827
1828#if 0
1829int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1830 struct abis_nm_abis_channel *chan)
1831{
1832}
1833#endif
1834
1835int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001836 uint8_t e1_port, uint8_t e1_timeslot,
1837 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001838{
1839 struct gsm_bts *bts = ts->trx->bts;
1840 struct abis_om_hdr *oh;
1841 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001842 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001843
1844 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1845 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001846 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001847
1848 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1849 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1850
Harald Weltef325eb42009-02-19 17:07:39 +00001851 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1852 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001853 e1_port, e1_timeslot, e1_subslot);
1854
Harald Welte52b1f982008-12-23 20:25:15 +00001855 return abis_nm_sendmsg(bts, msg);
1856}
1857
1858#if 0
1859int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1860 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001861 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001862{
1863}
1864#endif
1865
Harald Welte22af0db2009-02-14 15:41:08 +00001866/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001867int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001868{
1869 struct abis_om_hdr *oh;
1870 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001871 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001872
1873 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1874
1875 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001876 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 +00001877 cur = msgb_put(msg, attr_len);
1878 memcpy(cur, attr, attr_len);
1879
1880 return abis_nm_sendmsg(bts, msg);
1881}
1882
1883/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001884int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001885{
1886 struct abis_om_hdr *oh;
1887 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001888 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001889
1890 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1891
1892 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1893 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001894 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001895 cur = msgb_put(msg, attr_len);
1896 memcpy(cur, attr, attr_len);
1897
1898 return abis_nm_sendmsg(trx->bts, msg);
1899}
1900
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001901static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001902{
1903 int i;
1904
1905 /* As it turns out, the BS-11 has some very peculiar restrictions
1906 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301907 switch (ts->trx->bts->type) {
1908 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001909 switch (chan_comb) {
1910 case NM_CHANC_TCHHalf:
1911 case NM_CHANC_TCHHalf2:
1912 /* not supported */
1913 return -EINVAL;
1914 case NM_CHANC_SDCCH:
1915 /* only one SDCCH/8 per TRX */
1916 for (i = 0; i < TRX_NR_TS; i++) {
1917 if (i == ts->nr)
1918 continue;
1919 if (ts->trx->ts[i].nm_chan_comb ==
1920 NM_CHANC_SDCCH)
1921 return -EINVAL;
1922 }
1923 /* not allowed for TS0 of BCCH-TRX */
1924 if (ts->trx == ts->trx->bts->c0 &&
1925 ts->nr == 0)
1926 return -EINVAL;
1927 /* not on the same TRX that has a BCCH+SDCCH4
1928 * combination */
1929 if (ts->trx == ts->trx->bts->c0 &&
1930 (ts->trx->ts[0].nm_chan_comb == 5 ||
1931 ts->trx->ts[0].nm_chan_comb == 8))
1932 return -EINVAL;
1933 break;
1934 case NM_CHANC_mainBCCH:
1935 case NM_CHANC_BCCHComb:
1936 /* allowed only for TS0 of C0 */
1937 if (ts->trx != ts->trx->bts->c0 ||
1938 ts->nr != 0)
1939 return -EINVAL;
1940 break;
1941 case NM_CHANC_BCCH:
1942 /* allowed only for TS 2/4/6 of C0 */
1943 if (ts->trx != ts->trx->bts->c0)
1944 return -EINVAL;
1945 if (ts->nr != 2 && ts->nr != 4 &&
1946 ts->nr != 6)
1947 return -EINVAL;
1948 break;
1949 case 8: /* this is not like 08.58, but in fact
1950 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1951 /* FIXME: only one CBCH allowed per cell */
1952 break;
1953 }
Harald Welted6575f92009-12-02 02:45:23 +05301954 break;
1955 case GSM_BTS_TYPE_NANOBTS:
1956 switch (ts->nr) {
1957 case 0:
1958 if (ts->trx->nr == 0) {
1959 /* only on TRX0 */
1960 switch (chan_comb) {
1961 case NM_CHANC_BCCH:
1962 case NM_CHANC_mainBCCH:
1963 case NM_CHANC_BCCHComb:
1964 return 0;
1965 break;
1966 default:
1967 return -EINVAL;
1968 }
1969 } else {
1970 switch (chan_comb) {
1971 case NM_CHANC_TCHFull:
1972 case NM_CHANC_TCHHalf:
1973 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1974 return 0;
1975 default:
1976 return -EINVAL;
1977 }
1978 }
1979 break;
1980 case 1:
1981 if (ts->trx->nr == 0) {
1982 switch (chan_comb) {
1983 case NM_CHANC_SDCCH_CBCH:
1984 if (ts->trx->ts[0].nm_chan_comb ==
1985 NM_CHANC_mainBCCH)
1986 return 0;
1987 return -EINVAL;
1988 case NM_CHANC_SDCCH:
1989 case NM_CHANC_TCHFull:
1990 case NM_CHANC_TCHHalf:
1991 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1992 case NM_CHANC_IPAC_TCHFull_PDCH:
1993 return 0;
1994 }
1995 } else {
1996 switch (chan_comb) {
1997 case NM_CHANC_SDCCH:
1998 case NM_CHANC_TCHFull:
1999 case NM_CHANC_TCHHalf:
2000 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2001 return 0;
2002 default:
2003 return -EINVAL;
2004 }
2005 }
2006 break;
2007 case 2:
2008 case 3:
2009 case 4:
2010 case 5:
2011 case 6:
2012 case 7:
2013 switch (chan_comb) {
2014 case NM_CHANC_TCHFull:
2015 case NM_CHANC_TCHHalf:
2016 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2017 return 0;
2018 case NM_CHANC_IPAC_PDCH:
2019 case NM_CHANC_IPAC_TCHFull_PDCH:
2020 if (ts->trx->nr == 0)
2021 return 0;
2022 else
2023 return -EINVAL;
2024 }
2025 break;
2026 }
2027 return -EINVAL;
2028 default:
2029 /* unknown BTS type */
2030 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002031 }
2032 return 0;
2033}
2034
Harald Welte22af0db2009-02-14 15:41:08 +00002035/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002036int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00002037{
2038 struct gsm_bts *bts = ts->trx->bts;
2039 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002040 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002041 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002042 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00002043
2044 if (bts->type == GSM_BTS_TYPE_BS11)
2045 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002046
Harald Weltef325eb42009-02-19 17:07:39 +00002047 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002048 if (verify_chan_comb(ts, chan_comb) < 0) {
2049 msgb_free(msg);
2050 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2051 return -EINVAL;
2052 }
2053 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002054
Harald Welte52b1f982008-12-23 20:25:15 +00002055 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002056 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002057 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002058 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002059 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002060 if (ts->hopping.enabled) {
2061 unsigned int i;
2062 uint8_t *len;
2063
Harald Welte6e0cd042009-09-12 13:05:33 +02002064 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2065 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002066
2067 /* build the ARFCN list */
2068 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2069 len = msgb_put(msg, 1);
2070 *len = 0;
2071 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2072 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2073 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002074 /* At least BS-11 wants a TLV16 here */
2075 if (bts->type == GSM_BTS_TYPE_BS11)
2076 *len += 1;
2077 else
2078 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002079 }
2080 }
Harald Weltee0590df2009-02-15 03:34:15 +00002081 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002082 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002083 if (bts->type == GSM_BTS_TYPE_BS11)
2084 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002085
2086 return abis_nm_sendmsg(bts, msg);
2087}
2088
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002089int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
2090 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002091{
2092 struct abis_om_hdr *oh;
2093 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002094 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2095 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00002096
2097 if (nack) {
2098 len += 2;
2099 msgtype = NM_MT_SW_ACT_REQ_NACK;
2100 }
Harald Welte34a99682009-02-13 02:41:40 +00002101
2102 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002103 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2104
Harald Welte34a99682009-02-13 02:41:40 +00002105 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002106 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00002107 memcpy(ptr, attr, att_len);
2108 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002109 if (nack)
2110 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002111
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002112 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002113}
2114
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002115int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002116{
Harald Welte8470bf22008-12-25 23:28:35 +00002117 struct msgb *msg = nm_msgb_alloc();
2118 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002119 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00002120
2121 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2122 fill_om_hdr(oh, len);
2123 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002124 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
2129/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002130static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00002131{
2132 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002133 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002134
2135 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002136 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002137 0xff, 0xff, 0xff);
2138
2139 return abis_nm_sendmsg(bts, msg);
2140}
2141
Harald Welte34a99682009-02-13 02:41:40 +00002142/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002143int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Harald Welte34a99682009-02-13 02:41:40 +00002144{
2145 struct abis_om_hdr *oh;
2146 struct msgb *msg = nm_msgb_alloc();
2147
2148 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2149 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2150
Harald Weltea8bd6d42009-10-20 09:56:18 +02002151 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2152 DEBUGPC(DNM, "Sending OPSTART\n");
2153
Harald Welte34a99682009-02-13 02:41:40 +00002154 return abis_nm_sendmsg(bts, msg);
2155}
2156
2157/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002158int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
2159 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002160{
2161 struct abis_om_hdr *oh;
2162 struct msgb *msg = nm_msgb_alloc();
2163
2164 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2165 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2166 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2167
2168 return abis_nm_sendmsg(bts, msg);
2169}
2170
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002171int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
2172 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02002173{
2174 struct abis_om_hdr *oh;
2175 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002176 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02002177
2178 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2179 e1_port0, ts0, e1_port1, ts1);
2180
2181 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2182 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2183 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2184
2185 attr = msgb_put(msg, 3);
2186 attr[0] = NM_ATT_MDROP_LINK;
2187 attr[1] = e1_port0;
2188 attr[2] = ts0;
2189
2190 attr = msgb_put(msg, 3);
2191 attr[0] = NM_ATT_MDROP_NEXT;
2192 attr[1] = e1_port1;
2193 attr[2] = ts1;
2194
2195 return abis_nm_sendmsg(bts, msg);
2196}
Harald Welte34a99682009-02-13 02:41:40 +00002197
Harald Weltec7310382009-08-08 00:02:36 +02002198/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002199int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2200 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2201 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002202{
2203 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002204
Harald Welte4d54d0b2011-02-19 16:48:17 +01002205 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002206
2207 if (!msg)
2208 msg = nm_msgb_alloc();
2209
2210 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2211 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2212 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2213 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002214 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002215
2216 return abis_nm_sendmsg(bts, msg);
2217}
2218
Harald Welte52b1f982008-12-23 20:25:15 +00002219int abis_nm_event_reports(struct gsm_bts *bts, int on)
2220{
2221 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002222 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002223 else
Harald Welte227d4072009-01-03 08:16:25 +00002224 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002225}
2226
Harald Welte47d88ae2009-01-04 12:02:08 +00002227/* Siemens (or BS-11) specific commands */
2228
Harald Welte3ffd1372009-02-01 22:15:49 +00002229int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2230{
2231 if (reconnect == 0)
2232 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2233 else
2234 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2235}
2236
Harald Welteb8427972009-02-05 19:27:17 +00002237int abis_nm_bs11_restart(struct gsm_bts *bts)
2238{
2239 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2240}
2241
2242
Harald Welte268bb402009-02-01 19:11:56 +00002243struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002244 uint16_t year;
2245 uint8_t month;
2246 uint8_t day;
2247 uint8_t hour;
2248 uint8_t min;
2249 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002250} __attribute__((packed));
2251
2252
2253void get_bs11_date_time(struct bs11_date_time *aet)
2254{
2255 time_t t;
2256 struct tm *tm;
2257
2258 t = time(NULL);
2259 tm = localtime(&t);
2260 aet->sec = tm->tm_sec;
2261 aet->min = tm->tm_min;
2262 aet->hour = tm->tm_hour;
2263 aet->day = tm->tm_mday;
2264 aet->month = tm->tm_mon;
2265 aet->year = htons(1900 + tm->tm_year);
2266}
2267
Harald Welte05188ee2009-01-18 11:39:08 +00002268int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002269{
Harald Welte4668fda2009-01-03 08:19:29 +00002270 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002271}
2272
Harald Welte05188ee2009-01-18 11:39:08 +00002273int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002274{
2275 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002276 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002277 else
Harald Welte4668fda2009-01-03 08:19:29 +00002278 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002279}
Harald Welte47d88ae2009-01-04 12:02:08 +00002280
Harald Welte05188ee2009-01-18 11:39:08 +00002281int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002282 enum abis_bs11_objtype type, uint8_t idx,
2283 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002284{
2285 struct abis_om_hdr *oh;
2286 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002287 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002288
2289 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002290 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002291 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002292 cur = msgb_put(msg, attr_len);
2293 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002294
2295 return abis_nm_sendmsg(bts, msg);
2296}
2297
Harald Welte78fc0d42009-02-19 02:50:57 +00002298int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002299 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002300{
2301 struct abis_om_hdr *oh;
2302 struct msgb *msg = nm_msgb_alloc();
2303
2304 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2305 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2306 NM_OC_BS11, type, 0, idx);
2307
2308 return abis_nm_sendmsg(bts, msg);
2309}
2310
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002311int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002312{
2313 struct abis_om_hdr *oh;
2314 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002315 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002316
2317 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002318 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002319 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2320 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002321
2322 return abis_nm_sendmsg(bts, msg);
2323}
2324
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002325int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002326{
2327 struct abis_om_hdr *oh;
2328 struct msgb *msg = nm_msgb_alloc();
2329
2330 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2331 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002332 idx, 0xff, 0xff);
2333
2334 return abis_nm_sendmsg(bts, msg);
2335}
2336
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002337int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002338{
2339 struct abis_om_hdr *oh;
2340 struct msgb *msg = nm_msgb_alloc();
2341
2342 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2343 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2344 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002345
2346 return abis_nm_sendmsg(bts, msg);
2347}
Harald Welte05188ee2009-01-18 11:39:08 +00002348
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002349static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002350int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2351{
2352 struct abis_om_hdr *oh;
2353 struct msgb *msg = nm_msgb_alloc();
2354
2355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2356 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2357 0xff, 0xff, 0xff);
2358 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2359
2360 return abis_nm_sendmsg(bts, msg);
2361}
2362
Harald Welteb6c92ae2009-02-21 20:15:32 +00002363/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002364int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2365 uint8_t e1_timeslot, uint8_t e1_subslot,
2366 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002367{
2368 struct abis_om_hdr *oh;
2369 struct abis_nm_channel *ch;
2370 struct msgb *msg = nm_msgb_alloc();
2371
2372 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002373 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002374 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2375
2376 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2377 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002378 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002379
2380 return abis_nm_sendmsg(bts, msg);
2381}
2382
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002383int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002384{
2385 struct abis_om_hdr *oh;
2386 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002387
2388 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002389 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002390 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2391 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2392
2393 return abis_nm_sendmsg(trx->bts, msg);
2394}
2395
Harald Welte78fc0d42009-02-19 02:50:57 +00002396int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2397{
2398 struct abis_om_hdr *oh;
2399 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002400 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002401
2402 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2403 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2404 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2405 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2406
2407 return abis_nm_sendmsg(trx->bts, msg);
2408}
2409
Harald Welteaaf02d92009-04-29 13:25:57 +00002410int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2411{
2412 struct abis_om_hdr *oh;
2413 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002414 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002415
2416 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2417 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2418 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002419 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002420
2421 return abis_nm_sendmsg(bts, msg);
2422}
2423
Harald Welteef061952009-05-17 12:43:42 +00002424int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2425{
2426 struct abis_om_hdr *oh;
2427 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002428 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002429 NM_ATT_BS11_CCLK_TYPE };
2430
2431 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2432 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2433 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2434 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2435
2436 return abis_nm_sendmsg(bts, msg);
2437
2438}
Harald Welteaaf02d92009-04-29 13:25:57 +00002439
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002440//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002441
Harald Welte1bc09062009-01-18 14:17:52 +00002442int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002443{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002444 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2445}
2446
Daniel Willmann4b054c82010-01-07 00:46:26 +01002447int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2448{
2449 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2450}
2451
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002452int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002453{
Harald Welte05188ee2009-01-18 11:39:08 +00002454 struct abis_om_hdr *oh;
2455 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002456 struct bs11_date_time bdt;
2457
2458 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002459
2460 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002461 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002462 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002463 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002464 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002465 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002466 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002467 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002468 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002469 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002470 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002471 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002472 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002473 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002474 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002475 }
Harald Welte05188ee2009-01-18 11:39:08 +00002476
2477 return abis_nm_sendmsg(bts, msg);
2478}
Harald Welte1bc09062009-01-18 14:17:52 +00002479
2480int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2481{
2482 struct abis_om_hdr *oh;
2483 struct msgb *msg;
2484
2485 if (strlen(password) != 10)
2486 return -EINVAL;
2487
2488 msg = nm_msgb_alloc();
2489 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002490 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002491 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002492 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002493
2494 return abis_nm_sendmsg(bts, msg);
2495}
2496
Harald Weltee69f5fb2009-04-28 16:31:38 +00002497/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2498int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2499{
2500 struct abis_om_hdr *oh;
2501 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002502 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002503
2504 msg = nm_msgb_alloc();
2505 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2506 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2507 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002508
2509 if (locked)
2510 tlv_value = BS11_LI_PLL_LOCKED;
2511 else
2512 tlv_value = BS11_LI_PLL_STANDALONE;
2513
2514 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002515
2516 return abis_nm_sendmsg(bts, msg);
2517}
2518
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002519/* Set the calibration value of the PLL (work value/set value)
2520 * It depends on the login which one is changed */
2521int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2522{
2523 struct abis_om_hdr *oh;
2524 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002525 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002526
2527 msg = nm_msgb_alloc();
2528 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2529 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2530 BS11_OBJ_TRX1, 0x00, 0x00);
2531
2532 tlv_value[0] = value>>8;
2533 tlv_value[1] = value&0xff;
2534
2535 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2536
2537 return abis_nm_sendmsg(bts, msg);
2538}
2539
Harald Welte1bc09062009-01-18 14:17:52 +00002540int abis_nm_bs11_get_state(struct gsm_bts *bts)
2541{
2542 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2543}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002544
2545/* BS11 SWL */
2546
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002547void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002548
Harald Welte5e4d1b32009-02-01 13:36:56 +00002549struct abis_nm_bs11_sw {
2550 struct gsm_bts *bts;
2551 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002552 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002553 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002554 struct llist_head file_list;
2555 gsm_cbfn *user_cb; /* specified by the user */
2556};
2557static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2558
2559struct file_list_entry {
2560 struct llist_head list;
2561 char fname[PATH_MAX];
2562};
2563
2564struct file_list_entry *fl_dequeue(struct llist_head *queue)
2565{
2566 struct llist_head *lh;
2567
2568 if (llist_empty(queue))
2569 return NULL;
2570
2571 lh = queue->next;
2572 llist_del(lh);
2573
2574 return llist_entry(lh, struct file_list_entry, list);
2575}
2576
2577static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2578{
2579 char linebuf[255];
2580 struct llist_head *lh, *lh2;
2581 FILE *swl;
2582 int rc = 0;
2583
2584 swl = fopen(bs11_sw->swl_fname, "r");
2585 if (!swl)
2586 return -ENODEV;
2587
2588 /* zero the stale file list, if any */
2589 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2590 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002591 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002592 }
2593
2594 while (fgets(linebuf, sizeof(linebuf), swl)) {
2595 char file_id[12+1];
2596 char file_version[80+1];
2597 struct file_list_entry *fle;
2598 static char dir[PATH_MAX];
2599
2600 if (strlen(linebuf) < 4)
2601 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002602
Harald Welte5e4d1b32009-02-01 13:36:56 +00002603 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2604 if (rc < 0) {
2605 perror("ERR parsing SWL file");
2606 rc = -EINVAL;
2607 goto out;
2608 }
2609 if (rc < 2)
2610 continue;
2611
Harald Welte470ec292009-06-26 20:25:23 +02002612 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002613 if (!fle) {
2614 rc = -ENOMEM;
2615 goto out;
2616 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002617
2618 /* construct new filename */
2619 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2620 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2621 strcat(fle->fname, "/");
2622 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002623
2624 llist_add_tail(&fle->list, &bs11_sw->file_list);
2625 }
2626
2627out:
2628 fclose(swl);
2629 return rc;
2630}
2631
2632/* bs11 swload specific callback, passed to abis_nm core swload */
2633static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2634 struct msgb *msg, void *data, void *param)
2635{
2636 struct abis_nm_bs11_sw *bs11_sw = data;
2637 struct file_list_entry *fle;
2638 int rc = 0;
2639
Harald Welte5e4d1b32009-02-01 13:36:56 +00002640 switch (event) {
2641 case NM_MT_LOAD_END_ACK:
2642 fle = fl_dequeue(&bs11_sw->file_list);
2643 if (fle) {
2644 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002645 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002646 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002647 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002648 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002649 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002650 } else {
2651 /* activate the SWL */
2652 rc = abis_nm_software_activate(bs11_sw->bts,
2653 bs11_sw->swl_fname,
2654 bs11_swload_cbfn,
2655 bs11_sw);
2656 }
2657 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002658 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002659 case NM_MT_LOAD_END_NACK:
2660 case NM_MT_LOAD_INIT_ACK:
2661 case NM_MT_LOAD_INIT_NACK:
2662 case NM_MT_ACTIVATE_SW_NACK:
2663 case NM_MT_ACTIVATE_SW_ACK:
2664 default:
2665 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002666 if (bs11_sw->user_cb)
2667 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002668 break;
2669 }
2670
2671 return rc;
2672}
2673
2674/* Siemens provides a SWL file that is a mere listing of all the other
2675 * files that are part of a software release. We need to upload first
2676 * the list file, and then each file that is listed in the list file */
2677int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002678 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002679{
2680 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2681 struct file_list_entry *fle;
2682 int rc = 0;
2683
2684 INIT_LLIST_HEAD(&bs11_sw->file_list);
2685 bs11_sw->bts = bts;
2686 bs11_sw->win_size = win_size;
2687 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002688 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002689
2690 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2691 rc = bs11_read_swl_file(bs11_sw);
2692 if (rc < 0)
2693 return rc;
2694
2695 /* dequeue next item in file list */
2696 fle = fl_dequeue(&bs11_sw->file_list);
2697 if (!fle)
2698 return -EINVAL;
2699
2700 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002701 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002702 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002703 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002704 return rc;
2705}
2706
Harald Welte5083b0b2009-02-02 19:20:52 +00002707#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002708static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002709 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2710 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2711 NM_ATT_BS11_LMT_USER_NAME,
2712
2713 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2714
2715 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2716
2717 NM_ATT_BS11_SW_LOAD_STORED };
2718
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002719static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002720 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2721 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2722 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2723 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002724#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002725
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002726static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002727 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2728 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002729 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002730
2731int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2732{
2733 struct abis_om_hdr *oh;
2734 struct msgb *msg = nm_msgb_alloc();
2735
2736 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2737 /* SiemensHW CCTRL object */
2738 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2739 0x03, 0x00, 0x00);
2740 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2741
2742 return abis_nm_sendmsg(bts, msg);
2743}
Harald Welte268bb402009-02-01 19:11:56 +00002744
2745int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2746{
2747 struct abis_om_hdr *oh;
2748 struct msgb *msg = nm_msgb_alloc();
2749 struct bs11_date_time aet;
2750
2751 get_bs11_date_time(&aet);
2752 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2753 /* SiemensHW CCTRL object */
2754 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2755 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002756 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002757
2758 return abis_nm_sendmsg(bts, msg);
2759}
Harald Welte5c1e4582009-02-15 11:57:29 +00002760
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002761int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002762{
2763 struct abis_om_hdr *oh;
2764 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002765 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002766
2767 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2768 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2769 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2770 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2771
2772 return abis_nm_sendmsg(bts, msg);
2773}
2774
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002775int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002776{
2777 struct abis_om_hdr *oh;
2778 struct msgb *msg = nm_msgb_alloc();
2779 struct bs11_date_time aet;
2780
2781 get_bs11_date_time(&aet);
2782 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2783 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2784 bport, 0xff, 0x02);
2785 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2786
2787 return abis_nm_sendmsg(bts, msg);
2788}
2789
Harald Welte5c1e4582009-02-15 11:57:29 +00002790/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002791static const char ipaccess_magic[] = "com.ipaccess";
2792
Harald Welte677c21f2009-02-17 13:22:23 +00002793
2794static int abis_nm_rx_ipacc(struct msgb *msg)
2795{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002796 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002797 struct abis_om_hdr *oh = msgb_l2(msg);
2798 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002799 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002800 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002801 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002802
2803 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002804 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002805 return -EINVAL;
2806 }
2807
Harald Welte193fefc2009-04-30 15:16:27 +00002808 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002809 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002810
Harald Weltea8bd6d42009-10-20 09:56:18 +02002811 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002812
Harald Welte746d6092009-10-19 22:11:11 +02002813 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002814
Harald Welte677c21f2009-02-17 13:22:23 +00002815 switch (foh->msg_type) {
2816 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002817 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002818 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2819 memcpy(&addr,
2820 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2821
2822 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2823 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002824 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002825 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002826 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002827 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002828 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2829 DEBUGPC(DNM, "STREAM=0x%02x ",
2830 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002831 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002832 break;
2833 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002834 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002835 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002836 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002837 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002838 else
2839 DEBUGPC(DNM, "\n");
2840 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002841 case NM_MT_IPACC_SET_NVATTR_ACK:
2842 DEBUGPC(DNM, "SET NVATTR ACK\n");
2843 /* FIXME: decode and show the actual attributes */
2844 break;
2845 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002846 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002847 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002848 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002849 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2850 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002851 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002852 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002853 case NM_MT_IPACC_GET_NVATTR_ACK:
2854 DEBUGPC(DNM, "GET NVATTR ACK\n");
2855 /* FIXME: decode and show the actual attributes */
2856 break;
2857 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002858 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002859 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002860 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002861 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2862 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002863 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002864 break;
Harald Welte15c44172009-10-08 20:15:24 +02002865 case NM_MT_IPACC_SET_ATTR_ACK:
2866 DEBUGPC(DNM, "SET ATTR ACK\n");
2867 break;
2868 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002869 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002870 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002871 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002872 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2873 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002874 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002875 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002876 default:
2877 DEBUGPC(DNM, "unknown\n");
2878 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002879 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002880
2881 /* signal handling */
2882 switch (foh->msg_type) {
2883 case NM_MT_IPACC_RSL_CONNECT_NACK:
2884 case NM_MT_IPACC_SET_NVATTR_NACK:
2885 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002886 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002887 signal.msg_type = foh->msg_type;
2888 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002889 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002890 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002891 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002892 signal.msg_type = foh->msg_type;
2893 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002894 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002895 default:
2896 break;
2897 }
2898
Harald Welte677c21f2009-02-17 13:22:23 +00002899 return 0;
2900}
2901
Harald Welte193fefc2009-04-30 15:16:27 +00002902/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002903int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2904 uint8_t obj_class, uint8_t bts_nr,
2905 uint8_t trx_nr, uint8_t ts_nr,
2906 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002907{
2908 struct msgb *msg = nm_msgb_alloc();
2909 struct abis_om_hdr *oh;
2910 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002911 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002912
2913 /* construct the 12.21 OM header, observe the erroneous length */
2914 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2915 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2916 oh->mdisc = ABIS_OM_MDISC_MANUF;
2917
2918 /* add the ip.access magic */
2919 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2920 *data++ = sizeof(ipaccess_magic);
2921 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2922
2923 /* fill the 12.21 FOM header */
2924 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2925 foh->msg_type = msg_type;
2926 foh->obj_class = obj_class;
2927 foh->obj_inst.bts_nr = bts_nr;
2928 foh->obj_inst.trx_nr = trx_nr;
2929 foh->obj_inst.ts_nr = ts_nr;
2930
2931 if (attr && attr_len) {
2932 data = msgb_put(msg, attr_len);
2933 memcpy(data, attr, attr_len);
2934 }
2935
2936 return abis_nm_sendmsg(bts, msg);
2937}
Harald Welte677c21f2009-02-17 13:22:23 +00002938
Harald Welte193fefc2009-04-30 15:16:27 +00002939/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002940int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002941 int attr_len)
2942{
Harald Welte2ef156d2010-01-07 20:39:42 +01002943 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2944 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002945 attr_len);
2946}
2947
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002948int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002949 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002950{
2951 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002952 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002953 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2954 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2955
2956 int attr_len = sizeof(attr);
2957
2958 ia.s_addr = htonl(ip);
2959 attr[1] = stream;
2960 attr[3] = port >> 8;
2961 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002962 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002963
2964 /* if ip == 0, we use the default IP */
2965 if (ip == 0)
2966 attr_len -= 5;
2967
2968 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002969 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002970
2971 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2972 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2973 trx->nr, 0xff, attr, attr_len);
2974}
2975
Harald Welte193fefc2009-04-30 15:16:27 +00002976/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002977int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002978{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002979 struct abis_om_hdr *oh;
2980 struct msgb *msg = nm_msgb_alloc();
2981
2982 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2983 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2984 trx->bts->nr, trx->nr, 0xff);
2985
2986 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002987}
Harald Weltedaef5212009-10-24 10:20:41 +02002988
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002989int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2990 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2991 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002992{
2993 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2994 obj_class, bts_nr, trx_nr, ts_nr,
2995 attr, attr_len);
2996}
Harald Welte0f255852009-11-12 14:48:42 +01002997
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002998void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002999{
3000 /* we simply reuse the GSM48 function and overwrite the RAC
3001 * with the Cell ID */
3002 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003003 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08003004}
3005
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003006void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
3007{
3008 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
3009
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01003010 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003011 if (!trx->bts || !trx->bts->oml_link)
3012 return;
3013
3014 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3015 trx->bts->bts_nr, trx->nr, 0xff,
3016 new_state);
3017}
3018
Harald Welte92b1fe42010-03-25 11:45:30 +08003019static const struct value_string ipacc_testres_names[] = {
3020 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3021 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3022 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3023 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3024 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3025 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01003026};
3027
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003028const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01003029{
Harald Welte92b1fe42010-03-25 11:45:30 +08003030 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003031}
3032
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003033void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01003034{
3035 cid->mcc = (buf[0] & 0xf) * 100;
3036 cid->mcc += (buf[0] >> 4) * 10;
3037 cid->mcc += (buf[1] & 0xf) * 1;
3038
3039 if (buf[1] >> 4 == 0xf) {
3040 cid->mnc = (buf[2] & 0xf) * 10;
3041 cid->mnc += (buf[2] >> 4) * 1;
3042 } else {
3043 cid->mnc = (buf[2] & 0xf) * 100;
3044 cid->mnc += (buf[2] >> 4) * 10;
3045 cid->mnc += (buf[1] >> 4) * 1;
3046 }
3047
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003048 cid->lac = ntohs(*((uint16_t *)&buf[3]));
3049 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003050}
3051
Harald Welte0f255852009-11-12 14:48:42 +01003052/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003053int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01003054{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003055 uint8_t *cur = buf;
3056 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01003057
Harald Welteaf109b92010-07-22 18:14:36 +02003058 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003059
3060 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3061 return -EINVAL;
3062 cur++;
3063
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003064 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003065 cur += 2;
3066
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003067 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003068 cur += 2;
3069
3070 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3071 binf->freq_qual = *cur >> 2;
3072
Harald Welteaf109b92010-07-22 18:14:36 +02003073 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003074 binf->arfcn |= *cur++;
3075
3076 if (binf->info_type & IPAC_BINF_RXLEV)
3077 binf->rx_lev = *cur & 0x3f;
3078 cur++;
3079
3080 if (binf->info_type & IPAC_BINF_RXQUAL)
3081 binf->rx_qual = *cur & 0x7;
3082 cur++;
3083
3084 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003085 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003086 cur += 2;
3087
3088 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003089 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003090 cur += 2;
3091
3092 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003093 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003094 cur += 4;
3095
Harald Weltea780a3d2010-07-30 22:34:42 +02003096#if 0
3097 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003098 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003099#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003100 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003101 cur++;
3102
Harald Welteb40a38f2009-11-13 11:56:05 +01003103 ipac_parse_cgi(&binf->cgi, cur);
3104 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003105
3106 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3107 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3108 cur += sizeof(binf->ba_list_si2);
3109 }
3110
3111 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3112 memcpy(binf->ba_list_si2bis, cur,
3113 sizeof(binf->ba_list_si2bis));
3114 cur += sizeof(binf->ba_list_si2bis);
3115 }
3116
3117 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3118 memcpy(binf->ba_list_si2ter, cur,
3119 sizeof(binf->ba_list_si2ter));
3120 cur += sizeof(binf->ba_list_si2ter);
3121 }
3122
3123 return 0;
3124}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003125
3126void abis_nm_clear_queue(struct gsm_bts *bts)
3127{
3128 struct msgb *msg;
3129
3130 while (!llist_empty(&bts->abis_queue)) {
3131 msg = msgb_dequeue(&bts->abis_queue);
3132 msgb_free(msg);
3133 }
3134
3135 bts->abis_nm_pend = 0;
3136}