blob: 0d122c697f513b7918a9ba29534fcc35a0651169 [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 Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
41#include <osmocom/core/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000042#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000043#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000044#include <openbsc/signal.h>
Harald Welte52b1f982008-12-23 20:25:15 +000045
Harald Welte8470bf22008-12-25 23:28:35 +000046#define OM_ALLOC_SIZE 1024
47#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010048#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000049
50/* unidirectional messages from BTS to BSC */
51static const enum abis_nm_msgtype reports[] = {
52 NM_MT_SW_ACTIVATED_REP,
53 NM_MT_TEST_REP,
54 NM_MT_STATECHG_EVENT_REP,
55 NM_MT_FAILURE_EVENT_REP,
56};
57
58/* messages without ACK/NACK */
59static const enum abis_nm_msgtype no_ack_nack[] = {
60 NM_MT_MEAS_RES_REQ,
61 NM_MT_STOP_MEAS,
62 NM_MT_START_MEAS,
63};
64
Harald Welte4724f992009-01-18 18:01:49 +000065/* Messages related to software load */
66static const enum abis_nm_msgtype sw_load_msgs[] = {
67 NM_MT_LOAD_INIT_ACK,
68 NM_MT_LOAD_INIT_NACK,
69 NM_MT_LOAD_SEG_ACK,
70 NM_MT_LOAD_ABORT,
71 NM_MT_LOAD_END_ACK,
72 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000073 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000074 NM_MT_ACTIVATE_SW_ACK,
75 NM_MT_ACTIVATE_SW_NACK,
76 NM_MT_SW_ACTIVATED_REP,
77};
78
Harald Weltee0590df2009-02-15 03:34:15 +000079static const enum abis_nm_msgtype nacks[] = {
80 NM_MT_LOAD_INIT_NACK,
81 NM_MT_LOAD_END_NACK,
82 NM_MT_SW_ACT_REQ_NACK,
83 NM_MT_ACTIVATE_SW_NACK,
84 NM_MT_ESTABLISH_TEI_NACK,
85 NM_MT_CONN_TERR_SIGN_NACK,
86 NM_MT_DISC_TERR_SIGN_NACK,
87 NM_MT_CONN_TERR_TRAF_NACK,
88 NM_MT_DISC_TERR_TRAF_NACK,
89 NM_MT_CONN_MDROP_LINK_NACK,
90 NM_MT_DISC_MDROP_LINK_NACK,
91 NM_MT_SET_BTS_ATTR_NACK,
92 NM_MT_SET_RADIO_ATTR_NACK,
93 NM_MT_SET_CHAN_ATTR_NACK,
94 NM_MT_PERF_TEST_NACK,
95 NM_MT_SEND_TEST_REP_NACK,
96 NM_MT_STOP_TEST_NACK,
97 NM_MT_STOP_EVENT_REP_NACK,
98 NM_MT_REST_EVENT_REP_NACK,
99 NM_MT_CHG_ADM_STATE_NACK,
100 NM_MT_CHG_ADM_STATE_REQ_NACK,
101 NM_MT_REP_OUTST_ALARMS_NACK,
102 NM_MT_CHANGEOVER_NACK,
103 NM_MT_OPSTART_NACK,
104 NM_MT_REINIT_NACK,
105 NM_MT_SET_SITE_OUT_NACK,
106 NM_MT_CHG_HW_CONF_NACK,
107 NM_MT_GET_ATTR_NACK,
108 NM_MT_SET_ALARM_THRES_NACK,
109 NM_MT_BS11_BEGIN_DB_TX_NACK,
110 NM_MT_BS11_END_DB_TX_NACK,
111 NM_MT_BS11_CREATE_OBJ_NACK,
112 NM_MT_BS11_DELETE_OBJ_NACK,
113};
Harald Welte78fc0d42009-02-19 02:50:57 +0000114
Harald Welte92b1fe42010-03-25 11:45:30 +0800115static const struct value_string nack_names[] = {
116 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
117 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
118 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
119 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
120 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
121 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
122 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
123 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
124 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
125 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
126 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
127 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
128 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
129 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
130 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
131 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
132 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
133 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
134 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
135 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
136 { NM_MT_CHG_ADM_STATE_REQ_NACK,
137 "CHANGE ADMINISTRATIVE STATE REQUEST" },
138 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
139 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
140 { NM_MT_OPSTART_NACK, "OPSTART" },
141 { NM_MT_REINIT_NACK, "REINIT" },
142 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
143 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
144 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
145 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
146 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
147 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
148 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
149 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
150 { 0, NULL }
Harald Welte78fc0d42009-02-19 02:50:57 +0000151};
152
Harald Welte6c96ba52009-05-01 13:03:40 +0000153/* Chapter 9.4.36 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800154static const struct value_string nack_cause_names[] = {
Harald Welte6c96ba52009-05-01 13:03:40 +0000155 /* General Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800156 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
157 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
158 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
159 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
160 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
161 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
162 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
163 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
164 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
165 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
166 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
167 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
168 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte6c96ba52009-05-01 13:03:40 +0000169 /* Specific Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800170 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
171 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
172 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
173 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
174 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
175 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
176 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
177 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
178 { NM_NACK_TEST_NOSUCH, "No such test" },
179 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
180 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
181 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
182 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
183 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
184 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
185 { NM_NACK_WAIT, "Wait" },
186 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
187 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
188 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
189 { 0, NULL }
Harald Welte6c96ba52009-05-01 13:03:40 +0000190};
191
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200192static const char *nack_cause_name(uint8_t cause)
Harald Welte6c96ba52009-05-01 13:03:40 +0000193{
Harald Welte92b1fe42010-03-25 11:45:30 +0800194 return get_value_string(nack_cause_names, cause);
Harald Welte6c96ba52009-05-01 13:03:40 +0000195}
196
Harald Welte0db97b22009-05-01 17:22:47 +0000197/* Chapter 9.4.16: Event Type */
Harald Welte92b1fe42010-03-25 11:45:30 +0800198static const struct value_string event_type_names[] = {
199 { NM_EVT_COMM_FAIL, "communication failure" },
200 { NM_EVT_QOS_FAIL, "quality of service failure" },
201 { NM_EVT_PROC_FAIL, "processing failure" },
202 { NM_EVT_EQUIP_FAIL, "equipment failure" },
203 { NM_EVT_ENV_FAIL, "environment failure" },
204 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000205};
206
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200207static const char *event_type_name(uint8_t cause)
Harald Welte0db97b22009-05-01 17:22:47 +0000208{
Harald Welte92b1fe42010-03-25 11:45:30 +0800209 return get_value_string(event_type_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000210}
211
212/* Chapter 9.4.63: Perceived Severity */
Harald Welte92b1fe42010-03-25 11:45:30 +0800213static const struct value_string severity_names[] = {
214 { NM_SEVER_CEASED, "failure ceased" },
215 { NM_SEVER_CRITICAL, "critical failure" },
216 { NM_SEVER_MAJOR, "major failure" },
217 { NM_SEVER_MINOR, "minor failure" },
218 { NM_SEVER_WARNING, "warning level failure" },
219 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
220 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000221};
222
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200223static const char *severity_name(uint8_t cause)
Harald Welte0db97b22009-05-01 17:22:47 +0000224{
Harald Welte92b1fe42010-03-25 11:45:30 +0800225 return get_value_string(severity_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000226}
227
Harald Welte52b1f982008-12-23 20:25:15 +0000228/* Attributes that the BSC can set, not only get, according to Section 9.4 */
229static const enum abis_nm_attr nm_att_settable[] = {
230 NM_ATT_ADD_INFO,
231 NM_ATT_ADD_TEXT,
232 NM_ATT_DEST,
233 NM_ATT_EVENT_TYPE,
234 NM_ATT_FILE_DATA,
235 NM_ATT_GET_ARI,
236 NM_ATT_HW_CONF_CHG,
237 NM_ATT_LIST_REQ_ATTR,
238 NM_ATT_MDROP_LINK,
239 NM_ATT_MDROP_NEXT,
240 NM_ATT_NACK_CAUSES,
241 NM_ATT_OUTST_ALARM,
242 NM_ATT_PHYS_CONF,
243 NM_ATT_PROB_CAUSE,
244 NM_ATT_RAD_SUBC,
245 NM_ATT_SOURCE,
246 NM_ATT_SPEC_PROB,
247 NM_ATT_START_TIME,
248 NM_ATT_TEST_DUR,
249 NM_ATT_TEST_NO,
250 NM_ATT_TEST_REPORT,
251 NM_ATT_WINDOW_SIZE,
252 NM_ATT_SEVERITY,
253 NM_ATT_MEAS_RES,
254 NM_ATT_MEAS_TYPE,
255};
256
Harald Welte39315c42010-01-10 18:01:52 +0100257const struct tlv_definition nm_att_tlvdef = {
Harald Weltee0590df2009-02-15 03:34:15 +0000258 .def = {
259 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
260 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
261 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
262 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
263 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
264 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
265 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
266 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
267 [NM_ATT_BSIC] = { TLV_TYPE_TV },
268 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
269 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
270 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
271 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
272 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
273 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
274 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
275 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
276 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
277 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
278 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
279 [NM_ATT_HSN] = { TLV_TYPE_TV },
280 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
281 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
282 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
283 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
284 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
285 [NM_ATT_MAIO] = { TLV_TYPE_TV },
286 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
287 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
288 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
289 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
290 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
291 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
292 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
293 [NM_ATT_NY1] = { TLV_TYPE_TV },
294 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
295 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
296 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
297 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
298 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
299 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
300 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
301 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
302 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
303 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
304 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
305 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
306 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
307 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
308 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
309 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
310 [NM_ATT_TEI] = { TLV_TYPE_TV },
311 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
312 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
313 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
314 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
315 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
316 [NM_ATT_TSC] = { TLV_TYPE_TV },
317 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
318 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
319 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
320 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
321 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000322 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Weltee0590df2009-02-15 03:34:15 +0000323 },
324};
Harald Welte03133942009-02-18 19:51:53 +0000325
Harald Welte21bd3a52009-08-10 12:21:22 +0200326static const enum abis_nm_chan_comb chcomb4pchan[] = {
327 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
328 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
329 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
330 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
331 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200332 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
333 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200334 /* FIXME: bounds check */
335};
336
337int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
338{
339 if (pchan < ARRAY_SIZE(chcomb4pchan))
340 return chcomb4pchan[pchan];
341
342 return -EINVAL;
343}
344
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200345int 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 +0000346{
Harald Welte39315c42010-01-10 18:01:52 +0100347 if (!bts->model)
348 return -EIO;
349 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000350}
Harald Weltee0590df2009-02-15 03:34:15 +0000351
Harald Welte52b1f982008-12-23 20:25:15 +0000352static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
353{
354 int i;
355
356 for (i = 0; i < size; i++) {
357 if (arr[i] == mt)
358 return 1;
359 }
360
361 return 0;
362}
363
Holger Freytherca362a62009-01-04 21:05:01 +0000364#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000365/* is this msgtype the usual ACK/NACK type ? */
366static int is_ack_nack(enum abis_nm_msgtype mt)
367{
368 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
369}
Holger Freytherca362a62009-01-04 21:05:01 +0000370#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000371
372/* is this msgtype a report ? */
373static int is_report(enum abis_nm_msgtype mt)
374{
Harald Welte8470bf22008-12-25 23:28:35 +0000375 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000376}
377
378#define MT_ACK(x) (x+1)
379#define MT_NACK(x) (x+2)
380
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200381static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +0000382{
383 oh->mdisc = ABIS_OM_MDISC_FOM;
384 oh->placement = ABIS_OM_PLACEMENT_ONLY;
385 oh->sequence = 0;
386 oh->length = len;
387}
388
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200389static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
390 uint8_t msg_type, uint8_t obj_class,
391 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000392{
393 struct abis_om_fom_hdr *foh =
394 (struct abis_om_fom_hdr *) oh->data;
395
Harald Welte702d8702008-12-26 20:25:35 +0000396 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000397 foh->msg_type = msg_type;
398 foh->obj_class = obj_class;
399 foh->obj_inst.bts_nr = bts_nr;
400 foh->obj_inst.trx_nr = trx_nr;
401 foh->obj_inst.ts_nr = ts_nr;
402}
403
Harald Welte8470bf22008-12-25 23:28:35 +0000404static struct msgb *nm_msgb_alloc(void)
405{
Harald Welte966636f2009-06-26 19:39:35 +0200406 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
407 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000408}
409
Harald Welte52b1f982008-12-23 20:25:15 +0000410/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100411static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000412{
Holger Freyther59639e82009-02-09 23:09:55 +0000413 msg->trx = bts->c0;
414
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100415 /* queue OML messages */
416 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
417 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +0100418 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100419 } else {
420 msgb_enqueue(&bts->abis_queue, msg);
421 return 0;
422 }
423
424}
425
426int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
427{
428 OBSC_NM_W_ACK_CB(msg) = 1;
429 return abis_nm_queue_msg(bts, msg);
430}
431
432static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
433{
434 OBSC_NM_W_ACK_CB(msg) = 0;
435 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000436}
437
Harald Welte4724f992009-01-18 18:01:49 +0000438static int abis_nm_rcvmsg_sw(struct msgb *mb);
439
Harald Welte81c9b9c2010-05-31 16:40:40 +0200440const struct value_string abis_nm_obj_class_names[] = {
441 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800442 { NM_OC_BTS, "BTS" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200443 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
444 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800445 { NM_OC_CHANNEL, "CHANNEL" },
446 { NM_OC_BS11_ADJC, "ADJC" },
447 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200448 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800449 { NM_OC_BS11_BTSE, "BTSE" },
450 { NM_OC_BS11_RACK, "RACK" },
451 { NM_OC_BS11_TEST, "TEST" },
452 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
453 { NM_OC_BS11_BPORT, "BPORT" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200454 { NM_OC_GPRS_NSE, "GPRS-NSE" },
455 { NM_OC_GPRS_CELL, "GPRS-CELL" },
456 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800457 { NM_OC_BS11, "SIEMENSHW" },
458 { 0, NULL }
459};
460
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200461static const char *obj_class_name(uint8_t oc)
Harald Welte34a99682009-02-13 02:41:40 +0000462{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200463 return get_value_string(abis_nm_obj_class_names, oc);
Harald Welte34a99682009-02-13 02:41:40 +0000464}
465
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200466const char *nm_opstate_name(uint8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000467{
468 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100469 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000470 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100471 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000472 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100473 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000474 return "NULL";
475 default:
476 return "RFU";
477 }
478}
479
Harald Weltee0590df2009-02-15 03:34:15 +0000480/* Chapter 9.4.7 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800481static const struct value_string avail_names[] = {
482 { 0, "In test" },
483 { 1, "Failed" },
484 { 2, "Power off" },
485 { 3, "Off line" },
486 /* Not used */
487 { 5, "Dependency" },
488 { 6, "Degraded" },
489 { 7, "Not installed" },
490 { 0xff, "OK" },
491 { 0, NULL }
Harald Weltee0590df2009-02-15 03:34:15 +0000492};
493
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200494const char *nm_avail_name(uint8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000495{
Harald Welte92b1fe42010-03-25 11:45:30 +0800496 return get_value_string(avail_names, avail);
Harald Weltee0590df2009-02-15 03:34:15 +0000497}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000498
Harald Welte0f255852009-11-12 14:48:42 +0100499static struct value_string test_names[] = {
500 /* FIXME: standard test names */
501 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
502 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
503 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
504 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
505 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
506 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
507 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
508 { 0, NULL }
509};
510
Harald Welte81c9b9c2010-05-31 16:40:40 +0200511const struct value_string abis_nm_adm_state_names[] = {
512 { NM_STATE_LOCKED, "Locked" },
513 { NM_STATE_UNLOCKED, "Unlocked" },
514 { NM_STATE_SHUTDOWN, "Shutdown" },
515 { NM_STATE_NULL, "NULL" },
516 { 0, NULL }
517};
518
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200519const char *nm_adm_name(uint8_t adm)
Harald Welte7b26bcb2009-05-28 11:39:21 +0000520{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200521 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte7b26bcb2009-05-28 11:39:21 +0000522}
Harald Weltee0590df2009-02-15 03:34:15 +0000523
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100524int nm_is_running(struct gsm_nm_state *s) {
525 return (s->operational == NM_OPSTATE_ENABLED) && (
526 (s->availability == NM_AVSTATE_OK) ||
527 (s->availability == 0xff)
528 );
529}
530
Harald Weltea8bd6d42009-10-20 09:56:18 +0200531static void debugp_foh(struct abis_om_fom_hdr *foh)
532{
533 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200534 obj_class_name(foh->obj_class), foh->obj_class,
Harald Weltea8bd6d42009-10-20 09:56:18 +0200535 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
536 foh->obj_inst.ts_nr);
537}
538
Harald Weltee0590df2009-02-15 03:34:15 +0000539/* obtain the gsm_nm_state data structure for a given object instance */
540static struct gsm_nm_state *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200541objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000542 struct abis_om_obj_inst *obj_inst)
543{
544 struct gsm_bts_trx *trx;
545 struct gsm_nm_state *nm_state = NULL;
546
547 switch (obj_class) {
548 case NM_OC_BTS:
549 nm_state = &bts->nm_state;
550 break;
551 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100552 if (obj_inst->trx_nr >= bts->num_trx) {
553 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000554 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100555 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200556 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000557 nm_state = &trx->nm_state;
558 break;
559 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100560 if (obj_inst->trx_nr >= bts->num_trx) {
561 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000562 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100563 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200564 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000565 nm_state = &trx->bb_transc.nm_state;
566 break;
567 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100568 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100569 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000570 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100571 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200572 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000573 if (obj_inst->ts_nr >= TRX_NR_TS)
574 return NULL;
575 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
576 break;
577 case NM_OC_SITE_MANAGER:
578 nm_state = &bts->site_mgr.nm_state;
579 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000580 case NM_OC_BS11:
581 switch (obj_inst->bts_nr) {
582 case BS11_OBJ_CCLK:
583 nm_state = &bts->bs11.cclk.nm_state;
584 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000585 case BS11_OBJ_BBSIG:
586 if (obj_inst->ts_nr > bts->num_trx)
587 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200588 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000589 nm_state = &trx->bs11.bbsig.nm_state;
590 break;
591 case BS11_OBJ_PA:
592 if (obj_inst->ts_nr > bts->num_trx)
593 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200594 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000595 nm_state = &trx->bs11.pa.nm_state;
596 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000597 default:
598 return NULL;
599 }
600 case NM_OC_BS11_RACK:
601 nm_state = &bts->bs11.rack.nm_state;
602 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000603 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100604 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000605 return NULL;
606 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
607 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200608 case NM_OC_GPRS_NSE:
609 nm_state = &bts->gprs.nse.nm_state;
610 break;
611 case NM_OC_GPRS_CELL:
612 nm_state = &bts->gprs.cell.nm_state;
613 break;
614 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100615 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200616 return NULL;
617 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
618 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000619 }
620 return nm_state;
621}
622
623/* obtain the in-memory data structure of a given object instance */
624static void *
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200625objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
Harald Weltee0590df2009-02-15 03:34:15 +0000626 struct abis_om_obj_inst *obj_inst)
627{
628 struct gsm_bts_trx *trx;
629 void *obj = NULL;
630
631 switch (obj_class) {
632 case NM_OC_BTS:
633 obj = bts;
634 break;
635 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100636 if (obj_inst->trx_nr >= bts->num_trx) {
637 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000638 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100639 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200640 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000641 obj = trx;
642 break;
643 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100644 if (obj_inst->trx_nr >= bts->num_trx) {
645 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000646 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100647 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200648 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000649 obj = &trx->bb_transc;
650 break;
651 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100652 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100653 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000654 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100655 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200656 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000657 if (obj_inst->ts_nr >= TRX_NR_TS)
658 return NULL;
659 obj = &trx->ts[obj_inst->ts_nr];
660 break;
661 case NM_OC_SITE_MANAGER:
662 obj = &bts->site_mgr;
663 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200664 case NM_OC_GPRS_NSE:
665 obj = &bts->gprs.nse;
666 break;
667 case NM_OC_GPRS_CELL:
668 obj = &bts->gprs.cell;
669 break;
670 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100671 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200672 return NULL;
673 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
674 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000675 }
676 return obj;
677}
678
679/* Update the administrative state of a given object in our in-memory data
680 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200681static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
682 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000683{
Harald Welteaeedeb42009-05-01 13:08:14 +0000684 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100685 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000686
Harald Welteaf9b8102011-03-06 21:20:38 +0100687 memset(&nsd, 0, sizeof(nsd));
688
Harald Weltef338a032011-01-14 15:55:42 +0100689 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
690 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100691 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000692 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
693 if (!nm_state)
694 return -1;
695
696 new_state = *nm_state;
697 new_state.administrative = adm_state;
698
Harald Weltef38ca9a2011-03-06 22:11:32 +0100699 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100700 nsd.obj_class = obj_class;
701 nsd.old_state = nm_state;
702 nsd.new_state = &new_state;
703 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200704 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000705
706 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000707
Harald Weltef338a032011-01-14 15:55:42 +0100708 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000709}
710
Harald Welte97ed1e72009-02-06 13:38:02 +0000711static int abis_nm_rx_statechg_rep(struct msgb *mb)
712{
Harald Weltee0590df2009-02-15 03:34:15 +0000713 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000714 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000715 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000716 struct tlv_parsed tp;
717 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000718
Harald Welte23897662009-05-01 14:52:51 +0000719 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000720
Harald Welte8b697c72009-06-05 19:18:45 +0000721 memset(&new_state, 0, sizeof(new_state));
722
Harald Weltee0590df2009-02-15 03:34:15 +0000723 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
724 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100725 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000726 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000727 }
Harald Weltee0590df2009-02-15 03:34:15 +0000728
729 new_state = *nm_state;
730
Harald Welte39315c42010-01-10 18:01:52 +0100731 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000732 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
733 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000734 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000735 }
736 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000737 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
738 new_state.availability = 0xff;
739 else
740 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000741 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000742 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100743 } else
744 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000745 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
746 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200747 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000748 }
749 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000750
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100751 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
752 new_state.operational != nm_state->operational ||
753 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000754 /* Update the operational state of a given object in our in-memory data
755 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100756 struct nm_statechg_signal_data nsd;
757 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
758 nsd.obj_class = foh->obj_class;
759 nsd.old_state = nm_state;
760 nsd.new_state = &new_state;
761 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100762 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200763 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100764 nm_state->operational = new_state.operational;
765 nm_state->availability = new_state.availability;
766 if (nm_state->administrative == 0)
767 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000768 }
769#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000770 if (op_state == 1) {
771 /* try to enable objects that are disabled */
772 abis_nm_opstart(bts, foh->obj_class,
773 foh->obj_inst.bts_nr,
774 foh->obj_inst.trx_nr,
775 foh->obj_inst.ts_nr);
776 }
Harald Weltee0590df2009-02-15 03:34:15 +0000777#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000778 return 0;
779}
780
Harald Welte0db97b22009-05-01 17:22:47 +0000781static int rx_fail_evt_rep(struct msgb *mb)
782{
783 struct abis_om_hdr *oh = msgb_l2(mb);
784 struct abis_om_fom_hdr *foh = msgb_l3(mb);
785 struct tlv_parsed tp;
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100786 const uint8_t *p_val;
787 char *p_text;
Harald Welte0db97b22009-05-01 17:22:47 +0000788
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200789 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte0db97b22009-05-01 17:22:47 +0000790
Harald Welte39315c42010-01-10 18:01:52 +0100791 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000792
793 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200794 LOGPC(DNM, LOGL_ERROR, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte0db97b22009-05-01 17:22:47 +0000795 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200796 LOGPC(DNM, LOGL_ERROR, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100797 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
798 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200799 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100800 }
801 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
802 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
803 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
804 if (p_text) {
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200805 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100806 talloc_free(p_text);
807 }
808 }
Harald Welte0db97b22009-05-01 17:22:47 +0000809
Holger Hans Peter Freyther5deb6c32011-04-26 09:29:01 +0200810 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte0db97b22009-05-01 17:22:47 +0000811
812 return 0;
813}
814
Harald Welte97ed1e72009-02-06 13:38:02 +0000815static int abis_nm_rcvmsg_report(struct msgb *mb)
816{
817 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200818 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000819
Harald Weltea8bd6d42009-10-20 09:56:18 +0200820 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000821
Harald Welte97ed1e72009-02-06 13:38:02 +0000822 //nmh->cfg->report_cb(mb, foh);
823
824 switch (mt) {
825 case NM_MT_STATECHG_EVENT_REP:
826 return abis_nm_rx_statechg_rep(mb);
827 break;
Harald Welte34a99682009-02-13 02:41:40 +0000828 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000829 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200830 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000831 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000832 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000833 rx_fail_evt_rep(mb);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200834 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000835 break;
Harald Weltec7310382009-08-08 00:02:36 +0200836 case NM_MT_TEST_REP:
837 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200838 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200839 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000840 default:
Harald Welte23897662009-05-01 14:52:51 +0000841 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000842 break;
843
Harald Welte97ed1e72009-02-06 13:38:02 +0000844 };
845
Harald Welte97ed1e72009-02-06 13:38:02 +0000846 return 0;
847}
848
Harald Welte34a99682009-02-13 02:41:40 +0000849/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200850static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
851 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000852{
853 struct abis_om_hdr *oh;
854 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200855 uint8_t len = swdesc_len;
856 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000857
858 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
859 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
860
861 trailer = msgb_put(msg, swdesc_len);
862 memcpy(trailer, sw_desc, swdesc_len);
863
864 return abis_nm_sendmsg(bts, msg);
865}
866
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200867static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100868{
869 static const struct tlv_definition sw_descr_def = {
870 .def = {
871 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
872 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
873 },
874 };
875
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200876 uint8_t tag;
877 uint16_t tag_len;
878 const uint8_t *val;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100879 int ofs = 0, len;
880
881 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
882 * nested nature and the fact you have to assume it contains only two sub
883 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
884
885 if (sw_descr[0] != NM_ATT_SW_DESCR) {
886 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
887 return -1;
888 }
889 ofs += 1;
890
891 len = tlv_parse_one(&tag, &tag_len, &val,
892 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
893 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
894 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
895 return -2;
896 }
897 ofs += len;
898
899 len = tlv_parse_one(&tag, &tag_len, &val,
900 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
901 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
902 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
903 return -3;
904 }
905 ofs += len;
906
907 return ofs;
908}
909
Harald Welte34a99682009-02-13 02:41:40 +0000910static int abis_nm_rx_sw_act_req(struct msgb *mb)
911{
912 struct abis_om_hdr *oh = msgb_l2(mb);
913 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200914 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200915 const uint8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100916 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000917
Harald Weltea8bd6d42009-10-20 09:56:18 +0200918 debugp_foh(foh);
919
920 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000921
Harald Welte97a282b2010-03-14 15:37:43 +0800922 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000923
924 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000925 foh->obj_inst.bts_nr,
926 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800927 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000928 foh->data, oh->length-sizeof(*foh));
929
Harald Welte39315c42010-01-10 18:01:52 +0100930 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200931 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
932 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
933 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
934 DEBUGP(DNM, "SW config not found! Can't continue.\n");
935 return -EINVAL;
936 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200937 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200938 }
939
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100940 /* Use the first SW_DESCR present in SW config */
941 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
942 if (sw_descr_len < 0)
943 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200944
Harald Welte34a99682009-02-13 02:41:40 +0000945 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
946 foh->obj_inst.bts_nr,
947 foh->obj_inst.trx_nr,
948 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100949 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000950}
951
Harald Weltee0590df2009-02-15 03:34:15 +0000952/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
953static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
954{
955 struct abis_om_hdr *oh = msgb_l2(mb);
956 struct abis_om_fom_hdr *foh = msgb_l3(mb);
957 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200958 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000959
Harald Welte39315c42010-01-10 18:01:52 +0100960 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000961 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
962 return -EINVAL;
963
964 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
965
966 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
967}
968
Harald Welteee670472009-02-22 21:58:49 +0000969static int abis_nm_rx_lmt_event(struct msgb *mb)
970{
971 struct abis_om_hdr *oh = msgb_l2(mb);
972 struct abis_om_fom_hdr *foh = msgb_l3(mb);
973 struct tlv_parsed tp;
974
975 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100976 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000977 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
978 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200979 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000980 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
981 }
982 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
983 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200984 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000985 DEBUGPC(DNM, "Level=%u ", level);
986 }
987 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
988 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
989 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
990 DEBUGPC(DNM, "Username=%s ", name);
991 }
992 DEBUGPC(DNM, "\n");
993 /* FIXME: parse LMT LOGON TIME */
994 return 0;
995}
996
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100997static void abis_nm_queue_send_next(struct gsm_bts *bts)
998{
999 int wait = 0;
1000 struct msgb *msg;
1001 /* the queue is empty */
1002 while (!llist_empty(&bts->abis_queue)) {
1003 msg = msgb_dequeue(&bts->abis_queue);
1004 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welted88a3872011-02-14 15:26:13 +01001005 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001006
1007 if (wait)
1008 break;
1009 }
1010
1011 bts->abis_nm_pend = wait;
1012}
1013
Harald Welte52b1f982008-12-23 20:25:15 +00001014/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +00001015static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +00001016{
Harald Welte6c96ba52009-05-01 13:03:40 +00001017 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001018 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001019 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001020 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001021
1022 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001023 if (is_report(mt))
1024 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001025
Harald Welte4724f992009-01-18 18:01:49 +00001026 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1027 return abis_nm_rcvmsg_sw(mb);
1028
Harald Welte78fc0d42009-02-19 02:50:57 +00001029 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001030 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +00001031 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001032
Harald Weltea8bd6d42009-10-20 09:56:18 +02001033 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001034
Harald Welte92b1fe42010-03-25 11:45:30 +08001035 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +00001036
Harald Welte39315c42010-01-10 18:01:52 +01001037 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +00001038 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001039 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00001040 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1041 else
1042 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001043
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001044 nack_data.msg = mb;
1045 nack_data.mt = mt;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02001046 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001047 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001048 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001049 }
Harald Weltead384642008-12-26 10:20:07 +00001050#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001051 /* check if last message is to be acked */
1052 if (is_ack_nack(nmh->last_msgtype)) {
1053 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001054 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001055 /* we got our ACK, continue sending the next msg */
1056 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1057 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001058 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001059 /* FIXME: somehow signal this to the caller */
1060 } else {
1061 /* really strange things happen */
1062 return -EINVAL;
1063 }
1064 }
Harald Weltead384642008-12-26 10:20:07 +00001065#endif
1066
Harald Welte97ed1e72009-02-06 13:38:02 +00001067 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001068 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001069 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +00001070 break;
Harald Welte34a99682009-02-13 02:41:40 +00001071 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001072 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +00001073 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001074 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001075 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001076 break;
Harald Welte1989c082009-08-06 17:58:31 +02001077 case NM_MT_CONN_MDROP_LINK_ACK:
1078 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1079 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001080 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02001081 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001082 break;
1083 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02001084 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001085 break;
Harald Weltefd355a32011-03-04 13:41:31 +01001086 case NM_MT_SET_BTS_ATTR_ACK:
1087 /* The HSL wants an OPSTART _after_ the SI has been set */
1088 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
1089 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
1090 }
1091 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001092 }
1093
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001094 abis_nm_queue_send_next(mb->trx->bts);
1095 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001096}
1097
Harald Welte677c21f2009-02-17 13:22:23 +00001098static int abis_nm_rx_ipacc(struct msgb *mb);
1099
1100static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1101{
1102 int rc;
1103 int bts_type = mb->trx->bts->type;
1104
1105 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001106 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001107 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001108 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +00001109 break;
1110 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001111 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1112 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001113 rc = 0;
1114 break;
1115 }
1116
1117 return rc;
1118}
1119
Harald Welte52b1f982008-12-23 20:25:15 +00001120/* High-Level API */
1121/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001122int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001123{
Harald Welte52b1f982008-12-23 20:25:15 +00001124 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001125 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001126
1127 /* Various consistency checks */
1128 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001129 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001130 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001131 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1132 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001133 }
1134 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001135 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001136 oh->sequence);
1137 return -EINVAL;
1138 }
Harald Welte702d8702008-12-26 20:25:35 +00001139#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001140 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +00001141 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001142 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001143 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001144 oh->length + sizeof(*oh), l2_len);
1145 return -EINVAL;
1146 }
Harald Welte702d8702008-12-26 20:25:35 +00001147 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001148 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 +00001149#endif
Harald Weltead384642008-12-26 10:20:07 +00001150 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001151
1152 switch (oh->mdisc) {
1153 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001154 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001155 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001156 case ABIS_OM_MDISC_MANUF:
1157 rc = abis_nm_rcvmsg_manuf(msg);
1158 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001159 case ABIS_OM_MDISC_MMI:
1160 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001161 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001162 oh->mdisc);
1163 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001164 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001165 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001166 oh->mdisc);
1167 return -EINVAL;
1168 }
1169
Harald Weltead384642008-12-26 10:20:07 +00001170 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001171 return rc;
1172}
1173
1174#if 0
1175/* initialized all resources */
1176struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1177{
1178 struct abis_nm_h *nmh;
1179
1180 nmh = malloc(sizeof(*nmh));
1181 if (!nmh)
1182 return NULL;
1183
1184 nmh->cfg = cfg;
1185
1186 return nmh;
1187}
1188
1189/* free all resources */
1190void abis_nm_fini(struct abis_nm_h *nmh)
1191{
1192 free(nmh);
1193}
1194#endif
1195
1196/* Here we are trying to define a high-level API that can be used by
1197 * the actual BSC implementation. However, the architecture is currently
1198 * still under design. Ideally the calls to this API would be synchronous,
1199 * while the underlying stack behind the APi runs in a traditional select
1200 * based state machine.
1201 */
1202
Harald Welte4724f992009-01-18 18:01:49 +00001203/* 6.2 Software Load: */
1204enum sw_state {
1205 SW_STATE_NONE,
1206 SW_STATE_WAIT_INITACK,
1207 SW_STATE_WAIT_SEGACK,
1208 SW_STATE_WAIT_ENDACK,
1209 SW_STATE_WAIT_ACTACK,
1210 SW_STATE_ERROR,
1211};
Harald Welte52b1f982008-12-23 20:25:15 +00001212
Harald Welte52b1f982008-12-23 20:25:15 +00001213struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001214 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001215 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001216 gsm_cbfn *cbfn;
1217 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001218 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001219
Harald Welte52b1f982008-12-23 20:25:15 +00001220 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001221 uint8_t obj_class;
1222 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001223
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001224 uint8_t file_id[255];
1225 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +00001226
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001227 uint8_t file_version[255];
1228 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001229
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001230 uint8_t window_size;
1231 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +00001232
1233 int fd;
1234 FILE *stream;
1235 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001236 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001237};
1238
Harald Welte4724f992009-01-18 18:01:49 +00001239static struct abis_nm_sw g_sw;
1240
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001241static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1242{
1243 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1244 msgb_v_put(msg, NM_ATT_SW_DESCR);
1245 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1246 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1247 sw->file_version);
1248 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1249 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1250 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1251 sw->file_version);
1252 } else {
1253 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1254 }
1255}
1256
Harald Welte4724f992009-01-18 18:01:49 +00001257/* 6.2.1 / 8.3.1: Load Data Initiate */
1258static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001259{
Harald Welte4724f992009-01-18 18:01:49 +00001260 struct abis_om_hdr *oh;
1261 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001262 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001263
1264 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1265 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1266 sw->obj_instance[0], sw->obj_instance[1],
1267 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001268
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001269 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001270 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1271
1272 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001273}
1274
Harald Welte1602ade2009-01-29 21:12:39 +00001275static int is_last_line(FILE *stream)
1276{
1277 char next_seg_buf[256];
1278 long pos;
1279
1280 /* check if we're sending the last line */
1281 pos = ftell(stream);
1282 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1283 fseek(stream, pos, SEEK_SET);
1284 return 1;
1285 }
1286
1287 fseek(stream, pos, SEEK_SET);
1288 return 0;
1289}
1290
Harald Welte4724f992009-01-18 18:01:49 +00001291/* 6.2.2 / 8.3.2 Load Data Segment */
1292static int sw_load_segment(struct abis_nm_sw *sw)
1293{
1294 struct abis_om_hdr *oh;
1295 struct msgb *msg = nm_msgb_alloc();
1296 char seg_buf[256];
1297 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001298 unsigned char *tlv;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001299 uint8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001300
1301 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001302
1303 switch (sw->bts->type) {
1304 case GSM_BTS_TYPE_BS11:
1305 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1306 perror("fgets reading segment");
1307 return -EINVAL;
1308 }
1309 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001310
1311 /* check if we're sending the last line */
1312 sw->last_seg = is_last_line(sw->stream);
1313 if (sw->last_seg)
1314 seg_buf[1] = 0;
1315 else
1316 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001317
1318 len = strlen(line_buf) + 2;
1319 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001320 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001321 /* BS11 wants CR + LF in excess of the TLV length !?! */
1322 tlv[1] -= 2;
1323
1324 /* we only now know the exact length for the OM hdr */
1325 len = strlen(line_buf)+2;
1326 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001327 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001328 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001329 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1330 if (len < 0) {
1331 perror("read failed");
1332 return -EINVAL;
1333 }
1334
1335 if (len != IPACC_SEGMENT_SIZE)
1336 sw->last_seg = 1;
1337
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001338 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001339 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001340 len += 3;
1341 break;
1342 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001343 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001344 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001345 /* FIXME: Other BTS types */
1346 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001347 }
Harald Welte4724f992009-01-18 18:01:49 +00001348
Harald Welte4724f992009-01-18 18:01:49 +00001349 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1350 sw->obj_instance[0], sw->obj_instance[1],
1351 sw->obj_instance[2]);
1352
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001353 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001354}
1355
1356/* 6.2.4 / 8.3.4 Load Data End */
1357static int sw_load_end(struct abis_nm_sw *sw)
1358{
1359 struct abis_om_hdr *oh;
1360 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001361 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001362
1363 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1364 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1365 sw->obj_instance[0], sw->obj_instance[1],
1366 sw->obj_instance[2]);
1367
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001368 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001369 return abis_nm_sendmsg(sw->bts, msg);
1370}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001371
Harald Welte52b1f982008-12-23 20:25:15 +00001372/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001373static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001374{
Harald Welte4724f992009-01-18 18:01:49 +00001375 struct abis_om_hdr *oh;
1376 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001377 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001378
Harald Welte4724f992009-01-18 18:01:49 +00001379 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1380 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1381 sw->obj_instance[0], sw->obj_instance[1],
1382 sw->obj_instance[2]);
1383
1384 /* FIXME: this is BS11 specific format */
1385 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1386 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1387 sw->file_version);
1388
1389 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001390}
Harald Welte4724f992009-01-18 18:01:49 +00001391
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001392struct sdp_firmware {
1393 char magic[4];
1394 char more_magic[4];
1395 unsigned int header_length;
1396 unsigned int file_length;
1397} __attribute__ ((packed));
1398
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001399static int parse_sdp_header(struct abis_nm_sw *sw)
1400{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001401 struct sdp_firmware firmware_header;
1402 int rc;
1403 struct stat stat;
1404
1405 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1406 if (rc != sizeof(firmware_header)) {
1407 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1408 return -1;
1409 }
1410
1411 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1412 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1413 return -1;
1414 }
1415
1416 if (firmware_header.more_magic[0] != 0x10 ||
1417 firmware_header.more_magic[1] != 0x02 ||
1418 firmware_header.more_magic[2] != 0x00 ||
1419 firmware_header.more_magic[3] != 0x00) {
1420 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1421 return -1;
1422 }
1423
1424
1425 if (fstat(sw->fd, &stat) == -1) {
1426 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1427 return -1;
1428 }
1429
1430 if (ntohl(firmware_header.file_length) != stat.st_size) {
1431 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1432 return -1;
1433 }
1434
1435 /* go back to the start as we checked the whole filesize.. */
1436 lseek(sw->fd, 0l, SEEK_SET);
1437 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1438 "There might be checksums in the file that are not\n"
1439 "verified and incomplete firmware might be flashed.\n"
1440 "There is absolutely no WARRANTY that flashing will\n"
1441 "work.\n");
1442 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001443}
1444
Harald Welte4724f992009-01-18 18:01:49 +00001445static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1446{
1447 char file_id[12+1];
1448 char file_version[80+1];
1449 int rc;
1450
1451 sw->fd = open(fname, O_RDONLY);
1452 if (sw->fd < 0)
1453 return sw->fd;
1454
1455 switch (sw->bts->type) {
1456 case GSM_BTS_TYPE_BS11:
1457 sw->stream = fdopen(sw->fd, "r");
1458 if (!sw->stream) {
1459 perror("fdopen");
1460 return -1;
1461 }
1462 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001463 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001464 file_id, file_version);
1465 if (rc != 2) {
1466 perror("parsing header line of software file");
1467 return -1;
1468 }
1469 strcpy((char *)sw->file_id, file_id);
1470 sw->file_id_len = strlen(file_id);
1471 strcpy((char *)sw->file_version, file_version);
1472 sw->file_version_len = strlen(file_version);
1473 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001474 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001475 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001476 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001477 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001478 rc = parse_sdp_header(sw);
1479 if (rc < 0) {
1480 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1481 return -1;
1482 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001483
1484 strcpy((char *)sw->file_id, "id");
1485 sw->file_id_len = 3;
1486 strcpy((char *)sw->file_version, "version");
1487 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001488 break;
Harald Welte4724f992009-01-18 18:01:49 +00001489 default:
1490 /* We don't know how to treat them yet */
1491 close(sw->fd);
1492 return -EINVAL;
1493 }
1494
1495 return 0;
1496}
1497
1498static void sw_close_file(struct abis_nm_sw *sw)
1499{
1500 switch (sw->bts->type) {
1501 case GSM_BTS_TYPE_BS11:
1502 fclose(sw->stream);
1503 break;
1504 default:
1505 close(sw->fd);
1506 break;
1507 }
1508}
1509
1510/* Fill the window */
1511static int sw_fill_window(struct abis_nm_sw *sw)
1512{
1513 int rc;
1514
1515 while (sw->seg_in_window < sw->window_size) {
1516 rc = sw_load_segment(sw);
1517 if (rc < 0)
1518 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001519 if (sw->last_seg)
1520 break;
Harald Welte4724f992009-01-18 18:01:49 +00001521 }
1522 return 0;
1523}
1524
1525/* callback function from abis_nm_rcvmsg() handler */
1526static int abis_nm_rcvmsg_sw(struct msgb *mb)
1527{
1528 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1529 int rc = -1;
1530 struct abis_nm_sw *sw = &g_sw;
1531 enum sw_state old_state = sw->state;
1532
Harald Welte3ffd1372009-02-01 22:15:49 +00001533 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001534
1535 switch (sw->state) {
1536 case SW_STATE_WAIT_INITACK:
1537 switch (foh->msg_type) {
1538 case NM_MT_LOAD_INIT_ACK:
1539 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001540 if (sw->cbfn)
1541 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1542 NM_MT_LOAD_INIT_ACK, mb,
1543 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001544 rc = sw_fill_window(sw);
1545 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001546 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001547 break;
1548 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001549 if (sw->forced) {
1550 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1551 "Init NACK\n");
1552 if (sw->cbfn)
1553 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1554 NM_MT_LOAD_INIT_ACK, mb,
1555 sw->cb_data, NULL);
1556 rc = sw_fill_window(sw);
1557 sw->state = SW_STATE_WAIT_SEGACK;
1558 } else {
1559 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001560 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001561 if (sw->cbfn)
1562 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1563 NM_MT_LOAD_INIT_NACK, mb,
1564 sw->cb_data, NULL);
1565 sw->state = SW_STATE_ERROR;
1566 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001567 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001568 break;
1569 }
1570 break;
1571 case SW_STATE_WAIT_SEGACK:
1572 switch (foh->msg_type) {
1573 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001574 if (sw->cbfn)
1575 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1576 NM_MT_LOAD_SEG_ACK, mb,
1577 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001578 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001579 if (!sw->last_seg) {
1580 /* fill window with more segments */
1581 rc = sw_fill_window(sw);
1582 sw->state = SW_STATE_WAIT_SEGACK;
1583 } else {
1584 /* end the transfer */
1585 sw->state = SW_STATE_WAIT_ENDACK;
1586 rc = sw_load_end(sw);
1587 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001588 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001589 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001590 case NM_MT_LOAD_ABORT:
1591 if (sw->cbfn)
1592 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1593 NM_MT_LOAD_ABORT, mb,
1594 sw->cb_data, NULL);
1595 break;
Harald Welte4724f992009-01-18 18:01:49 +00001596 }
1597 break;
1598 case SW_STATE_WAIT_ENDACK:
1599 switch (foh->msg_type) {
1600 case NM_MT_LOAD_END_ACK:
1601 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001602 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1603 sw->bts->nr);
1604 sw->state = SW_STATE_NONE;
1605 if (sw->cbfn)
1606 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1607 NM_MT_LOAD_END_ACK, mb,
1608 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001609 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001610 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001611 break;
1612 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001613 if (sw->forced) {
1614 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1615 "End NACK\n");
1616 sw->state = SW_STATE_NONE;
1617 if (sw->cbfn)
1618 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1619 NM_MT_LOAD_END_ACK, mb,
1620 sw->cb_data, NULL);
1621 } else {
1622 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001623 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001624 sw->state = SW_STATE_ERROR;
1625 if (sw->cbfn)
1626 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1627 NM_MT_LOAD_END_NACK, mb,
1628 sw->cb_data, NULL);
1629 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001630 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001631 break;
1632 }
1633 case SW_STATE_WAIT_ACTACK:
1634 switch (foh->msg_type) {
1635 case NM_MT_ACTIVATE_SW_ACK:
1636 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001637 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001638 sw->state = SW_STATE_NONE;
1639 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001640 if (sw->cbfn)
1641 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1642 NM_MT_ACTIVATE_SW_ACK, mb,
1643 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001644 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001645 break;
1646 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001647 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001648 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001649 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001650 if (sw->cbfn)
1651 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1652 NM_MT_ACTIVATE_SW_NACK, mb,
1653 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001654 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001655 break;
1656 }
1657 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001658 switch (foh->msg_type) {
1659 case NM_MT_ACTIVATE_SW_ACK:
1660 rc = 0;
1661 break;
1662 }
1663 break;
Harald Welte4724f992009-01-18 18:01:49 +00001664 case SW_STATE_ERROR:
1665 break;
1666 }
1667
1668 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001669 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001670 foh->msg_type, old_state, sw->state);
1671
1672 return rc;
1673}
1674
1675/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001676int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001677 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001678 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001679{
1680 struct abis_nm_sw *sw = &g_sw;
1681 int rc;
1682
Harald Welte5e4d1b32009-02-01 13:36:56 +00001683 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1684 bts->nr, fname);
1685
Harald Welte4724f992009-01-18 18:01:49 +00001686 if (sw->state != SW_STATE_NONE)
1687 return -EBUSY;
1688
1689 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001690 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001691
1692 switch (bts->type) {
1693 case GSM_BTS_TYPE_BS11:
1694 sw->obj_class = NM_OC_SITE_MANAGER;
1695 sw->obj_instance[0] = 0xff;
1696 sw->obj_instance[1] = 0xff;
1697 sw->obj_instance[2] = 0xff;
1698 break;
1699 case GSM_BTS_TYPE_NANOBTS:
1700 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001701 sw->obj_instance[0] = sw->bts->nr;
1702 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001703 sw->obj_instance[2] = 0xff;
1704 break;
1705 case GSM_BTS_TYPE_UNKNOWN:
1706 default:
1707 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1708 return -1;
1709 break;
1710 }
Harald Welte4724f992009-01-18 18:01:49 +00001711 sw->window_size = win_size;
1712 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001713 sw->cbfn = cbfn;
1714 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001715 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001716
1717 rc = sw_open_file(sw, fname);
1718 if (rc < 0) {
1719 sw->state = SW_STATE_NONE;
1720 return rc;
1721 }
1722
1723 return sw_load_init(sw);
1724}
Harald Welte52b1f982008-12-23 20:25:15 +00001725
Harald Welte1602ade2009-01-29 21:12:39 +00001726int abis_nm_software_load_status(struct gsm_bts *bts)
1727{
1728 struct abis_nm_sw *sw = &g_sw;
1729 struct stat st;
1730 int rc, percent;
1731
1732 rc = fstat(sw->fd, &st);
1733 if (rc < 0) {
1734 perror("ERROR during stat");
1735 return rc;
1736 }
1737
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001738 if (sw->stream)
1739 percent = (ftell(sw->stream) * 100) / st.st_size;
1740 else
1741 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001742 return percent;
1743}
1744
Harald Welte5e4d1b32009-02-01 13:36:56 +00001745/* Activate the specified software into the BTS */
1746int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1747 gsm_cbfn *cbfn, void *cb_data)
1748{
1749 struct abis_nm_sw *sw = &g_sw;
1750 int rc;
1751
1752 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1753 bts->nr, fname);
1754
1755 if (sw->state != SW_STATE_NONE)
1756 return -EBUSY;
1757
1758 sw->bts = bts;
1759 sw->obj_class = NM_OC_SITE_MANAGER;
1760 sw->obj_instance[0] = 0xff;
1761 sw->obj_instance[1] = 0xff;
1762 sw->obj_instance[2] = 0xff;
1763 sw->state = SW_STATE_WAIT_ACTACK;
1764 sw->cbfn = cbfn;
1765 sw->cb_data = cb_data;
1766
1767 /* Open the file in order to fill some sw struct members */
1768 rc = sw_open_file(sw, fname);
1769 if (rc < 0) {
1770 sw->state = SW_STATE_NONE;
1771 return rc;
1772 }
1773 sw_close_file(sw);
1774
1775 return sw_activate(sw);
1776}
1777
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001778static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1779 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001780{
Harald Welteadaf08b2009-01-18 11:08:10 +00001781 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001782 ch->bts_port = bts_port;
1783 ch->timeslot = ts_nr;
1784 ch->subslot = subslot_nr;
1785}
1786
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001787int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1788 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1789 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001790{
1791 struct abis_om_hdr *oh;
1792 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001793 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001794 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001795
1796 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1797 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1798 bts->bts_nr, trx_nr, 0xff);
1799
Harald Welte8470bf22008-12-25 23:28:35 +00001800 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001801
1802 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1803 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1804
1805 return abis_nm_sendmsg(bts, msg);
1806}
1807
1808/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1809int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001810 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001811{
Harald Welte8470bf22008-12-25 23:28:35 +00001812 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001813 struct abis_om_hdr *oh;
1814 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001815 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001816
1817 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001818 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001819 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1820
1821 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1822 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1823
1824 return abis_nm_sendmsg(bts, msg);
1825}
1826
1827#if 0
1828int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1829 struct abis_nm_abis_channel *chan)
1830{
1831}
1832#endif
1833
1834int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001835 uint8_t e1_port, uint8_t e1_timeslot,
1836 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001837{
1838 struct gsm_bts *bts = ts->trx->bts;
1839 struct abis_om_hdr *oh;
1840 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001841 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001842
1843 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1844 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001845 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001846
1847 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1848 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1849
Harald Weltef325eb42009-02-19 17:07:39 +00001850 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1851 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001852 e1_port, e1_timeslot, e1_subslot);
1853
Harald Welte52b1f982008-12-23 20:25:15 +00001854 return abis_nm_sendmsg(bts, msg);
1855}
1856
1857#if 0
1858int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1859 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001860 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001861{
1862}
1863#endif
1864
Harald Welte22af0db2009-02-14 15:41:08 +00001865/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001866int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001867{
1868 struct abis_om_hdr *oh;
1869 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001870 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001871
1872 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1873
1874 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001875 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 +00001876 cur = msgb_put(msg, attr_len);
1877 memcpy(cur, attr, attr_len);
1878
1879 return abis_nm_sendmsg(bts, msg);
1880}
1881
1882/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001883int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001884{
1885 struct abis_om_hdr *oh;
1886 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001887 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001888
1889 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1890
1891 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1892 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001893 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001894 cur = msgb_put(msg, attr_len);
1895 memcpy(cur, attr, attr_len);
1896
1897 return abis_nm_sendmsg(trx->bts, msg);
1898}
1899
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001900static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte39c7deb2009-08-09 21:49:48 +02001901{
1902 int i;
1903
1904 /* As it turns out, the BS-11 has some very peculiar restrictions
1905 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301906 switch (ts->trx->bts->type) {
1907 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001908 switch (chan_comb) {
1909 case NM_CHANC_TCHHalf:
1910 case NM_CHANC_TCHHalf2:
1911 /* not supported */
1912 return -EINVAL;
1913 case NM_CHANC_SDCCH:
1914 /* only one SDCCH/8 per TRX */
1915 for (i = 0; i < TRX_NR_TS; i++) {
1916 if (i == ts->nr)
1917 continue;
1918 if (ts->trx->ts[i].nm_chan_comb ==
1919 NM_CHANC_SDCCH)
1920 return -EINVAL;
1921 }
1922 /* not allowed for TS0 of BCCH-TRX */
1923 if (ts->trx == ts->trx->bts->c0 &&
1924 ts->nr == 0)
1925 return -EINVAL;
1926 /* not on the same TRX that has a BCCH+SDCCH4
1927 * combination */
1928 if (ts->trx == ts->trx->bts->c0 &&
1929 (ts->trx->ts[0].nm_chan_comb == 5 ||
1930 ts->trx->ts[0].nm_chan_comb == 8))
1931 return -EINVAL;
1932 break;
1933 case NM_CHANC_mainBCCH:
1934 case NM_CHANC_BCCHComb:
1935 /* allowed only for TS0 of C0 */
1936 if (ts->trx != ts->trx->bts->c0 ||
1937 ts->nr != 0)
1938 return -EINVAL;
1939 break;
1940 case NM_CHANC_BCCH:
1941 /* allowed only for TS 2/4/6 of C0 */
1942 if (ts->trx != ts->trx->bts->c0)
1943 return -EINVAL;
1944 if (ts->nr != 2 && ts->nr != 4 &&
1945 ts->nr != 6)
1946 return -EINVAL;
1947 break;
1948 case 8: /* this is not like 08.58, but in fact
1949 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1950 /* FIXME: only one CBCH allowed per cell */
1951 break;
1952 }
Harald Welted6575f92009-12-02 02:45:23 +05301953 break;
1954 case GSM_BTS_TYPE_NANOBTS:
1955 switch (ts->nr) {
1956 case 0:
1957 if (ts->trx->nr == 0) {
1958 /* only on TRX0 */
1959 switch (chan_comb) {
1960 case NM_CHANC_BCCH:
1961 case NM_CHANC_mainBCCH:
1962 case NM_CHANC_BCCHComb:
1963 return 0;
1964 break;
1965 default:
1966 return -EINVAL;
1967 }
1968 } else {
1969 switch (chan_comb) {
1970 case NM_CHANC_TCHFull:
1971 case NM_CHANC_TCHHalf:
1972 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1973 return 0;
1974 default:
1975 return -EINVAL;
1976 }
1977 }
1978 break;
1979 case 1:
1980 if (ts->trx->nr == 0) {
1981 switch (chan_comb) {
1982 case NM_CHANC_SDCCH_CBCH:
1983 if (ts->trx->ts[0].nm_chan_comb ==
1984 NM_CHANC_mainBCCH)
1985 return 0;
1986 return -EINVAL;
1987 case NM_CHANC_SDCCH:
1988 case NM_CHANC_TCHFull:
1989 case NM_CHANC_TCHHalf:
1990 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1991 case NM_CHANC_IPAC_TCHFull_PDCH:
1992 return 0;
1993 }
1994 } else {
1995 switch (chan_comb) {
1996 case NM_CHANC_SDCCH:
1997 case NM_CHANC_TCHFull:
1998 case NM_CHANC_TCHHalf:
1999 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2000 return 0;
2001 default:
2002 return -EINVAL;
2003 }
2004 }
2005 break;
2006 case 2:
2007 case 3:
2008 case 4:
2009 case 5:
2010 case 6:
2011 case 7:
2012 switch (chan_comb) {
2013 case NM_CHANC_TCHFull:
2014 case NM_CHANC_TCHHalf:
2015 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2016 return 0;
2017 case NM_CHANC_IPAC_PDCH:
2018 case NM_CHANC_IPAC_TCHFull_PDCH:
2019 if (ts->trx->nr == 0)
2020 return 0;
2021 else
2022 return -EINVAL;
2023 }
2024 break;
2025 }
2026 return -EINVAL;
2027 default:
2028 /* unknown BTS type */
2029 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002030 }
2031 return 0;
2032}
2033
Harald Welte22af0db2009-02-14 15:41:08 +00002034/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002035int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00002036{
2037 struct gsm_bts *bts = ts->trx->bts;
2038 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002039 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002040 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002041 uint8_t len = 2 + 2;
Harald Weltee0590df2009-02-15 03:34:15 +00002042
2043 if (bts->type == GSM_BTS_TYPE_BS11)
2044 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002045
Harald Weltef325eb42009-02-19 17:07:39 +00002046 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002047 if (verify_chan_comb(ts, chan_comb) < 0) {
2048 msgb_free(msg);
2049 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2050 return -EINVAL;
2051 }
2052 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002053
Harald Welte52b1f982008-12-23 20:25:15 +00002054 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002055 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002056 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002057 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002058 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002059 if (ts->hopping.enabled) {
2060 unsigned int i;
2061 uint8_t *len;
2062
Harald Welte6e0cd042009-09-12 13:05:33 +02002063 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2064 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002065
2066 /* build the ARFCN list */
2067 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2068 len = msgb_put(msg, 1);
2069 *len = 0;
2070 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2071 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2072 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002073 /* At least BS-11 wants a TLV16 here */
2074 if (bts->type == GSM_BTS_TYPE_BS11)
2075 *len += 1;
2076 else
2077 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002078 }
2079 }
Harald Weltee0590df2009-02-15 03:34:15 +00002080 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002081 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002082 if (bts->type == GSM_BTS_TYPE_BS11)
2083 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002084
2085 return abis_nm_sendmsg(bts, msg);
2086}
2087
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002088int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
2089 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002090{
2091 struct abis_om_hdr *oh;
2092 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002093 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2094 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00002095
2096 if (nack) {
2097 len += 2;
2098 msgtype = NM_MT_SW_ACT_REQ_NACK;
2099 }
Harald Welte34a99682009-02-13 02:41:40 +00002100
2101 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002102 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2103
Harald Welte34a99682009-02-13 02:41:40 +00002104 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002105 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00002106 memcpy(ptr, attr, att_len);
2107 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002108 if (nack)
2109 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002110
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002111 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002112}
2113
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002114int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002115{
Harald Welte8470bf22008-12-25 23:28:35 +00002116 struct msgb *msg = nm_msgb_alloc();
2117 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002118 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00002119
2120 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2121 fill_om_hdr(oh, len);
2122 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002123 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002124
2125 return abis_nm_sendmsg(bts, msg);
2126}
2127
2128/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002129static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00002130{
2131 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002132 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002133
2134 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002135 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002136 0xff, 0xff, 0xff);
2137
2138 return abis_nm_sendmsg(bts, msg);
2139}
2140
Harald Welte34a99682009-02-13 02:41:40 +00002141/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002142int 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 +00002143{
2144 struct abis_om_hdr *oh;
2145 struct msgb *msg = nm_msgb_alloc();
2146
2147 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2148 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2149
Harald Weltea8bd6d42009-10-20 09:56:18 +02002150 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2151 DEBUGPC(DNM, "Sending OPSTART\n");
2152
Harald Welte34a99682009-02-13 02:41:40 +00002153 return abis_nm_sendmsg(bts, msg);
2154}
2155
2156/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002157int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
2158 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002159{
2160 struct abis_om_hdr *oh;
2161 struct msgb *msg = nm_msgb_alloc();
2162
2163 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2164 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2165 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2166
2167 return abis_nm_sendmsg(bts, msg);
2168}
2169
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002170int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
2171 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02002172{
2173 struct abis_om_hdr *oh;
2174 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002175 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02002176
2177 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2178 e1_port0, ts0, e1_port1, ts1);
2179
2180 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2181 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2182 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2183
2184 attr = msgb_put(msg, 3);
2185 attr[0] = NM_ATT_MDROP_LINK;
2186 attr[1] = e1_port0;
2187 attr[2] = ts0;
2188
2189 attr = msgb_put(msg, 3);
2190 attr[0] = NM_ATT_MDROP_NEXT;
2191 attr[1] = e1_port1;
2192 attr[2] = ts1;
2193
2194 return abis_nm_sendmsg(bts, msg);
2195}
Harald Welte34a99682009-02-13 02:41:40 +00002196
Harald Weltec7310382009-08-08 00:02:36 +02002197/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002198int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2199 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2200 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002201{
2202 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002203
Harald Welte4d54d0b2011-02-19 16:48:17 +01002204 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002205
2206 if (!msg)
2207 msg = nm_msgb_alloc();
2208
2209 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2210 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2211 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2212 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002213 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002214
2215 return abis_nm_sendmsg(bts, msg);
2216}
2217
Harald Welte52b1f982008-12-23 20:25:15 +00002218int abis_nm_event_reports(struct gsm_bts *bts, int on)
2219{
2220 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002221 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002222 else
Harald Welte227d4072009-01-03 08:16:25 +00002223 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002224}
2225
Harald Welte47d88ae2009-01-04 12:02:08 +00002226/* Siemens (or BS-11) specific commands */
2227
Harald Welte3ffd1372009-02-01 22:15:49 +00002228int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2229{
2230 if (reconnect == 0)
2231 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2232 else
2233 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2234}
2235
Harald Welteb8427972009-02-05 19:27:17 +00002236int abis_nm_bs11_restart(struct gsm_bts *bts)
2237{
2238 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2239}
2240
2241
Harald Welte268bb402009-02-01 19:11:56 +00002242struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002243 uint16_t year;
2244 uint8_t month;
2245 uint8_t day;
2246 uint8_t hour;
2247 uint8_t min;
2248 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002249} __attribute__((packed));
2250
2251
2252void get_bs11_date_time(struct bs11_date_time *aet)
2253{
2254 time_t t;
2255 struct tm *tm;
2256
2257 t = time(NULL);
2258 tm = localtime(&t);
2259 aet->sec = tm->tm_sec;
2260 aet->min = tm->tm_min;
2261 aet->hour = tm->tm_hour;
2262 aet->day = tm->tm_mday;
2263 aet->month = tm->tm_mon;
2264 aet->year = htons(1900 + tm->tm_year);
2265}
2266
Harald Welte05188ee2009-01-18 11:39:08 +00002267int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002268{
Harald Welte4668fda2009-01-03 08:19:29 +00002269 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002270}
2271
Harald Welte05188ee2009-01-18 11:39:08 +00002272int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002273{
2274 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002275 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002276 else
Harald Welte4668fda2009-01-03 08:19:29 +00002277 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002278}
Harald Welte47d88ae2009-01-04 12:02:08 +00002279
Harald Welte05188ee2009-01-18 11:39:08 +00002280int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002281 enum abis_bs11_objtype type, uint8_t idx,
2282 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002283{
2284 struct abis_om_hdr *oh;
2285 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002286 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002287
2288 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002289 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002290 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002291 cur = msgb_put(msg, attr_len);
2292 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002293
2294 return abis_nm_sendmsg(bts, msg);
2295}
2296
Harald Welte78fc0d42009-02-19 02:50:57 +00002297int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002298 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002299{
2300 struct abis_om_hdr *oh;
2301 struct msgb *msg = nm_msgb_alloc();
2302
2303 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2304 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2305 NM_OC_BS11, type, 0, idx);
2306
2307 return abis_nm_sendmsg(bts, msg);
2308}
2309
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002310int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002311{
2312 struct abis_om_hdr *oh;
2313 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002314 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002315
2316 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002317 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002318 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2319 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002320
2321 return abis_nm_sendmsg(bts, msg);
2322}
2323
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002324int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002325{
2326 struct abis_om_hdr *oh;
2327 struct msgb *msg = nm_msgb_alloc();
2328
2329 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2330 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002331 idx, 0xff, 0xff);
2332
2333 return abis_nm_sendmsg(bts, msg);
2334}
2335
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002336int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002337{
2338 struct abis_om_hdr *oh;
2339 struct msgb *msg = nm_msgb_alloc();
2340
2341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2342 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2343 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002344
2345 return abis_nm_sendmsg(bts, msg);
2346}
Harald Welte05188ee2009-01-18 11:39:08 +00002347
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002348static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002349int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2350{
2351 struct abis_om_hdr *oh;
2352 struct msgb *msg = nm_msgb_alloc();
2353
2354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2355 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2356 0xff, 0xff, 0xff);
2357 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2358
2359 return abis_nm_sendmsg(bts, msg);
2360}
2361
Harald Welteb6c92ae2009-02-21 20:15:32 +00002362/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002363int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2364 uint8_t e1_timeslot, uint8_t e1_subslot,
2365 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002366{
2367 struct abis_om_hdr *oh;
2368 struct abis_nm_channel *ch;
2369 struct msgb *msg = nm_msgb_alloc();
2370
2371 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002372 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002373 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2374
2375 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2376 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002377 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002378
2379 return abis_nm_sendmsg(bts, msg);
2380}
2381
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002382int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002383{
2384 struct abis_om_hdr *oh;
2385 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002386
2387 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002388 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002389 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2390 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2391
2392 return abis_nm_sendmsg(trx->bts, msg);
2393}
2394
Harald Welte78fc0d42009-02-19 02:50:57 +00002395int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2396{
2397 struct abis_om_hdr *oh;
2398 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002399 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002400
2401 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2402 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2403 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2404 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2405
2406 return abis_nm_sendmsg(trx->bts, msg);
2407}
2408
Harald Welteaaf02d92009-04-29 13:25:57 +00002409int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2410{
2411 struct abis_om_hdr *oh;
2412 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002413 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002414
2415 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2416 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2417 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002418 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002419
2420 return abis_nm_sendmsg(bts, msg);
2421}
2422
Harald Welteef061952009-05-17 12:43:42 +00002423int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2424{
2425 struct abis_om_hdr *oh;
2426 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002427 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002428 NM_ATT_BS11_CCLK_TYPE };
2429
2430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2431 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2432 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2433 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2434
2435 return abis_nm_sendmsg(bts, msg);
2436
2437}
Harald Welteaaf02d92009-04-29 13:25:57 +00002438
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002439//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002440
Harald Welte1bc09062009-01-18 14:17:52 +00002441int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002442{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002443 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2444}
2445
Daniel Willmann4b054c82010-01-07 00:46:26 +01002446int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2447{
2448 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2449}
2450
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002451int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002452{
Harald Welte05188ee2009-01-18 11:39:08 +00002453 struct abis_om_hdr *oh;
2454 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002455 struct bs11_date_time bdt;
2456
2457 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002458
2459 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002460 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002461 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002462 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002463 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002464 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002465 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002466 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002467 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002468 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002469 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002470 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002471 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002472 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002473 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002474 }
Harald Welte05188ee2009-01-18 11:39:08 +00002475
2476 return abis_nm_sendmsg(bts, msg);
2477}
Harald Welte1bc09062009-01-18 14:17:52 +00002478
2479int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2480{
2481 struct abis_om_hdr *oh;
2482 struct msgb *msg;
2483
2484 if (strlen(password) != 10)
2485 return -EINVAL;
2486
2487 msg = nm_msgb_alloc();
2488 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002489 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002490 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002491 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002492
2493 return abis_nm_sendmsg(bts, msg);
2494}
2495
Harald Weltee69f5fb2009-04-28 16:31:38 +00002496/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2497int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2498{
2499 struct abis_om_hdr *oh;
2500 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002501 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002502
2503 msg = nm_msgb_alloc();
2504 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2505 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2506 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002507
2508 if (locked)
2509 tlv_value = BS11_LI_PLL_LOCKED;
2510 else
2511 tlv_value = BS11_LI_PLL_STANDALONE;
2512
2513 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002514
2515 return abis_nm_sendmsg(bts, msg);
2516}
2517
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002518/* Set the calibration value of the PLL (work value/set value)
2519 * It depends on the login which one is changed */
2520int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2521{
2522 struct abis_om_hdr *oh;
2523 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002524 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002525
2526 msg = nm_msgb_alloc();
2527 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2528 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2529 BS11_OBJ_TRX1, 0x00, 0x00);
2530
2531 tlv_value[0] = value>>8;
2532 tlv_value[1] = value&0xff;
2533
2534 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2535
2536 return abis_nm_sendmsg(bts, msg);
2537}
2538
Harald Welte1bc09062009-01-18 14:17:52 +00002539int abis_nm_bs11_get_state(struct gsm_bts *bts)
2540{
2541 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2542}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002543
2544/* BS11 SWL */
2545
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002546void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002547
Harald Welte5e4d1b32009-02-01 13:36:56 +00002548struct abis_nm_bs11_sw {
2549 struct gsm_bts *bts;
2550 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002551 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002552 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002553 struct llist_head file_list;
2554 gsm_cbfn *user_cb; /* specified by the user */
2555};
2556static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2557
2558struct file_list_entry {
2559 struct llist_head list;
2560 char fname[PATH_MAX];
2561};
2562
2563struct file_list_entry *fl_dequeue(struct llist_head *queue)
2564{
2565 struct llist_head *lh;
2566
2567 if (llist_empty(queue))
2568 return NULL;
2569
2570 lh = queue->next;
2571 llist_del(lh);
2572
2573 return llist_entry(lh, struct file_list_entry, list);
2574}
2575
2576static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2577{
2578 char linebuf[255];
2579 struct llist_head *lh, *lh2;
2580 FILE *swl;
2581 int rc = 0;
2582
2583 swl = fopen(bs11_sw->swl_fname, "r");
2584 if (!swl)
2585 return -ENODEV;
2586
2587 /* zero the stale file list, if any */
2588 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2589 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002590 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002591 }
2592
2593 while (fgets(linebuf, sizeof(linebuf), swl)) {
2594 char file_id[12+1];
2595 char file_version[80+1];
2596 struct file_list_entry *fle;
2597 static char dir[PATH_MAX];
2598
2599 if (strlen(linebuf) < 4)
2600 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002601
Harald Welte5e4d1b32009-02-01 13:36:56 +00002602 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2603 if (rc < 0) {
2604 perror("ERR parsing SWL file");
2605 rc = -EINVAL;
2606 goto out;
2607 }
2608 if (rc < 2)
2609 continue;
2610
Harald Welte470ec292009-06-26 20:25:23 +02002611 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002612 if (!fle) {
2613 rc = -ENOMEM;
2614 goto out;
2615 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002616
2617 /* construct new filename */
2618 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2619 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2620 strcat(fle->fname, "/");
2621 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002622
2623 llist_add_tail(&fle->list, &bs11_sw->file_list);
2624 }
2625
2626out:
2627 fclose(swl);
2628 return rc;
2629}
2630
2631/* bs11 swload specific callback, passed to abis_nm core swload */
2632static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2633 struct msgb *msg, void *data, void *param)
2634{
2635 struct abis_nm_bs11_sw *bs11_sw = data;
2636 struct file_list_entry *fle;
2637 int rc = 0;
2638
Harald Welte5e4d1b32009-02-01 13:36:56 +00002639 switch (event) {
2640 case NM_MT_LOAD_END_ACK:
2641 fle = fl_dequeue(&bs11_sw->file_list);
2642 if (fle) {
2643 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002644 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002645 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002646 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002647 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002648 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002649 } else {
2650 /* activate the SWL */
2651 rc = abis_nm_software_activate(bs11_sw->bts,
2652 bs11_sw->swl_fname,
2653 bs11_swload_cbfn,
2654 bs11_sw);
2655 }
2656 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002657 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002658 case NM_MT_LOAD_END_NACK:
2659 case NM_MT_LOAD_INIT_ACK:
2660 case NM_MT_LOAD_INIT_NACK:
2661 case NM_MT_ACTIVATE_SW_NACK:
2662 case NM_MT_ACTIVATE_SW_ACK:
2663 default:
2664 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002665 if (bs11_sw->user_cb)
2666 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002667 break;
2668 }
2669
2670 return rc;
2671}
2672
2673/* Siemens provides a SWL file that is a mere listing of all the other
2674 * files that are part of a software release. We need to upload first
2675 * the list file, and then each file that is listed in the list file */
2676int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002677 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002678{
2679 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2680 struct file_list_entry *fle;
2681 int rc = 0;
2682
2683 INIT_LLIST_HEAD(&bs11_sw->file_list);
2684 bs11_sw->bts = bts;
2685 bs11_sw->win_size = win_size;
2686 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002687 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002688
2689 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2690 rc = bs11_read_swl_file(bs11_sw);
2691 if (rc < 0)
2692 return rc;
2693
2694 /* dequeue next item in file list */
2695 fle = fl_dequeue(&bs11_sw->file_list);
2696 if (!fle)
2697 return -EINVAL;
2698
2699 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002700 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002701 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002702 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002703 return rc;
2704}
2705
Harald Welte5083b0b2009-02-02 19:20:52 +00002706#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002707static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002708 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2709 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2710 NM_ATT_BS11_LMT_USER_NAME,
2711
2712 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2713
2714 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2715
2716 NM_ATT_BS11_SW_LOAD_STORED };
2717
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002718static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002719 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2720 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2721 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2722 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002723#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002724
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002725static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002726 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2727 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002728 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002729
2730int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2731{
2732 struct abis_om_hdr *oh;
2733 struct msgb *msg = nm_msgb_alloc();
2734
2735 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2736 /* SiemensHW CCTRL object */
2737 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2738 0x03, 0x00, 0x00);
2739 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2740
2741 return abis_nm_sendmsg(bts, msg);
2742}
Harald Welte268bb402009-02-01 19:11:56 +00002743
2744int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2745{
2746 struct abis_om_hdr *oh;
2747 struct msgb *msg = nm_msgb_alloc();
2748 struct bs11_date_time aet;
2749
2750 get_bs11_date_time(&aet);
2751 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2752 /* SiemensHW CCTRL object */
2753 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2754 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002755 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002756
2757 return abis_nm_sendmsg(bts, msg);
2758}
Harald Welte5c1e4582009-02-15 11:57:29 +00002759
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002760int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002761{
2762 struct abis_om_hdr *oh;
2763 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002764 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002765
2766 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2767 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2768 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2769 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2770
2771 return abis_nm_sendmsg(bts, msg);
2772}
2773
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002774int 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 +02002775{
2776 struct abis_om_hdr *oh;
2777 struct msgb *msg = nm_msgb_alloc();
2778 struct bs11_date_time aet;
2779
2780 get_bs11_date_time(&aet);
2781 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2782 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2783 bport, 0xff, 0x02);
2784 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2785
2786 return abis_nm_sendmsg(bts, msg);
2787}
2788
Harald Welte5c1e4582009-02-15 11:57:29 +00002789/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002790static const char ipaccess_magic[] = "com.ipaccess";
2791
Harald Welte677c21f2009-02-17 13:22:23 +00002792
2793static int abis_nm_rx_ipacc(struct msgb *msg)
2794{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002795 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002796 struct abis_om_hdr *oh = msgb_l2(msg);
2797 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002798 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002799 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002800 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002801
2802 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002803 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002804 return -EINVAL;
2805 }
2806
Harald Welte193fefc2009-04-30 15:16:27 +00002807 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002808 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002809
Harald Weltea8bd6d42009-10-20 09:56:18 +02002810 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002811
Harald Welte746d6092009-10-19 22:11:11 +02002812 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002813
Harald Welte677c21f2009-02-17 13:22:23 +00002814 switch (foh->msg_type) {
2815 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002816 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002817 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2818 memcpy(&addr,
2819 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2820
2821 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2822 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002823 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002824 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002825 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002826 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002827 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2828 DEBUGPC(DNM, "STREAM=0x%02x ",
2829 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002830 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002831 break;
2832 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002833 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002834 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002835 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002836 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002837 else
2838 DEBUGPC(DNM, "\n");
2839 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002840 case NM_MT_IPACC_SET_NVATTR_ACK:
2841 DEBUGPC(DNM, "SET NVATTR ACK\n");
2842 /* FIXME: decode and show the actual attributes */
2843 break;
2844 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002845 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002846 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002847 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002848 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2849 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002850 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002851 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002852 case NM_MT_IPACC_GET_NVATTR_ACK:
2853 DEBUGPC(DNM, "GET NVATTR ACK\n");
2854 /* FIXME: decode and show the actual attributes */
2855 break;
2856 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002857 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002858 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002859 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002860 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2861 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002862 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002863 break;
Harald Welte15c44172009-10-08 20:15:24 +02002864 case NM_MT_IPACC_SET_ATTR_ACK:
2865 DEBUGPC(DNM, "SET ATTR ACK\n");
2866 break;
2867 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002868 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002869 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002870 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002871 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2872 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002873 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002874 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002875 default:
2876 DEBUGPC(DNM, "unknown\n");
2877 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002878 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002879
2880 /* signal handling */
2881 switch (foh->msg_type) {
2882 case NM_MT_IPACC_RSL_CONNECT_NACK:
2883 case NM_MT_IPACC_SET_NVATTR_NACK:
2884 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002885 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002886 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002887 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002888 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002889 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002890 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002891 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002892 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002893 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002894 default:
2895 break;
2896 }
2897
Harald Welte677c21f2009-02-17 13:22:23 +00002898 return 0;
2899}
2900
Harald Welte193fefc2009-04-30 15:16:27 +00002901/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002902int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2903 uint8_t obj_class, uint8_t bts_nr,
2904 uint8_t trx_nr, uint8_t ts_nr,
2905 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002906{
2907 struct msgb *msg = nm_msgb_alloc();
2908 struct abis_om_hdr *oh;
2909 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002910 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002911
2912 /* construct the 12.21 OM header, observe the erroneous length */
2913 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2914 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2915 oh->mdisc = ABIS_OM_MDISC_MANUF;
2916
2917 /* add the ip.access magic */
2918 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2919 *data++ = sizeof(ipaccess_magic);
2920 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2921
2922 /* fill the 12.21 FOM header */
2923 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2924 foh->msg_type = msg_type;
2925 foh->obj_class = obj_class;
2926 foh->obj_inst.bts_nr = bts_nr;
2927 foh->obj_inst.trx_nr = trx_nr;
2928 foh->obj_inst.ts_nr = ts_nr;
2929
2930 if (attr && attr_len) {
2931 data = msgb_put(msg, attr_len);
2932 memcpy(data, attr, attr_len);
2933 }
2934
2935 return abis_nm_sendmsg(bts, msg);
2936}
Harald Welte677c21f2009-02-17 13:22:23 +00002937
Harald Welte193fefc2009-04-30 15:16:27 +00002938/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002939int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002940 int attr_len)
2941{
Harald Welte2ef156d2010-01-07 20:39:42 +01002942 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2943 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002944 attr_len);
2945}
2946
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002947int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002948 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002949{
2950 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002951 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002952 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2953 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2954
2955 int attr_len = sizeof(attr);
2956
2957 ia.s_addr = htonl(ip);
2958 attr[1] = stream;
2959 attr[3] = port >> 8;
2960 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002961 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002962
2963 /* if ip == 0, we use the default IP */
2964 if (ip == 0)
2965 attr_len -= 5;
2966
2967 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002968 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002969
2970 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2971 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2972 trx->nr, 0xff, attr, attr_len);
2973}
2974
Harald Welte193fefc2009-04-30 15:16:27 +00002975/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002976int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002977{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002978 struct abis_om_hdr *oh;
2979 struct msgb *msg = nm_msgb_alloc();
2980
2981 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2982 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2983 trx->bts->nr, trx->nr, 0xff);
2984
2985 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002986}
Harald Weltedaef5212009-10-24 10:20:41 +02002987
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002988int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2989 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2990 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002991{
2992 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2993 obj_class, bts_nr, trx_nr, ts_nr,
2994 attr, attr_len);
2995}
Harald Welte0f255852009-11-12 14:48:42 +01002996
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002997void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002998{
2999 /* we simply reuse the GSM48 function and overwrite the RAC
3000 * with the Cell ID */
3001 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003002 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08003003}
3004
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003005void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
3006{
3007 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
3008
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01003009 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01003010 if (!trx->bts || !trx->bts->oml_link)
3011 return;
3012
3013 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3014 trx->bts->bts_nr, trx->nr, 0xff,
3015 new_state);
3016}
3017
Harald Welte92b1fe42010-03-25 11:45:30 +08003018static const struct value_string ipacc_testres_names[] = {
3019 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3020 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3021 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3022 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3023 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3024 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01003025};
3026
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003027const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01003028{
Harald Welte92b1fe42010-03-25 11:45:30 +08003029 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003030}
3031
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003032void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01003033{
3034 cid->mcc = (buf[0] & 0xf) * 100;
3035 cid->mcc += (buf[0] >> 4) * 10;
3036 cid->mcc += (buf[1] & 0xf) * 1;
3037
3038 if (buf[1] >> 4 == 0xf) {
3039 cid->mnc = (buf[2] & 0xf) * 10;
3040 cid->mnc += (buf[2] >> 4) * 1;
3041 } else {
3042 cid->mnc = (buf[2] & 0xf) * 100;
3043 cid->mnc += (buf[2] >> 4) * 10;
3044 cid->mnc += (buf[1] >> 4) * 1;
3045 }
3046
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003047 cid->lac = ntohs(*((uint16_t *)&buf[3]));
3048 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003049}
3050
Harald Welte0f255852009-11-12 14:48:42 +01003051/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003052int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01003053{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003054 uint8_t *cur = buf;
3055 uint16_t len;
Harald Welte0f255852009-11-12 14:48:42 +01003056
Harald Welteaf109b92010-07-22 18:14:36 +02003057 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003058
3059 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3060 return -EINVAL;
3061 cur++;
3062
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003063 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003064 cur += 2;
3065
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003066 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003067 cur += 2;
3068
3069 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3070 binf->freq_qual = *cur >> 2;
3071
Harald Welteaf109b92010-07-22 18:14:36 +02003072 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003073 binf->arfcn |= *cur++;
3074
3075 if (binf->info_type & IPAC_BINF_RXLEV)
3076 binf->rx_lev = *cur & 0x3f;
3077 cur++;
3078
3079 if (binf->info_type & IPAC_BINF_RXQUAL)
3080 binf->rx_qual = *cur & 0x7;
3081 cur++;
3082
3083 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003084 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003085 cur += 2;
3086
3087 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003088 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003089 cur += 2;
3090
3091 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02003092 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01003093 cur += 4;
3094
Harald Weltea780a3d2010-07-30 22:34:42 +02003095#if 0
3096 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003097 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003098#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003099 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003100 cur++;
3101
Harald Welteb40a38f2009-11-13 11:56:05 +01003102 ipac_parse_cgi(&binf->cgi, cur);
3103 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003104
3105 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3106 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3107 cur += sizeof(binf->ba_list_si2);
3108 }
3109
3110 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3111 memcpy(binf->ba_list_si2bis, cur,
3112 sizeof(binf->ba_list_si2bis));
3113 cur += sizeof(binf->ba_list_si2bis);
3114 }
3115
3116 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3117 memcpy(binf->ba_list_si2ter, cur,
3118 sizeof(binf->ba_list_si2ter));
3119 cur += sizeof(binf->ba_list_si2ter);
3120 }
3121
3122 return 0;
3123}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003124
3125void abis_nm_clear_queue(struct gsm_bts *bts)
3126{
3127 struct msgb *msg;
3128
3129 while (!llist_empty(&bts->abis_queue)) {
3130 msg = msgb_dequeue(&bts->abis_queue);
3131 msgb_free(msg);
3132 }
3133
3134 bts->abis_nm_pend = 0;
3135}