blob: 761dda182b9f9fc8915b1f27e71d05b0b71ffeea [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte59b04682009-06-10 05:40:52 +080011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37
38#include <openbsc/gsm_data.h>
39#include <openbsc/debug.h>
Harald Weltef4625b12010-02-20 16:24:02 +010040#include <osmocore/msgb.h>
41#include <osmocore/tlv.h>
42#include <osmocore/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080043#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
46
47#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010049#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080050
51/* unidirectional messages from BTS to BSC */
52static const enum abis_nm_msgtype reports[] = {
53 NM_MT_SW_ACTIVATED_REP,
54 NM_MT_TEST_REP,
55 NM_MT_STATECHG_EVENT_REP,
56 NM_MT_FAILURE_EVENT_REP,
57};
58
59/* messages without ACK/NACK */
60static const enum abis_nm_msgtype no_ack_nack[] = {
61 NM_MT_MEAS_RES_REQ,
62 NM_MT_STOP_MEAS,
63 NM_MT_START_MEAS,
64};
65
66/* Messages related to software load */
67static const enum abis_nm_msgtype sw_load_msgs[] = {
68 NM_MT_LOAD_INIT_ACK,
69 NM_MT_LOAD_INIT_NACK,
70 NM_MT_LOAD_SEG_ACK,
71 NM_MT_LOAD_ABORT,
72 NM_MT_LOAD_END_ACK,
73 NM_MT_LOAD_END_NACK,
74 //NM_MT_SW_ACT_REQ,
75 NM_MT_ACTIVATE_SW_ACK,
76 NM_MT_ACTIVATE_SW_NACK,
77 NM_MT_SW_ACTIVATED_REP,
78};
79
80static const enum abis_nm_msgtype nacks[] = {
81 NM_MT_LOAD_INIT_NACK,
82 NM_MT_LOAD_END_NACK,
83 NM_MT_SW_ACT_REQ_NACK,
84 NM_MT_ACTIVATE_SW_NACK,
85 NM_MT_ESTABLISH_TEI_NACK,
86 NM_MT_CONN_TERR_SIGN_NACK,
87 NM_MT_DISC_TERR_SIGN_NACK,
88 NM_MT_CONN_TERR_TRAF_NACK,
89 NM_MT_DISC_TERR_TRAF_NACK,
90 NM_MT_CONN_MDROP_LINK_NACK,
91 NM_MT_DISC_MDROP_LINK_NACK,
92 NM_MT_SET_BTS_ATTR_NACK,
93 NM_MT_SET_RADIO_ATTR_NACK,
94 NM_MT_SET_CHAN_ATTR_NACK,
95 NM_MT_PERF_TEST_NACK,
96 NM_MT_SEND_TEST_REP_NACK,
97 NM_MT_STOP_TEST_NACK,
98 NM_MT_STOP_EVENT_REP_NACK,
99 NM_MT_REST_EVENT_REP_NACK,
100 NM_MT_CHG_ADM_STATE_NACK,
101 NM_MT_CHG_ADM_STATE_REQ_NACK,
102 NM_MT_REP_OUTST_ALARMS_NACK,
103 NM_MT_CHANGEOVER_NACK,
104 NM_MT_OPSTART_NACK,
105 NM_MT_REINIT_NACK,
106 NM_MT_SET_SITE_OUT_NACK,
107 NM_MT_CHG_HW_CONF_NACK,
108 NM_MT_GET_ATTR_NACK,
109 NM_MT_SET_ALARM_THRES_NACK,
110 NM_MT_BS11_BEGIN_DB_TX_NACK,
111 NM_MT_BS11_END_DB_TX_NACK,
112 NM_MT_BS11_CREATE_OBJ_NACK,
113 NM_MT_BS11_DELETE_OBJ_NACK,
114};
115
Harald Welte453141f2010-03-25 11:45:30 +0800116static const struct value_string nack_names[] = {
117 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
118 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
119 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
120 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
121 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
122 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
123 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
124 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
125 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
126 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
127 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
128 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
129 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
130 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
131 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
132 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
133 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
134 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
135 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
136 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
137 { NM_MT_CHG_ADM_STATE_REQ_NACK,
138 "CHANGE ADMINISTRATIVE STATE REQUEST" },
139 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
140 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
141 { NM_MT_OPSTART_NACK, "OPSTART" },
142 { NM_MT_REINIT_NACK, "REINIT" },
143 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
144 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
145 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
146 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
147 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
148 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
149 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
150 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
151 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800152};
153
154/* Chapter 9.4.36 */
Harald Welte453141f2010-03-25 11:45:30 +0800155static const struct value_string nack_cause_names[] = {
Harald Welte59b04682009-06-10 05:40:52 +0800156 /* General Nack Causes */
Harald Welte453141f2010-03-25 11:45:30 +0800157 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
158 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
159 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
160 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
161 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
162 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
163 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
164 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
165 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
166 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
167 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
168 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
169 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte59b04682009-06-10 05:40:52 +0800170 /* Specific Nack Causes */
Harald Welte453141f2010-03-25 11:45:30 +0800171 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
172 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
173 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
174 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
175 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
176 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
177 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
178 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
179 { NM_NACK_TEST_NOSUCH, "No such test" },
180 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
181 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
182 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
183 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
184 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
185 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
186 { NM_NACK_WAIT, "Wait" },
187 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
188 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
189 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
190 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800191};
192
Harald Welte59b04682009-06-10 05:40:52 +0800193static const char *nack_cause_name(u_int8_t cause)
194{
Harald Welte453141f2010-03-25 11:45:30 +0800195 return get_value_string(nack_cause_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800196}
197
198/* Chapter 9.4.16: Event Type */
Harald Welte453141f2010-03-25 11:45:30 +0800199static const struct value_string event_type_names[] = {
200 { NM_EVT_COMM_FAIL, "communication failure" },
201 { NM_EVT_QOS_FAIL, "quality of service failure" },
202 { NM_EVT_PROC_FAIL, "processing failure" },
203 { NM_EVT_EQUIP_FAIL, "equipment failure" },
204 { NM_EVT_ENV_FAIL, "environment failure" },
205 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800206};
207
208static const char *event_type_name(u_int8_t cause)
209{
Harald Welte453141f2010-03-25 11:45:30 +0800210 return get_value_string(event_type_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800211}
212
213/* Chapter 9.4.63: Perceived Severity */
Harald Welte453141f2010-03-25 11:45:30 +0800214static const struct value_string severity_names[] = {
215 { NM_SEVER_CEASED, "failure ceased" },
216 { NM_SEVER_CRITICAL, "critical failure" },
217 { NM_SEVER_MAJOR, "major failure" },
218 { NM_SEVER_MINOR, "minor failure" },
219 { NM_SEVER_WARNING, "warning level failure" },
220 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
221 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800222};
223
224static const char *severity_name(u_int8_t cause)
225{
Harald Welte453141f2010-03-25 11:45:30 +0800226 return get_value_string(severity_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800227}
228
229/* Attributes that the BSC can set, not only get, according to Section 9.4 */
230static const enum abis_nm_attr nm_att_settable[] = {
231 NM_ATT_ADD_INFO,
232 NM_ATT_ADD_TEXT,
233 NM_ATT_DEST,
234 NM_ATT_EVENT_TYPE,
235 NM_ATT_FILE_DATA,
236 NM_ATT_GET_ARI,
237 NM_ATT_HW_CONF_CHG,
238 NM_ATT_LIST_REQ_ATTR,
239 NM_ATT_MDROP_LINK,
240 NM_ATT_MDROP_NEXT,
241 NM_ATT_NACK_CAUSES,
242 NM_ATT_OUTST_ALARM,
243 NM_ATT_PHYS_CONF,
244 NM_ATT_PROB_CAUSE,
245 NM_ATT_RAD_SUBC,
246 NM_ATT_SOURCE,
247 NM_ATT_SPEC_PROB,
248 NM_ATT_START_TIME,
249 NM_ATT_TEST_DUR,
250 NM_ATT_TEST_NO,
251 NM_ATT_TEST_REPORT,
252 NM_ATT_WINDOW_SIZE,
253 NM_ATT_SEVERITY,
254 NM_ATT_MEAS_RES,
255 NM_ATT_MEAS_TYPE,
256};
257
Harald Welte59698fb2010-01-10 18:01:52 +0100258const struct tlv_definition nm_att_tlvdef = {
Harald Welte59b04682009-06-10 05:40:52 +0800259 .def = {
260 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
261 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
262 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
264 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
265 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
266 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
267 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
268 [NM_ATT_BSIC] = { TLV_TYPE_TV },
269 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
270 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
272 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
273 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
274 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
275 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
276 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
277 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
279 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
280 [NM_ATT_HSN] = { TLV_TYPE_TV },
281 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
282 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
283 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
284 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
285 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
286 [NM_ATT_MAIO] = { TLV_TYPE_TV },
287 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
289 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
290 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
291 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
292 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
294 [NM_ATT_NY1] = { TLV_TYPE_TV },
295 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
297 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
298 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
299 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
300 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
302 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
303 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
304 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
305 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
306 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
308 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
309 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
310 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
311 [NM_ATT_TEI] = { TLV_TYPE_TV },
312 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
313 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
314 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
315 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
316 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
317 [NM_ATT_TSC] = { TLV_TYPE_TV },
318 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
319 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
320 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
321 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
322 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Welte59b04682009-06-10 05:40:52 +0800323 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Welte59b04682009-06-10 05:40:52 +0800324 },
325};
326
Harald Welte35cd5e92009-08-10 12:21:22 +0200327static const enum abis_nm_chan_comb chcomb4pchan[] = {
328 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
329 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
330 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
331 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
332 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Welte37884ed2009-10-24 10:25:50 +0200333 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
334 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte35cd5e92009-08-10 12:21:22 +0200335 /* FIXME: bounds check */
336};
337
338int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
339{
340 if (pchan < ARRAY_SIZE(chcomb4pchan))
341 return chcomb4pchan[pchan];
342
343 return -EINVAL;
344}
345
Harald Welte59698fb2010-01-10 18:01:52 +0100346int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
Harald Welte59b04682009-06-10 05:40:52 +0800347{
Harald Welte59698fb2010-01-10 18:01:52 +0100348 if (!bts->model)
349 return -EIO;
350 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +0800351}
352
353static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
354{
355 int i;
356
357 for (i = 0; i < size; i++) {
358 if (arr[i] == mt)
359 return 1;
360 }
361
362 return 0;
363}
364
365#if 0
366/* is this msgtype the usual ACK/NACK type ? */
367static int is_ack_nack(enum abis_nm_msgtype mt)
368{
369 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
370}
371#endif
372
373/* is this msgtype a report ? */
374static int is_report(enum abis_nm_msgtype mt)
375{
376 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
377}
378
379#define MT_ACK(x) (x+1)
380#define MT_NACK(x) (x+2)
381
382static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
383{
384 oh->mdisc = ABIS_OM_MDISC_FOM;
385 oh->placement = ABIS_OM_PLACEMENT_ONLY;
386 oh->sequence = 0;
387 oh->length = len;
388}
389
390static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
391 u_int8_t msg_type, u_int8_t obj_class,
392 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
393{
394 struct abis_om_fom_hdr *foh =
395 (struct abis_om_fom_hdr *) oh->data;
396
397 fill_om_hdr(oh, len+sizeof(*foh));
398 foh->msg_type = msg_type;
399 foh->obj_class = obj_class;
400 foh->obj_inst.bts_nr = bts_nr;
401 foh->obj_inst.trx_nr = trx_nr;
402 foh->obj_inst.ts_nr = ts_nr;
403}
404
405static struct msgb *nm_msgb_alloc(void)
406{
Harald Welte9cfc9352009-06-26 19:39:35 +0200407 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
408 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800409}
410
411/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100412static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800413{
414 msg->trx = bts->c0;
415
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100416 /* queue OML messages */
417 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
418 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Weltec5845042011-02-14 15:26:13 +0100419 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100420 } else {
421 msgb_enqueue(&bts->abis_queue, msg);
422 return 0;
423 }
424
425}
426
427int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
428{
429 OBSC_NM_W_ACK_CB(msg) = 1;
430 return abis_nm_queue_msg(bts, msg);
431}
432
433static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
434{
435 OBSC_NM_W_ACK_CB(msg) = 0;
436 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800437}
438
439static int abis_nm_rcvmsg_sw(struct msgb *mb);
440
Harald Welte63b964e2010-05-31 16:40:40 +0200441const struct value_string abis_nm_obj_class_names[] = {
442 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte453141f2010-03-25 11:45:30 +0800443 { NM_OC_BTS, "BTS" },
Harald Welte63b964e2010-05-31 16:40:40 +0200444 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
445 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte453141f2010-03-25 11:45:30 +0800446 { NM_OC_CHANNEL, "CHANNEL" },
447 { NM_OC_BS11_ADJC, "ADJC" },
448 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte63b964e2010-05-31 16:40:40 +0200449 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte453141f2010-03-25 11:45:30 +0800450 { NM_OC_BS11_BTSE, "BTSE" },
451 { NM_OC_BS11_RACK, "RACK" },
452 { NM_OC_BS11_TEST, "TEST" },
453 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
454 { NM_OC_BS11_BPORT, "BPORT" },
Harald Welte63b964e2010-05-31 16:40:40 +0200455 { NM_OC_GPRS_NSE, "GPRS-NSE" },
456 { NM_OC_GPRS_CELL, "GPRS-CELL" },
457 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte453141f2010-03-25 11:45:30 +0800458 { NM_OC_BS11, "SIEMENSHW" },
459 { 0, NULL }
460};
461
Harald Welte59b04682009-06-10 05:40:52 +0800462static const char *obj_class_name(u_int8_t oc)
463{
Harald Welte63b964e2010-05-31 16:40:40 +0200464 return get_value_string(abis_nm_obj_class_names, oc);
Harald Welte59b04682009-06-10 05:40:52 +0800465}
466
467const char *nm_opstate_name(u_int8_t os)
468{
469 switch (os) {
Harald Welte2c87ec12009-12-24 10:06:33 +0100470 case NM_OPSTATE_DISABLED:
Harald Welte59b04682009-06-10 05:40:52 +0800471 return "Disabled";
Harald Welte2c87ec12009-12-24 10:06:33 +0100472 case NM_OPSTATE_ENABLED:
Harald Welte59b04682009-06-10 05:40:52 +0800473 return "Enabled";
Harald Welte2c87ec12009-12-24 10:06:33 +0100474 case NM_OPSTATE_NULL:
Harald Welte59b04682009-06-10 05:40:52 +0800475 return "NULL";
476 default:
477 return "RFU";
478 }
479}
480
481/* Chapter 9.4.7 */
Harald Welte453141f2010-03-25 11:45:30 +0800482static const struct value_string avail_names[] = {
483 { 0, "In test" },
484 { 1, "Failed" },
485 { 2, "Power off" },
486 { 3, "Off line" },
487 /* Not used */
488 { 5, "Dependency" },
489 { 6, "Degraded" },
490 { 7, "Not installed" },
491 { 0xff, "OK" },
492 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800493};
494
495const char *nm_avail_name(u_int8_t avail)
496{
Harald Welte453141f2010-03-25 11:45:30 +0800497 return get_value_string(avail_names, avail);
Harald Welte59b04682009-06-10 05:40:52 +0800498}
499
Harald Weltebeeae412009-11-12 14:48:42 +0100500static struct value_string test_names[] = {
501 /* FIXME: standard test names */
502 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
503 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
504 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
505 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
506 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
507 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
508 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
509 { 0, NULL }
510};
511
Harald Welte63b964e2010-05-31 16:40:40 +0200512const struct value_string abis_nm_adm_state_names[] = {
513 { NM_STATE_LOCKED, "Locked" },
514 { NM_STATE_UNLOCKED, "Unlocked" },
515 { NM_STATE_SHUTDOWN, "Shutdown" },
516 { NM_STATE_NULL, "NULL" },
517 { 0, NULL }
518};
519
Harald Welte59b04682009-06-10 05:40:52 +0800520const char *nm_adm_name(u_int8_t adm)
521{
Harald Welte63b964e2010-05-31 16:40:40 +0200522 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte59b04682009-06-10 05:40:52 +0800523}
524
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100525int nm_is_running(struct gsm_nm_state *s) {
526 return (s->operational == NM_OPSTATE_ENABLED) && (
527 (s->availability == NM_AVSTATE_OK) ||
528 (s->availability == 0xff)
529 );
530}
531
Harald Welteb7284a92009-10-20 09:56:18 +0200532static void debugp_foh(struct abis_om_fom_hdr *foh)
533{
534 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200535 obj_class_name(foh->obj_class), foh->obj_class,
Harald Welteb7284a92009-10-20 09:56:18 +0200536 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
537 foh->obj_inst.ts_nr);
538}
539
Harald Welte59b04682009-06-10 05:40:52 +0800540/* obtain the gsm_nm_state data structure for a given object instance */
541static struct gsm_nm_state *
542objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
543 struct abis_om_obj_inst *obj_inst)
544{
545 struct gsm_bts_trx *trx;
546 struct gsm_nm_state *nm_state = NULL;
547
548 switch (obj_class) {
549 case NM_OC_BTS:
550 nm_state = &bts->nm_state;
551 break;
552 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100553 if (obj_inst->trx_nr >= bts->num_trx) {
554 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800555 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100556 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200557 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800558 nm_state = &trx->nm_state;
559 break;
560 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100561 if (obj_inst->trx_nr >= bts->num_trx) {
562 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800563 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100564 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200565 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800566 nm_state = &trx->bb_transc.nm_state;
567 break;
568 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100569 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100570 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800571 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100572 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200573 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800574 if (obj_inst->ts_nr >= TRX_NR_TS)
575 return NULL;
576 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
577 break;
578 case NM_OC_SITE_MANAGER:
579 nm_state = &bts->site_mgr.nm_state;
580 break;
581 case NM_OC_BS11:
582 switch (obj_inst->bts_nr) {
583 case BS11_OBJ_CCLK:
584 nm_state = &bts->bs11.cclk.nm_state;
585 break;
586 case BS11_OBJ_BBSIG:
587 if (obj_inst->ts_nr > bts->num_trx)
588 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200589 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800590 nm_state = &trx->bs11.bbsig.nm_state;
591 break;
592 case BS11_OBJ_PA:
593 if (obj_inst->ts_nr > bts->num_trx)
594 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200595 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800596 nm_state = &trx->bs11.pa.nm_state;
597 break;
598 default:
599 return NULL;
600 }
601 case NM_OC_BS11_RACK:
602 nm_state = &bts->bs11.rack.nm_state;
603 break;
604 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100605 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte59b04682009-06-10 05:40:52 +0800606 return NULL;
607 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
608 break;
Harald Welte439e1282009-10-24 10:19:14 +0200609 case NM_OC_GPRS_NSE:
610 nm_state = &bts->gprs.nse.nm_state;
611 break;
612 case NM_OC_GPRS_CELL:
613 nm_state = &bts->gprs.cell.nm_state;
614 break;
615 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100616 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200617 return NULL;
618 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
619 break;
Harald Welte59b04682009-06-10 05:40:52 +0800620 }
621 return nm_state;
622}
623
624/* obtain the in-memory data structure of a given object instance */
625static void *
626objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
627 struct abis_om_obj_inst *obj_inst)
628{
629 struct gsm_bts_trx *trx;
630 void *obj = NULL;
631
632 switch (obj_class) {
633 case NM_OC_BTS:
634 obj = bts;
635 break;
636 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100637 if (obj_inst->trx_nr >= bts->num_trx) {
638 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800639 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100640 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200641 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800642 obj = trx;
643 break;
644 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100645 if (obj_inst->trx_nr >= bts->num_trx) {
646 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800647 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100648 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200649 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800650 obj = &trx->bb_transc;
651 break;
652 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100653 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100654 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800655 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100656 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200657 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800658 if (obj_inst->ts_nr >= TRX_NR_TS)
659 return NULL;
660 obj = &trx->ts[obj_inst->ts_nr];
661 break;
662 case NM_OC_SITE_MANAGER:
663 obj = &bts->site_mgr;
664 break;
Harald Welte439e1282009-10-24 10:19:14 +0200665 case NM_OC_GPRS_NSE:
666 obj = &bts->gprs.nse;
667 break;
668 case NM_OC_GPRS_CELL:
669 obj = &bts->gprs.cell;
670 break;
671 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100672 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200673 return NULL;
674 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
675 break;
Harald Welte59b04682009-06-10 05:40:52 +0800676 }
677 return obj;
678}
679
680/* Update the administrative state of a given object in our in-memory data
681 * structures and send an event to the higher layer */
682static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
683 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
684{
685 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100686 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800687
Harald Weltea348c082011-03-06 21:20:38 +0100688 memset(&nsd, 0, sizeof(nsd));
689
Harald Welte4c826f72011-01-14 15:55:42 +0100690 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
691 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100692 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800693 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
694 if (!nm_state)
695 return -1;
696
697 new_state = *nm_state;
698 new_state.administrative = adm_state;
699
Harald Welteb03c4482011-03-06 22:11:32 +0100700 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100701 nsd.obj_class = obj_class;
702 nsd.old_state = nm_state;
703 nsd.new_state = &new_state;
704 nsd.obj_inst = obj_inst;
705 dispatch_signal(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800706
707 nm_state->administrative = adm_state;
708
Harald Welte4c826f72011-01-14 15:55:42 +0100709 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800710}
711
712static int abis_nm_rx_statechg_rep(struct msgb *mb)
713{
714 struct abis_om_hdr *oh = msgb_l2(mb);
715 struct abis_om_fom_hdr *foh = msgb_l3(mb);
716 struct gsm_bts *bts = mb->trx->bts;
717 struct tlv_parsed tp;
718 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800719
720 DEBUGPC(DNM, "STATE CHG: ");
721
722 memset(&new_state, 0, sizeof(new_state));
723
724 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
725 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100726 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800727 return -EINVAL;
728 }
729
730 new_state = *nm_state;
731
Harald Welte59698fb2010-01-10 18:01:52 +0100732 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800733 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
734 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
735 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
736 }
737 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
738 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
739 new_state.availability = 0xff;
740 else
741 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
742 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
743 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100744 } else
745 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800746 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
747 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther460fb3b2009-10-22 15:44:30 +0200748 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800749 }
750 DEBUGPC(DNM, "\n");
751
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100752 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
753 new_state.operational != nm_state->operational ||
754 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800755 /* Update the operational state of a given object in our in-memory data
756 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100757 struct nm_statechg_signal_data nsd;
758 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
759 nsd.obj_class = foh->obj_class;
760 nsd.old_state = nm_state;
761 nsd.new_state = &new_state;
762 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100763 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100764 dispatch_signal(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100765 nm_state->operational = new_state.operational;
766 nm_state->availability = new_state.availability;
767 if (nm_state->administrative == 0)
768 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800769 }
770#if 0
771 if (op_state == 1) {
772 /* try to enable objects that are disabled */
773 abis_nm_opstart(bts, foh->obj_class,
774 foh->obj_inst.bts_nr,
775 foh->obj_inst.trx_nr,
776 foh->obj_inst.ts_nr);
777 }
778#endif
779 return 0;
780}
781
782static int rx_fail_evt_rep(struct msgb *mb)
783{
784 struct abis_om_hdr *oh = msgb_l2(mb);
785 struct abis_om_fom_hdr *foh = msgb_l3(mb);
786 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100787 const uint8_t *p_val;
788 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800789
790 DEBUGPC(DNM, "Failure Event Report ");
791
Harald Welte59698fb2010-01-10 18:01:52 +0100792 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800793
794 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
795 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
796 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
797 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100798 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
799 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
800 DEBUGPC(DNM, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
801 }
802 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
803 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
804 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
805 if (p_text) {
806 DEBUGPC(DNM, "Additional Text=%s ", p_text);
807 talloc_free(p_text);
808 }
809 }
Harald Welte59b04682009-06-10 05:40:52 +0800810
811 DEBUGPC(DNM, "\n");
812
813 return 0;
814}
815
816static int abis_nm_rcvmsg_report(struct msgb *mb)
817{
818 struct abis_om_fom_hdr *foh = msgb_l3(mb);
819 u_int8_t mt = foh->msg_type;
820
Harald Welteb7284a92009-10-20 09:56:18 +0200821 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800822
823 //nmh->cfg->report_cb(mb, foh);
824
825 switch (mt) {
826 case NM_MT_STATECHG_EVENT_REP:
827 return abis_nm_rx_statechg_rep(mb);
828 break;
829 case NM_MT_SW_ACTIVATED_REP:
830 DEBUGPC(DNM, "Software Activated Report\n");
831 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
832 break;
833 case NM_MT_FAILURE_EVENT_REP:
834 rx_fail_evt_rep(mb);
835 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
836 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200837 case NM_MT_TEST_REP:
838 DEBUGPC(DNM, "Test Report\n");
839 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
840 break;
Harald Welte59b04682009-06-10 05:40:52 +0800841 default:
842 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
843 break;
844
845 };
846
847 return 0;
848}
849
850/* Activate the specified software into the BTS */
851static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
Mike Haben322fc582009-10-01 14:56:13 +0200852 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800853{
854 struct abis_om_hdr *oh;
855 struct msgb *msg = nm_msgb_alloc();
856 u_int8_t len = swdesc_len;
857 u_int8_t *trailer;
858
859 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
860 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
861
862 trailer = msgb_put(msg, swdesc_len);
863 memcpy(trailer, sw_desc, swdesc_len);
864
865 return abis_nm_sendmsg(bts, msg);
866}
867
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100868static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
869{
870 static const struct tlv_definition sw_descr_def = {
871 .def = {
872 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
873 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
874 },
875 };
876
877 u_int8_t tag;
878 u_int16_t tag_len;
879 const u_int8_t *val;
880 int ofs = 0, len;
881
882 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
883 * nested nature and the fact you have to assume it contains only two sub
884 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
885
886 if (sw_descr[0] != NM_ATT_SW_DESCR) {
887 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
888 return -1;
889 }
890 ofs += 1;
891
892 len = tlv_parse_one(&tag, &tag_len, &val,
893 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
894 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
895 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
896 return -2;
897 }
898 ofs += len;
899
900 len = tlv_parse_one(&tag, &tag_len, &val,
901 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
902 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
903 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
904 return -3;
905 }
906 ofs += len;
907
908 return ofs;
909}
910
Harald Welte59b04682009-06-10 05:40:52 +0800911static int abis_nm_rx_sw_act_req(struct msgb *mb)
912{
913 struct abis_om_hdr *oh = msgb_l2(mb);
914 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200915 struct tlv_parsed tp;
916 const u_int8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100917 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800918
Harald Welteb7284a92009-10-20 09:56:18 +0200919 debugp_foh(foh);
920
921 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800922
Harald Welte3055e332010-03-14 15:37:43 +0800923 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800924
925 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
926 foh->obj_inst.bts_nr,
927 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800928 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800929 foh->data, oh->length-sizeof(*foh));
930
Harald Welte59698fb2010-01-10 18:01:52 +0100931 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200932 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
933 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
934 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
935 DEBUGP(DNM, "SW config not found! Can't continue.\n");
936 return -EINVAL;
937 } else {
938 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
939 }
940
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100941 /* Use the first SW_DESCR present in SW config */
942 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
943 if (sw_descr_len < 0)
944 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200945
Harald Welte59b04682009-06-10 05:40:52 +0800946 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
947 foh->obj_inst.bts_nr,
948 foh->obj_inst.trx_nr,
949 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100950 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800951}
952
953/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
954static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
955{
956 struct abis_om_hdr *oh = msgb_l2(mb);
957 struct abis_om_fom_hdr *foh = msgb_l3(mb);
958 struct tlv_parsed tp;
959 u_int8_t adm_state;
960
Harald Welte59698fb2010-01-10 18:01:52 +0100961 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800962 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
963 return -EINVAL;
964
965 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
966
967 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
968}
969
970static int abis_nm_rx_lmt_event(struct msgb *mb)
971{
972 struct abis_om_hdr *oh = msgb_l2(mb);
973 struct abis_om_fom_hdr *foh = msgb_l3(mb);
974 struct tlv_parsed tp;
975
976 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100977 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800978 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
979 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
980 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
981 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
982 }
983 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
984 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
985 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
986 DEBUGPC(DNM, "Level=%u ", level);
987 }
988 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
989 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
990 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
991 DEBUGPC(DNM, "Username=%s ", name);
992 }
993 DEBUGPC(DNM, "\n");
994 /* FIXME: parse LMT LOGON TIME */
995 return 0;
996}
997
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100998static void abis_nm_queue_send_next(struct gsm_bts *bts)
999{
1000 int wait = 0;
1001 struct msgb *msg;
1002 /* the queue is empty */
1003 while (!llist_empty(&bts->abis_queue)) {
1004 msg = msgb_dequeue(&bts->abis_queue);
1005 wait = OBSC_NM_W_ACK_CB(msg);
Harald Weltec5845042011-02-14 15:26:13 +01001006 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001007
1008 if (wait)
1009 break;
1010 }
1011
1012 bts->abis_nm_pend = wait;
1013}
1014
Harald Welte59b04682009-06-10 05:40:52 +08001015/* Receive a OML NM Message from BTS */
1016static int abis_nm_rcvmsg_fom(struct msgb *mb)
1017{
1018 struct abis_om_hdr *oh = msgb_l2(mb);
1019 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1020 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001021 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001022
1023 /* check for unsolicited message */
1024 if (is_report(mt))
1025 return abis_nm_rcvmsg_report(mb);
1026
1027 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1028 return abis_nm_rcvmsg_sw(mb);
1029
1030 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001031 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +08001032 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +02001033
Harald Welteb7284a92009-10-20 09:56:18 +02001034 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +02001035
Harald Welte453141f2010-03-25 11:45:30 +08001036 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +08001037
Harald Welte59698fb2010-01-10 18:01:52 +01001038 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08001039 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001040 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08001041 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1042 else
1043 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001044
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001045 nack_data.msg = mb;
1046 nack_data.mt = mt;
1047 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001048 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001049 return 0;
Harald Welte59b04682009-06-10 05:40:52 +08001050 }
1051#if 0
1052 /* check if last message is to be acked */
1053 if (is_ack_nack(nmh->last_msgtype)) {
1054 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +01001055 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001056 /* we got our ACK, continue sending the next msg */
1057 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1058 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +01001059 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001060 /* FIXME: somehow signal this to the caller */
1061 } else {
1062 /* really strange things happen */
1063 return -EINVAL;
1064 }
1065 }
1066#endif
1067
1068 switch (mt) {
1069 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001070 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001071 break;
1072 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001073 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001074 break;
1075 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001076 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001077 break;
Harald Welte204317e2009-08-06 17:58:31 +02001078 case NM_MT_CONN_MDROP_LINK_ACK:
1079 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1080 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001081 case NM_MT_IPACC_RESTART_ACK:
1082 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1083 break;
1084 case NM_MT_IPACC_RESTART_NACK:
1085 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1086 break;
Harald Welte08011e22011-03-04 13:41:31 +01001087 case NM_MT_SET_BTS_ATTR_ACK:
1088 /* The HSL wants an OPSTART _after_ the SI has been set */
1089 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
1090 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
1091 }
1092 break;
Harald Welte59b04682009-06-10 05:40:52 +08001093 }
1094
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001095 abis_nm_queue_send_next(mb->trx->bts);
1096 return ret;
Harald Welte59b04682009-06-10 05:40:52 +08001097}
1098
1099static int abis_nm_rx_ipacc(struct msgb *mb);
1100
1101static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1102{
1103 int rc;
1104 int bts_type = mb->trx->bts->type;
1105
1106 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001107 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001108 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001109 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001110 break;
1111 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001112 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1113 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001114 rc = 0;
1115 break;
1116 }
1117
1118 return rc;
1119}
1120
1121/* High-Level API */
1122/* Entry-point where L2 OML from BTS enters the NM code */
1123int abis_nm_rcvmsg(struct msgb *msg)
1124{
1125 struct abis_om_hdr *oh = msgb_l2(msg);
1126 int rc = 0;
1127
1128 /* Various consistency checks */
1129 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001130 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001131 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +02001132 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1133 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +08001134 }
1135 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001136 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001137 oh->sequence);
1138 return -EINVAL;
1139 }
1140#if 0
1141 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1142 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1143 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001144 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001145 oh->length + sizeof(*oh), l2_len);
1146 return -EINVAL;
1147 }
1148 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001149 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte59b04682009-06-10 05:40:52 +08001150#endif
1151 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1152
1153 switch (oh->mdisc) {
1154 case ABIS_OM_MDISC_FOM:
1155 rc = abis_nm_rcvmsg_fom(msg);
1156 break;
1157 case ABIS_OM_MDISC_MANUF:
1158 rc = abis_nm_rcvmsg_manuf(msg);
1159 break;
1160 case ABIS_OM_MDISC_MMI:
1161 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001162 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001163 oh->mdisc);
1164 break;
1165 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001166 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001167 oh->mdisc);
1168 return -EINVAL;
1169 }
1170
1171 msgb_free(msg);
1172 return rc;
1173}
1174
1175#if 0
1176/* initialized all resources */
1177struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1178{
1179 struct abis_nm_h *nmh;
1180
1181 nmh = malloc(sizeof(*nmh));
1182 if (!nmh)
1183 return NULL;
1184
1185 nmh->cfg = cfg;
1186
1187 return nmh;
1188}
1189
1190/* free all resources */
1191void abis_nm_fini(struct abis_nm_h *nmh)
1192{
1193 free(nmh);
1194}
1195#endif
1196
1197/* Here we are trying to define a high-level API that can be used by
1198 * the actual BSC implementation. However, the architecture is currently
1199 * still under design. Ideally the calls to this API would be synchronous,
1200 * while the underlying stack behind the APi runs in a traditional select
1201 * based state machine.
1202 */
1203
1204/* 6.2 Software Load: */
1205enum sw_state {
1206 SW_STATE_NONE,
1207 SW_STATE_WAIT_INITACK,
1208 SW_STATE_WAIT_SEGACK,
1209 SW_STATE_WAIT_ENDACK,
1210 SW_STATE_WAIT_ACTACK,
1211 SW_STATE_ERROR,
1212};
1213
1214struct abis_nm_sw {
1215 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001216 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +08001217 gsm_cbfn *cbfn;
1218 void *cb_data;
1219 int forced;
1220
1221 /* this will become part of the SW LOAD INITIATE */
1222 u_int8_t obj_class;
1223 u_int8_t obj_instance[3];
1224
1225 u_int8_t file_id[255];
1226 u_int8_t file_id_len;
1227
1228 u_int8_t file_version[255];
1229 u_int8_t file_version_len;
1230
1231 u_int8_t window_size;
1232 u_int8_t seg_in_window;
1233
1234 int fd;
1235 FILE *stream;
1236 enum sw_state state;
1237 int last_seg;
1238};
1239
1240static struct abis_nm_sw g_sw;
1241
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001242static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1243{
1244 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1245 msgb_v_put(msg, NM_ATT_SW_DESCR);
1246 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1247 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1248 sw->file_version);
1249 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1250 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1251 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1252 sw->file_version);
1253 } else {
1254 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1255 }
1256}
1257
Harald Welte59b04682009-06-10 05:40:52 +08001258/* 6.2.1 / 8.3.1: Load Data Initiate */
1259static int sw_load_init(struct abis_nm_sw *sw)
1260{
1261 struct abis_om_hdr *oh;
1262 struct msgb *msg = nm_msgb_alloc();
1263 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1264
1265 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1266 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1267 sw->obj_instance[0], sw->obj_instance[1],
1268 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001269
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001270 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001271 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1272
1273 return abis_nm_sendmsg(sw->bts, msg);
1274}
1275
1276static int is_last_line(FILE *stream)
1277{
1278 char next_seg_buf[256];
1279 long pos;
1280
1281 /* check if we're sending the last line */
1282 pos = ftell(stream);
1283 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1284 fseek(stream, pos, SEEK_SET);
1285 return 1;
1286 }
1287
1288 fseek(stream, pos, SEEK_SET);
1289 return 0;
1290}
1291
1292/* 6.2.2 / 8.3.2 Load Data Segment */
1293static int sw_load_segment(struct abis_nm_sw *sw)
1294{
1295 struct abis_om_hdr *oh;
1296 struct msgb *msg = nm_msgb_alloc();
1297 char seg_buf[256];
1298 char *line_buf = seg_buf+2;
1299 unsigned char *tlv;
1300 u_int8_t len;
1301
1302 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1303
1304 switch (sw->bts->type) {
1305 case GSM_BTS_TYPE_BS11:
1306 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1307 perror("fgets reading segment");
1308 return -EINVAL;
1309 }
1310 seg_buf[0] = 0x00;
1311
1312 /* check if we're sending the last line */
1313 sw->last_seg = is_last_line(sw->stream);
1314 if (sw->last_seg)
1315 seg_buf[1] = 0;
1316 else
1317 seg_buf[1] = 1 + sw->seg_in_window++;
1318
1319 len = strlen(line_buf) + 2;
1320 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1321 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1322 /* BS11 wants CR + LF in excess of the TLV length !?! */
1323 tlv[1] -= 2;
1324
1325 /* we only now know the exact length for the OM hdr */
1326 len = strlen(line_buf)+2;
1327 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001328 case GSM_BTS_TYPE_NANOBTS: {
1329 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1330 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1331 if (len < 0) {
1332 perror("read failed");
1333 return -EINVAL;
1334 }
1335
1336 if (len != IPACC_SEGMENT_SIZE)
1337 sw->last_seg = 1;
1338
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001339 ++sw->seg_in_window;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001340 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1341 len += 3;
1342 break;
1343 }
Harald Welte59b04682009-06-10 05:40:52 +08001344 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001345 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001346 /* FIXME: Other BTS types */
1347 return -1;
1348 }
1349
1350 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1351 sw->obj_instance[0], sw->obj_instance[1],
1352 sw->obj_instance[2]);
1353
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001354 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001355}
1356
1357/* 6.2.4 / 8.3.4 Load Data End */
1358static int sw_load_end(struct abis_nm_sw *sw)
1359{
1360 struct abis_om_hdr *oh;
1361 struct msgb *msg = nm_msgb_alloc();
1362 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1363
1364 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1365 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1366 sw->obj_instance[0], sw->obj_instance[1],
1367 sw->obj_instance[2]);
1368
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001369 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001370 return abis_nm_sendmsg(sw->bts, msg);
1371}
1372
1373/* Activate the specified software into the BTS */
1374static int sw_activate(struct abis_nm_sw *sw)
1375{
1376 struct abis_om_hdr *oh;
1377 struct msgb *msg = nm_msgb_alloc();
1378 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1379
1380 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1381 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1382 sw->obj_instance[0], sw->obj_instance[1],
1383 sw->obj_instance[2]);
1384
1385 /* FIXME: this is BS11 specific format */
1386 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1387 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1388 sw->file_version);
1389
1390 return abis_nm_sendmsg(sw->bts, msg);
1391}
1392
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001393struct sdp_firmware {
1394 char magic[4];
1395 char more_magic[4];
1396 unsigned int header_length;
1397 unsigned int file_length;
1398} __attribute__ ((packed));
1399
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001400static int parse_sdp_header(struct abis_nm_sw *sw)
1401{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001402 struct sdp_firmware firmware_header;
1403 int rc;
1404 struct stat stat;
1405
1406 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1407 if (rc != sizeof(firmware_header)) {
1408 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1409 return -1;
1410 }
1411
1412 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1413 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1414 return -1;
1415 }
1416
1417 if (firmware_header.more_magic[0] != 0x10 ||
1418 firmware_header.more_magic[1] != 0x02 ||
1419 firmware_header.more_magic[2] != 0x00 ||
1420 firmware_header.more_magic[3] != 0x00) {
1421 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1422 return -1;
1423 }
1424
1425
1426 if (fstat(sw->fd, &stat) == -1) {
1427 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1428 return -1;
1429 }
1430
1431 if (ntohl(firmware_header.file_length) != stat.st_size) {
1432 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1433 return -1;
1434 }
1435
1436 /* go back to the start as we checked the whole filesize.. */
1437 lseek(sw->fd, 0l, SEEK_SET);
1438 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1439 "There might be checksums in the file that are not\n"
1440 "verified and incomplete firmware might be flashed.\n"
1441 "There is absolutely no WARRANTY that flashing will\n"
1442 "work.\n");
1443 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001444}
1445
Harald Welte59b04682009-06-10 05:40:52 +08001446static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1447{
1448 char file_id[12+1];
1449 char file_version[80+1];
1450 int rc;
1451
1452 sw->fd = open(fname, O_RDONLY);
1453 if (sw->fd < 0)
1454 return sw->fd;
1455
1456 switch (sw->bts->type) {
1457 case GSM_BTS_TYPE_BS11:
1458 sw->stream = fdopen(sw->fd, "r");
1459 if (!sw->stream) {
1460 perror("fdopen");
1461 return -1;
1462 }
1463 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001464 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001465 file_id, file_version);
1466 if (rc != 2) {
1467 perror("parsing header line of software file");
1468 return -1;
1469 }
1470 strcpy((char *)sw->file_id, file_id);
1471 sw->file_id_len = strlen(file_id);
1472 strcpy((char *)sw->file_version, file_version);
1473 sw->file_version_len = strlen(file_version);
1474 /* rewind to start of file */
1475 rewind(sw->stream);
1476 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001477 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001478 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001479 rc = parse_sdp_header(sw);
1480 if (rc < 0) {
1481 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1482 return -1;
1483 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001484
1485 strcpy((char *)sw->file_id, "id");
1486 sw->file_id_len = 3;
1487 strcpy((char *)sw->file_version, "version");
1488 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001489 break;
Harald Welte59b04682009-06-10 05:40:52 +08001490 default:
1491 /* We don't know how to treat them yet */
1492 close(sw->fd);
1493 return -EINVAL;
1494 }
1495
1496 return 0;
1497}
1498
1499static void sw_close_file(struct abis_nm_sw *sw)
1500{
1501 switch (sw->bts->type) {
1502 case GSM_BTS_TYPE_BS11:
1503 fclose(sw->stream);
1504 break;
1505 default:
1506 close(sw->fd);
1507 break;
1508 }
1509}
1510
1511/* Fill the window */
1512static int sw_fill_window(struct abis_nm_sw *sw)
1513{
1514 int rc;
1515
1516 while (sw->seg_in_window < sw->window_size) {
1517 rc = sw_load_segment(sw);
1518 if (rc < 0)
1519 return rc;
1520 if (sw->last_seg)
1521 break;
1522 }
1523 return 0;
1524}
1525
1526/* callback function from abis_nm_rcvmsg() handler */
1527static int abis_nm_rcvmsg_sw(struct msgb *mb)
1528{
1529 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1530 int rc = -1;
1531 struct abis_nm_sw *sw = &g_sw;
1532 enum sw_state old_state = sw->state;
1533
1534 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1535
1536 switch (sw->state) {
1537 case SW_STATE_WAIT_INITACK:
1538 switch (foh->msg_type) {
1539 case NM_MT_LOAD_INIT_ACK:
1540 /* fill window with segments */
1541 if (sw->cbfn)
1542 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1543 NM_MT_LOAD_INIT_ACK, mb,
1544 sw->cb_data, NULL);
1545 rc = sw_fill_window(sw);
1546 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001547 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001548 break;
1549 case NM_MT_LOAD_INIT_NACK:
1550 if (sw->forced) {
1551 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1552 "Init NACK\n");
1553 if (sw->cbfn)
1554 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1555 NM_MT_LOAD_INIT_ACK, mb,
1556 sw->cb_data, NULL);
1557 rc = sw_fill_window(sw);
1558 sw->state = SW_STATE_WAIT_SEGACK;
1559 } else {
1560 DEBUGP(DNM, "Software Load Init NACK\n");
1561 /* FIXME: cause */
1562 if (sw->cbfn)
1563 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1564 NM_MT_LOAD_INIT_NACK, mb,
1565 sw->cb_data, NULL);
1566 sw->state = SW_STATE_ERROR;
1567 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001568 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001569 break;
1570 }
1571 break;
1572 case SW_STATE_WAIT_SEGACK:
1573 switch (foh->msg_type) {
1574 case NM_MT_LOAD_SEG_ACK:
1575 if (sw->cbfn)
1576 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1577 NM_MT_LOAD_SEG_ACK, mb,
1578 sw->cb_data, NULL);
1579 sw->seg_in_window = 0;
1580 if (!sw->last_seg) {
1581 /* fill window with more segments */
1582 rc = sw_fill_window(sw);
1583 sw->state = SW_STATE_WAIT_SEGACK;
1584 } else {
1585 /* end the transfer */
1586 sw->state = SW_STATE_WAIT_ENDACK;
1587 rc = sw_load_end(sw);
1588 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001589 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001590 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001591 case NM_MT_LOAD_ABORT:
1592 if (sw->cbfn)
1593 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1594 NM_MT_LOAD_ABORT, mb,
1595 sw->cb_data, NULL);
1596 break;
Harald Welte59b04682009-06-10 05:40:52 +08001597 }
1598 break;
1599 case SW_STATE_WAIT_ENDACK:
1600 switch (foh->msg_type) {
1601 case NM_MT_LOAD_END_ACK:
1602 sw_close_file(sw);
1603 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1604 sw->bts->nr);
1605 sw->state = SW_STATE_NONE;
1606 if (sw->cbfn)
1607 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1608 NM_MT_LOAD_END_ACK, mb,
1609 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001610 rc = 0;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001611 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001612 break;
1613 case NM_MT_LOAD_END_NACK:
1614 if (sw->forced) {
1615 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1616 "End NACK\n");
1617 sw->state = SW_STATE_NONE;
1618 if (sw->cbfn)
1619 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1620 NM_MT_LOAD_END_ACK, mb,
1621 sw->cb_data, NULL);
1622 } else {
1623 DEBUGP(DNM, "Software Load End NACK\n");
1624 /* FIXME: cause */
1625 sw->state = SW_STATE_ERROR;
1626 if (sw->cbfn)
1627 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1628 NM_MT_LOAD_END_NACK, mb,
1629 sw->cb_data, NULL);
1630 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001631 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001632 break;
1633 }
1634 case SW_STATE_WAIT_ACTACK:
1635 switch (foh->msg_type) {
1636 case NM_MT_ACTIVATE_SW_ACK:
1637 /* we're done */
1638 DEBUGP(DNM, "Activate Software DONE!\n");
1639 sw->state = SW_STATE_NONE;
1640 rc = 0;
1641 if (sw->cbfn)
1642 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1643 NM_MT_ACTIVATE_SW_ACK, mb,
1644 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001645 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001646 break;
1647 case NM_MT_ACTIVATE_SW_NACK:
1648 DEBUGP(DNM, "Activate Software NACK\n");
1649 /* FIXME: cause */
1650 sw->state = SW_STATE_ERROR;
1651 if (sw->cbfn)
1652 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1653 NM_MT_ACTIVATE_SW_NACK, mb,
1654 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001655 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001656 break;
1657 }
1658 case SW_STATE_NONE:
1659 switch (foh->msg_type) {
1660 case NM_MT_ACTIVATE_SW_ACK:
1661 rc = 0;
1662 break;
1663 }
1664 break;
1665 case SW_STATE_ERROR:
1666 break;
1667 }
1668
1669 if (rc)
1670 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1671 foh->msg_type, old_state, sw->state);
1672
1673 return rc;
1674}
1675
1676/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001677int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte59b04682009-06-10 05:40:52 +08001678 u_int8_t win_size, int forced,
1679 gsm_cbfn *cbfn, void *cb_data)
1680{
1681 struct abis_nm_sw *sw = &g_sw;
1682 int rc;
1683
1684 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1685 bts->nr, fname);
1686
1687 if (sw->state != SW_STATE_NONE)
1688 return -EBUSY;
1689
1690 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001691 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001692
1693 switch (bts->type) {
1694 case GSM_BTS_TYPE_BS11:
1695 sw->obj_class = NM_OC_SITE_MANAGER;
1696 sw->obj_instance[0] = 0xff;
1697 sw->obj_instance[1] = 0xff;
1698 sw->obj_instance[2] = 0xff;
1699 break;
1700 case GSM_BTS_TYPE_NANOBTS:
1701 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001702 sw->obj_instance[0] = sw->bts->nr;
1703 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001704 sw->obj_instance[2] = 0xff;
1705 break;
1706 case GSM_BTS_TYPE_UNKNOWN:
1707 default:
1708 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1709 return -1;
1710 break;
1711 }
Harald Welte59b04682009-06-10 05:40:52 +08001712 sw->window_size = win_size;
1713 sw->state = SW_STATE_WAIT_INITACK;
1714 sw->cbfn = cbfn;
1715 sw->cb_data = cb_data;
1716 sw->forced = forced;
1717
1718 rc = sw_open_file(sw, fname);
1719 if (rc < 0) {
1720 sw->state = SW_STATE_NONE;
1721 return rc;
1722 }
1723
1724 return sw_load_init(sw);
1725}
1726
1727int abis_nm_software_load_status(struct gsm_bts *bts)
1728{
1729 struct abis_nm_sw *sw = &g_sw;
1730 struct stat st;
1731 int rc, percent;
1732
1733 rc = fstat(sw->fd, &st);
1734 if (rc < 0) {
1735 perror("ERROR during stat");
1736 return rc;
1737 }
1738
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001739 if (sw->stream)
1740 percent = (ftell(sw->stream) * 100) / st.st_size;
1741 else
1742 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001743 return percent;
1744}
1745
1746/* Activate the specified software into the BTS */
1747int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1748 gsm_cbfn *cbfn, void *cb_data)
1749{
1750 struct abis_nm_sw *sw = &g_sw;
1751 int rc;
1752
1753 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1754 bts->nr, fname);
1755
1756 if (sw->state != SW_STATE_NONE)
1757 return -EBUSY;
1758
1759 sw->bts = bts;
1760 sw->obj_class = NM_OC_SITE_MANAGER;
1761 sw->obj_instance[0] = 0xff;
1762 sw->obj_instance[1] = 0xff;
1763 sw->obj_instance[2] = 0xff;
1764 sw->state = SW_STATE_WAIT_ACTACK;
1765 sw->cbfn = cbfn;
1766 sw->cb_data = cb_data;
1767
1768 /* Open the file in order to fill some sw struct members */
1769 rc = sw_open_file(sw, fname);
1770 if (rc < 0) {
1771 sw->state = SW_STATE_NONE;
1772 return rc;
1773 }
1774 sw_close_file(sw);
1775
1776 return sw_activate(sw);
1777}
1778
1779static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1780 u_int8_t ts_nr, u_int8_t subslot_nr)
1781{
1782 ch->attrib = NM_ATT_ABIS_CHANNEL;
1783 ch->bts_port = bts_port;
1784 ch->timeslot = ts_nr;
1785 ch->subslot = subslot_nr;
1786}
1787
1788int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1789 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1790 u_int8_t tei)
1791{
1792 struct abis_om_hdr *oh;
1793 struct abis_nm_channel *ch;
1794 u_int8_t len = sizeof(*ch) + 2;
1795 struct msgb *msg = nm_msgb_alloc();
1796
1797 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1798 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1799 bts->bts_nr, trx_nr, 0xff);
1800
1801 msgb_tv_put(msg, NM_ATT_TEI, tei);
1802
1803 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1804 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1805
1806 return abis_nm_sendmsg(bts, msg);
1807}
1808
1809/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1810int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1811 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1812{
1813 struct gsm_bts *bts = trx->bts;
1814 struct abis_om_hdr *oh;
1815 struct abis_nm_channel *ch;
1816 struct msgb *msg = nm_msgb_alloc();
1817
1818 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1819 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1820 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1821
1822 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1823 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1824
1825 return abis_nm_sendmsg(bts, msg);
1826}
1827
1828#if 0
1829int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1830 struct abis_nm_abis_channel *chan)
1831{
1832}
1833#endif
1834
1835int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1836 u_int8_t e1_port, u_int8_t e1_timeslot,
1837 u_int8_t e1_subslot)
1838{
1839 struct gsm_bts *bts = ts->trx->bts;
1840 struct abis_om_hdr *oh;
1841 struct abis_nm_channel *ch;
1842 struct msgb *msg = nm_msgb_alloc();
1843
1844 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1845 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1846 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1847
1848 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1849 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1850
1851 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1852 gsm_ts_name(ts),
1853 e1_port, e1_timeslot, e1_subslot);
1854
1855 return abis_nm_sendmsg(bts, msg);
1856}
1857
1858#if 0
1859int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1860 struct abis_nm_abis_channel *chan,
1861 u_int8_t subchan)
1862{
1863}
1864#endif
1865
1866/* Chapter 8.6.1 */
1867int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1868{
1869 struct abis_om_hdr *oh;
1870 struct msgb *msg = nm_msgb_alloc();
1871 u_int8_t *cur;
1872
1873 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1874
1875 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1876 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1877 cur = msgb_put(msg, attr_len);
1878 memcpy(cur, attr, attr_len);
1879
1880 return abis_nm_sendmsg(bts, msg);
1881}
1882
1883/* Chapter 8.6.2 */
1884int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1885{
1886 struct abis_om_hdr *oh;
1887 struct msgb *msg = nm_msgb_alloc();
1888 u_int8_t *cur;
1889
1890 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1891
1892 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1893 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1894 trx->bts->bts_nr, trx->nr, 0xff);
1895 cur = msgb_put(msg, attr_len);
1896 memcpy(cur, attr, attr_len);
1897
1898 return abis_nm_sendmsg(trx->bts, msg);
1899}
1900
Harald Weltef2eb2782009-08-09 21:49:48 +02001901static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1902{
1903 int i;
1904
1905 /* As it turns out, the BS-11 has some very peculiar restrictions
1906 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301907 switch (ts->trx->bts->type) {
1908 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001909 switch (chan_comb) {
1910 case NM_CHANC_TCHHalf:
1911 case NM_CHANC_TCHHalf2:
1912 /* not supported */
1913 return -EINVAL;
1914 case NM_CHANC_SDCCH:
1915 /* only one SDCCH/8 per TRX */
1916 for (i = 0; i < TRX_NR_TS; i++) {
1917 if (i == ts->nr)
1918 continue;
1919 if (ts->trx->ts[i].nm_chan_comb ==
1920 NM_CHANC_SDCCH)
1921 return -EINVAL;
1922 }
1923 /* not allowed for TS0 of BCCH-TRX */
1924 if (ts->trx == ts->trx->bts->c0 &&
1925 ts->nr == 0)
1926 return -EINVAL;
1927 /* not on the same TRX that has a BCCH+SDCCH4
1928 * combination */
1929 if (ts->trx == ts->trx->bts->c0 &&
1930 (ts->trx->ts[0].nm_chan_comb == 5 ||
1931 ts->trx->ts[0].nm_chan_comb == 8))
1932 return -EINVAL;
1933 break;
1934 case NM_CHANC_mainBCCH:
1935 case NM_CHANC_BCCHComb:
1936 /* allowed only for TS0 of C0 */
1937 if (ts->trx != ts->trx->bts->c0 ||
1938 ts->nr != 0)
1939 return -EINVAL;
1940 break;
1941 case NM_CHANC_BCCH:
1942 /* allowed only for TS 2/4/6 of C0 */
1943 if (ts->trx != ts->trx->bts->c0)
1944 return -EINVAL;
1945 if (ts->nr != 2 && ts->nr != 4 &&
1946 ts->nr != 6)
1947 return -EINVAL;
1948 break;
1949 case 8: /* this is not like 08.58, but in fact
1950 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1951 /* FIXME: only one CBCH allowed per cell */
1952 break;
1953 }
Harald Welte76ba8812009-12-02 02:45:23 +05301954 break;
1955 case GSM_BTS_TYPE_NANOBTS:
1956 switch (ts->nr) {
1957 case 0:
1958 if (ts->trx->nr == 0) {
1959 /* only on TRX0 */
1960 switch (chan_comb) {
1961 case NM_CHANC_BCCH:
1962 case NM_CHANC_mainBCCH:
1963 case NM_CHANC_BCCHComb:
1964 return 0;
1965 break;
1966 default:
1967 return -EINVAL;
1968 }
1969 } else {
1970 switch (chan_comb) {
1971 case NM_CHANC_TCHFull:
1972 case NM_CHANC_TCHHalf:
1973 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1974 return 0;
1975 default:
1976 return -EINVAL;
1977 }
1978 }
1979 break;
1980 case 1:
1981 if (ts->trx->nr == 0) {
1982 switch (chan_comb) {
1983 case NM_CHANC_SDCCH_CBCH:
1984 if (ts->trx->ts[0].nm_chan_comb ==
1985 NM_CHANC_mainBCCH)
1986 return 0;
1987 return -EINVAL;
1988 case NM_CHANC_SDCCH:
1989 case NM_CHANC_TCHFull:
1990 case NM_CHANC_TCHHalf:
1991 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1992 case NM_CHANC_IPAC_TCHFull_PDCH:
1993 return 0;
1994 }
1995 } else {
1996 switch (chan_comb) {
1997 case NM_CHANC_SDCCH:
1998 case NM_CHANC_TCHFull:
1999 case NM_CHANC_TCHHalf:
2000 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2001 return 0;
2002 default:
2003 return -EINVAL;
2004 }
2005 }
2006 break;
2007 case 2:
2008 case 3:
2009 case 4:
2010 case 5:
2011 case 6:
2012 case 7:
2013 switch (chan_comb) {
2014 case NM_CHANC_TCHFull:
2015 case NM_CHANC_TCHHalf:
2016 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2017 return 0;
2018 case NM_CHANC_IPAC_PDCH:
2019 case NM_CHANC_IPAC_TCHFull_PDCH:
2020 if (ts->trx->nr == 0)
2021 return 0;
2022 else
2023 return -EINVAL;
2024 }
2025 break;
2026 }
2027 return -EINVAL;
2028 default:
2029 /* unknown BTS type */
2030 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02002031 }
2032 return 0;
2033}
2034
Harald Welte59b04682009-06-10 05:40:52 +08002035/* Chapter 8.6.3 */
2036int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2037{
2038 struct gsm_bts *bts = ts->trx->bts;
2039 struct abis_om_hdr *oh;
Harald Welte59b04682009-06-10 05:40:52 +08002040 u_int8_t zero = 0x00;
2041 struct msgb *msg = nm_msgb_alloc();
2042 u_int8_t len = 2 + 2;
2043
2044 if (bts->type == GSM_BTS_TYPE_BS11)
2045 len += 4 + 2 + 2 + 3;
2046
2047 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02002048 if (verify_chan_comb(ts, chan_comb) < 0) {
2049 msgb_free(msg);
2050 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2051 return -EINVAL;
2052 }
2053 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08002054
2055 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2056 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
2057 NM_OC_CHANNEL, bts->bts_nr,
2058 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08002059 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02002060 if (ts->hopping.enabled) {
2061 unsigned int i;
2062 uint8_t *len;
2063
Harald Welte67104d12009-09-12 13:05:33 +02002064 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2065 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02002066
2067 /* build the ARFCN list */
2068 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2069 len = msgb_put(msg, 1);
2070 *len = 0;
2071 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2072 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2073 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02002074 /* At least BS-11 wants a TLV16 here */
2075 if (bts->type == GSM_BTS_TYPE_BS11)
2076 *len += 1;
2077 else
2078 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02002079 }
2080 }
Harald Welte59b04682009-06-10 05:40:52 +08002081 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02002082 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08002083 if (bts->type == GSM_BTS_TYPE_BS11)
2084 msgb_tlv_put(msg, 0x59, 1, &zero);
2085
2086 return abis_nm_sendmsg(bts, msg);
2087}
2088
2089int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
2090 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
2091{
2092 struct abis_om_hdr *oh;
2093 struct msgb *msg = nm_msgb_alloc();
2094 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2095 u_int8_t len = att_len;
2096
2097 if (nack) {
2098 len += 2;
2099 msgtype = NM_MT_SW_ACT_REQ_NACK;
2100 }
2101
2102 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2103 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2104
2105 if (attr) {
2106 u_int8_t *ptr = msgb_put(msg, att_len);
2107 memcpy(ptr, attr, att_len);
2108 }
2109 if (nack)
2110 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2111
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002112 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002113}
2114
2115int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2116{
2117 struct msgb *msg = nm_msgb_alloc();
2118 struct abis_om_hdr *oh;
2119 u_int8_t *data;
2120
2121 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2122 fill_om_hdr(oh, len);
2123 data = msgb_put(msg, len);
2124 memcpy(data, rawmsg, len);
2125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
2129/* Siemens specific commands */
2130static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2131{
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, 0, msg_type, NM_OC_SITE_MANAGER,
2137 0xff, 0xff, 0xff);
2138
2139 return abis_nm_sendmsg(bts, msg);
2140}
2141
2142/* Chapter 8.9.2 */
2143int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2144{
2145 struct abis_om_hdr *oh;
2146 struct msgb *msg = nm_msgb_alloc();
2147
Harald Welte59b04682009-06-10 05:40:52 +08002148 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2149 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2150
Harald Welteb7284a92009-10-20 09:56:18 +02002151 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2152 DEBUGPC(DNM, "Sending OPSTART\n");
2153
Harald Welte59b04682009-06-10 05:40:52 +08002154 return abis_nm_sendmsg(bts, msg);
2155}
2156
2157/* Chapter 8.8.5 */
2158int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002159 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002160{
2161 struct abis_om_hdr *oh;
2162 struct msgb *msg = nm_msgb_alloc();
2163
2164 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2165 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2166 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2167
2168 return abis_nm_sendmsg(bts, msg);
2169}
2170
Harald Welte204317e2009-08-06 17:58:31 +02002171int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2172 u_int8_t e1_port1, u_int8_t ts1)
2173{
2174 struct abis_om_hdr *oh;
2175 struct msgb *msg = nm_msgb_alloc();
2176 u_int8_t *attr;
2177
2178 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2179 e1_port0, ts0, e1_port1, ts1);
2180
2181 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2182 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2183 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2184
2185 attr = msgb_put(msg, 3);
2186 attr[0] = NM_ATT_MDROP_LINK;
2187 attr[1] = e1_port0;
2188 attr[2] = ts0;
2189
2190 attr = msgb_put(msg, 3);
2191 attr[0] = NM_ATT_MDROP_NEXT;
2192 attr[1] = e1_port1;
2193 attr[2] = ts1;
2194
2195 return abis_nm_sendmsg(bts, msg);
2196}
Harald Welte59b04682009-06-10 05:40:52 +08002197
Harald Welte0bf8e302009-08-08 00:02:36 +02002198/* Chapter 8.7.1 */
2199int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2200 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welteb31c9df2010-03-06 11:38:05 +01002201 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02002202{
2203 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02002204
Harald Welte30f93fb2011-02-19 16:48:17 +01002205 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01002206
2207 if (!msg)
2208 msg = nm_msgb_alloc();
2209
2210 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2211 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2212 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2213 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02002214 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02002215
2216 return abis_nm_sendmsg(bts, msg);
2217}
2218
Harald Welte59b04682009-06-10 05:40:52 +08002219int abis_nm_event_reports(struct gsm_bts *bts, int on)
2220{
2221 if (on == 0)
2222 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2223 else
2224 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2225}
2226
2227/* Siemens (or BS-11) specific commands */
2228
2229int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2230{
2231 if (reconnect == 0)
2232 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2233 else
2234 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2235}
2236
2237int abis_nm_bs11_restart(struct gsm_bts *bts)
2238{
2239 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2240}
2241
2242
2243struct bs11_date_time {
2244 u_int16_t year;
2245 u_int8_t month;
2246 u_int8_t day;
2247 u_int8_t hour;
2248 u_int8_t min;
2249 u_int8_t sec;
2250} __attribute__((packed));
2251
2252
2253void get_bs11_date_time(struct bs11_date_time *aet)
2254{
2255 time_t t;
2256 struct tm *tm;
2257
2258 t = time(NULL);
2259 tm = localtime(&t);
2260 aet->sec = tm->tm_sec;
2261 aet->min = tm->tm_min;
2262 aet->hour = tm->tm_hour;
2263 aet->day = tm->tm_mday;
2264 aet->month = tm->tm_mon;
2265 aet->year = htons(1900 + tm->tm_year);
2266}
2267
2268int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2269{
2270 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2271}
2272
2273int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2274{
2275 if (begin)
2276 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2277 else
2278 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2279}
2280
2281int abis_nm_bs11_create_object(struct gsm_bts *bts,
2282 enum abis_bs11_objtype type, u_int8_t idx,
2283 u_int8_t attr_len, const u_int8_t *attr)
2284{
2285 struct abis_om_hdr *oh;
2286 struct msgb *msg = nm_msgb_alloc();
2287 u_int8_t *cur;
2288
2289 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2290 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2291 NM_OC_BS11, type, 0, idx);
2292 cur = msgb_put(msg, attr_len);
2293 memcpy(cur, attr, attr_len);
2294
2295 return abis_nm_sendmsg(bts, msg);
2296}
2297
2298int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2299 enum abis_bs11_objtype type, u_int8_t idx)
2300{
2301 struct abis_om_hdr *oh;
2302 struct msgb *msg = nm_msgb_alloc();
2303
2304 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2305 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2306 NM_OC_BS11, type, 0, idx);
2307
2308 return abis_nm_sendmsg(bts, msg);
2309}
2310
2311int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2312{
2313 struct abis_om_hdr *oh;
2314 struct msgb *msg = nm_msgb_alloc();
2315 u_int8_t zero = 0x00;
2316
2317 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2318 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2319 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2320 msgb_tlv_put(msg, 0x99, 1, &zero);
2321
2322 return abis_nm_sendmsg(bts, msg);
2323}
2324
2325int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2326{
2327 struct abis_om_hdr *oh;
2328 struct msgb *msg = nm_msgb_alloc();
2329
2330 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2331 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002332 idx, 0xff, 0xff);
2333
2334 return abis_nm_sendmsg(bts, msg);
2335}
2336
2337int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2338{
2339 struct abis_om_hdr *oh;
2340 struct msgb *msg = nm_msgb_alloc();
2341
2342 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2343 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2344 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002345
2346 return abis_nm_sendmsg(bts, msg);
2347}
2348
2349static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2350int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2351{
2352 struct abis_om_hdr *oh;
2353 struct msgb *msg = nm_msgb_alloc();
2354
2355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2356 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2357 0xff, 0xff, 0xff);
2358 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2359
2360 return abis_nm_sendmsg(bts, msg);
2361}
2362
2363/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002364int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welte59b04682009-06-10 05:40:52 +08002365 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2366 u_int8_t tei)
2367{
2368 struct abis_om_hdr *oh;
2369 struct abis_nm_channel *ch;
2370 struct msgb *msg = nm_msgb_alloc();
2371
2372 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2373 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2374 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2375
2376 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2377 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2378 msgb_tv_put(msg, NM_ATT_TEI, tei);
2379
2380 return abis_nm_sendmsg(bts, msg);
2381}
2382
2383int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2384{
2385 struct abis_om_hdr *oh;
2386 struct msgb *msg = nm_msgb_alloc();
2387
2388 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2389 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2390 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2391 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2392
2393 return abis_nm_sendmsg(trx->bts, msg);
2394}
2395
2396int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2397{
2398 struct abis_om_hdr *oh;
2399 struct msgb *msg = nm_msgb_alloc();
2400 u_int8_t attr = NM_ATT_BS11_TXPWR;
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_PA, 0x00, trx->nr);
2405 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2406
2407 return abis_nm_sendmsg(trx->bts, msg);
2408}
2409
2410int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2411{
2412 struct abis_om_hdr *oh;
2413 struct msgb *msg = nm_msgb_alloc();
2414 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2415
2416 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2417 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2418 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2419 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2420
2421 return abis_nm_sendmsg(bts, msg);
2422}
2423
2424int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2425{
2426 struct abis_om_hdr *oh;
2427 struct msgb *msg = nm_msgb_alloc();
2428 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2429 NM_ATT_BS11_CCLK_TYPE };
2430
2431 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2432 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2433 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2434 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2435
2436 return abis_nm_sendmsg(bts, msg);
2437
2438}
2439
2440//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002441
2442int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2443{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002444 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2445}
2446
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002447int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2448{
2449 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2450}
2451
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002452int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2453{
Harald Welte59b04682009-06-10 05:40:52 +08002454 struct abis_om_hdr *oh;
2455 struct msgb *msg = nm_msgb_alloc();
2456 struct bs11_date_time bdt;
2457
2458 get_bs11_date_time(&bdt);
2459
2460 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2461 if (on) {
2462 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002463 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002464 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2465 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2466 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2467 sizeof(bdt), (u_int8_t *) &bdt);
2468 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002469 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002470 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002471 strlen(name), (u_int8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002472 } else {
2473 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2474 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2475 }
2476
2477 return abis_nm_sendmsg(bts, msg);
2478}
2479
2480int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2481{
2482 struct abis_om_hdr *oh;
2483 struct msgb *msg;
2484
2485 if (strlen(password) != 10)
2486 return -EINVAL;
2487
2488 msg = nm_msgb_alloc();
2489 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2490 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2491 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2492 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2493
2494 return abis_nm_sendmsg(bts, msg);
2495}
2496
2497/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2498int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2499{
2500 struct abis_om_hdr *oh;
2501 struct msgb *msg;
2502 u_int8_t tlv_value;
2503
2504 msg = nm_msgb_alloc();
2505 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2506 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2507 BS11_OBJ_LI, 0x00, 0x00);
2508
2509 if (locked)
2510 tlv_value = BS11_LI_PLL_LOCKED;
2511 else
2512 tlv_value = BS11_LI_PLL_STANDALONE;
2513
2514 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2515
2516 return abis_nm_sendmsg(bts, msg);
2517}
2518
Daniel Willmann10b07db2010-01-07 00:54:01 +01002519/* Set the calibration value of the PLL (work value/set value)
2520 * It depends on the login which one is changed */
2521int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2522{
2523 struct abis_om_hdr *oh;
2524 struct msgb *msg;
2525 u_int8_t tlv_value[2];
2526
2527 msg = nm_msgb_alloc();
2528 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2529 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2530 BS11_OBJ_TRX1, 0x00, 0x00);
2531
2532 tlv_value[0] = value>>8;
2533 tlv_value[1] = value&0xff;
2534
2535 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2536
2537 return abis_nm_sendmsg(bts, msg);
2538}
2539
Harald Welte59b04682009-06-10 05:40:52 +08002540int abis_nm_bs11_get_state(struct gsm_bts *bts)
2541{
2542 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2543}
2544
2545/* BS11 SWL */
2546
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002547void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002548
Harald Welte59b04682009-06-10 05:40:52 +08002549struct abis_nm_bs11_sw {
2550 struct gsm_bts *bts;
2551 char swl_fname[PATH_MAX];
2552 u_int8_t win_size;
2553 int forced;
2554 struct llist_head file_list;
2555 gsm_cbfn *user_cb; /* specified by the user */
2556};
2557static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2558
2559struct file_list_entry {
2560 struct llist_head list;
2561 char fname[PATH_MAX];
2562};
2563
2564struct file_list_entry *fl_dequeue(struct llist_head *queue)
2565{
2566 struct llist_head *lh;
2567
2568 if (llist_empty(queue))
2569 return NULL;
2570
2571 lh = queue->next;
2572 llist_del(lh);
2573
2574 return llist_entry(lh, struct file_list_entry, list);
2575}
2576
2577static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2578{
2579 char linebuf[255];
2580 struct llist_head *lh, *lh2;
2581 FILE *swl;
2582 int rc = 0;
2583
2584 swl = fopen(bs11_sw->swl_fname, "r");
2585 if (!swl)
2586 return -ENODEV;
2587
2588 /* zero the stale file list, if any */
2589 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2590 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002591 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002592 }
2593
2594 while (fgets(linebuf, sizeof(linebuf), swl)) {
2595 char file_id[12+1];
2596 char file_version[80+1];
2597 struct file_list_entry *fle;
2598 static char dir[PATH_MAX];
2599
2600 if (strlen(linebuf) < 4)
2601 continue;
2602
2603 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2604 if (rc < 0) {
2605 perror("ERR parsing SWL file");
2606 rc = -EINVAL;
2607 goto out;
2608 }
2609 if (rc < 2)
2610 continue;
2611
Harald Welte857e00d2009-06-26 20:25:23 +02002612 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002613 if (!fle) {
2614 rc = -ENOMEM;
2615 goto out;
2616 }
Harald Welte59b04682009-06-10 05:40:52 +08002617
2618 /* construct new filename */
2619 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2620 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2621 strcat(fle->fname, "/");
2622 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2623
2624 llist_add_tail(&fle->list, &bs11_sw->file_list);
2625 }
2626
2627out:
2628 fclose(swl);
2629 return rc;
2630}
2631
2632/* bs11 swload specific callback, passed to abis_nm core swload */
2633static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2634 struct msgb *msg, void *data, void *param)
2635{
2636 struct abis_nm_bs11_sw *bs11_sw = data;
2637 struct file_list_entry *fle;
2638 int rc = 0;
2639
2640 switch (event) {
2641 case NM_MT_LOAD_END_ACK:
2642 fle = fl_dequeue(&bs11_sw->file_list);
2643 if (fle) {
2644 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002645 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002646 bs11_sw->win_size,
2647 bs11_sw->forced,
2648 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002649 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002650 } else {
2651 /* activate the SWL */
2652 rc = abis_nm_software_activate(bs11_sw->bts,
2653 bs11_sw->swl_fname,
2654 bs11_swload_cbfn,
2655 bs11_sw);
2656 }
2657 break;
2658 case NM_MT_LOAD_SEG_ACK:
2659 case NM_MT_LOAD_END_NACK:
2660 case NM_MT_LOAD_INIT_ACK:
2661 case NM_MT_LOAD_INIT_NACK:
2662 case NM_MT_ACTIVATE_SW_NACK:
2663 case NM_MT_ACTIVATE_SW_ACK:
2664 default:
2665 /* fallthrough to the user callback */
2666 if (bs11_sw->user_cb)
2667 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2668 break;
2669 }
2670
2671 return rc;
2672}
2673
2674/* Siemens provides a SWL file that is a mere listing of all the other
2675 * files that are part of a software release. We need to upload first
2676 * the list file, and then each file that is listed in the list file */
2677int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2678 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2679{
2680 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2681 struct file_list_entry *fle;
2682 int rc = 0;
2683
2684 INIT_LLIST_HEAD(&bs11_sw->file_list);
2685 bs11_sw->bts = bts;
2686 bs11_sw->win_size = win_size;
2687 bs11_sw->user_cb = cbfn;
2688 bs11_sw->forced = forced;
2689
2690 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2691 rc = bs11_read_swl_file(bs11_sw);
2692 if (rc < 0)
2693 return rc;
2694
2695 /* dequeue next item in file list */
2696 fle = fl_dequeue(&bs11_sw->file_list);
2697 if (!fle)
2698 return -EINVAL;
2699
2700 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002701 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002702 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002703 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002704 return rc;
2705}
2706
2707#if 0
2708static u_int8_t req_attr_btse[] = {
2709 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2710 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2711 NM_ATT_BS11_LMT_USER_NAME,
2712
2713 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2714
2715 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2716
2717 NM_ATT_BS11_SW_LOAD_STORED };
2718
2719static u_int8_t req_attr_btsm[] = {
2720 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2721 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2722 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2723 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2724#endif
2725
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002726static u_int8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002727 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2728 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2729 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2730
2731int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2732{
2733 struct abis_om_hdr *oh;
2734 struct msgb *msg = nm_msgb_alloc();
2735
2736 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2737 /* SiemensHW CCTRL object */
2738 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2739 0x03, 0x00, 0x00);
2740 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2741
2742 return abis_nm_sendmsg(bts, msg);
2743}
2744
2745int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2746{
2747 struct abis_om_hdr *oh;
2748 struct msgb *msg = nm_msgb_alloc();
2749 struct bs11_date_time aet;
2750
2751 get_bs11_date_time(&aet);
2752 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2753 /* SiemensHW CCTRL object */
2754 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2755 0xff, 0xff, 0xff);
2756 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2757
2758 return abis_nm_sendmsg(bts, msg);
2759}
2760
Harald Welte30534c52010-12-14 12:52:16 +01002761int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2762{
2763 struct abis_om_hdr *oh;
2764 struct msgb *msg = nm_msgb_alloc();
2765 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2766
2767 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2768 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2769 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2770 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2771
2772 return abis_nm_sendmsg(bts, msg);
2773}
2774
Daniel Willmann5655afe2009-08-10 11:49:36 +02002775int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2776{
2777 struct abis_om_hdr *oh;
2778 struct msgb *msg = nm_msgb_alloc();
2779 struct bs11_date_time aet;
2780
2781 get_bs11_date_time(&aet);
2782 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2783 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2784 bport, 0xff, 0x02);
2785 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2786
2787 return abis_nm_sendmsg(bts, msg);
2788}
2789
Harald Welte59b04682009-06-10 05:40:52 +08002790/* ip.access nanoBTS specific commands */
2791static const char ipaccess_magic[] = "com.ipaccess";
2792
2793
2794static int abis_nm_rx_ipacc(struct msgb *msg)
2795{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002796 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002797 struct abis_om_hdr *oh = msgb_l2(msg);
2798 struct abis_om_fom_hdr *foh;
2799 u_int8_t idstrlen = oh->data[0];
2800 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002801 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002802
2803 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002804 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002805 return -EINVAL;
2806 }
2807
2808 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002809 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002810
Harald Welteb7284a92009-10-20 09:56:18 +02002811 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002812
Harald Welte5aeedd42009-10-19 22:11:11 +02002813 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002814
2815 switch (foh->msg_type) {
2816 case NM_MT_IPACC_RSL_CONNECT_ACK:
2817 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002818 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2819 memcpy(&addr,
2820 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2821
2822 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2823 }
Harald Welte4206d982009-07-12 09:33:54 +02002824 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002825 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002826 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002827 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002828 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2829 DEBUGPC(DNM, "STREAM=0x%02x ",
2830 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002831 DEBUGPC(DNM, "\n");
2832 break;
2833 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002834 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002835 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002836 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002837 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2838 else
2839 DEBUGPC(DNM, "\n");
2840 break;
2841 case NM_MT_IPACC_SET_NVATTR_ACK:
2842 DEBUGPC(DNM, "SET NVATTR ACK\n");
2843 /* FIXME: decode and show the actual attributes */
2844 break;
2845 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002846 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002847 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002848 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002849 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2850 else
Harald Weltede4477a2009-12-24 12:20:20 +01002851 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002852 break;
Harald Welte21460f02009-07-03 11:26:45 +02002853 case NM_MT_IPACC_GET_NVATTR_ACK:
2854 DEBUGPC(DNM, "GET NVATTR ACK\n");
2855 /* FIXME: decode and show the actual attributes */
2856 break;
2857 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002858 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002859 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002860 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002861 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2862 else
Harald Weltede4477a2009-12-24 12:20:20 +01002863 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002864 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002865 case NM_MT_IPACC_SET_ATTR_ACK:
2866 DEBUGPC(DNM, "SET ATTR ACK\n");
2867 break;
2868 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002869 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002870 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002871 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002872 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2873 else
Harald Weltede4477a2009-12-24 12:20:20 +01002874 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002875 break;
Harald Welte59b04682009-06-10 05:40:52 +08002876 default:
2877 DEBUGPC(DNM, "unknown\n");
2878 break;
2879 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002880
2881 /* signal handling */
2882 switch (foh->msg_type) {
2883 case NM_MT_IPACC_RSL_CONNECT_NACK:
2884 case NM_MT_IPACC_SET_NVATTR_NACK:
2885 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002886 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002887 signal.msg_type = foh->msg_type;
2888 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002889 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002890 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002891 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002892 signal.msg_type = foh->msg_type;
2893 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002894 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002895 default:
2896 break;
2897 }
2898
Harald Welte59b04682009-06-10 05:40:52 +08002899 return 0;
2900}
2901
2902/* send an ip-access manufacturer specific message */
2903int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2904 u_int8_t obj_class, u_int8_t bts_nr,
2905 u_int8_t trx_nr, u_int8_t ts_nr,
2906 u_int8_t *attr, int attr_len)
2907{
2908 struct msgb *msg = nm_msgb_alloc();
2909 struct abis_om_hdr *oh;
2910 struct abis_om_fom_hdr *foh;
2911 u_int8_t *data;
2912
2913 /* construct the 12.21 OM header, observe the erroneous length */
2914 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2915 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2916 oh->mdisc = ABIS_OM_MDISC_MANUF;
2917
2918 /* add the ip.access magic */
2919 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2920 *data++ = sizeof(ipaccess_magic);
2921 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2922
2923 /* fill the 12.21 FOM header */
2924 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2925 foh->msg_type = msg_type;
2926 foh->obj_class = obj_class;
2927 foh->obj_inst.bts_nr = bts_nr;
2928 foh->obj_inst.trx_nr = trx_nr;
2929 foh->obj_inst.ts_nr = ts_nr;
2930
2931 if (attr && attr_len) {
2932 data = msgb_put(msg, attr_len);
2933 memcpy(data, attr, attr_len);
2934 }
2935
2936 return abis_nm_sendmsg(bts, msg);
2937}
2938
2939/* set some attributes in NVRAM */
Harald Weltef12c1052010-01-07 20:39:42 +01002940int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002941 int attr_len)
2942{
Harald Weltef12c1052010-01-07 20:39:42 +01002943 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2944 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002945 attr_len);
2946}
2947
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002948int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte5aeedd42009-10-19 22:11:11 +02002949 u_int32_t ip, u_int16_t port, u_int8_t stream)
2950{
2951 struct in_addr ia;
2952 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2953 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2954 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2955
2956 int attr_len = sizeof(attr);
2957
2958 ia.s_addr = htonl(ip);
2959 attr[1] = stream;
2960 attr[3] = port >> 8;
2961 attr[4] = port & 0xff;
2962 *(u_int32_t *)(attr+6) = ia.s_addr;
2963
2964 /* if ip == 0, we use the default IP */
2965 if (ip == 0)
2966 attr_len -= 5;
2967
2968 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002969 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002970
2971 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2972 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2973 trx->nr, 0xff, attr, attr_len);
2974}
2975
Harald Welte59b04682009-06-10 05:40:52 +08002976/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002977int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002978{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002979 struct abis_om_hdr *oh;
2980 struct msgb *msg = nm_msgb_alloc();
2981
2982 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2983 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2984 trx->bts->nr, trx->nr, 0xff);
2985
2986 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002987}
Harald Welte0dfc6232009-10-24 10:20:41 +02002988
2989int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2990 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2991 u_int8_t *attr, u_int8_t attr_len)
2992{
2993 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2994 obj_class, bts_nr, trx_nr, ts_nr,
2995 attr, attr_len);
2996}
Harald Weltebeeae412009-11-12 14:48:42 +01002997
Harald Welte3055e332010-03-14 15:37:43 +08002998void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2999{
3000 /* we simply reuse the GSM48 function and overwrite the RAC
3001 * with the Cell ID */
3002 gsm48_ra_id_by_bts(buf, bts);
3003 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
3004}
3005
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01003006void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
3007{
3008 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
3009
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01003010 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01003011 if (!trx->bts || !trx->bts->oml_link)
3012 return;
3013
3014 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3015 trx->bts->bts_nr, trx->nr, 0xff,
3016 new_state);
3017}
3018
Harald Welte453141f2010-03-25 11:45:30 +08003019static const struct value_string ipacc_testres_names[] = {
3020 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3021 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3022 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3023 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3024 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3025 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01003026};
3027
3028const char *ipacc_testres_name(u_int8_t res)
3029{
Harald Welte453141f2010-03-25 11:45:30 +08003030 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01003031}
3032
Harald Weltebfc21092009-11-13 11:56:05 +01003033void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3034{
3035 cid->mcc = (buf[0] & 0xf) * 100;
3036 cid->mcc += (buf[0] >> 4) * 10;
3037 cid->mcc += (buf[1] & 0xf) * 1;
3038
3039 if (buf[1] >> 4 == 0xf) {
3040 cid->mnc = (buf[2] & 0xf) * 10;
3041 cid->mnc += (buf[2] >> 4) * 1;
3042 } else {
3043 cid->mnc = (buf[2] & 0xf) * 100;
3044 cid->mnc += (buf[2] >> 4) * 10;
3045 cid->mnc += (buf[1] >> 4) * 1;
3046 }
3047
Harald Welte161b4be2009-11-13 14:41:52 +01003048 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3049 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01003050}
3051
Harald Weltebeeae412009-11-12 14:48:42 +01003052/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3053int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3054{
3055 u_int8_t *cur = buf;
3056 u_int16_t len;
3057
Harald Welteb784df82010-07-22 18:14:36 +02003058 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01003059
3060 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3061 return -EINVAL;
3062 cur++;
3063
3064 len = ntohs(*(u_int16_t *)cur);
3065 cur += 2;
3066
3067 binf->info_type = ntohs(*(u_int16_t *)cur);
3068 cur += 2;
3069
3070 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3071 binf->freq_qual = *cur >> 2;
3072
Harald Welteb784df82010-07-22 18:14:36 +02003073 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01003074 binf->arfcn |= *cur++;
3075
3076 if (binf->info_type & IPAC_BINF_RXLEV)
3077 binf->rx_lev = *cur & 0x3f;
3078 cur++;
3079
3080 if (binf->info_type & IPAC_BINF_RXQUAL)
3081 binf->rx_qual = *cur & 0x7;
3082 cur++;
3083
3084 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3085 binf->freq_err = ntohs(*(u_int16_t *)cur);
3086 cur += 2;
3087
3088 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3089 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3090 cur += 2;
3091
3092 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3093 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3094 cur += 4;
3095
Harald Welte22cb81f2010-07-30 22:34:42 +02003096#if 0
3097 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01003098 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02003099#endif
Harald Welte161b4be2009-11-13 14:41:52 +01003100 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01003101 cur++;
3102
Harald Weltebfc21092009-11-13 11:56:05 +01003103 ipac_parse_cgi(&binf->cgi, cur);
3104 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01003105
3106 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3107 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3108 cur += sizeof(binf->ba_list_si2);
3109 }
3110
3111 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3112 memcpy(binf->ba_list_si2bis, cur,
3113 sizeof(binf->ba_list_si2bis));
3114 cur += sizeof(binf->ba_list_si2bis);
3115 }
3116
3117 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3118 memcpy(binf->ba_list_si2ter, cur,
3119 sizeof(binf->ba_list_si2ter));
3120 cur += sizeof(binf->ba_list_si2ter);
3121 }
3122
3123 return 0;
3124}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01003125
3126void abis_nm_clear_queue(struct gsm_bts *bts)
3127{
3128 struct msgb *msg;
3129
3130 while (!llist_empty(&bts->abis_queue)) {
3131 msg = msgb_dequeue(&bts->abis_queue);
3132 msgb_free(msg);
3133 }
3134
3135 bts->abis_nm_pend = 0;
3136}