blob: 8bcc96bac14e46c7a5963b7372d1e7f1a763c010 [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
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (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
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000026#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000027#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000028#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000029#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000030#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000031#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000032#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000033
Harald Welte52b1f982008-12-23 20:25:15 +000034#include <sys/types.h>
Harald Welte4724f992009-01-18 18:01:49 +000035#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000036#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000037#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000038
Harald Welte8470bf22008-12-25 23:28:35 +000039#include <openbsc/gsm_data.h>
40#include <openbsc/debug.h>
Harald Weltedfe6c7d2010-02-20 16:24:02 +010041#include <osmocore/msgb.h>
42#include <osmocore/tlv.h>
43#include <osmocore/talloc.h>
Harald Welte8470bf22008-12-25 23:28:35 +000044#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000045#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000046#include <openbsc/signal.h>
Harald Welte52b1f982008-12-23 20:25:15 +000047
Harald Welte8470bf22008-12-25 23:28:35 +000048#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000051
52/* unidirectional messages from BTS to BSC */
53static const enum abis_nm_msgtype reports[] = {
54 NM_MT_SW_ACTIVATED_REP,
55 NM_MT_TEST_REP,
56 NM_MT_STATECHG_EVENT_REP,
57 NM_MT_FAILURE_EVENT_REP,
58};
59
60/* messages without ACK/NACK */
61static const enum abis_nm_msgtype no_ack_nack[] = {
62 NM_MT_MEAS_RES_REQ,
63 NM_MT_STOP_MEAS,
64 NM_MT_START_MEAS,
65};
66
Harald Welte4724f992009-01-18 18:01:49 +000067/* Messages related to software load */
68static const enum abis_nm_msgtype sw_load_msgs[] = {
69 NM_MT_LOAD_INIT_ACK,
70 NM_MT_LOAD_INIT_NACK,
71 NM_MT_LOAD_SEG_ACK,
72 NM_MT_LOAD_ABORT,
73 NM_MT_LOAD_END_ACK,
74 NM_MT_LOAD_END_NACK,
Harald Welte34a99682009-02-13 02:41:40 +000075 //NM_MT_SW_ACT_REQ,
Harald Welte4724f992009-01-18 18:01:49 +000076 NM_MT_ACTIVATE_SW_ACK,
77 NM_MT_ACTIVATE_SW_NACK,
78 NM_MT_SW_ACTIVATED_REP,
79};
80
Harald Weltee0590df2009-02-15 03:34:15 +000081static const enum abis_nm_msgtype nacks[] = {
82 NM_MT_LOAD_INIT_NACK,
83 NM_MT_LOAD_END_NACK,
84 NM_MT_SW_ACT_REQ_NACK,
85 NM_MT_ACTIVATE_SW_NACK,
86 NM_MT_ESTABLISH_TEI_NACK,
87 NM_MT_CONN_TERR_SIGN_NACK,
88 NM_MT_DISC_TERR_SIGN_NACK,
89 NM_MT_CONN_TERR_TRAF_NACK,
90 NM_MT_DISC_TERR_TRAF_NACK,
91 NM_MT_CONN_MDROP_LINK_NACK,
92 NM_MT_DISC_MDROP_LINK_NACK,
93 NM_MT_SET_BTS_ATTR_NACK,
94 NM_MT_SET_RADIO_ATTR_NACK,
95 NM_MT_SET_CHAN_ATTR_NACK,
96 NM_MT_PERF_TEST_NACK,
97 NM_MT_SEND_TEST_REP_NACK,
98 NM_MT_STOP_TEST_NACK,
99 NM_MT_STOP_EVENT_REP_NACK,
100 NM_MT_REST_EVENT_REP_NACK,
101 NM_MT_CHG_ADM_STATE_NACK,
102 NM_MT_CHG_ADM_STATE_REQ_NACK,
103 NM_MT_REP_OUTST_ALARMS_NACK,
104 NM_MT_CHANGEOVER_NACK,
105 NM_MT_OPSTART_NACK,
106 NM_MT_REINIT_NACK,
107 NM_MT_SET_SITE_OUT_NACK,
108 NM_MT_CHG_HW_CONF_NACK,
109 NM_MT_GET_ATTR_NACK,
110 NM_MT_SET_ALARM_THRES_NACK,
111 NM_MT_BS11_BEGIN_DB_TX_NACK,
112 NM_MT_BS11_END_DB_TX_NACK,
113 NM_MT_BS11_CREATE_OBJ_NACK,
114 NM_MT_BS11_DELETE_OBJ_NACK,
115};
Harald Welte78fc0d42009-02-19 02:50:57 +0000116
Harald Welte92b1fe42010-03-25 11:45:30 +0800117static const struct value_string nack_names[] = {
118 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
119 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
120 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
121 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
122 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
123 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
124 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
125 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
126 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
127 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
128 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
129 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
130 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
131 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
132 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
133 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
134 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
135 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
136 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
137 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
138 { NM_MT_CHG_ADM_STATE_REQ_NACK,
139 "CHANGE ADMINISTRATIVE STATE REQUEST" },
140 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
141 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
142 { NM_MT_OPSTART_NACK, "OPSTART" },
143 { NM_MT_REINIT_NACK, "REINIT" },
144 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
145 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
146 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
147 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
148 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
149 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
150 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
151 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
152 { 0, NULL }
Harald Welte78fc0d42009-02-19 02:50:57 +0000153};
154
Harald Welte6c96ba52009-05-01 13:03:40 +0000155/* Chapter 9.4.36 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800156static const struct value_string nack_cause_names[] = {
Harald Welte6c96ba52009-05-01 13:03:40 +0000157 /* General Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800158 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
159 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
160 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
161 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
162 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
163 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
164 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
165 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
166 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
167 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
168 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
169 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
170 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte6c96ba52009-05-01 13:03:40 +0000171 /* Specific Nack Causes */
Harald Welte92b1fe42010-03-25 11:45:30 +0800172 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
173 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
174 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
175 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
176 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
177 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
178 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
179 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
180 { NM_NACK_TEST_NOSUCH, "No such test" },
181 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
182 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
183 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
184 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
185 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
186 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
187 { NM_NACK_WAIT, "Wait" },
188 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
189 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
190 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
191 { 0, NULL }
Harald Welte6c96ba52009-05-01 13:03:40 +0000192};
193
Harald Welte6c96ba52009-05-01 13:03:40 +0000194static const char *nack_cause_name(u_int8_t cause)
195{
Harald Welte92b1fe42010-03-25 11:45:30 +0800196 return get_value_string(nack_cause_names, cause);
Harald Welte6c96ba52009-05-01 13:03:40 +0000197}
198
Harald Welte0db97b22009-05-01 17:22:47 +0000199/* Chapter 9.4.16: Event Type */
Harald Welte92b1fe42010-03-25 11:45:30 +0800200static const struct value_string event_type_names[] = {
201 { NM_EVT_COMM_FAIL, "communication failure" },
202 { NM_EVT_QOS_FAIL, "quality of service failure" },
203 { NM_EVT_PROC_FAIL, "processing failure" },
204 { NM_EVT_EQUIP_FAIL, "equipment failure" },
205 { NM_EVT_ENV_FAIL, "environment failure" },
206 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000207};
208
209static const char *event_type_name(u_int8_t cause)
210{
Harald Welte92b1fe42010-03-25 11:45:30 +0800211 return get_value_string(event_type_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000212}
213
214/* Chapter 9.4.63: Perceived Severity */
Harald Welte92b1fe42010-03-25 11:45:30 +0800215static const struct value_string severity_names[] = {
216 { NM_SEVER_CEASED, "failure ceased" },
217 { NM_SEVER_CRITICAL, "critical failure" },
218 { NM_SEVER_MAJOR, "major failure" },
219 { NM_SEVER_MINOR, "minor failure" },
220 { NM_SEVER_WARNING, "warning level failure" },
221 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
222 { 0, NULL }
Harald Welte0db97b22009-05-01 17:22:47 +0000223};
224
225static const char *severity_name(u_int8_t cause)
226{
Harald Welte92b1fe42010-03-25 11:45:30 +0800227 return get_value_string(severity_names, cause);
Harald Welte0db97b22009-05-01 17:22:47 +0000228}
229
Harald Welte52b1f982008-12-23 20:25:15 +0000230/* Attributes that the BSC can set, not only get, according to Section 9.4 */
231static const enum abis_nm_attr nm_att_settable[] = {
232 NM_ATT_ADD_INFO,
233 NM_ATT_ADD_TEXT,
234 NM_ATT_DEST,
235 NM_ATT_EVENT_TYPE,
236 NM_ATT_FILE_DATA,
237 NM_ATT_GET_ARI,
238 NM_ATT_HW_CONF_CHG,
239 NM_ATT_LIST_REQ_ATTR,
240 NM_ATT_MDROP_LINK,
241 NM_ATT_MDROP_NEXT,
242 NM_ATT_NACK_CAUSES,
243 NM_ATT_OUTST_ALARM,
244 NM_ATT_PHYS_CONF,
245 NM_ATT_PROB_CAUSE,
246 NM_ATT_RAD_SUBC,
247 NM_ATT_SOURCE,
248 NM_ATT_SPEC_PROB,
249 NM_ATT_START_TIME,
250 NM_ATT_TEST_DUR,
251 NM_ATT_TEST_NO,
252 NM_ATT_TEST_REPORT,
253 NM_ATT_WINDOW_SIZE,
254 NM_ATT_SEVERITY,
255 NM_ATT_MEAS_RES,
256 NM_ATT_MEAS_TYPE,
257};
258
Harald Welte39315c42010-01-10 18:01:52 +0100259const struct tlv_definition nm_att_tlvdef = {
Harald Weltee0590df2009-02-15 03:34:15 +0000260 .def = {
261 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
262 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
264 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
265 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
266 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
267 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
268 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
269 [NM_ATT_BSIC] = { TLV_TYPE_TV },
270 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
272 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
273 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
274 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
275 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
276 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
277 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
279 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
280 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
281 [NM_ATT_HSN] = { TLV_TYPE_TV },
282 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
283 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
284 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
285 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
286 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
287 [NM_ATT_MAIO] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
289 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
290 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
291 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
292 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
294 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
295 [NM_ATT_NY1] = { TLV_TYPE_TV },
296 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
297 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
298 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
299 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
300 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
302 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
303 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
304 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
305 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
306 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
308 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
309 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
310 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
311 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
312 [NM_ATT_TEI] = { TLV_TYPE_TV },
313 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
314 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
315 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
316 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
317 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
318 [NM_ATT_TSC] = { TLV_TYPE_TV },
319 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
320 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
321 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
322 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
323 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Weltee0590df2009-02-15 03:34:15 +0000324 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Weltee0590df2009-02-15 03:34:15 +0000325 },
326};
Harald Welte03133942009-02-18 19:51:53 +0000327
Harald Welte21bd3a52009-08-10 12:21:22 +0200328static const enum abis_nm_chan_comb chcomb4pchan[] = {
329 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
330 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
331 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
332 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
333 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Weltea1499d02009-10-24 10:25:50 +0200334 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
335 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte21bd3a52009-08-10 12:21:22 +0200336 /* FIXME: bounds check */
337};
338
339int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
340{
341 if (pchan < ARRAY_SIZE(chcomb4pchan))
342 return chcomb4pchan[pchan];
343
344 return -EINVAL;
345}
346
Harald Welte39315c42010-01-10 18:01:52 +0100347int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +0000348{
Harald Welte39315c42010-01-10 18:01:52 +0100349 if (!bts->model)
350 return -EIO;
351 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +0000352}
Harald Weltee0590df2009-02-15 03:34:15 +0000353
Harald Welte52b1f982008-12-23 20:25:15 +0000354static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
355{
356 int i;
357
358 for (i = 0; i < size; i++) {
359 if (arr[i] == mt)
360 return 1;
361 }
362
363 return 0;
364}
365
Holger Freytherca362a62009-01-04 21:05:01 +0000366#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000367/* is this msgtype the usual ACK/NACK type ? */
368static int is_ack_nack(enum abis_nm_msgtype mt)
369{
370 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
371}
Holger Freytherca362a62009-01-04 21:05:01 +0000372#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000373
374/* is this msgtype a report ? */
375static int is_report(enum abis_nm_msgtype mt)
376{
Harald Welte8470bf22008-12-25 23:28:35 +0000377 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000378}
379
380#define MT_ACK(x) (x+1)
381#define MT_NACK(x) (x+2)
382
383static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
384{
385 oh->mdisc = ABIS_OM_MDISC_FOM;
386 oh->placement = ABIS_OM_PLACEMENT_ONLY;
387 oh->sequence = 0;
388 oh->length = len;
389}
390
391static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
392 u_int8_t msg_type, u_int8_t obj_class,
393 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
394{
395 struct abis_om_fom_hdr *foh =
396 (struct abis_om_fom_hdr *) oh->data;
397
Harald Welte702d8702008-12-26 20:25:35 +0000398 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000399 foh->msg_type = msg_type;
400 foh->obj_class = obj_class;
401 foh->obj_inst.bts_nr = bts_nr;
402 foh->obj_inst.trx_nr = trx_nr;
403 foh->obj_inst.ts_nr = ts_nr;
404}
405
Harald Welte8470bf22008-12-25 23:28:35 +0000406static struct msgb *nm_msgb_alloc(void)
407{
Harald Welte966636f2009-06-26 19:39:35 +0200408 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
409 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000410}
411
Harald Welte52b1f982008-12-23 20:25:15 +0000412/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100413static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000414{
Holger Freyther59639e82009-02-09 23:09:55 +0000415 msg->trx = bts->c0;
416
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100417 /* queue OML messages */
418 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
419 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
420 return _abis_nm_sendmsg(msg);
421 } else {
422 msgb_enqueue(&bts->abis_queue, msg);
423 return 0;
424 }
425
426}
427
428int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
429{
430 OBSC_NM_W_ACK_CB(msg) = 1;
431 return abis_nm_queue_msg(bts, msg);
432}
433
434static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
435{
436 OBSC_NM_W_ACK_CB(msg) = 0;
437 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000438}
439
Harald Welte4724f992009-01-18 18:01:49 +0000440static int abis_nm_rcvmsg_sw(struct msgb *mb);
441
Harald Welte81c9b9c2010-05-31 16:40:40 +0200442const struct value_string abis_nm_obj_class_names[] = {
443 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800444 { NM_OC_BTS, "BTS" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200445 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
446 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800447 { NM_OC_CHANNEL, "CHANNEL" },
448 { NM_OC_BS11_ADJC, "ADJC" },
449 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200450 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800451 { NM_OC_BS11_BTSE, "BTSE" },
452 { NM_OC_BS11_RACK, "RACK" },
453 { NM_OC_BS11_TEST, "TEST" },
454 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
455 { NM_OC_BS11_BPORT, "BPORT" },
Harald Welte81c9b9c2010-05-31 16:40:40 +0200456 { NM_OC_GPRS_NSE, "GPRS-NSE" },
457 { NM_OC_GPRS_CELL, "GPRS-CELL" },
458 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte92b1fe42010-03-25 11:45:30 +0800459 { NM_OC_BS11, "SIEMENSHW" },
460 { 0, NULL }
461};
462
Harald Welte34a99682009-02-13 02:41:40 +0000463static const char *obj_class_name(u_int8_t oc)
464{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200465 return get_value_string(abis_nm_obj_class_names, oc);
Harald Welte34a99682009-02-13 02:41:40 +0000466}
467
Harald Welte4d87f242009-03-10 19:43:44 +0000468const char *nm_opstate_name(u_int8_t os)
Harald Welte34a99682009-02-13 02:41:40 +0000469{
470 switch (os) {
Harald Welted6847a92009-12-24 10:06:33 +0100471 case NM_OPSTATE_DISABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000472 return "Disabled";
Harald Welted6847a92009-12-24 10:06:33 +0100473 case NM_OPSTATE_ENABLED:
Harald Welte34a99682009-02-13 02:41:40 +0000474 return "Enabled";
Harald Welted6847a92009-12-24 10:06:33 +0100475 case NM_OPSTATE_NULL:
Harald Welte34a99682009-02-13 02:41:40 +0000476 return "NULL";
477 default:
478 return "RFU";
479 }
480}
481
Harald Weltee0590df2009-02-15 03:34:15 +0000482/* Chapter 9.4.7 */
Harald Welte92b1fe42010-03-25 11:45:30 +0800483static const struct value_string avail_names[] = {
484 { 0, "In test" },
485 { 1, "Failed" },
486 { 2, "Power off" },
487 { 3, "Off line" },
488 /* Not used */
489 { 5, "Dependency" },
490 { 6, "Degraded" },
491 { 7, "Not installed" },
492 { 0xff, "OK" },
493 { 0, NULL }
Harald Weltee0590df2009-02-15 03:34:15 +0000494};
495
Harald Welte4d87f242009-03-10 19:43:44 +0000496const char *nm_avail_name(u_int8_t avail)
Harald Weltee0590df2009-02-15 03:34:15 +0000497{
Harald Welte92b1fe42010-03-25 11:45:30 +0800498 return get_value_string(avail_names, avail);
Harald Weltee0590df2009-02-15 03:34:15 +0000499}
Harald Welte7b26bcb2009-05-28 11:39:21 +0000500
Harald Welte0f255852009-11-12 14:48:42 +0100501static struct value_string test_names[] = {
502 /* FIXME: standard test names */
503 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
504 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
505 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
506 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
507 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
508 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
509 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
510 { 0, NULL }
511};
512
Harald Welte81c9b9c2010-05-31 16:40:40 +0200513const struct value_string abis_nm_adm_state_names[] = {
514 { NM_STATE_LOCKED, "Locked" },
515 { NM_STATE_UNLOCKED, "Unlocked" },
516 { NM_STATE_SHUTDOWN, "Shutdown" },
517 { NM_STATE_NULL, "NULL" },
518 { 0, NULL }
519};
520
Harald Welte7b26bcb2009-05-28 11:39:21 +0000521const char *nm_adm_name(u_int8_t adm)
522{
Harald Welte81c9b9c2010-05-31 16:40:40 +0200523 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte7b26bcb2009-05-28 11:39:21 +0000524}
Harald Weltee0590df2009-02-15 03:34:15 +0000525
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100526int nm_is_running(struct gsm_nm_state *s) {
527 return (s->operational == NM_OPSTATE_ENABLED) && (
528 (s->availability == NM_AVSTATE_OK) ||
529 (s->availability == 0xff)
530 );
531}
532
Harald Weltea8bd6d42009-10-20 09:56:18 +0200533static void debugp_foh(struct abis_om_fom_hdr *foh)
534{
535 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200536 obj_class_name(foh->obj_class), foh->obj_class,
Harald Weltea8bd6d42009-10-20 09:56:18 +0200537 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
538 foh->obj_inst.ts_nr);
539}
540
Harald Weltee0590df2009-02-15 03:34:15 +0000541/* obtain the gsm_nm_state data structure for a given object instance */
542static struct gsm_nm_state *
543objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
544 struct abis_om_obj_inst *obj_inst)
545{
546 struct gsm_bts_trx *trx;
547 struct gsm_nm_state *nm_state = NULL;
548
549 switch (obj_class) {
550 case NM_OC_BTS:
551 nm_state = &bts->nm_state;
552 break;
553 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100554 if (obj_inst->trx_nr >= bts->num_trx) {
555 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000556 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100557 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200558 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000559 nm_state = &trx->nm_state;
560 break;
561 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100562 if (obj_inst->trx_nr >= bts->num_trx) {
563 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000564 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100565 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200566 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000567 nm_state = &trx->bb_transc.nm_state;
568 break;
569 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100570 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100571 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000572 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100573 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200574 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000575 if (obj_inst->ts_nr >= TRX_NR_TS)
576 return NULL;
577 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
578 break;
579 case NM_OC_SITE_MANAGER:
580 nm_state = &bts->site_mgr.nm_state;
581 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000582 case NM_OC_BS11:
583 switch (obj_inst->bts_nr) {
584 case BS11_OBJ_CCLK:
585 nm_state = &bts->bs11.cclk.nm_state;
586 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000587 case BS11_OBJ_BBSIG:
588 if (obj_inst->ts_nr > bts->num_trx)
589 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200590 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000591 nm_state = &trx->bs11.bbsig.nm_state;
592 break;
593 case BS11_OBJ_PA:
594 if (obj_inst->ts_nr > bts->num_trx)
595 return NULL;
Harald Weltee441d9c2009-06-21 16:17:15 +0200596 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte8b697c72009-06-05 19:18:45 +0000597 nm_state = &trx->bs11.pa.nm_state;
598 break;
Harald Welte7b26bcb2009-05-28 11:39:21 +0000599 default:
600 return NULL;
601 }
602 case NM_OC_BS11_RACK:
603 nm_state = &bts->bs11.rack.nm_state;
604 break;
Harald Welte8b697c72009-06-05 19:18:45 +0000605 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100606 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte8b697c72009-06-05 19:18:45 +0000607 return NULL;
608 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
609 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200610 case NM_OC_GPRS_NSE:
611 nm_state = &bts->gprs.nse.nm_state;
612 break;
613 case NM_OC_GPRS_CELL:
614 nm_state = &bts->gprs.cell.nm_state;
615 break;
616 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100617 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200618 return NULL;
619 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
620 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000621 }
622 return nm_state;
623}
624
625/* obtain the in-memory data structure of a given object instance */
626static void *
627objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
628 struct abis_om_obj_inst *obj_inst)
629{
630 struct gsm_bts_trx *trx;
631 void *obj = NULL;
632
633 switch (obj_class) {
634 case NM_OC_BTS:
635 obj = bts;
636 break;
637 case NM_OC_RADIO_CARRIER:
Harald Welte999549d2009-11-13 12:10:18 +0100638 if (obj_inst->trx_nr >= bts->num_trx) {
639 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000640 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100641 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200642 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000643 obj = trx;
644 break;
645 case NM_OC_BASEB_TRANSC:
Harald Welte999549d2009-11-13 12:10:18 +0100646 if (obj_inst->trx_nr >= bts->num_trx) {
647 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000648 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100649 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200650 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000651 obj = &trx->bb_transc;
652 break;
653 case NM_OC_CHANNEL:
Holger Hans Peter Freyther17c24c92009-12-21 16:56:28 +0100654 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte999549d2009-11-13 12:10:18 +0100655 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000656 return NULL;
Harald Welte999549d2009-11-13 12:10:18 +0100657 }
Harald Weltee441d9c2009-06-21 16:17:15 +0200658 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Weltee0590df2009-02-15 03:34:15 +0000659 if (obj_inst->ts_nr >= TRX_NR_TS)
660 return NULL;
661 obj = &trx->ts[obj_inst->ts_nr];
662 break;
663 case NM_OC_SITE_MANAGER:
664 obj = &bts->site_mgr;
665 break;
Harald Welte55dd4432009-10-24 10:19:14 +0200666 case NM_OC_GPRS_NSE:
667 obj = &bts->gprs.nse;
668 break;
669 case NM_OC_GPRS_CELL:
670 obj = &bts->gprs.cell;
671 break;
672 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther306b7212009-12-21 17:06:07 +0100673 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte55dd4432009-10-24 10:19:14 +0200674 return NULL;
675 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
676 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000677 }
678 return obj;
679}
680
681/* Update the administrative state of a given object in our in-memory data
682 * structures and send an event to the higher layer */
683static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
684 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
685{
Harald Welteaeedeb42009-05-01 13:08:14 +0000686 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000687 void *obj;
688 int rc;
689
Harald Weltee0590df2009-02-15 03:34:15 +0000690 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte999549d2009-11-13 12:10:18 +0100691 if (!obj)
692 return -EINVAL;
Harald Welteaeedeb42009-05-01 13:08:14 +0000693 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
694 if (!nm_state)
695 return -1;
696
697 new_state = *nm_state;
698 new_state.administrative = adm_state;
699
Holger Hans Peter Freytheraa0db802010-05-13 00:37:48 +0800700 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000701
702 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000703
704 return rc;
705}
706
Harald Welte97ed1e72009-02-06 13:38:02 +0000707static int abis_nm_rx_statechg_rep(struct msgb *mb)
708{
Harald Weltee0590df2009-02-15 03:34:15 +0000709 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000710 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Harald Welte22af0db2009-02-14 15:41:08 +0000711 struct gsm_bts *bts = mb->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000712 struct tlv_parsed tp;
713 struct gsm_nm_state *nm_state, new_state;
714 int rc;
715
Harald Welte23897662009-05-01 14:52:51 +0000716 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000717
Harald Welte8b697c72009-06-05 19:18:45 +0000718 memset(&new_state, 0, sizeof(new_state));
719
Harald Weltee0590df2009-02-15 03:34:15 +0000720 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
721 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100722 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000723 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000724 }
Harald Weltee0590df2009-02-15 03:34:15 +0000725
726 new_state = *nm_state;
727
Harald Welte39315c42010-01-10 18:01:52 +0100728 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000729 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
730 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte4d87f242009-03-10 19:43:44 +0000731 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000732 }
733 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000734 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
735 new_state.availability = 0xff;
736 else
737 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte4d87f242009-03-10 19:43:44 +0000738 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000739 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100740 } else
741 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000742 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
743 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther2c481b22009-10-22 15:44:30 +0200744 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000745 }
746 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000747
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100748 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
749 new_state.operational != nm_state->operational ||
750 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000751 /* Update the operational state of a given object in our in-memory data
752 * structures and send an event to the higher layer */
753 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Holger Hans Peter Freytheraa0db802010-05-13 00:37:48 +0800754 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100755 nm_state->operational = new_state.operational;
756 nm_state->availability = new_state.availability;
757 if (nm_state->administrative == 0)
758 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000759 }
760#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000761 if (op_state == 1) {
762 /* try to enable objects that are disabled */
763 abis_nm_opstart(bts, foh->obj_class,
764 foh->obj_inst.bts_nr,
765 foh->obj_inst.trx_nr,
766 foh->obj_inst.ts_nr);
767 }
Harald Weltee0590df2009-02-15 03:34:15 +0000768#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000769 return 0;
770}
771
Harald Welte0db97b22009-05-01 17:22:47 +0000772static int rx_fail_evt_rep(struct msgb *mb)
773{
774 struct abis_om_hdr *oh = msgb_l2(mb);
775 struct abis_om_fom_hdr *foh = msgb_l3(mb);
776 struct tlv_parsed tp;
777
778 DEBUGPC(DNM, "Failure Event Report ");
779
Harald Welte39315c42010-01-10 18:01:52 +0100780 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte0db97b22009-05-01 17:22:47 +0000781
782 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
783 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
784 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
785 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
786
787 DEBUGPC(DNM, "\n");
788
789 return 0;
790}
791
Harald Welte97ed1e72009-02-06 13:38:02 +0000792static int abis_nm_rcvmsg_report(struct msgb *mb)
793{
794 struct abis_om_fom_hdr *foh = msgb_l3(mb);
795 u_int8_t mt = foh->msg_type;
796
Harald Weltea8bd6d42009-10-20 09:56:18 +0200797 debugp_foh(foh);
Harald Welte23897662009-05-01 14:52:51 +0000798
Harald Welte97ed1e72009-02-06 13:38:02 +0000799 //nmh->cfg->report_cb(mb, foh);
800
801 switch (mt) {
802 case NM_MT_STATECHG_EVENT_REP:
803 return abis_nm_rx_statechg_rep(mb);
804 break;
Harald Welte34a99682009-02-13 02:41:40 +0000805 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000806 DEBUGPC(DNM, "Software Activated Report\n");
Harald Weltef9a8cc32009-05-01 15:39:49 +0000807 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000808 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000809 case NM_MT_FAILURE_EVENT_REP:
Harald Welte0db97b22009-05-01 17:22:47 +0000810 rx_fail_evt_rep(mb);
Harald Weltef9a8cc32009-05-01 15:39:49 +0000811 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000812 break;
Harald Weltec7310382009-08-08 00:02:36 +0200813 case NM_MT_TEST_REP:
814 DEBUGPC(DNM, "Test Report\n");
815 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
816 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000817 default:
Harald Welte23897662009-05-01 14:52:51 +0000818 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000819 break;
820
Harald Welte97ed1e72009-02-06 13:38:02 +0000821 };
822
Harald Welte97ed1e72009-02-06 13:38:02 +0000823 return 0;
824}
825
Harald Welte34a99682009-02-13 02:41:40 +0000826/* Activate the specified software into the BTS */
827static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
Mike Habena03f9772009-10-01 14:56:13 +0200828 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000829{
830 struct abis_om_hdr *oh;
831 struct msgb *msg = nm_msgb_alloc();
832 u_int8_t len = swdesc_len;
833 u_int8_t *trailer;
834
835 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
836 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
837
838 trailer = msgb_put(msg, swdesc_len);
839 memcpy(trailer, sw_desc, swdesc_len);
840
841 return abis_nm_sendmsg(bts, msg);
842}
843
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100844static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
845{
846 static const struct tlv_definition sw_descr_def = {
847 .def = {
848 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
849 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
850 },
851 };
852
853 u_int8_t tag;
854 u_int16_t tag_len;
855 const u_int8_t *val;
856 int ofs = 0, len;
857
858 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
859 * nested nature and the fact you have to assume it contains only two sub
860 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
861
862 if (sw_descr[0] != NM_ATT_SW_DESCR) {
863 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
864 return -1;
865 }
866 ofs += 1;
867
868 len = tlv_parse_one(&tag, &tag_len, &val,
869 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
870 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
871 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
872 return -2;
873 }
874 ofs += len;
875
876 len = tlv_parse_one(&tag, &tag_len, &val,
877 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
878 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
879 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
880 return -3;
881 }
882 ofs += len;
883
884 return ofs;
885}
886
Harald Welte34a99682009-02-13 02:41:40 +0000887static int abis_nm_rx_sw_act_req(struct msgb *mb)
888{
889 struct abis_om_hdr *oh = msgb_l2(mb);
890 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Habena03f9772009-10-01 14:56:13 +0200891 struct tlv_parsed tp;
892 const u_int8_t *sw_config;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100893 int ret, sw_config_len, sw_descr_len;
Harald Welte34a99682009-02-13 02:41:40 +0000894
Harald Weltea8bd6d42009-10-20 09:56:18 +0200895 debugp_foh(foh);
896
897 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000898
Harald Welte97a282b2010-03-14 15:37:43 +0800899 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000900
901 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000902 foh->obj_inst.bts_nr,
903 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800904 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000905 foh->data, oh->length-sizeof(*foh));
906
Harald Welte39315c42010-01-10 18:01:52 +0100907 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200908 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
909 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
910 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
911 DEBUGP(DNM, "SW config not found! Can't continue.\n");
912 return -EINVAL;
913 } else {
914 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
915 }
916
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100917 /* Use the first SW_DESCR present in SW config */
918 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
919 if (sw_descr_len < 0)
920 return -EINVAL;
Mike Habena03f9772009-10-01 14:56:13 +0200921
Harald Welte34a99682009-02-13 02:41:40 +0000922 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
923 foh->obj_inst.bts_nr,
924 foh->obj_inst.trx_nr,
925 foh->obj_inst.ts_nr,
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100926 sw_config, sw_descr_len);
Harald Welte34a99682009-02-13 02:41:40 +0000927}
928
Harald Weltee0590df2009-02-15 03:34:15 +0000929/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
930static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
931{
932 struct abis_om_hdr *oh = msgb_l2(mb);
933 struct abis_om_fom_hdr *foh = msgb_l3(mb);
934 struct tlv_parsed tp;
935 u_int8_t adm_state;
936
Harald Welte39315c42010-01-10 18:01:52 +0100937 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000938 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
939 return -EINVAL;
940
941 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
942
943 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
944}
945
Harald Welteee670472009-02-22 21:58:49 +0000946static int abis_nm_rx_lmt_event(struct msgb *mb)
947{
948 struct abis_om_hdr *oh = msgb_l2(mb);
949 struct abis_om_fom_hdr *foh = msgb_l3(mb);
950 struct tlv_parsed tp;
951
952 DEBUGP(DNM, "LMT Event ");
Harald Welte39315c42010-01-10 18:01:52 +0100953 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000954 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
955 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
956 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
957 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
958 }
959 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
960 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
961 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
962 DEBUGPC(DNM, "Level=%u ", level);
963 }
964 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
965 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
966 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
967 DEBUGPC(DNM, "Username=%s ", name);
968 }
969 DEBUGPC(DNM, "\n");
970 /* FIXME: parse LMT LOGON TIME */
971 return 0;
972}
973
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100974static void abis_nm_queue_send_next(struct gsm_bts *bts)
975{
976 int wait = 0;
977 struct msgb *msg;
978 /* the queue is empty */
979 while (!llist_empty(&bts->abis_queue)) {
980 msg = msgb_dequeue(&bts->abis_queue);
981 wait = OBSC_NM_W_ACK_CB(msg);
982 _abis_nm_sendmsg(msg);
983
984 if (wait)
985 break;
986 }
987
988 bts->abis_nm_pend = wait;
989}
990
Harald Welte52b1f982008-12-23 20:25:15 +0000991/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000992static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000993{
Harald Welte6c96ba52009-05-01 13:03:40 +0000994 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000995 struct abis_om_fom_hdr *foh = msgb_l3(mb);
996 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100997 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000998
999 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +00001000 if (is_report(mt))
1001 return abis_nm_rcvmsg_report(mb);
Harald Welte52b1f982008-12-23 20:25:15 +00001002
Harald Welte4724f992009-01-18 18:01:49 +00001003 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1004 return abis_nm_rcvmsg_sw(mb);
1005
Harald Welte78fc0d42009-02-19 02:50:57 +00001006 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001007 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +00001008 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +02001009
Harald Weltea8bd6d42009-10-20 09:56:18 +02001010 debugp_foh(foh);
Harald Welte4bd0a982009-10-08 20:18:59 +02001011
Harald Welte92b1fe42010-03-25 11:45:30 +08001012 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte6c96ba52009-05-01 13:03:40 +00001013
Harald Welte39315c42010-01-10 18:01:52 +01001014 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +00001015 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001016 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00001017 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1018 else
1019 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001020
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +08001021 nack_data.msg = mb;
1022 nack_data.mt = mt;
1023 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001024 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +02001025 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +00001026 }
Harald Weltead384642008-12-26 10:20:07 +00001027#if 0
Harald Welte52b1f982008-12-23 20:25:15 +00001028 /* check if last message is to be acked */
1029 if (is_ack_nack(nmh->last_msgtype)) {
1030 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01001031 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001032 /* we got our ACK, continue sending the next msg */
1033 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1034 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +01001035 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +00001036 /* FIXME: somehow signal this to the caller */
1037 } else {
1038 /* really strange things happen */
1039 return -EINVAL;
1040 }
1041 }
Harald Weltead384642008-12-26 10:20:07 +00001042#endif
1043
Harald Welte97ed1e72009-02-06 13:38:02 +00001044 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +00001045 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001046 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +00001047 break;
Harald Welte34a99682009-02-13 02:41:40 +00001048 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001049 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +00001050 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001051 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001052 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +00001053 break;
Harald Welte1989c082009-08-06 17:58:31 +02001054 case NM_MT_CONN_MDROP_LINK_ACK:
1055 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1056 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +01001057 case NM_MT_IPACC_RESTART_ACK:
1058 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1059 break;
1060 case NM_MT_IPACC_RESTART_NACK:
1061 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1062 break;
Harald Welte97ed1e72009-02-06 13:38:02 +00001063 }
1064
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001065 abis_nm_queue_send_next(mb->trx->bts);
1066 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +00001067}
1068
Harald Welte677c21f2009-02-17 13:22:23 +00001069static int abis_nm_rx_ipacc(struct msgb *mb);
1070
1071static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1072{
1073 int rc;
1074 int bts_type = mb->trx->bts->type;
1075
1076 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +01001077 case GSM_BTS_TYPE_NANOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +00001078 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001079 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +00001080 break;
1081 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001082 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1083 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +00001084 rc = 0;
1085 break;
1086 }
1087
1088 return rc;
1089}
1090
Harald Welte52b1f982008-12-23 20:25:15 +00001091/* High-Level API */
1092/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +00001093int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +00001094{
Harald Welte52b1f982008-12-23 20:25:15 +00001095 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +00001096 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +00001097
1098 /* Various consistency checks */
1099 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001100 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001101 oh->placement);
Harald Weltec95cf102010-07-22 20:12:09 +02001102 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1103 return -EINVAL;
Harald Welte52b1f982008-12-23 20:25:15 +00001104 }
1105 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001106 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001107 oh->sequence);
1108 return -EINVAL;
1109 }
Harald Welte702d8702008-12-26 20:25:35 +00001110#if 0
Holger Freytherca362a62009-01-04 21:05:01 +00001111 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1112 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +00001113 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001114 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001115 oh->length + sizeof(*oh), l2_len);
1116 return -EINVAL;
1117 }
Harald Welte702d8702008-12-26 20:25:35 +00001118 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001119 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 +00001120#endif
Harald Weltead384642008-12-26 10:20:07 +00001121 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +00001122
1123 switch (oh->mdisc) {
1124 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +00001125 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001126 break;
Harald Welte677c21f2009-02-17 13:22:23 +00001127 case ABIS_OM_MDISC_MANUF:
1128 rc = abis_nm_rcvmsg_manuf(msg);
1129 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001130 case ABIS_OM_MDISC_MMI:
1131 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001132 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +00001133 oh->mdisc);
1134 break;
Harald Welte52b1f982008-12-23 20:25:15 +00001135 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +01001136 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +00001137 oh->mdisc);
1138 return -EINVAL;
1139 }
1140
Harald Weltead384642008-12-26 10:20:07 +00001141 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001142 return rc;
1143}
1144
1145#if 0
1146/* initialized all resources */
1147struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1148{
1149 struct abis_nm_h *nmh;
1150
1151 nmh = malloc(sizeof(*nmh));
1152 if (!nmh)
1153 return NULL;
1154
1155 nmh->cfg = cfg;
1156
1157 return nmh;
1158}
1159
1160/* free all resources */
1161void abis_nm_fini(struct abis_nm_h *nmh)
1162{
1163 free(nmh);
1164}
1165#endif
1166
1167/* Here we are trying to define a high-level API that can be used by
1168 * the actual BSC implementation. However, the architecture is currently
1169 * still under design. Ideally the calls to this API would be synchronous,
1170 * while the underlying stack behind the APi runs in a traditional select
1171 * based state machine.
1172 */
1173
Harald Welte4724f992009-01-18 18:01:49 +00001174/* 6.2 Software Load: */
1175enum sw_state {
1176 SW_STATE_NONE,
1177 SW_STATE_WAIT_INITACK,
1178 SW_STATE_WAIT_SEGACK,
1179 SW_STATE_WAIT_ENDACK,
1180 SW_STATE_WAIT_ACTACK,
1181 SW_STATE_ERROR,
1182};
Harald Welte52b1f982008-12-23 20:25:15 +00001183
Harald Welte52b1f982008-12-23 20:25:15 +00001184struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +00001185 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001186 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001187 gsm_cbfn *cbfn;
1188 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001189 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001190
Harald Welte52b1f982008-12-23 20:25:15 +00001191 /* this will become part of the SW LOAD INITIATE */
1192 u_int8_t obj_class;
1193 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +00001194
1195 u_int8_t file_id[255];
1196 u_int8_t file_id_len;
1197
1198 u_int8_t file_version[255];
1199 u_int8_t file_version_len;
1200
1201 u_int8_t window_size;
1202 u_int8_t seg_in_window;
1203
1204 int fd;
1205 FILE *stream;
1206 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +00001207 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +00001208};
1209
Harald Welte4724f992009-01-18 18:01:49 +00001210static struct abis_nm_sw g_sw;
1211
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001212static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1213{
1214 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1215 msgb_v_put(msg, NM_ATT_SW_DESCR);
1216 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1217 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1218 sw->file_version);
1219 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1220 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1221 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1222 sw->file_version);
1223 } else {
1224 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1225 }
1226}
1227
Harald Welte4724f992009-01-18 18:01:49 +00001228/* 6.2.1 / 8.3.1: Load Data Initiate */
1229static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001230{
Harald Welte4724f992009-01-18 18:01:49 +00001231 struct abis_om_hdr *oh;
1232 struct msgb *msg = nm_msgb_alloc();
1233 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1234
1235 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1236 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1237 sw->obj_instance[0], sw->obj_instance[1],
1238 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001239
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001240 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001241 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1242
1243 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001244}
1245
Harald Welte1602ade2009-01-29 21:12:39 +00001246static int is_last_line(FILE *stream)
1247{
1248 char next_seg_buf[256];
1249 long pos;
1250
1251 /* check if we're sending the last line */
1252 pos = ftell(stream);
1253 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1254 fseek(stream, pos, SEEK_SET);
1255 return 1;
1256 }
1257
1258 fseek(stream, pos, SEEK_SET);
1259 return 0;
1260}
1261
Harald Welte4724f992009-01-18 18:01:49 +00001262/* 6.2.2 / 8.3.2 Load Data Segment */
1263static int sw_load_segment(struct abis_nm_sw *sw)
1264{
1265 struct abis_om_hdr *oh;
1266 struct msgb *msg = nm_msgb_alloc();
1267 char seg_buf[256];
1268 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001269 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +00001270 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +00001271
1272 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001273
1274 switch (sw->bts->type) {
1275 case GSM_BTS_TYPE_BS11:
1276 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1277 perror("fgets reading segment");
1278 return -EINVAL;
1279 }
1280 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001281
1282 /* check if we're sending the last line */
1283 sw->last_seg = is_last_line(sw->stream);
1284 if (sw->last_seg)
1285 seg_buf[1] = 0;
1286 else
1287 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001288
1289 len = strlen(line_buf) + 2;
1290 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1291 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1292 /* BS11 wants CR + LF in excess of the TLV length !?! */
1293 tlv[1] -= 2;
1294
1295 /* we only now know the exact length for the OM hdr */
1296 len = strlen(line_buf)+2;
1297 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001298 case GSM_BTS_TYPE_NANOBTS: {
1299 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1300 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1301 if (len < 0) {
1302 perror("read failed");
1303 return -EINVAL;
1304 }
1305
1306 if (len != IPACC_SEGMENT_SIZE)
1307 sw->last_seg = 1;
1308
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001309 ++sw->seg_in_window;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001310 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1311 len += 3;
1312 break;
1313 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001314 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001315 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001316 /* FIXME: Other BTS types */
1317 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001318 }
Harald Welte4724f992009-01-18 18:01:49 +00001319
Harald Welte4724f992009-01-18 18:01:49 +00001320 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1321 sw->obj_instance[0], sw->obj_instance[1],
1322 sw->obj_instance[2]);
1323
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001324 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001325}
1326
1327/* 6.2.4 / 8.3.4 Load Data End */
1328static int sw_load_end(struct abis_nm_sw *sw)
1329{
1330 struct abis_om_hdr *oh;
1331 struct msgb *msg = nm_msgb_alloc();
1332 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1333
1334 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1335 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1336 sw->obj_instance[0], sw->obj_instance[1],
1337 sw->obj_instance[2]);
1338
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001339 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001340 return abis_nm_sendmsg(sw->bts, msg);
1341}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001342
Harald Welte52b1f982008-12-23 20:25:15 +00001343/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001344static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001345{
Harald Welte4724f992009-01-18 18:01:49 +00001346 struct abis_om_hdr *oh;
1347 struct msgb *msg = nm_msgb_alloc();
1348 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001349
Harald Welte4724f992009-01-18 18:01:49 +00001350 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1351 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1352 sw->obj_instance[0], sw->obj_instance[1],
1353 sw->obj_instance[2]);
1354
1355 /* FIXME: this is BS11 specific format */
1356 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1357 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1358 sw->file_version);
1359
1360 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001361}
Harald Welte4724f992009-01-18 18:01:49 +00001362
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001363struct sdp_firmware {
1364 char magic[4];
1365 char more_magic[4];
1366 unsigned int header_length;
1367 unsigned int file_length;
1368} __attribute__ ((packed));
1369
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001370static int parse_sdp_header(struct abis_nm_sw *sw)
1371{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001372 struct sdp_firmware firmware_header;
1373 int rc;
1374 struct stat stat;
1375
1376 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1377 if (rc != sizeof(firmware_header)) {
1378 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1379 return -1;
1380 }
1381
1382 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1383 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1384 return -1;
1385 }
1386
1387 if (firmware_header.more_magic[0] != 0x10 ||
1388 firmware_header.more_magic[1] != 0x02 ||
1389 firmware_header.more_magic[2] != 0x00 ||
1390 firmware_header.more_magic[3] != 0x00) {
1391 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1392 return -1;
1393 }
1394
1395
1396 if (fstat(sw->fd, &stat) == -1) {
1397 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1398 return -1;
1399 }
1400
1401 if (ntohl(firmware_header.file_length) != stat.st_size) {
1402 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1403 return -1;
1404 }
1405
1406 /* go back to the start as we checked the whole filesize.. */
1407 lseek(sw->fd, 0l, SEEK_SET);
1408 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1409 "There might be checksums in the file that are not\n"
1410 "verified and incomplete firmware might be flashed.\n"
1411 "There is absolutely no WARRANTY that flashing will\n"
1412 "work.\n");
1413 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001414}
1415
Harald Welte4724f992009-01-18 18:01:49 +00001416static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1417{
1418 char file_id[12+1];
1419 char file_version[80+1];
1420 int rc;
1421
1422 sw->fd = open(fname, O_RDONLY);
1423 if (sw->fd < 0)
1424 return sw->fd;
1425
1426 switch (sw->bts->type) {
1427 case GSM_BTS_TYPE_BS11:
1428 sw->stream = fdopen(sw->fd, "r");
1429 if (!sw->stream) {
1430 perror("fdopen");
1431 return -1;
1432 }
1433 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001434 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001435 file_id, file_version);
1436 if (rc != 2) {
1437 perror("parsing header line of software file");
1438 return -1;
1439 }
1440 strcpy((char *)sw->file_id, file_id);
1441 sw->file_id_len = strlen(file_id);
1442 strcpy((char *)sw->file_version, file_version);
1443 sw->file_version_len = strlen(file_version);
1444 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001445 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001446 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001447 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001448 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001449 rc = parse_sdp_header(sw);
1450 if (rc < 0) {
1451 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1452 return -1;
1453 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001454
1455 strcpy((char *)sw->file_id, "id");
1456 sw->file_id_len = 3;
1457 strcpy((char *)sw->file_version, "version");
1458 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001459 break;
Harald Welte4724f992009-01-18 18:01:49 +00001460 default:
1461 /* We don't know how to treat them yet */
1462 close(sw->fd);
1463 return -EINVAL;
1464 }
1465
1466 return 0;
1467}
1468
1469static void sw_close_file(struct abis_nm_sw *sw)
1470{
1471 switch (sw->bts->type) {
1472 case GSM_BTS_TYPE_BS11:
1473 fclose(sw->stream);
1474 break;
1475 default:
1476 close(sw->fd);
1477 break;
1478 }
1479}
1480
1481/* Fill the window */
1482static int sw_fill_window(struct abis_nm_sw *sw)
1483{
1484 int rc;
1485
1486 while (sw->seg_in_window < sw->window_size) {
1487 rc = sw_load_segment(sw);
1488 if (rc < 0)
1489 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001490 if (sw->last_seg)
1491 break;
Harald Welte4724f992009-01-18 18:01:49 +00001492 }
1493 return 0;
1494}
1495
1496/* callback function from abis_nm_rcvmsg() handler */
1497static int abis_nm_rcvmsg_sw(struct msgb *mb)
1498{
1499 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1500 int rc = -1;
1501 struct abis_nm_sw *sw = &g_sw;
1502 enum sw_state old_state = sw->state;
1503
Harald Welte3ffd1372009-02-01 22:15:49 +00001504 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001505
1506 switch (sw->state) {
1507 case SW_STATE_WAIT_INITACK:
1508 switch (foh->msg_type) {
1509 case NM_MT_LOAD_INIT_ACK:
1510 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001511 if (sw->cbfn)
1512 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1513 NM_MT_LOAD_INIT_ACK, mb,
1514 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001515 rc = sw_fill_window(sw);
1516 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001517 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001518 break;
1519 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001520 if (sw->forced) {
1521 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1522 "Init NACK\n");
1523 if (sw->cbfn)
1524 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1525 NM_MT_LOAD_INIT_ACK, mb,
1526 sw->cb_data, NULL);
1527 rc = sw_fill_window(sw);
1528 sw->state = SW_STATE_WAIT_SEGACK;
1529 } else {
1530 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001531 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001532 if (sw->cbfn)
1533 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1534 NM_MT_LOAD_INIT_NACK, mb,
1535 sw->cb_data, NULL);
1536 sw->state = SW_STATE_ERROR;
1537 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001538 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001539 break;
1540 }
1541 break;
1542 case SW_STATE_WAIT_SEGACK:
1543 switch (foh->msg_type) {
1544 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001545 if (sw->cbfn)
1546 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1547 NM_MT_LOAD_SEG_ACK, mb,
1548 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001549 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001550 if (!sw->last_seg) {
1551 /* fill window with more segments */
1552 rc = sw_fill_window(sw);
1553 sw->state = SW_STATE_WAIT_SEGACK;
1554 } else {
1555 /* end the transfer */
1556 sw->state = SW_STATE_WAIT_ENDACK;
1557 rc = sw_load_end(sw);
1558 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001559 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001560 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001561 case NM_MT_LOAD_ABORT:
1562 if (sw->cbfn)
1563 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1564 NM_MT_LOAD_ABORT, mb,
1565 sw->cb_data, NULL);
1566 break;
Harald Welte4724f992009-01-18 18:01:49 +00001567 }
1568 break;
1569 case SW_STATE_WAIT_ENDACK:
1570 switch (foh->msg_type) {
1571 case NM_MT_LOAD_END_ACK:
1572 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001573 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1574 sw->bts->nr);
1575 sw->state = SW_STATE_NONE;
1576 if (sw->cbfn)
1577 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1578 NM_MT_LOAD_END_ACK, mb,
1579 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001580 rc = 0;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001581 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001582 break;
1583 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001584 if (sw->forced) {
1585 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1586 "End NACK\n");
1587 sw->state = SW_STATE_NONE;
1588 if (sw->cbfn)
1589 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1590 NM_MT_LOAD_END_ACK, mb,
1591 sw->cb_data, NULL);
1592 } else {
1593 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001594 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001595 sw->state = SW_STATE_ERROR;
1596 if (sw->cbfn)
1597 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1598 NM_MT_LOAD_END_NACK, mb,
1599 sw->cb_data, NULL);
1600 }
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001601 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001602 break;
1603 }
1604 case SW_STATE_WAIT_ACTACK:
1605 switch (foh->msg_type) {
1606 case NM_MT_ACTIVATE_SW_ACK:
1607 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001608 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001609 sw->state = SW_STATE_NONE;
1610 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001611 if (sw->cbfn)
1612 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1613 NM_MT_ACTIVATE_SW_ACK, mb,
1614 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001615 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001616 break;
1617 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001618 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001619 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001620 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001621 if (sw->cbfn)
1622 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1623 NM_MT_ACTIVATE_SW_NACK, mb,
1624 sw->cb_data, NULL);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001625 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001626 break;
1627 }
1628 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001629 switch (foh->msg_type) {
1630 case NM_MT_ACTIVATE_SW_ACK:
1631 rc = 0;
1632 break;
1633 }
1634 break;
Harald Welte4724f992009-01-18 18:01:49 +00001635 case SW_STATE_ERROR:
1636 break;
1637 }
1638
1639 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001640 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001641 foh->msg_type, old_state, sw->state);
1642
1643 return rc;
1644}
1645
1646/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001647int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00001648 u_int8_t win_size, int forced,
1649 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001650{
1651 struct abis_nm_sw *sw = &g_sw;
1652 int rc;
1653
Harald Welte5e4d1b32009-02-01 13:36:56 +00001654 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1655 bts->nr, fname);
1656
Harald Welte4724f992009-01-18 18:01:49 +00001657 if (sw->state != SW_STATE_NONE)
1658 return -EBUSY;
1659
1660 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001661 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001662
1663 switch (bts->type) {
1664 case GSM_BTS_TYPE_BS11:
1665 sw->obj_class = NM_OC_SITE_MANAGER;
1666 sw->obj_instance[0] = 0xff;
1667 sw->obj_instance[1] = 0xff;
1668 sw->obj_instance[2] = 0xff;
1669 break;
1670 case GSM_BTS_TYPE_NANOBTS:
1671 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001672 sw->obj_instance[0] = sw->bts->nr;
1673 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001674 sw->obj_instance[2] = 0xff;
1675 break;
1676 case GSM_BTS_TYPE_UNKNOWN:
1677 default:
1678 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1679 return -1;
1680 break;
1681 }
Harald Welte4724f992009-01-18 18:01:49 +00001682 sw->window_size = win_size;
1683 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001684 sw->cbfn = cbfn;
1685 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001686 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001687
1688 rc = sw_open_file(sw, fname);
1689 if (rc < 0) {
1690 sw->state = SW_STATE_NONE;
1691 return rc;
1692 }
1693
1694 return sw_load_init(sw);
1695}
Harald Welte52b1f982008-12-23 20:25:15 +00001696
Harald Welte1602ade2009-01-29 21:12:39 +00001697int abis_nm_software_load_status(struct gsm_bts *bts)
1698{
1699 struct abis_nm_sw *sw = &g_sw;
1700 struct stat st;
1701 int rc, percent;
1702
1703 rc = fstat(sw->fd, &st);
1704 if (rc < 0) {
1705 perror("ERROR during stat");
1706 return rc;
1707 }
1708
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001709 if (sw->stream)
1710 percent = (ftell(sw->stream) * 100) / st.st_size;
1711 else
1712 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001713 return percent;
1714}
1715
Harald Welte5e4d1b32009-02-01 13:36:56 +00001716/* Activate the specified software into the BTS */
1717int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1718 gsm_cbfn *cbfn, void *cb_data)
1719{
1720 struct abis_nm_sw *sw = &g_sw;
1721 int rc;
1722
1723 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1724 bts->nr, fname);
1725
1726 if (sw->state != SW_STATE_NONE)
1727 return -EBUSY;
1728
1729 sw->bts = bts;
1730 sw->obj_class = NM_OC_SITE_MANAGER;
1731 sw->obj_instance[0] = 0xff;
1732 sw->obj_instance[1] = 0xff;
1733 sw->obj_instance[2] = 0xff;
1734 sw->state = SW_STATE_WAIT_ACTACK;
1735 sw->cbfn = cbfn;
1736 sw->cb_data = cb_data;
1737
1738 /* Open the file in order to fill some sw struct members */
1739 rc = sw_open_file(sw, fname);
1740 if (rc < 0) {
1741 sw->state = SW_STATE_NONE;
1742 return rc;
1743 }
1744 sw_close_file(sw);
1745
1746 return sw_activate(sw);
1747}
1748
Harald Welte8470bf22008-12-25 23:28:35 +00001749static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +00001750 u_int8_t ts_nr, u_int8_t subslot_nr)
1751{
Harald Welteadaf08b2009-01-18 11:08:10 +00001752 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001753 ch->bts_port = bts_port;
1754 ch->timeslot = ts_nr;
1755 ch->subslot = subslot_nr;
1756}
1757
1758int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1759 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1760 u_int8_t tei)
1761{
1762 struct abis_om_hdr *oh;
1763 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +00001764 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001765 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001766
1767 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1768 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1769 bts->bts_nr, trx_nr, 0xff);
1770
Harald Welte8470bf22008-12-25 23:28:35 +00001771 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001772
1773 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1774 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1775
1776 return abis_nm_sendmsg(bts, msg);
1777}
1778
1779/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1780int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1781 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1782{
Harald Welte8470bf22008-12-25 23:28:35 +00001783 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001784 struct abis_om_hdr *oh;
1785 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001786 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001787
1788 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001789 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001790 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1791
1792 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1793 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1794
1795 return abis_nm_sendmsg(bts, msg);
1796}
1797
1798#if 0
1799int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1800 struct abis_nm_abis_channel *chan)
1801{
1802}
1803#endif
1804
1805int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1806 u_int8_t e1_port, u_int8_t e1_timeslot,
1807 u_int8_t e1_subslot)
1808{
1809 struct gsm_bts *bts = ts->trx->bts;
1810 struct abis_om_hdr *oh;
1811 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001812 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001813
1814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1815 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001816 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001817
1818 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1819 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1820
Harald Weltef325eb42009-02-19 17:07:39 +00001821 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1822 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001823 e1_port, e1_timeslot, e1_subslot);
1824
Harald Welte52b1f982008-12-23 20:25:15 +00001825 return abis_nm_sendmsg(bts, msg);
1826}
1827
1828#if 0
1829int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1830 struct abis_nm_abis_channel *chan,
1831 u_int8_t subchan)
1832{
1833}
1834#endif
1835
Harald Welte22af0db2009-02-14 15:41:08 +00001836/* Chapter 8.6.1 */
1837int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1838{
1839 struct abis_om_hdr *oh;
1840 struct msgb *msg = nm_msgb_alloc();
1841 u_int8_t *cur;
1842
1843 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1844
1845 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001846 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 +00001847 cur = msgb_put(msg, attr_len);
1848 memcpy(cur, attr, attr_len);
1849
1850 return abis_nm_sendmsg(bts, msg);
1851}
1852
1853/* Chapter 8.6.2 */
1854int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1855{
1856 struct abis_om_hdr *oh;
1857 struct msgb *msg = nm_msgb_alloc();
1858 u_int8_t *cur;
1859
1860 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1861
1862 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1863 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001864 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001865 cur = msgb_put(msg, attr_len);
1866 memcpy(cur, attr, attr_len);
1867
1868 return abis_nm_sendmsg(trx->bts, msg);
1869}
1870
Harald Welte39c7deb2009-08-09 21:49:48 +02001871static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1872{
1873 int i;
1874
1875 /* As it turns out, the BS-11 has some very peculiar restrictions
1876 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301877 switch (ts->trx->bts->type) {
1878 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001879 switch (chan_comb) {
1880 case NM_CHANC_TCHHalf:
1881 case NM_CHANC_TCHHalf2:
1882 /* not supported */
1883 return -EINVAL;
1884 case NM_CHANC_SDCCH:
1885 /* only one SDCCH/8 per TRX */
1886 for (i = 0; i < TRX_NR_TS; i++) {
1887 if (i == ts->nr)
1888 continue;
1889 if (ts->trx->ts[i].nm_chan_comb ==
1890 NM_CHANC_SDCCH)
1891 return -EINVAL;
1892 }
1893 /* not allowed for TS0 of BCCH-TRX */
1894 if (ts->trx == ts->trx->bts->c0 &&
1895 ts->nr == 0)
1896 return -EINVAL;
1897 /* not on the same TRX that has a BCCH+SDCCH4
1898 * combination */
1899 if (ts->trx == ts->trx->bts->c0 &&
1900 (ts->trx->ts[0].nm_chan_comb == 5 ||
1901 ts->trx->ts[0].nm_chan_comb == 8))
1902 return -EINVAL;
1903 break;
1904 case NM_CHANC_mainBCCH:
1905 case NM_CHANC_BCCHComb:
1906 /* allowed only for TS0 of C0 */
1907 if (ts->trx != ts->trx->bts->c0 ||
1908 ts->nr != 0)
1909 return -EINVAL;
1910 break;
1911 case NM_CHANC_BCCH:
1912 /* allowed only for TS 2/4/6 of C0 */
1913 if (ts->trx != ts->trx->bts->c0)
1914 return -EINVAL;
1915 if (ts->nr != 2 && ts->nr != 4 &&
1916 ts->nr != 6)
1917 return -EINVAL;
1918 break;
1919 case 8: /* this is not like 08.58, but in fact
1920 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1921 /* FIXME: only one CBCH allowed per cell */
1922 break;
1923 }
Harald Welted6575f92009-12-02 02:45:23 +05301924 break;
1925 case GSM_BTS_TYPE_NANOBTS:
1926 switch (ts->nr) {
1927 case 0:
1928 if (ts->trx->nr == 0) {
1929 /* only on TRX0 */
1930 switch (chan_comb) {
1931 case NM_CHANC_BCCH:
1932 case NM_CHANC_mainBCCH:
1933 case NM_CHANC_BCCHComb:
1934 return 0;
1935 break;
1936 default:
1937 return -EINVAL;
1938 }
1939 } else {
1940 switch (chan_comb) {
1941 case NM_CHANC_TCHFull:
1942 case NM_CHANC_TCHHalf:
1943 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1944 return 0;
1945 default:
1946 return -EINVAL;
1947 }
1948 }
1949 break;
1950 case 1:
1951 if (ts->trx->nr == 0) {
1952 switch (chan_comb) {
1953 case NM_CHANC_SDCCH_CBCH:
1954 if (ts->trx->ts[0].nm_chan_comb ==
1955 NM_CHANC_mainBCCH)
1956 return 0;
1957 return -EINVAL;
1958 case NM_CHANC_SDCCH:
1959 case NM_CHANC_TCHFull:
1960 case NM_CHANC_TCHHalf:
1961 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1962 case NM_CHANC_IPAC_TCHFull_PDCH:
1963 return 0;
1964 }
1965 } else {
1966 switch (chan_comb) {
1967 case NM_CHANC_SDCCH:
1968 case NM_CHANC_TCHFull:
1969 case NM_CHANC_TCHHalf:
1970 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1971 return 0;
1972 default:
1973 return -EINVAL;
1974 }
1975 }
1976 break;
1977 case 2:
1978 case 3:
1979 case 4:
1980 case 5:
1981 case 6:
1982 case 7:
1983 switch (chan_comb) {
1984 case NM_CHANC_TCHFull:
1985 case NM_CHANC_TCHHalf:
1986 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1987 return 0;
1988 case NM_CHANC_IPAC_PDCH:
1989 case NM_CHANC_IPAC_TCHFull_PDCH:
1990 if (ts->trx->nr == 0)
1991 return 0;
1992 else
1993 return -EINVAL;
1994 }
1995 break;
1996 }
1997 return -EINVAL;
1998 default:
1999 /* unknown BTS type */
2000 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02002001 }
2002 return 0;
2003}
2004
Harald Welte22af0db2009-02-14 15:41:08 +00002005/* Chapter 8.6.3 */
Harald Welte52b1f982008-12-23 20:25:15 +00002006int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2007{
2008 struct gsm_bts *bts = ts->trx->bts;
2009 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002010 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +00002011 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00002012 struct msgb *msg = nm_msgb_alloc();
Harald Weltee0590df2009-02-15 03:34:15 +00002013 u_int8_t len = 2 + 2;
2014
2015 if (bts->type == GSM_BTS_TYPE_BS11)
2016 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00002017
Harald Weltef325eb42009-02-19 17:07:39 +00002018 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Welte39c7deb2009-08-09 21:49:48 +02002019 if (verify_chan_comb(ts, chan_comb) < 0) {
2020 msgb_free(msg);
2021 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2022 return -EINVAL;
2023 }
2024 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00002025
Harald Welte52b1f982008-12-23 20:25:15 +00002026 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002027 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00002028 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00002029 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00002030 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02002031 if (ts->hopping.enabled) {
2032 unsigned int i;
2033 uint8_t *len;
2034
Harald Welte6e0cd042009-09-12 13:05:33 +02002035 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2036 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02002037
2038 /* build the ARFCN list */
2039 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2040 len = msgb_put(msg, 1);
2041 *len = 0;
2042 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2043 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2044 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02002045 /* At least BS-11 wants a TLV16 here */
2046 if (bts->type == GSM_BTS_TYPE_BS11)
2047 *len += 1;
2048 else
2049 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02002050 }
2051 }
Harald Weltee0590df2009-02-15 03:34:15 +00002052 }
Harald Weltee6c22d92009-07-21 20:40:05 +02002053 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00002054 if (bts->type == GSM_BTS_TYPE_BS11)
2055 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00002056
2057 return abis_nm_sendmsg(bts, msg);
2058}
2059
Harald Welte34a99682009-02-13 02:41:40 +00002060int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
Harald Welte5c1e4582009-02-15 11:57:29 +00002061 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00002062{
2063 struct abis_om_hdr *oh;
2064 struct msgb *msg = nm_msgb_alloc();
Harald Welte5c1e4582009-02-15 11:57:29 +00002065 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2066 u_int8_t len = att_len;
2067
2068 if (nack) {
2069 len += 2;
2070 msgtype = NM_MT_SW_ACT_REQ_NACK;
2071 }
Harald Welte34a99682009-02-13 02:41:40 +00002072
2073 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00002074 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2075
Harald Welte34a99682009-02-13 02:41:40 +00002076 if (attr) {
2077 u_int8_t *ptr = msgb_put(msg, att_len);
2078 memcpy(ptr, attr, att_len);
2079 }
Harald Welte5c1e4582009-02-15 11:57:29 +00002080 if (nack)
2081 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00002082
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002083 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00002084}
2085
Harald Welte8470bf22008-12-25 23:28:35 +00002086int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00002087{
Harald Welte8470bf22008-12-25 23:28:35 +00002088 struct msgb *msg = nm_msgb_alloc();
2089 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +00002090 u_int8_t *data;
2091
2092 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2093 fill_om_hdr(oh, len);
2094 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00002095 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00002096
2097 return abis_nm_sendmsg(bts, msg);
2098}
2099
2100/* Siemens specific commands */
2101static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2102{
2103 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00002104 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00002105
2106 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00002107 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00002108 0xff, 0xff, 0xff);
2109
2110 return abis_nm_sendmsg(bts, msg);
2111}
2112
Harald Welte34a99682009-02-13 02:41:40 +00002113/* Chapter 8.9.2 */
2114int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2115{
2116 struct abis_om_hdr *oh;
2117 struct msgb *msg = nm_msgb_alloc();
2118
2119 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2120 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2121
Harald Weltea8bd6d42009-10-20 09:56:18 +02002122 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2123 DEBUGPC(DNM, "Sending OPSTART\n");
2124
Harald Welte34a99682009-02-13 02:41:40 +00002125 return abis_nm_sendmsg(bts, msg);
2126}
2127
2128/* Chapter 8.8.5 */
2129int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002130 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00002131{
2132 struct abis_om_hdr *oh;
2133 struct msgb *msg = nm_msgb_alloc();
2134
2135 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2136 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2137 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2138
2139 return abis_nm_sendmsg(bts, msg);
2140}
2141
Harald Welte1989c082009-08-06 17:58:31 +02002142int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2143 u_int8_t e1_port1, u_int8_t ts1)
2144{
2145 struct abis_om_hdr *oh;
2146 struct msgb *msg = nm_msgb_alloc();
2147 u_int8_t *attr;
2148
2149 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2150 e1_port0, ts0, e1_port1, ts1);
2151
2152 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2153 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2154 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2155
2156 attr = msgb_put(msg, 3);
2157 attr[0] = NM_ATT_MDROP_LINK;
2158 attr[1] = e1_port0;
2159 attr[2] = ts0;
2160
2161 attr = msgb_put(msg, 3);
2162 attr[0] = NM_ATT_MDROP_NEXT;
2163 attr[1] = e1_port1;
2164 attr[2] = ts1;
2165
2166 return abis_nm_sendmsg(bts, msg);
2167}
Harald Welte34a99682009-02-13 02:41:40 +00002168
Harald Weltec7310382009-08-08 00:02:36 +02002169/* Chapter 8.7.1 */
2170int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2171 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welte887deab2010-03-06 11:38:05 +01002172 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002173{
2174 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002175
2176 DEBUGP(DNM, "PEFORM TEST\n");
Harald Welte887deab2010-03-06 11:38:05 +01002177
2178 if (!msg)
2179 msg = nm_msgb_alloc();
2180
2181 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2182 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2183 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2184 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002185 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002186
2187 return abis_nm_sendmsg(bts, msg);
2188}
2189
Harald Welte52b1f982008-12-23 20:25:15 +00002190int abis_nm_event_reports(struct gsm_bts *bts, int on)
2191{
2192 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002193 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002194 else
Harald Welte227d4072009-01-03 08:16:25 +00002195 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002196}
2197
Harald Welte47d88ae2009-01-04 12:02:08 +00002198/* Siemens (or BS-11) specific commands */
2199
Harald Welte3ffd1372009-02-01 22:15:49 +00002200int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2201{
2202 if (reconnect == 0)
2203 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2204 else
2205 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2206}
2207
Harald Welteb8427972009-02-05 19:27:17 +00002208int abis_nm_bs11_restart(struct gsm_bts *bts)
2209{
2210 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2211}
2212
2213
Harald Welte268bb402009-02-01 19:11:56 +00002214struct bs11_date_time {
2215 u_int16_t year;
2216 u_int8_t month;
2217 u_int8_t day;
2218 u_int8_t hour;
2219 u_int8_t min;
2220 u_int8_t sec;
2221} __attribute__((packed));
2222
2223
2224void get_bs11_date_time(struct bs11_date_time *aet)
2225{
2226 time_t t;
2227 struct tm *tm;
2228
2229 t = time(NULL);
2230 tm = localtime(&t);
2231 aet->sec = tm->tm_sec;
2232 aet->min = tm->tm_min;
2233 aet->hour = tm->tm_hour;
2234 aet->day = tm->tm_mday;
2235 aet->month = tm->tm_mon;
2236 aet->year = htons(1900 + tm->tm_year);
2237}
2238
Harald Welte05188ee2009-01-18 11:39:08 +00002239int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002240{
Harald Welte4668fda2009-01-03 08:19:29 +00002241 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002242}
2243
Harald Welte05188ee2009-01-18 11:39:08 +00002244int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002245{
2246 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002247 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002248 else
Harald Welte4668fda2009-01-03 08:19:29 +00002249 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002250}
Harald Welte47d88ae2009-01-04 12:02:08 +00002251
Harald Welte05188ee2009-01-18 11:39:08 +00002252int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +00002253 enum abis_bs11_objtype type, u_int8_t idx,
2254 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002255{
2256 struct abis_om_hdr *oh;
2257 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002258 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002259
2260 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002261 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002262 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002263 cur = msgb_put(msg, attr_len);
2264 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002265
2266 return abis_nm_sendmsg(bts, msg);
2267}
2268
Harald Welte78fc0d42009-02-19 02:50:57 +00002269int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2270 enum abis_bs11_objtype type, u_int8_t idx)
2271{
2272 struct abis_om_hdr *oh;
2273 struct msgb *msg = nm_msgb_alloc();
2274
2275 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2276 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2277 NM_OC_BS11, type, 0, idx);
2278
2279 return abis_nm_sendmsg(bts, msg);
2280}
2281
Harald Welte05188ee2009-01-18 11:39:08 +00002282int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002283{
2284 struct abis_om_hdr *oh;
2285 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +00002286 u_int8_t zero = 0x00;
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, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002290 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2291 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002292
2293 return abis_nm_sendmsg(bts, msg);
2294}
2295
Harald Welte05188ee2009-01-18 11:39:08 +00002296int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002297{
2298 struct abis_om_hdr *oh;
2299 struct msgb *msg = nm_msgb_alloc();
2300
2301 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2302 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002303 idx, 0xff, 0xff);
2304
2305 return abis_nm_sendmsg(bts, msg);
2306}
2307
2308int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2309{
2310 struct abis_om_hdr *oh;
2311 struct msgb *msg = nm_msgb_alloc();
2312
2313 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2314 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2315 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002316
2317 return abis_nm_sendmsg(bts, msg);
2318}
Harald Welte05188ee2009-01-18 11:39:08 +00002319
Harald Welte78fc0d42009-02-19 02:50:57 +00002320static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2321int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2322{
2323 struct abis_om_hdr *oh;
2324 struct msgb *msg = nm_msgb_alloc();
2325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2327 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2328 0xff, 0xff, 0xff);
2329 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2330
2331 return abis_nm_sendmsg(bts, msg);
2332}
2333
Harald Welteb6c92ae2009-02-21 20:15:32 +00002334/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002335int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welteb6c92ae2009-02-21 20:15:32 +00002336 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2337 u_int8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002338{
2339 struct abis_om_hdr *oh;
2340 struct abis_nm_channel *ch;
2341 struct msgb *msg = nm_msgb_alloc();
2342
2343 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002344 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002345 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2346
2347 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2348 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002349 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002350
2351 return abis_nm_sendmsg(bts, msg);
2352}
2353
2354int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2355{
2356 struct abis_om_hdr *oh;
2357 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002358
2359 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002360 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002361 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2362 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2363
2364 return abis_nm_sendmsg(trx->bts, msg);
2365}
2366
Harald Welte78fc0d42009-02-19 02:50:57 +00002367int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2368{
2369 struct abis_om_hdr *oh;
2370 struct msgb *msg = nm_msgb_alloc();
2371 u_int8_t attr = NM_ATT_BS11_TXPWR;
2372
2373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2374 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2375 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2376 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2377
2378 return abis_nm_sendmsg(trx->bts, msg);
2379}
2380
Harald Welteaaf02d92009-04-29 13:25:57 +00002381int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2382{
2383 struct abis_om_hdr *oh;
2384 struct msgb *msg = nm_msgb_alloc();
Harald Weltea7cfa032009-04-29 22:33:02 +00002385 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002386
2387 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2388 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2389 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002390 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002391
2392 return abis_nm_sendmsg(bts, msg);
2393}
2394
Harald Welteef061952009-05-17 12:43:42 +00002395int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2396{
2397 struct abis_om_hdr *oh;
2398 struct msgb *msg = nm_msgb_alloc();
2399 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2400 NM_ATT_BS11_CCLK_TYPE };
2401
2402 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2403 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2404 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2405 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2406
2407 return abis_nm_sendmsg(bts, msg);
2408
2409}
Harald Welteaaf02d92009-04-29 13:25:57 +00002410
Harald Welte268bb402009-02-01 19:11:56 +00002411//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002412
Harald Welte1bc09062009-01-18 14:17:52 +00002413int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002414{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002415 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2416}
2417
Daniel Willmann4b054c82010-01-07 00:46:26 +01002418int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2419{
2420 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2421}
2422
Daniel Willmann493db4e2010-01-07 00:43:11 +01002423int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2424{
Harald Welte05188ee2009-01-18 11:39:08 +00002425 struct abis_om_hdr *oh;
2426 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002427 struct bs11_date_time bdt;
2428
2429 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002430
2431 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002432 if (on) {
Harald Welte268bb402009-02-01 19:11:56 +00002433 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002434 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002435 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002436 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002437 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Harald Welte5083b0b2009-02-02 19:20:52 +00002438 sizeof(bdt), (u_int8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002439 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002440 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002441 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002442 strlen(name), (u_int8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002443 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002444 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002445 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002446 }
Harald Welte05188ee2009-01-18 11:39:08 +00002447
2448 return abis_nm_sendmsg(bts, msg);
2449}
Harald Welte1bc09062009-01-18 14:17:52 +00002450
2451int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2452{
2453 struct abis_om_hdr *oh;
2454 struct msgb *msg;
2455
2456 if (strlen(password) != 10)
2457 return -EINVAL;
2458
2459 msg = nm_msgb_alloc();
2460 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002461 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002462 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2463 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2464
2465 return abis_nm_sendmsg(bts, msg);
2466}
2467
Harald Weltee69f5fb2009-04-28 16:31:38 +00002468/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2469int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2470{
2471 struct abis_om_hdr *oh;
2472 struct msgb *msg;
Harald Weltea432cd32009-04-29 13:01:50 +00002473 u_int8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002474
2475 msg = nm_msgb_alloc();
2476 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2477 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2478 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002479
2480 if (locked)
2481 tlv_value = BS11_LI_PLL_LOCKED;
2482 else
2483 tlv_value = BS11_LI_PLL_STANDALONE;
2484
2485 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002486
2487 return abis_nm_sendmsg(bts, msg);
2488}
2489
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002490/* Set the calibration value of the PLL (work value/set value)
2491 * It depends on the login which one is changed */
2492int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2493{
2494 struct abis_om_hdr *oh;
2495 struct msgb *msg;
2496 u_int8_t tlv_value[2];
2497
2498 msg = nm_msgb_alloc();
2499 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2500 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2501 BS11_OBJ_TRX1, 0x00, 0x00);
2502
2503 tlv_value[0] = value>>8;
2504 tlv_value[1] = value&0xff;
2505
2506 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2507
2508 return abis_nm_sendmsg(bts, msg);
2509}
2510
Harald Welte1bc09062009-01-18 14:17:52 +00002511int abis_nm_bs11_get_state(struct gsm_bts *bts)
2512{
2513 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2514}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002515
2516/* BS11 SWL */
2517
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002518void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002519
Harald Welte5e4d1b32009-02-01 13:36:56 +00002520struct abis_nm_bs11_sw {
2521 struct gsm_bts *bts;
2522 char swl_fname[PATH_MAX];
2523 u_int8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002524 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002525 struct llist_head file_list;
2526 gsm_cbfn *user_cb; /* specified by the user */
2527};
2528static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2529
2530struct file_list_entry {
2531 struct llist_head list;
2532 char fname[PATH_MAX];
2533};
2534
2535struct file_list_entry *fl_dequeue(struct llist_head *queue)
2536{
2537 struct llist_head *lh;
2538
2539 if (llist_empty(queue))
2540 return NULL;
2541
2542 lh = queue->next;
2543 llist_del(lh);
2544
2545 return llist_entry(lh, struct file_list_entry, list);
2546}
2547
2548static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2549{
2550 char linebuf[255];
2551 struct llist_head *lh, *lh2;
2552 FILE *swl;
2553 int rc = 0;
2554
2555 swl = fopen(bs11_sw->swl_fname, "r");
2556 if (!swl)
2557 return -ENODEV;
2558
2559 /* zero the stale file list, if any */
2560 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2561 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002562 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002563 }
2564
2565 while (fgets(linebuf, sizeof(linebuf), swl)) {
2566 char file_id[12+1];
2567 char file_version[80+1];
2568 struct file_list_entry *fle;
2569 static char dir[PATH_MAX];
2570
2571 if (strlen(linebuf) < 4)
2572 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002573
Harald Welte5e4d1b32009-02-01 13:36:56 +00002574 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2575 if (rc < 0) {
2576 perror("ERR parsing SWL file");
2577 rc = -EINVAL;
2578 goto out;
2579 }
2580 if (rc < 2)
2581 continue;
2582
Harald Welte470ec292009-06-26 20:25:23 +02002583 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002584 if (!fle) {
2585 rc = -ENOMEM;
2586 goto out;
2587 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002588
2589 /* construct new filename */
2590 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2591 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2592 strcat(fle->fname, "/");
2593 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002594
2595 llist_add_tail(&fle->list, &bs11_sw->file_list);
2596 }
2597
2598out:
2599 fclose(swl);
2600 return rc;
2601}
2602
2603/* bs11 swload specific callback, passed to abis_nm core swload */
2604static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2605 struct msgb *msg, void *data, void *param)
2606{
2607 struct abis_nm_bs11_sw *bs11_sw = data;
2608 struct file_list_entry *fle;
2609 int rc = 0;
2610
Harald Welte5e4d1b32009-02-01 13:36:56 +00002611 switch (event) {
2612 case NM_MT_LOAD_END_ACK:
2613 fle = fl_dequeue(&bs11_sw->file_list);
2614 if (fle) {
2615 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002616 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002617 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002618 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002619 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002620 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002621 } else {
2622 /* activate the SWL */
2623 rc = abis_nm_software_activate(bs11_sw->bts,
2624 bs11_sw->swl_fname,
2625 bs11_swload_cbfn,
2626 bs11_sw);
2627 }
2628 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002629 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002630 case NM_MT_LOAD_END_NACK:
2631 case NM_MT_LOAD_INIT_ACK:
2632 case NM_MT_LOAD_INIT_NACK:
2633 case NM_MT_ACTIVATE_SW_NACK:
2634 case NM_MT_ACTIVATE_SW_ACK:
2635 default:
2636 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002637 if (bs11_sw->user_cb)
2638 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002639 break;
2640 }
2641
2642 return rc;
2643}
2644
2645/* Siemens provides a SWL file that is a mere listing of all the other
2646 * files that are part of a software release. We need to upload first
2647 * the list file, and then each file that is listed in the list file */
2648int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Harald Welte3ffd1372009-02-01 22:15:49 +00002649 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002650{
2651 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2652 struct file_list_entry *fle;
2653 int rc = 0;
2654
2655 INIT_LLIST_HEAD(&bs11_sw->file_list);
2656 bs11_sw->bts = bts;
2657 bs11_sw->win_size = win_size;
2658 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002659 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002660
2661 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2662 rc = bs11_read_swl_file(bs11_sw);
2663 if (rc < 0)
2664 return rc;
2665
2666 /* dequeue next item in file list */
2667 fle = fl_dequeue(&bs11_sw->file_list);
2668 if (!fle)
2669 return -EINVAL;
2670
2671 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002672 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002673 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002674 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002675 return rc;
2676}
2677
Harald Welte5083b0b2009-02-02 19:20:52 +00002678#if 0
Harald Welte5e4d1b32009-02-01 13:36:56 +00002679static u_int8_t req_attr_btse[] = {
2680 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2681 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2682 NM_ATT_BS11_LMT_USER_NAME,
2683
2684 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2685
2686 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2687
2688 NM_ATT_BS11_SW_LOAD_STORED };
2689
2690static u_int8_t req_attr_btsm[] = {
2691 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2692 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2693 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2694 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002695#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002696
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002697static u_int8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002698 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2699 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002700 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002701
2702int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2703{
2704 struct abis_om_hdr *oh;
2705 struct msgb *msg = nm_msgb_alloc();
2706
2707 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2708 /* SiemensHW CCTRL object */
2709 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2710 0x03, 0x00, 0x00);
2711 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2712
2713 return abis_nm_sendmsg(bts, msg);
2714}
Harald Welte268bb402009-02-01 19:11:56 +00002715
2716int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2717{
2718 struct abis_om_hdr *oh;
2719 struct msgb *msg = nm_msgb_alloc();
2720 struct bs11_date_time aet;
2721
2722 get_bs11_date_time(&aet);
2723 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2724 /* SiemensHW CCTRL object */
2725 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2726 0xff, 0xff, 0xff);
Harald Welte5083b0b2009-02-02 19:20:52 +00002727 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002728
2729 return abis_nm_sendmsg(bts, msg);
2730}
Harald Welte5c1e4582009-02-15 11:57:29 +00002731
Harald Weltef751a102010-12-14 12:52:16 +01002732int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2733{
2734 struct abis_om_hdr *oh;
2735 struct msgb *msg = nm_msgb_alloc();
2736 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2737
2738 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2739 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2740 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2741 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2742
2743 return abis_nm_sendmsg(bts, msg);
2744}
2745
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002746int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2747{
2748 struct abis_om_hdr *oh;
2749 struct msgb *msg = nm_msgb_alloc();
2750 struct bs11_date_time aet;
2751
2752 get_bs11_date_time(&aet);
2753 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2754 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2755 bport, 0xff, 0x02);
2756 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2757
2758 return abis_nm_sendmsg(bts, msg);
2759}
2760
Harald Welte5c1e4582009-02-15 11:57:29 +00002761/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002762static const char ipaccess_magic[] = "com.ipaccess";
2763
Harald Welte677c21f2009-02-17 13:22:23 +00002764
2765static int abis_nm_rx_ipacc(struct msgb *msg)
2766{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002767 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002768 struct abis_om_hdr *oh = msgb_l2(msg);
2769 struct abis_om_fom_hdr *foh;
2770 u_int8_t idstrlen = oh->data[0];
2771 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002772 struct ipacc_ack_signal_data signal;
Harald Welte677c21f2009-02-17 13:22:23 +00002773
2774 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002775 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002776 return -EINVAL;
2777 }
2778
Harald Welte193fefc2009-04-30 15:16:27 +00002779 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte39315c42010-01-10 18:01:52 +01002780 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002781
Harald Weltea8bd6d42009-10-20 09:56:18 +02002782 debugp_foh(foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002783
Harald Welte746d6092009-10-19 22:11:11 +02002784 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002785
Harald Welte677c21f2009-02-17 13:22:23 +00002786 switch (foh->msg_type) {
2787 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002788 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002789 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2790 memcpy(&addr,
2791 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2792
2793 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2794 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002795 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002796 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002797 ntohs(*((u_int16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002798 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002799 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2800 DEBUGPC(DNM, "STREAM=0x%02x ",
2801 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002802 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002803 break;
2804 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002805 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002806 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002807 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002808 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002809 else
2810 DEBUGPC(DNM, "\n");
2811 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002812 case NM_MT_IPACC_SET_NVATTR_ACK:
2813 DEBUGPC(DNM, "SET NVATTR ACK\n");
2814 /* FIXME: decode and show the actual attributes */
2815 break;
2816 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002817 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002818 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002819 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte6c96ba52009-05-01 13:03:40 +00002820 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2821 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002822 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002823 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002824 case NM_MT_IPACC_GET_NVATTR_ACK:
2825 DEBUGPC(DNM, "GET NVATTR ACK\n");
2826 /* FIXME: decode and show the actual attributes */
2827 break;
2828 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002829 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002830 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002831 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte684b1a82009-07-03 11:26:45 +02002832 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2833 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002834 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002835 break;
Harald Welte15c44172009-10-08 20:15:24 +02002836 case NM_MT_IPACC_SET_ATTR_ACK:
2837 DEBUGPC(DNM, "SET ATTR ACK\n");
2838 break;
2839 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002840 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002841 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002842 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c44172009-10-08 20:15:24 +02002843 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2844 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002845 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002846 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002847 default:
2848 DEBUGPC(DNM, "unknown\n");
2849 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002850 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002851
2852 /* signal handling */
2853 switch (foh->msg_type) {
2854 case NM_MT_IPACC_RSL_CONNECT_NACK:
2855 case NM_MT_IPACC_SET_NVATTR_NACK:
2856 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002857 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002858 signal.msg_type = foh->msg_type;
2859 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002860 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002861 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002862 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002863 signal.msg_type = foh->msg_type;
2864 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002865 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002866 default:
2867 break;
2868 }
2869
Harald Welte677c21f2009-02-17 13:22:23 +00002870 return 0;
2871}
2872
Harald Welte193fefc2009-04-30 15:16:27 +00002873/* send an ip-access manufacturer specific message */
Harald Welte5c1e4582009-02-15 11:57:29 +00002874int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2875 u_int8_t obj_class, u_int8_t bts_nr,
2876 u_int8_t trx_nr, u_int8_t ts_nr,
2877 u_int8_t *attr, int attr_len)
2878{
2879 struct msgb *msg = nm_msgb_alloc();
2880 struct abis_om_hdr *oh;
2881 struct abis_om_fom_hdr *foh;
2882 u_int8_t *data;
2883
2884 /* construct the 12.21 OM header, observe the erroneous length */
2885 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2886 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2887 oh->mdisc = ABIS_OM_MDISC_MANUF;
2888
2889 /* add the ip.access magic */
2890 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2891 *data++ = sizeof(ipaccess_magic);
2892 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2893
2894 /* fill the 12.21 FOM header */
2895 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2896 foh->msg_type = msg_type;
2897 foh->obj_class = obj_class;
2898 foh->obj_inst.bts_nr = bts_nr;
2899 foh->obj_inst.trx_nr = trx_nr;
2900 foh->obj_inst.ts_nr = ts_nr;
2901
2902 if (attr && attr_len) {
2903 data = msgb_put(msg, attr_len);
2904 memcpy(data, attr, attr_len);
2905 }
2906
2907 return abis_nm_sendmsg(bts, msg);
2908}
Harald Welte677c21f2009-02-17 13:22:23 +00002909
Harald Welte193fefc2009-04-30 15:16:27 +00002910/* set some attributes in NVRAM */
Harald Welte2ef156d2010-01-07 20:39:42 +01002911int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002912 int attr_len)
2913{
Harald Welte2ef156d2010-01-07 20:39:42 +01002914 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2915 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002916 attr_len);
2917}
2918
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002919int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte746d6092009-10-19 22:11:11 +02002920 u_int32_t ip, u_int16_t port, u_int8_t stream)
2921{
2922 struct in_addr ia;
2923 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2924 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2925 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2926
2927 int attr_len = sizeof(attr);
2928
2929 ia.s_addr = htonl(ip);
2930 attr[1] = stream;
2931 attr[3] = port >> 8;
2932 attr[4] = port & 0xff;
2933 *(u_int32_t *)(attr+6) = ia.s_addr;
2934
2935 /* if ip == 0, we use the default IP */
2936 if (ip == 0)
2937 attr_len -= 5;
2938
2939 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002940 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002941
2942 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2943 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2944 trx->nr, 0xff, attr, attr_len);
2945}
2946
Harald Welte193fefc2009-04-30 15:16:27 +00002947/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002948int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002949{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002950 struct abis_om_hdr *oh;
2951 struct msgb *msg = nm_msgb_alloc();
2952
2953 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2954 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2955 trx->bts->nr, trx->nr, 0xff);
2956
2957 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002958}
Harald Weltedaef5212009-10-24 10:20:41 +02002959
2960int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2961 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2962 u_int8_t *attr, u_int8_t attr_len)
2963{
2964 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2965 obj_class, bts_nr, trx_nr, ts_nr,
2966 attr, attr_len);
2967}
Harald Welte0f255852009-11-12 14:48:42 +01002968
Harald Welte97a282b2010-03-14 15:37:43 +08002969void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2970{
2971 /* we simply reuse the GSM48 function and overwrite the RAC
2972 * with the Cell ID */
2973 gsm48_ra_id_by_bts(buf, bts);
2974 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2975}
2976
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002977void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2978{
2979 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2980
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +01002981 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002982 if (!trx->bts || !trx->bts->oml_link)
2983 return;
2984
2985 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2986 trx->bts->bts_nr, trx->nr, 0xff,
2987 new_state);
2988}
2989
Harald Welte92b1fe42010-03-25 11:45:30 +08002990static const struct value_string ipacc_testres_names[] = {
2991 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2992 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2993 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2994 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2995 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2996 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002997};
2998
2999const char *ipacc_testres_name(u_int8_t res)
3000{
Harald Welte92b1fe42010-03-25 11:45:30 +08003001 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01003002}
3003
Harald Welteb40a38f2009-11-13 11:56:05 +01003004void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3005{
3006 cid->mcc = (buf[0] & 0xf) * 100;
3007 cid->mcc += (buf[0] >> 4) * 10;
3008 cid->mcc += (buf[1] & 0xf) * 1;
3009
3010 if (buf[1] >> 4 == 0xf) {
3011 cid->mnc = (buf[2] & 0xf) * 10;
3012 cid->mnc += (buf[2] >> 4) * 1;
3013 } else {
3014 cid->mnc = (buf[2] & 0xf) * 100;
3015 cid->mnc += (buf[2] >> 4) * 10;
3016 cid->mnc += (buf[1] >> 4) * 1;
3017 }
3018
Harald Welteaff237d2009-11-13 14:41:52 +01003019 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3020 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01003021}
3022
Harald Welte0f255852009-11-12 14:48:42 +01003023/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3024int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3025{
3026 u_int8_t *cur = buf;
3027 u_int16_t len;
3028
Harald Welteaf109b92010-07-22 18:14:36 +02003029 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01003030
3031 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3032 return -EINVAL;
3033 cur++;
3034
3035 len = ntohs(*(u_int16_t *)cur);
3036 cur += 2;
3037
3038 binf->info_type = ntohs(*(u_int16_t *)cur);
3039 cur += 2;
3040
3041 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3042 binf->freq_qual = *cur >> 2;
3043
Harald Welteaf109b92010-07-22 18:14:36 +02003044 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01003045 binf->arfcn |= *cur++;
3046
3047 if (binf->info_type & IPAC_BINF_RXLEV)
3048 binf->rx_lev = *cur & 0x3f;
3049 cur++;
3050
3051 if (binf->info_type & IPAC_BINF_RXQUAL)
3052 binf->rx_qual = *cur & 0x7;
3053 cur++;
3054
3055 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3056 binf->freq_err = ntohs(*(u_int16_t *)cur);
3057 cur += 2;
3058
3059 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3060 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3061 cur += 2;
3062
3063 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3064 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3065 cur += 4;
3066
Harald Weltea780a3d2010-07-30 22:34:42 +02003067#if 0
3068 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01003069 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02003070#endif
Harald Welteaff237d2009-11-13 14:41:52 +01003071 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01003072 cur++;
3073
Harald Welteb40a38f2009-11-13 11:56:05 +01003074 ipac_parse_cgi(&binf->cgi, cur);
3075 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01003076
3077 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3078 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3079 cur += sizeof(binf->ba_list_si2);
3080 }
3081
3082 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3083 memcpy(binf->ba_list_si2bis, cur,
3084 sizeof(binf->ba_list_si2bis));
3085 cur += sizeof(binf->ba_list_si2bis);
3086 }
3087
3088 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3089 memcpy(binf->ba_list_si2ter, cur,
3090 sizeof(binf->ba_list_si2ter));
3091 cur += sizeof(binf->ba_list_si2ter);
3092 }
3093
3094 return 0;
3095}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01003096
3097void abis_nm_clear_queue(struct gsm_bts *bts)
3098{
3099 struct msgb *msg;
3100
3101 while (!llist_empty(&bts->abis_queue)) {
3102 msg = msgb_dequeue(&bts->abis_queue);
3103 msgb_free(msg);
3104 }
3105
3106 bts->abis_nm_pend = 0;
3107}