blob: 0e7fc8d8c3dd8e3260ee4a0f973e25616389419d [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 Welte4c826f72011-01-14 15:55:42 +0100688 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
689 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100690 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800691 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
692 if (!nm_state)
693 return -1;
694
695 new_state = *nm_state;
696 new_state.administrative = adm_state;
697
Harald Welte4c826f72011-01-14 15:55:42 +0100698 nsd.obj_class = obj_class;
699 nsd.old_state = nm_state;
700 nsd.new_state = &new_state;
701 nsd.obj_inst = obj_inst;
702 dispatch_signal(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800703
704 nm_state->administrative = adm_state;
705
Harald Welte4c826f72011-01-14 15:55:42 +0100706 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800707}
708
709static int abis_nm_rx_statechg_rep(struct msgb *mb)
710{
711 struct abis_om_hdr *oh = msgb_l2(mb);
712 struct abis_om_fom_hdr *foh = msgb_l3(mb);
713 struct gsm_bts *bts = mb->trx->bts;
714 struct tlv_parsed tp;
715 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800716
717 DEBUGPC(DNM, "STATE CHG: ");
718
719 memset(&new_state, 0, sizeof(new_state));
720
721 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
722 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100723 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800724 return -EINVAL;
725 }
726
727 new_state = *nm_state;
728
Harald Welte59698fb2010-01-10 18:01:52 +0100729 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800730 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
731 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
732 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
733 }
734 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
735 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
736 new_state.availability = 0xff;
737 else
738 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
739 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
740 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100741 } else
742 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800743 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
744 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther460fb3b2009-10-22 15:44:30 +0200745 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800746 }
747 DEBUGPC(DNM, "\n");
748
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100749 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
750 new_state.operational != nm_state->operational ||
751 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800752 /* Update the operational state of a given object in our in-memory data
753 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100754 struct nm_statechg_signal_data nsd;
755 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
756 nsd.obj_class = foh->obj_class;
757 nsd.old_state = nm_state;
758 nsd.new_state = &new_state;
759 nsd.obj_inst = &foh->obj_inst;
760 dispatch_signal(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100761 nm_state->operational = new_state.operational;
762 nm_state->availability = new_state.availability;
763 if (nm_state->administrative == 0)
764 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800765 }
766#if 0
767 if (op_state == 1) {
768 /* try to enable objects that are disabled */
769 abis_nm_opstart(bts, foh->obj_class,
770 foh->obj_inst.bts_nr,
771 foh->obj_inst.trx_nr,
772 foh->obj_inst.ts_nr);
773 }
774#endif
775 return 0;
776}
777
778static int rx_fail_evt_rep(struct msgb *mb)
779{
780 struct abis_om_hdr *oh = msgb_l2(mb);
781 struct abis_om_fom_hdr *foh = msgb_l3(mb);
782 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100783 const uint8_t *p_val;
784 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800785
786 DEBUGPC(DNM, "Failure Event Report ");
787
Harald Welte59698fb2010-01-10 18:01:52 +0100788 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800789
790 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
791 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
792 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
793 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100794 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
795 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
796 DEBUGPC(DNM, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
797 }
798 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
799 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
800 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
801 if (p_text) {
802 DEBUGPC(DNM, "Additional Text=%s ", p_text);
803 talloc_free(p_text);
804 }
805 }
Harald Welte59b04682009-06-10 05:40:52 +0800806
807 DEBUGPC(DNM, "\n");
808
809 return 0;
810}
811
812static int abis_nm_rcvmsg_report(struct msgb *mb)
813{
814 struct abis_om_fom_hdr *foh = msgb_l3(mb);
815 u_int8_t mt = foh->msg_type;
816
Harald Welteb7284a92009-10-20 09:56:18 +0200817 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800818
819 //nmh->cfg->report_cb(mb, foh);
820
821 switch (mt) {
822 case NM_MT_STATECHG_EVENT_REP:
823 return abis_nm_rx_statechg_rep(mb);
824 break;
825 case NM_MT_SW_ACTIVATED_REP:
826 DEBUGPC(DNM, "Software Activated Report\n");
827 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
828 break;
829 case NM_MT_FAILURE_EVENT_REP:
830 rx_fail_evt_rep(mb);
831 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
832 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200833 case NM_MT_TEST_REP:
834 DEBUGPC(DNM, "Test Report\n");
835 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
836 break;
Harald Welte59b04682009-06-10 05:40:52 +0800837 default:
838 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
839 break;
840
841 };
842
843 return 0;
844}
845
846/* Activate the specified software into the BTS */
847static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
Mike Haben322fc582009-10-01 14:56:13 +0200848 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800849{
850 struct abis_om_hdr *oh;
851 struct msgb *msg = nm_msgb_alloc();
852 u_int8_t len = swdesc_len;
853 u_int8_t *trailer;
854
855 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
856 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
857
858 trailer = msgb_put(msg, swdesc_len);
859 memcpy(trailer, sw_desc, swdesc_len);
860
861 return abis_nm_sendmsg(bts, msg);
862}
863
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100864static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
865{
866 static const struct tlv_definition sw_descr_def = {
867 .def = {
868 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
869 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
870 },
871 };
872
873 u_int8_t tag;
874 u_int16_t tag_len;
875 const u_int8_t *val;
876 int ofs = 0, len;
877
878 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
879 * nested nature and the fact you have to assume it contains only two sub
880 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
881
882 if (sw_descr[0] != NM_ATT_SW_DESCR) {
883 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
884 return -1;
885 }
886 ofs += 1;
887
888 len = tlv_parse_one(&tag, &tag_len, &val,
889 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
890 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
891 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
892 return -2;
893 }
894 ofs += len;
895
896 len = tlv_parse_one(&tag, &tag_len, &val,
897 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
898 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
899 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
900 return -3;
901 }
902 ofs += len;
903
904 return ofs;
905}
906
Harald Welte59b04682009-06-10 05:40:52 +0800907static int abis_nm_rx_sw_act_req(struct msgb *mb)
908{
909 struct abis_om_hdr *oh = msgb_l2(mb);
910 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200911 struct tlv_parsed tp;
912 const u_int8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100913 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800914
Harald Welteb7284a92009-10-20 09:56:18 +0200915 debugp_foh(foh);
916
917 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800918
Harald Welte3055e332010-03-14 15:37:43 +0800919 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800920
921 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
922 foh->obj_inst.bts_nr,
923 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800924 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800925 foh->data, oh->length-sizeof(*foh));
926
Harald Welte59698fb2010-01-10 18:01:52 +0100927 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200928 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
929 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
930 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
931 DEBUGP(DNM, "SW config not found! Can't continue.\n");
932 return -EINVAL;
933 } else {
934 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
935 }
936
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100937 /* Use the first SW_DESCR present in SW config */
938 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
939 if (sw_descr_len < 0)
940 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200941
Harald Welte59b04682009-06-10 05:40:52 +0800942 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
943 foh->obj_inst.bts_nr,
944 foh->obj_inst.trx_nr,
945 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100946 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800947}
948
949/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
950static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
951{
952 struct abis_om_hdr *oh = msgb_l2(mb);
953 struct abis_om_fom_hdr *foh = msgb_l3(mb);
954 struct tlv_parsed tp;
955 u_int8_t adm_state;
956
Harald Welte59698fb2010-01-10 18:01:52 +0100957 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800958 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
959 return -EINVAL;
960
961 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
962
963 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
964}
965
966static int abis_nm_rx_lmt_event(struct msgb *mb)
967{
968 struct abis_om_hdr *oh = msgb_l2(mb);
969 struct abis_om_fom_hdr *foh = msgb_l3(mb);
970 struct tlv_parsed tp;
971
972 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100973 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800974 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
975 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
976 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
977 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
978 }
979 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
980 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
981 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
982 DEBUGPC(DNM, "Level=%u ", level);
983 }
984 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
985 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
986 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
987 DEBUGPC(DNM, "Username=%s ", name);
988 }
989 DEBUGPC(DNM, "\n");
990 /* FIXME: parse LMT LOGON TIME */
991 return 0;
992}
993
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100994static void abis_nm_queue_send_next(struct gsm_bts *bts)
995{
996 int wait = 0;
997 struct msgb *msg;
998 /* the queue is empty */
999 while (!llist_empty(&bts->abis_queue)) {
1000 msg = msgb_dequeue(&bts->abis_queue);
1001 wait = OBSC_NM_W_ACK_CB(msg);
Harald Weltec5845042011-02-14 15:26:13 +01001002 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001003
1004 if (wait)
1005 break;
1006 }
1007
1008 bts->abis_nm_pend = wait;
1009}
1010
Harald Welte59b04682009-06-10 05:40:52 +08001011/* Receive a OML NM Message from BTS */
1012static int abis_nm_rcvmsg_fom(struct msgb *mb)
1013{
1014 struct abis_om_hdr *oh = msgb_l2(mb);
1015 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1016 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001017 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001018
1019 /* check for unsolicited message */
1020 if (is_report(mt))
1021 return abis_nm_rcvmsg_report(mb);
1022
1023 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1024 return abis_nm_rcvmsg_sw(mb);
1025
1026 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001027 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +08001028 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +02001029
Harald Welteb7284a92009-10-20 09:56:18 +02001030 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +02001031
Harald Welte453141f2010-03-25 11:45:30 +08001032 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +08001033
Harald Welte59698fb2010-01-10 18:01:52 +01001034 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08001035 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001036 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08001037 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1038 else
1039 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001040
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001041 nack_data.msg = mb;
1042 nack_data.mt = mt;
1043 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001044 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001045 return 0;
Harald Welte59b04682009-06-10 05:40:52 +08001046 }
1047#if 0
1048 /* check if last message is to be acked */
1049 if (is_ack_nack(nmh->last_msgtype)) {
1050 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +01001051 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001052 /* we got our ACK, continue sending the next msg */
1053 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1054 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +01001055 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001056 /* FIXME: somehow signal this to the caller */
1057 } else {
1058 /* really strange things happen */
1059 return -EINVAL;
1060 }
1061 }
1062#endif
1063
1064 switch (mt) {
1065 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001066 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001067 break;
1068 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001069 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001070 break;
1071 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001072 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001073 break;
Harald Welte204317e2009-08-06 17:58:31 +02001074 case NM_MT_CONN_MDROP_LINK_ACK:
1075 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1076 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001077 case NM_MT_IPACC_RESTART_ACK:
1078 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1079 break;
1080 case NM_MT_IPACC_RESTART_NACK:
1081 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1082 break;
Harald Welte08011e22011-03-04 13:41:31 +01001083 case NM_MT_SET_BTS_ATTR_ACK:
1084 /* The HSL wants an OPSTART _after_ the SI has been set */
1085 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
1086 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
1087 }
1088 break;
Harald Welte59b04682009-06-10 05:40:52 +08001089 }
1090
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001091 abis_nm_queue_send_next(mb->trx->bts);
1092 return ret;
Harald Welte59b04682009-06-10 05:40:52 +08001093}
1094
1095static int abis_nm_rx_ipacc(struct msgb *mb);
1096
1097static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1098{
1099 int rc;
1100 int bts_type = mb->trx->bts->type;
1101
1102 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001103 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001104 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001105 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001106 break;
1107 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001108 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1109 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001110 rc = 0;
1111 break;
1112 }
1113
1114 return rc;
1115}
1116
1117/* High-Level API */
1118/* Entry-point where L2 OML from BTS enters the NM code */
1119int abis_nm_rcvmsg(struct msgb *msg)
1120{
1121 struct abis_om_hdr *oh = msgb_l2(msg);
1122 int rc = 0;
1123
1124 /* Various consistency checks */
1125 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001126 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001127 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +02001128 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1129 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +08001130 }
1131 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001132 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001133 oh->sequence);
1134 return -EINVAL;
1135 }
1136#if 0
1137 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1138 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1139 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001140 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001141 oh->length + sizeof(*oh), l2_len);
1142 return -EINVAL;
1143 }
1144 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001145 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 +08001146#endif
1147 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1148
1149 switch (oh->mdisc) {
1150 case ABIS_OM_MDISC_FOM:
1151 rc = abis_nm_rcvmsg_fom(msg);
1152 break;
1153 case ABIS_OM_MDISC_MANUF:
1154 rc = abis_nm_rcvmsg_manuf(msg);
1155 break;
1156 case ABIS_OM_MDISC_MMI:
1157 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001158 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001159 oh->mdisc);
1160 break;
1161 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001162 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001163 oh->mdisc);
1164 return -EINVAL;
1165 }
1166
1167 msgb_free(msg);
1168 return rc;
1169}
1170
1171#if 0
1172/* initialized all resources */
1173struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1174{
1175 struct abis_nm_h *nmh;
1176
1177 nmh = malloc(sizeof(*nmh));
1178 if (!nmh)
1179 return NULL;
1180
1181 nmh->cfg = cfg;
1182
1183 return nmh;
1184}
1185
1186/* free all resources */
1187void abis_nm_fini(struct abis_nm_h *nmh)
1188{
1189 free(nmh);
1190}
1191#endif
1192
1193/* Here we are trying to define a high-level API that can be used by
1194 * the actual BSC implementation. However, the architecture is currently
1195 * still under design. Ideally the calls to this API would be synchronous,
1196 * while the underlying stack behind the APi runs in a traditional select
1197 * based state machine.
1198 */
1199
1200/* 6.2 Software Load: */
1201enum sw_state {
1202 SW_STATE_NONE,
1203 SW_STATE_WAIT_INITACK,
1204 SW_STATE_WAIT_SEGACK,
1205 SW_STATE_WAIT_ENDACK,
1206 SW_STATE_WAIT_ACTACK,
1207 SW_STATE_ERROR,
1208};
1209
1210struct abis_nm_sw {
1211 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001212 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +08001213 gsm_cbfn *cbfn;
1214 void *cb_data;
1215 int forced;
1216
1217 /* this will become part of the SW LOAD INITIATE */
1218 u_int8_t obj_class;
1219 u_int8_t obj_instance[3];
1220
1221 u_int8_t file_id[255];
1222 u_int8_t file_id_len;
1223
1224 u_int8_t file_version[255];
1225 u_int8_t file_version_len;
1226
1227 u_int8_t window_size;
1228 u_int8_t seg_in_window;
1229
1230 int fd;
1231 FILE *stream;
1232 enum sw_state state;
1233 int last_seg;
1234};
1235
1236static struct abis_nm_sw g_sw;
1237
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001238static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1239{
1240 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1241 msgb_v_put(msg, NM_ATT_SW_DESCR);
1242 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1243 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1244 sw->file_version);
1245 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1246 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1247 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1248 sw->file_version);
1249 } else {
1250 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1251 }
1252}
1253
Harald Welte59b04682009-06-10 05:40:52 +08001254/* 6.2.1 / 8.3.1: Load Data Initiate */
1255static int sw_load_init(struct abis_nm_sw *sw)
1256{
1257 struct abis_om_hdr *oh;
1258 struct msgb *msg = nm_msgb_alloc();
1259 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1260
1261 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1262 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1263 sw->obj_instance[0], sw->obj_instance[1],
1264 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001265
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001266 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001267 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1268
1269 return abis_nm_sendmsg(sw->bts, msg);
1270}
1271
1272static int is_last_line(FILE *stream)
1273{
1274 char next_seg_buf[256];
1275 long pos;
1276
1277 /* check if we're sending the last line */
1278 pos = ftell(stream);
1279 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1280 fseek(stream, pos, SEEK_SET);
1281 return 1;
1282 }
1283
1284 fseek(stream, pos, SEEK_SET);
1285 return 0;
1286}
1287
1288/* 6.2.2 / 8.3.2 Load Data Segment */
1289static int sw_load_segment(struct abis_nm_sw *sw)
1290{
1291 struct abis_om_hdr *oh;
1292 struct msgb *msg = nm_msgb_alloc();
1293 char seg_buf[256];
1294 char *line_buf = seg_buf+2;
1295 unsigned char *tlv;
1296 u_int8_t len;
1297
1298 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1299
1300 switch (sw->bts->type) {
1301 case GSM_BTS_TYPE_BS11:
1302 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1303 perror("fgets reading segment");
1304 return -EINVAL;
1305 }
1306 seg_buf[0] = 0x00;
1307
1308 /* check if we're sending the last line */
1309 sw->last_seg = is_last_line(sw->stream);
1310 if (sw->last_seg)
1311 seg_buf[1] = 0;
1312 else
1313 seg_buf[1] = 1 + sw->seg_in_window++;
1314
1315 len = strlen(line_buf) + 2;
1316 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1317 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1318 /* BS11 wants CR + LF in excess of the TLV length !?! */
1319 tlv[1] -= 2;
1320
1321 /* we only now know the exact length for the OM hdr */
1322 len = strlen(line_buf)+2;
1323 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001324 case GSM_BTS_TYPE_NANOBTS: {
1325 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1326 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1327 if (len < 0) {
1328 perror("read failed");
1329 return -EINVAL;
1330 }
1331
1332 if (len != IPACC_SEGMENT_SIZE)
1333 sw->last_seg = 1;
1334
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001335 ++sw->seg_in_window;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001336 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1337 len += 3;
1338 break;
1339 }
Harald Welte59b04682009-06-10 05:40:52 +08001340 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001341 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001342 /* FIXME: Other BTS types */
1343 return -1;
1344 }
1345
1346 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1347 sw->obj_instance[0], sw->obj_instance[1],
1348 sw->obj_instance[2]);
1349
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001350 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001351}
1352
1353/* 6.2.4 / 8.3.4 Load Data End */
1354static int sw_load_end(struct abis_nm_sw *sw)
1355{
1356 struct abis_om_hdr *oh;
1357 struct msgb *msg = nm_msgb_alloc();
1358 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1359
1360 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1361 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1362 sw->obj_instance[0], sw->obj_instance[1],
1363 sw->obj_instance[2]);
1364
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001365 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001366 return abis_nm_sendmsg(sw->bts, msg);
1367}
1368
1369/* Activate the specified software into the BTS */
1370static int sw_activate(struct abis_nm_sw *sw)
1371{
1372 struct abis_om_hdr *oh;
1373 struct msgb *msg = nm_msgb_alloc();
1374 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1375
1376 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1377 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1378 sw->obj_instance[0], sw->obj_instance[1],
1379 sw->obj_instance[2]);
1380
1381 /* FIXME: this is BS11 specific format */
1382 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1383 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1384 sw->file_version);
1385
1386 return abis_nm_sendmsg(sw->bts, msg);
1387}
1388
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001389struct sdp_firmware {
1390 char magic[4];
1391 char more_magic[4];
1392 unsigned int header_length;
1393 unsigned int file_length;
1394} __attribute__ ((packed));
1395
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001396static int parse_sdp_header(struct abis_nm_sw *sw)
1397{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001398 struct sdp_firmware firmware_header;
1399 int rc;
1400 struct stat stat;
1401
1402 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1403 if (rc != sizeof(firmware_header)) {
1404 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1405 return -1;
1406 }
1407
1408 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1409 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1410 return -1;
1411 }
1412
1413 if (firmware_header.more_magic[0] != 0x10 ||
1414 firmware_header.more_magic[1] != 0x02 ||
1415 firmware_header.more_magic[2] != 0x00 ||
1416 firmware_header.more_magic[3] != 0x00) {
1417 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1418 return -1;
1419 }
1420
1421
1422 if (fstat(sw->fd, &stat) == -1) {
1423 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1424 return -1;
1425 }
1426
1427 if (ntohl(firmware_header.file_length) != stat.st_size) {
1428 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1429 return -1;
1430 }
1431
1432 /* go back to the start as we checked the whole filesize.. */
1433 lseek(sw->fd, 0l, SEEK_SET);
1434 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1435 "There might be checksums in the file that are not\n"
1436 "verified and incomplete firmware might be flashed.\n"
1437 "There is absolutely no WARRANTY that flashing will\n"
1438 "work.\n");
1439 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001440}
1441
Harald Welte59b04682009-06-10 05:40:52 +08001442static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1443{
1444 char file_id[12+1];
1445 char file_version[80+1];
1446 int rc;
1447
1448 sw->fd = open(fname, O_RDONLY);
1449 if (sw->fd < 0)
1450 return sw->fd;
1451
1452 switch (sw->bts->type) {
1453 case GSM_BTS_TYPE_BS11:
1454 sw->stream = fdopen(sw->fd, "r");
1455 if (!sw->stream) {
1456 perror("fdopen");
1457 return -1;
1458 }
1459 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001460 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001461 file_id, file_version);
1462 if (rc != 2) {
1463 perror("parsing header line of software file");
1464 return -1;
1465 }
1466 strcpy((char *)sw->file_id, file_id);
1467 sw->file_id_len = strlen(file_id);
1468 strcpy((char *)sw->file_version, file_version);
1469 sw->file_version_len = strlen(file_version);
1470 /* rewind to start of file */
1471 rewind(sw->stream);
1472 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001473 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001474 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001475 rc = parse_sdp_header(sw);
1476 if (rc < 0) {
1477 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1478 return -1;
1479 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001480
1481 strcpy((char *)sw->file_id, "id");
1482 sw->file_id_len = 3;
1483 strcpy((char *)sw->file_version, "version");
1484 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001485 break;
Harald Welte59b04682009-06-10 05:40:52 +08001486 default:
1487 /* We don't know how to treat them yet */
1488 close(sw->fd);
1489 return -EINVAL;
1490 }
1491
1492 return 0;
1493}
1494
1495static void sw_close_file(struct abis_nm_sw *sw)
1496{
1497 switch (sw->bts->type) {
1498 case GSM_BTS_TYPE_BS11:
1499 fclose(sw->stream);
1500 break;
1501 default:
1502 close(sw->fd);
1503 break;
1504 }
1505}
1506
1507/* Fill the window */
1508static int sw_fill_window(struct abis_nm_sw *sw)
1509{
1510 int rc;
1511
1512 while (sw->seg_in_window < sw->window_size) {
1513 rc = sw_load_segment(sw);
1514 if (rc < 0)
1515 return rc;
1516 if (sw->last_seg)
1517 break;
1518 }
1519 return 0;
1520}
1521
1522/* callback function from abis_nm_rcvmsg() handler */
1523static int abis_nm_rcvmsg_sw(struct msgb *mb)
1524{
1525 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1526 int rc = -1;
1527 struct abis_nm_sw *sw = &g_sw;
1528 enum sw_state old_state = sw->state;
1529
1530 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1531
1532 switch (sw->state) {
1533 case SW_STATE_WAIT_INITACK:
1534 switch (foh->msg_type) {
1535 case NM_MT_LOAD_INIT_ACK:
1536 /* fill window with segments */
1537 if (sw->cbfn)
1538 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1539 NM_MT_LOAD_INIT_ACK, mb,
1540 sw->cb_data, NULL);
1541 rc = sw_fill_window(sw);
1542 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001543 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001544 break;
1545 case NM_MT_LOAD_INIT_NACK:
1546 if (sw->forced) {
1547 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1548 "Init NACK\n");
1549 if (sw->cbfn)
1550 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1551 NM_MT_LOAD_INIT_ACK, mb,
1552 sw->cb_data, NULL);
1553 rc = sw_fill_window(sw);
1554 sw->state = SW_STATE_WAIT_SEGACK;
1555 } else {
1556 DEBUGP(DNM, "Software Load Init NACK\n");
1557 /* FIXME: cause */
1558 if (sw->cbfn)
1559 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1560 NM_MT_LOAD_INIT_NACK, mb,
1561 sw->cb_data, NULL);
1562 sw->state = SW_STATE_ERROR;
1563 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001564 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001565 break;
1566 }
1567 break;
1568 case SW_STATE_WAIT_SEGACK:
1569 switch (foh->msg_type) {
1570 case NM_MT_LOAD_SEG_ACK:
1571 if (sw->cbfn)
1572 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1573 NM_MT_LOAD_SEG_ACK, mb,
1574 sw->cb_data, NULL);
1575 sw->seg_in_window = 0;
1576 if (!sw->last_seg) {
1577 /* fill window with more segments */
1578 rc = sw_fill_window(sw);
1579 sw->state = SW_STATE_WAIT_SEGACK;
1580 } else {
1581 /* end the transfer */
1582 sw->state = SW_STATE_WAIT_ENDACK;
1583 rc = sw_load_end(sw);
1584 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001585 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001586 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001587 case NM_MT_LOAD_ABORT:
1588 if (sw->cbfn)
1589 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1590 NM_MT_LOAD_ABORT, mb,
1591 sw->cb_data, NULL);
1592 break;
Harald Welte59b04682009-06-10 05:40:52 +08001593 }
1594 break;
1595 case SW_STATE_WAIT_ENDACK:
1596 switch (foh->msg_type) {
1597 case NM_MT_LOAD_END_ACK:
1598 sw_close_file(sw);
1599 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1600 sw->bts->nr);
1601 sw->state = SW_STATE_NONE;
1602 if (sw->cbfn)
1603 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1604 NM_MT_LOAD_END_ACK, mb,
1605 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001606 rc = 0;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001607 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001608 break;
1609 case NM_MT_LOAD_END_NACK:
1610 if (sw->forced) {
1611 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1612 "End NACK\n");
1613 sw->state = SW_STATE_NONE;
1614 if (sw->cbfn)
1615 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1616 NM_MT_LOAD_END_ACK, mb,
1617 sw->cb_data, NULL);
1618 } else {
1619 DEBUGP(DNM, "Software Load End NACK\n");
1620 /* FIXME: cause */
1621 sw->state = SW_STATE_ERROR;
1622 if (sw->cbfn)
1623 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1624 NM_MT_LOAD_END_NACK, mb,
1625 sw->cb_data, NULL);
1626 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001627 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001628 break;
1629 }
1630 case SW_STATE_WAIT_ACTACK:
1631 switch (foh->msg_type) {
1632 case NM_MT_ACTIVATE_SW_ACK:
1633 /* we're done */
1634 DEBUGP(DNM, "Activate Software DONE!\n");
1635 sw->state = SW_STATE_NONE;
1636 rc = 0;
1637 if (sw->cbfn)
1638 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1639 NM_MT_ACTIVATE_SW_ACK, mb,
1640 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001641 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001642 break;
1643 case NM_MT_ACTIVATE_SW_NACK:
1644 DEBUGP(DNM, "Activate Software NACK\n");
1645 /* FIXME: cause */
1646 sw->state = SW_STATE_ERROR;
1647 if (sw->cbfn)
1648 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1649 NM_MT_ACTIVATE_SW_NACK, mb,
1650 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001651 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001652 break;
1653 }
1654 case SW_STATE_NONE:
1655 switch (foh->msg_type) {
1656 case NM_MT_ACTIVATE_SW_ACK:
1657 rc = 0;
1658 break;
1659 }
1660 break;
1661 case SW_STATE_ERROR:
1662 break;
1663 }
1664
1665 if (rc)
1666 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1667 foh->msg_type, old_state, sw->state);
1668
1669 return rc;
1670}
1671
1672/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001673int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte59b04682009-06-10 05:40:52 +08001674 u_int8_t win_size, int forced,
1675 gsm_cbfn *cbfn, void *cb_data)
1676{
1677 struct abis_nm_sw *sw = &g_sw;
1678 int rc;
1679
1680 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1681 bts->nr, fname);
1682
1683 if (sw->state != SW_STATE_NONE)
1684 return -EBUSY;
1685
1686 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001687 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001688
1689 switch (bts->type) {
1690 case GSM_BTS_TYPE_BS11:
1691 sw->obj_class = NM_OC_SITE_MANAGER;
1692 sw->obj_instance[0] = 0xff;
1693 sw->obj_instance[1] = 0xff;
1694 sw->obj_instance[2] = 0xff;
1695 break;
1696 case GSM_BTS_TYPE_NANOBTS:
1697 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001698 sw->obj_instance[0] = sw->bts->nr;
1699 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001700 sw->obj_instance[2] = 0xff;
1701 break;
1702 case GSM_BTS_TYPE_UNKNOWN:
1703 default:
1704 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1705 return -1;
1706 break;
1707 }
Harald Welte59b04682009-06-10 05:40:52 +08001708 sw->window_size = win_size;
1709 sw->state = SW_STATE_WAIT_INITACK;
1710 sw->cbfn = cbfn;
1711 sw->cb_data = cb_data;
1712 sw->forced = forced;
1713
1714 rc = sw_open_file(sw, fname);
1715 if (rc < 0) {
1716 sw->state = SW_STATE_NONE;
1717 return rc;
1718 }
1719
1720 return sw_load_init(sw);
1721}
1722
1723int abis_nm_software_load_status(struct gsm_bts *bts)
1724{
1725 struct abis_nm_sw *sw = &g_sw;
1726 struct stat st;
1727 int rc, percent;
1728
1729 rc = fstat(sw->fd, &st);
1730 if (rc < 0) {
1731 perror("ERROR during stat");
1732 return rc;
1733 }
1734
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001735 if (sw->stream)
1736 percent = (ftell(sw->stream) * 100) / st.st_size;
1737 else
1738 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001739 return percent;
1740}
1741
1742/* Activate the specified software into the BTS */
1743int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1744 gsm_cbfn *cbfn, void *cb_data)
1745{
1746 struct abis_nm_sw *sw = &g_sw;
1747 int rc;
1748
1749 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1750 bts->nr, fname);
1751
1752 if (sw->state != SW_STATE_NONE)
1753 return -EBUSY;
1754
1755 sw->bts = bts;
1756 sw->obj_class = NM_OC_SITE_MANAGER;
1757 sw->obj_instance[0] = 0xff;
1758 sw->obj_instance[1] = 0xff;
1759 sw->obj_instance[2] = 0xff;
1760 sw->state = SW_STATE_WAIT_ACTACK;
1761 sw->cbfn = cbfn;
1762 sw->cb_data = cb_data;
1763
1764 /* Open the file in order to fill some sw struct members */
1765 rc = sw_open_file(sw, fname);
1766 if (rc < 0) {
1767 sw->state = SW_STATE_NONE;
1768 return rc;
1769 }
1770 sw_close_file(sw);
1771
1772 return sw_activate(sw);
1773}
1774
1775static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1776 u_int8_t ts_nr, u_int8_t subslot_nr)
1777{
1778 ch->attrib = NM_ATT_ABIS_CHANNEL;
1779 ch->bts_port = bts_port;
1780 ch->timeslot = ts_nr;
1781 ch->subslot = subslot_nr;
1782}
1783
1784int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1785 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1786 u_int8_t tei)
1787{
1788 struct abis_om_hdr *oh;
1789 struct abis_nm_channel *ch;
1790 u_int8_t len = sizeof(*ch) + 2;
1791 struct msgb *msg = nm_msgb_alloc();
1792
1793 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1794 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1795 bts->bts_nr, trx_nr, 0xff);
1796
1797 msgb_tv_put(msg, NM_ATT_TEI, tei);
1798
1799 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1800 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1801
1802 return abis_nm_sendmsg(bts, msg);
1803}
1804
1805/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1806int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1807 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1808{
1809 struct gsm_bts *bts = trx->bts;
1810 struct abis_om_hdr *oh;
1811 struct abis_nm_channel *ch;
1812 struct msgb *msg = nm_msgb_alloc();
1813
1814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1815 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1816 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1817
1818 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1819 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1820
1821 return abis_nm_sendmsg(bts, msg);
1822}
1823
1824#if 0
1825int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1826 struct abis_nm_abis_channel *chan)
1827{
1828}
1829#endif
1830
1831int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1832 u_int8_t e1_port, u_int8_t e1_timeslot,
1833 u_int8_t e1_subslot)
1834{
1835 struct gsm_bts *bts = ts->trx->bts;
1836 struct abis_om_hdr *oh;
1837 struct abis_nm_channel *ch;
1838 struct msgb *msg = nm_msgb_alloc();
1839
1840 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1841 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1842 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1843
1844 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1845 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1846
1847 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1848 gsm_ts_name(ts),
1849 e1_port, e1_timeslot, e1_subslot);
1850
1851 return abis_nm_sendmsg(bts, msg);
1852}
1853
1854#if 0
1855int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1856 struct abis_nm_abis_channel *chan,
1857 u_int8_t subchan)
1858{
1859}
1860#endif
1861
1862/* Chapter 8.6.1 */
1863int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1864{
1865 struct abis_om_hdr *oh;
1866 struct msgb *msg = nm_msgb_alloc();
1867 u_int8_t *cur;
1868
1869 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1870
1871 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1872 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1873 cur = msgb_put(msg, attr_len);
1874 memcpy(cur, attr, attr_len);
1875
1876 return abis_nm_sendmsg(bts, msg);
1877}
1878
1879/* Chapter 8.6.2 */
1880int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1881{
1882 struct abis_om_hdr *oh;
1883 struct msgb *msg = nm_msgb_alloc();
1884 u_int8_t *cur;
1885
1886 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1887
1888 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1889 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1890 trx->bts->bts_nr, trx->nr, 0xff);
1891 cur = msgb_put(msg, attr_len);
1892 memcpy(cur, attr, attr_len);
1893
1894 return abis_nm_sendmsg(trx->bts, msg);
1895}
1896
Harald Weltef2eb2782009-08-09 21:49:48 +02001897static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1898{
1899 int i;
1900
1901 /* As it turns out, the BS-11 has some very peculiar restrictions
1902 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301903 switch (ts->trx->bts->type) {
1904 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001905 switch (chan_comb) {
1906 case NM_CHANC_TCHHalf:
1907 case NM_CHANC_TCHHalf2:
1908 /* not supported */
1909 return -EINVAL;
1910 case NM_CHANC_SDCCH:
1911 /* only one SDCCH/8 per TRX */
1912 for (i = 0; i < TRX_NR_TS; i++) {
1913 if (i == ts->nr)
1914 continue;
1915 if (ts->trx->ts[i].nm_chan_comb ==
1916 NM_CHANC_SDCCH)
1917 return -EINVAL;
1918 }
1919 /* not allowed for TS0 of BCCH-TRX */
1920 if (ts->trx == ts->trx->bts->c0 &&
1921 ts->nr == 0)
1922 return -EINVAL;
1923 /* not on the same TRX that has a BCCH+SDCCH4
1924 * combination */
1925 if (ts->trx == ts->trx->bts->c0 &&
1926 (ts->trx->ts[0].nm_chan_comb == 5 ||
1927 ts->trx->ts[0].nm_chan_comb == 8))
1928 return -EINVAL;
1929 break;
1930 case NM_CHANC_mainBCCH:
1931 case NM_CHANC_BCCHComb:
1932 /* allowed only for TS0 of C0 */
1933 if (ts->trx != ts->trx->bts->c0 ||
1934 ts->nr != 0)
1935 return -EINVAL;
1936 break;
1937 case NM_CHANC_BCCH:
1938 /* allowed only for TS 2/4/6 of C0 */
1939 if (ts->trx != ts->trx->bts->c0)
1940 return -EINVAL;
1941 if (ts->nr != 2 && ts->nr != 4 &&
1942 ts->nr != 6)
1943 return -EINVAL;
1944 break;
1945 case 8: /* this is not like 08.58, but in fact
1946 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1947 /* FIXME: only one CBCH allowed per cell */
1948 break;
1949 }
Harald Welte76ba8812009-12-02 02:45:23 +05301950 break;
1951 case GSM_BTS_TYPE_NANOBTS:
1952 switch (ts->nr) {
1953 case 0:
1954 if (ts->trx->nr == 0) {
1955 /* only on TRX0 */
1956 switch (chan_comb) {
1957 case NM_CHANC_BCCH:
1958 case NM_CHANC_mainBCCH:
1959 case NM_CHANC_BCCHComb:
1960 return 0;
1961 break;
1962 default:
1963 return -EINVAL;
1964 }
1965 } else {
1966 switch (chan_comb) {
1967 case NM_CHANC_TCHFull:
1968 case NM_CHANC_TCHHalf:
1969 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1970 return 0;
1971 default:
1972 return -EINVAL;
1973 }
1974 }
1975 break;
1976 case 1:
1977 if (ts->trx->nr == 0) {
1978 switch (chan_comb) {
1979 case NM_CHANC_SDCCH_CBCH:
1980 if (ts->trx->ts[0].nm_chan_comb ==
1981 NM_CHANC_mainBCCH)
1982 return 0;
1983 return -EINVAL;
1984 case NM_CHANC_SDCCH:
1985 case NM_CHANC_TCHFull:
1986 case NM_CHANC_TCHHalf:
1987 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1988 case NM_CHANC_IPAC_TCHFull_PDCH:
1989 return 0;
1990 }
1991 } else {
1992 switch (chan_comb) {
1993 case NM_CHANC_SDCCH:
1994 case NM_CHANC_TCHFull:
1995 case NM_CHANC_TCHHalf:
1996 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1997 return 0;
1998 default:
1999 return -EINVAL;
2000 }
2001 }
2002 break;
2003 case 2:
2004 case 3:
2005 case 4:
2006 case 5:
2007 case 6:
2008 case 7:
2009 switch (chan_comb) {
2010 case NM_CHANC_TCHFull:
2011 case NM_CHANC_TCHHalf:
2012 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2013 return 0;
2014 case NM_CHANC_IPAC_PDCH:
2015 case NM_CHANC_IPAC_TCHFull_PDCH:
2016 if (ts->trx->nr == 0)
2017 return 0;
2018 else
2019 return -EINVAL;
2020 }
2021 break;
2022 }
2023 return -EINVAL;
2024 default:
2025 /* unknown BTS type */
2026 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02002027 }
2028 return 0;
2029}
2030
Harald Welte59b04682009-06-10 05:40:52 +08002031/* Chapter 8.6.3 */
2032int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2033{
2034 struct gsm_bts *bts = ts->trx->bts;
2035 struct abis_om_hdr *oh;
Harald Welte59b04682009-06-10 05:40:52 +08002036 u_int8_t zero = 0x00;
2037 struct msgb *msg = nm_msgb_alloc();
2038 u_int8_t len = 2 + 2;
2039
2040 if (bts->type == GSM_BTS_TYPE_BS11)
2041 len += 4 + 2 + 2 + 3;
2042
2043 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02002044 if (verify_chan_comb(ts, chan_comb) < 0) {
2045 msgb_free(msg);
2046 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2047 return -EINVAL;
2048 }
2049 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08002050
2051 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2052 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
2053 NM_OC_CHANNEL, bts->bts_nr,
2054 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08002055 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02002056 if (ts->hopping.enabled) {
2057 unsigned int i;
2058 uint8_t *len;
2059
Harald Welte67104d12009-09-12 13:05:33 +02002060 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2061 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02002062
2063 /* build the ARFCN list */
2064 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2065 len = msgb_put(msg, 1);
2066 *len = 0;
2067 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2068 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2069 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02002070 /* At least BS-11 wants a TLV16 here */
2071 if (bts->type == GSM_BTS_TYPE_BS11)
2072 *len += 1;
2073 else
2074 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02002075 }
2076 }
Harald Welte59b04682009-06-10 05:40:52 +08002077 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02002078 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08002079 if (bts->type == GSM_BTS_TYPE_BS11)
2080 msgb_tlv_put(msg, 0x59, 1, &zero);
2081
2082 return abis_nm_sendmsg(bts, msg);
2083}
2084
2085int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
2086 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
2087{
2088 struct abis_om_hdr *oh;
2089 struct msgb *msg = nm_msgb_alloc();
2090 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2091 u_int8_t len = att_len;
2092
2093 if (nack) {
2094 len += 2;
2095 msgtype = NM_MT_SW_ACT_REQ_NACK;
2096 }
2097
2098 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2099 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2100
2101 if (attr) {
2102 u_int8_t *ptr = msgb_put(msg, att_len);
2103 memcpy(ptr, attr, att_len);
2104 }
2105 if (nack)
2106 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2107
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002108 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002109}
2110
2111int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2112{
2113 struct msgb *msg = nm_msgb_alloc();
2114 struct abis_om_hdr *oh;
2115 u_int8_t *data;
2116
2117 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2118 fill_om_hdr(oh, len);
2119 data = msgb_put(msg, len);
2120 memcpy(data, rawmsg, len);
2121
2122 return abis_nm_sendmsg(bts, msg);
2123}
2124
2125/* Siemens specific commands */
2126static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2127{
2128 struct abis_om_hdr *oh;
2129 struct msgb *msg = nm_msgb_alloc();
2130
2131 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2132 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2133 0xff, 0xff, 0xff);
2134
2135 return abis_nm_sendmsg(bts, msg);
2136}
2137
2138/* Chapter 8.9.2 */
2139int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2140{
2141 struct abis_om_hdr *oh;
2142 struct msgb *msg = nm_msgb_alloc();
2143
Harald Welte59b04682009-06-10 05:40:52 +08002144 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2145 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2146
Harald Welteb7284a92009-10-20 09:56:18 +02002147 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2148 DEBUGPC(DNM, "Sending OPSTART\n");
2149
Harald Welte59b04682009-06-10 05:40:52 +08002150 return abis_nm_sendmsg(bts, msg);
2151}
2152
2153/* Chapter 8.8.5 */
2154int 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 +02002155 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002156{
2157 struct abis_om_hdr *oh;
2158 struct msgb *msg = nm_msgb_alloc();
2159
2160 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2161 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2162 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2163
2164 return abis_nm_sendmsg(bts, msg);
2165}
2166
Harald Welte204317e2009-08-06 17:58:31 +02002167int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2168 u_int8_t e1_port1, u_int8_t ts1)
2169{
2170 struct abis_om_hdr *oh;
2171 struct msgb *msg = nm_msgb_alloc();
2172 u_int8_t *attr;
2173
2174 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2175 e1_port0, ts0, e1_port1, ts1);
2176
2177 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2178 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2179 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2180
2181 attr = msgb_put(msg, 3);
2182 attr[0] = NM_ATT_MDROP_LINK;
2183 attr[1] = e1_port0;
2184 attr[2] = ts0;
2185
2186 attr = msgb_put(msg, 3);
2187 attr[0] = NM_ATT_MDROP_NEXT;
2188 attr[1] = e1_port1;
2189 attr[2] = ts1;
2190
2191 return abis_nm_sendmsg(bts, msg);
2192}
Harald Welte59b04682009-06-10 05:40:52 +08002193
Harald Welte0bf8e302009-08-08 00:02:36 +02002194/* Chapter 8.7.1 */
2195int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2196 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welteb31c9df2010-03-06 11:38:05 +01002197 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02002198{
2199 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02002200
Harald Welte30f93fb2011-02-19 16:48:17 +01002201 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01002202
2203 if (!msg)
2204 msg = nm_msgb_alloc();
2205
2206 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2207 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2208 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2209 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02002210 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02002211
2212 return abis_nm_sendmsg(bts, msg);
2213}
2214
Harald Welte59b04682009-06-10 05:40:52 +08002215int abis_nm_event_reports(struct gsm_bts *bts, int on)
2216{
2217 if (on == 0)
2218 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2219 else
2220 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2221}
2222
2223/* Siemens (or BS-11) specific commands */
2224
2225int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2226{
2227 if (reconnect == 0)
2228 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2229 else
2230 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2231}
2232
2233int abis_nm_bs11_restart(struct gsm_bts *bts)
2234{
2235 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2236}
2237
2238
2239struct bs11_date_time {
2240 u_int16_t year;
2241 u_int8_t month;
2242 u_int8_t day;
2243 u_int8_t hour;
2244 u_int8_t min;
2245 u_int8_t sec;
2246} __attribute__((packed));
2247
2248
2249void get_bs11_date_time(struct bs11_date_time *aet)
2250{
2251 time_t t;
2252 struct tm *tm;
2253
2254 t = time(NULL);
2255 tm = localtime(&t);
2256 aet->sec = tm->tm_sec;
2257 aet->min = tm->tm_min;
2258 aet->hour = tm->tm_hour;
2259 aet->day = tm->tm_mday;
2260 aet->month = tm->tm_mon;
2261 aet->year = htons(1900 + tm->tm_year);
2262}
2263
2264int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2265{
2266 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2267}
2268
2269int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2270{
2271 if (begin)
2272 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2273 else
2274 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2275}
2276
2277int abis_nm_bs11_create_object(struct gsm_bts *bts,
2278 enum abis_bs11_objtype type, u_int8_t idx,
2279 u_int8_t attr_len, const u_int8_t *attr)
2280{
2281 struct abis_om_hdr *oh;
2282 struct msgb *msg = nm_msgb_alloc();
2283 u_int8_t *cur;
2284
2285 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2286 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2287 NM_OC_BS11, type, 0, idx);
2288 cur = msgb_put(msg, attr_len);
2289 memcpy(cur, attr, attr_len);
2290
2291 return abis_nm_sendmsg(bts, msg);
2292}
2293
2294int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2295 enum abis_bs11_objtype type, u_int8_t idx)
2296{
2297 struct abis_om_hdr *oh;
2298 struct msgb *msg = nm_msgb_alloc();
2299
2300 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2301 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2302 NM_OC_BS11, type, 0, idx);
2303
2304 return abis_nm_sendmsg(bts, msg);
2305}
2306
2307int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2308{
2309 struct abis_om_hdr *oh;
2310 struct msgb *msg = nm_msgb_alloc();
2311 u_int8_t zero = 0x00;
2312
2313 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2314 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2315 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2316 msgb_tlv_put(msg, 0x99, 1, &zero);
2317
2318 return abis_nm_sendmsg(bts, msg);
2319}
2320
2321int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2322{
2323 struct abis_om_hdr *oh;
2324 struct msgb *msg = nm_msgb_alloc();
2325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2327 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002328 idx, 0xff, 0xff);
2329
2330 return abis_nm_sendmsg(bts, msg);
2331}
2332
2333int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2334{
2335 struct abis_om_hdr *oh;
2336 struct msgb *msg = nm_msgb_alloc();
2337
2338 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2339 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2340 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002341
2342 return abis_nm_sendmsg(bts, msg);
2343}
2344
2345static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2346int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2347{
2348 struct abis_om_hdr *oh;
2349 struct msgb *msg = nm_msgb_alloc();
2350
2351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2352 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2353 0xff, 0xff, 0xff);
2354 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2355
2356 return abis_nm_sendmsg(bts, msg);
2357}
2358
2359/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002360int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welte59b04682009-06-10 05:40:52 +08002361 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2362 u_int8_t tei)
2363{
2364 struct abis_om_hdr *oh;
2365 struct abis_nm_channel *ch;
2366 struct msgb *msg = nm_msgb_alloc();
2367
2368 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2369 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2370 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2371
2372 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2373 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2374 msgb_tv_put(msg, NM_ATT_TEI, tei);
2375
2376 return abis_nm_sendmsg(bts, msg);
2377}
2378
2379int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2380{
2381 struct abis_om_hdr *oh;
2382 struct msgb *msg = nm_msgb_alloc();
2383
2384 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2385 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2386 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2387 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2388
2389 return abis_nm_sendmsg(trx->bts, msg);
2390}
2391
2392int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2393{
2394 struct abis_om_hdr *oh;
2395 struct msgb *msg = nm_msgb_alloc();
2396 u_int8_t attr = NM_ATT_BS11_TXPWR;
2397
2398 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2399 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2400 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2401 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2402
2403 return abis_nm_sendmsg(trx->bts, msg);
2404}
2405
2406int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2407{
2408 struct abis_om_hdr *oh;
2409 struct msgb *msg = nm_msgb_alloc();
2410 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2411
2412 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2413 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2414 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2415 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2416
2417 return abis_nm_sendmsg(bts, msg);
2418}
2419
2420int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2421{
2422 struct abis_om_hdr *oh;
2423 struct msgb *msg = nm_msgb_alloc();
2424 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2425 NM_ATT_BS11_CCLK_TYPE };
2426
2427 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2428 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2429 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2430 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2431
2432 return abis_nm_sendmsg(bts, msg);
2433
2434}
2435
2436//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002437
2438int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2439{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002440 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2441}
2442
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002443int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2444{
2445 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2446}
2447
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002448int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2449{
Harald Welte59b04682009-06-10 05:40:52 +08002450 struct abis_om_hdr *oh;
2451 struct msgb *msg = nm_msgb_alloc();
2452 struct bs11_date_time bdt;
2453
2454 get_bs11_date_time(&bdt);
2455
2456 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2457 if (on) {
2458 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002459 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002460 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2461 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2462 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2463 sizeof(bdt), (u_int8_t *) &bdt);
2464 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002465 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002466 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002467 strlen(name), (u_int8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002468 } else {
2469 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2470 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2471 }
2472
2473 return abis_nm_sendmsg(bts, msg);
2474}
2475
2476int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2477{
2478 struct abis_om_hdr *oh;
2479 struct msgb *msg;
2480
2481 if (strlen(password) != 10)
2482 return -EINVAL;
2483
2484 msg = nm_msgb_alloc();
2485 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2486 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2487 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2488 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2489
2490 return abis_nm_sendmsg(bts, msg);
2491}
2492
2493/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2494int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2495{
2496 struct abis_om_hdr *oh;
2497 struct msgb *msg;
2498 u_int8_t tlv_value;
2499
2500 msg = nm_msgb_alloc();
2501 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2502 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2503 BS11_OBJ_LI, 0x00, 0x00);
2504
2505 if (locked)
2506 tlv_value = BS11_LI_PLL_LOCKED;
2507 else
2508 tlv_value = BS11_LI_PLL_STANDALONE;
2509
2510 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2511
2512 return abis_nm_sendmsg(bts, msg);
2513}
2514
Daniel Willmann10b07db2010-01-07 00:54:01 +01002515/* Set the calibration value of the PLL (work value/set value)
2516 * It depends on the login which one is changed */
2517int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2518{
2519 struct abis_om_hdr *oh;
2520 struct msgb *msg;
2521 u_int8_t tlv_value[2];
2522
2523 msg = nm_msgb_alloc();
2524 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2525 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2526 BS11_OBJ_TRX1, 0x00, 0x00);
2527
2528 tlv_value[0] = value>>8;
2529 tlv_value[1] = value&0xff;
2530
2531 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2532
2533 return abis_nm_sendmsg(bts, msg);
2534}
2535
Harald Welte59b04682009-06-10 05:40:52 +08002536int abis_nm_bs11_get_state(struct gsm_bts *bts)
2537{
2538 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2539}
2540
2541/* BS11 SWL */
2542
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002543void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002544
Harald Welte59b04682009-06-10 05:40:52 +08002545struct abis_nm_bs11_sw {
2546 struct gsm_bts *bts;
2547 char swl_fname[PATH_MAX];
2548 u_int8_t win_size;
2549 int forced;
2550 struct llist_head file_list;
2551 gsm_cbfn *user_cb; /* specified by the user */
2552};
2553static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2554
2555struct file_list_entry {
2556 struct llist_head list;
2557 char fname[PATH_MAX];
2558};
2559
2560struct file_list_entry *fl_dequeue(struct llist_head *queue)
2561{
2562 struct llist_head *lh;
2563
2564 if (llist_empty(queue))
2565 return NULL;
2566
2567 lh = queue->next;
2568 llist_del(lh);
2569
2570 return llist_entry(lh, struct file_list_entry, list);
2571}
2572
2573static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2574{
2575 char linebuf[255];
2576 struct llist_head *lh, *lh2;
2577 FILE *swl;
2578 int rc = 0;
2579
2580 swl = fopen(bs11_sw->swl_fname, "r");
2581 if (!swl)
2582 return -ENODEV;
2583
2584 /* zero the stale file list, if any */
2585 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2586 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002587 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002588 }
2589
2590 while (fgets(linebuf, sizeof(linebuf), swl)) {
2591 char file_id[12+1];
2592 char file_version[80+1];
2593 struct file_list_entry *fle;
2594 static char dir[PATH_MAX];
2595
2596 if (strlen(linebuf) < 4)
2597 continue;
2598
2599 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2600 if (rc < 0) {
2601 perror("ERR parsing SWL file");
2602 rc = -EINVAL;
2603 goto out;
2604 }
2605 if (rc < 2)
2606 continue;
2607
Harald Welte857e00d2009-06-26 20:25:23 +02002608 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002609 if (!fle) {
2610 rc = -ENOMEM;
2611 goto out;
2612 }
Harald Welte59b04682009-06-10 05:40:52 +08002613
2614 /* construct new filename */
2615 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2616 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2617 strcat(fle->fname, "/");
2618 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2619
2620 llist_add_tail(&fle->list, &bs11_sw->file_list);
2621 }
2622
2623out:
2624 fclose(swl);
2625 return rc;
2626}
2627
2628/* bs11 swload specific callback, passed to abis_nm core swload */
2629static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2630 struct msgb *msg, void *data, void *param)
2631{
2632 struct abis_nm_bs11_sw *bs11_sw = data;
2633 struct file_list_entry *fle;
2634 int rc = 0;
2635
2636 switch (event) {
2637 case NM_MT_LOAD_END_ACK:
2638 fle = fl_dequeue(&bs11_sw->file_list);
2639 if (fle) {
2640 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002641 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002642 bs11_sw->win_size,
2643 bs11_sw->forced,
2644 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002645 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002646 } else {
2647 /* activate the SWL */
2648 rc = abis_nm_software_activate(bs11_sw->bts,
2649 bs11_sw->swl_fname,
2650 bs11_swload_cbfn,
2651 bs11_sw);
2652 }
2653 break;
2654 case NM_MT_LOAD_SEG_ACK:
2655 case NM_MT_LOAD_END_NACK:
2656 case NM_MT_LOAD_INIT_ACK:
2657 case NM_MT_LOAD_INIT_NACK:
2658 case NM_MT_ACTIVATE_SW_NACK:
2659 case NM_MT_ACTIVATE_SW_ACK:
2660 default:
2661 /* fallthrough to the user callback */
2662 if (bs11_sw->user_cb)
2663 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2664 break;
2665 }
2666
2667 return rc;
2668}
2669
2670/* Siemens provides a SWL file that is a mere listing of all the other
2671 * files that are part of a software release. We need to upload first
2672 * the list file, and then each file that is listed in the list file */
2673int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2674 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2675{
2676 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2677 struct file_list_entry *fle;
2678 int rc = 0;
2679
2680 INIT_LLIST_HEAD(&bs11_sw->file_list);
2681 bs11_sw->bts = bts;
2682 bs11_sw->win_size = win_size;
2683 bs11_sw->user_cb = cbfn;
2684 bs11_sw->forced = forced;
2685
2686 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2687 rc = bs11_read_swl_file(bs11_sw);
2688 if (rc < 0)
2689 return rc;
2690
2691 /* dequeue next item in file list */
2692 fle = fl_dequeue(&bs11_sw->file_list);
2693 if (!fle)
2694 return -EINVAL;
2695
2696 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002697 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002698 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002699 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002700 return rc;
2701}
2702
2703#if 0
2704static u_int8_t req_attr_btse[] = {
2705 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2706 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2707 NM_ATT_BS11_LMT_USER_NAME,
2708
2709 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2710
2711 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2712
2713 NM_ATT_BS11_SW_LOAD_STORED };
2714
2715static u_int8_t req_attr_btsm[] = {
2716 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2717 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2718 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2719 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2720#endif
2721
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002722static u_int8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002723 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2724 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2725 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2726
2727int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2728{
2729 struct abis_om_hdr *oh;
2730 struct msgb *msg = nm_msgb_alloc();
2731
2732 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2733 /* SiemensHW CCTRL object */
2734 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2735 0x03, 0x00, 0x00);
2736 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2737
2738 return abis_nm_sendmsg(bts, msg);
2739}
2740
2741int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2742{
2743 struct abis_om_hdr *oh;
2744 struct msgb *msg = nm_msgb_alloc();
2745 struct bs11_date_time aet;
2746
2747 get_bs11_date_time(&aet);
2748 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2749 /* SiemensHW CCTRL object */
2750 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2751 0xff, 0xff, 0xff);
2752 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2753
2754 return abis_nm_sendmsg(bts, msg);
2755}
2756
Harald Welte30534c52010-12-14 12:52:16 +01002757int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2758{
2759 struct abis_om_hdr *oh;
2760 struct msgb *msg = nm_msgb_alloc();
2761 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2762
2763 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2764 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2765 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2766 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2767
2768 return abis_nm_sendmsg(bts, msg);
2769}
2770
Daniel Willmann5655afe2009-08-10 11:49:36 +02002771int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2772{
2773 struct abis_om_hdr *oh;
2774 struct msgb *msg = nm_msgb_alloc();
2775 struct bs11_date_time aet;
2776
2777 get_bs11_date_time(&aet);
2778 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2779 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2780 bport, 0xff, 0x02);
2781 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2782
2783 return abis_nm_sendmsg(bts, msg);
2784}
2785
Harald Welte59b04682009-06-10 05:40:52 +08002786/* ip.access nanoBTS specific commands */
2787static const char ipaccess_magic[] = "com.ipaccess";
2788
2789
2790static int abis_nm_rx_ipacc(struct msgb *msg)
2791{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002792 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002793 struct abis_om_hdr *oh = msgb_l2(msg);
2794 struct abis_om_fom_hdr *foh;
2795 u_int8_t idstrlen = oh->data[0];
2796 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002797 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002798
2799 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002800 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002801 return -EINVAL;
2802 }
2803
2804 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002805 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002806
Harald Welteb7284a92009-10-20 09:56:18 +02002807 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002808
Harald Welte5aeedd42009-10-19 22:11:11 +02002809 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002810
2811 switch (foh->msg_type) {
2812 case NM_MT_IPACC_RSL_CONNECT_ACK:
2813 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002814 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2815 memcpy(&addr,
2816 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2817
2818 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2819 }
Harald Welte4206d982009-07-12 09:33:54 +02002820 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002821 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002822 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002823 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002824 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2825 DEBUGPC(DNM, "STREAM=0x%02x ",
2826 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002827 DEBUGPC(DNM, "\n");
2828 break;
2829 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002830 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002831 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002832 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002833 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2834 else
2835 DEBUGPC(DNM, "\n");
2836 break;
2837 case NM_MT_IPACC_SET_NVATTR_ACK:
2838 DEBUGPC(DNM, "SET NVATTR ACK\n");
2839 /* FIXME: decode and show the actual attributes */
2840 break;
2841 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002842 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002843 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002844 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002845 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2846 else
Harald Weltede4477a2009-12-24 12:20:20 +01002847 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002848 break;
Harald Welte21460f02009-07-03 11:26:45 +02002849 case NM_MT_IPACC_GET_NVATTR_ACK:
2850 DEBUGPC(DNM, "GET NVATTR ACK\n");
2851 /* FIXME: decode and show the actual attributes */
2852 break;
2853 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002854 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002855 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002856 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002857 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2858 else
Harald Weltede4477a2009-12-24 12:20:20 +01002859 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002860 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002861 case NM_MT_IPACC_SET_ATTR_ACK:
2862 DEBUGPC(DNM, "SET ATTR ACK\n");
2863 break;
2864 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002865 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002866 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002867 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002868 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2869 else
Harald Weltede4477a2009-12-24 12:20:20 +01002870 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002871 break;
Harald Welte59b04682009-06-10 05:40:52 +08002872 default:
2873 DEBUGPC(DNM, "unknown\n");
2874 break;
2875 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002876
2877 /* signal handling */
2878 switch (foh->msg_type) {
2879 case NM_MT_IPACC_RSL_CONNECT_NACK:
2880 case NM_MT_IPACC_SET_NVATTR_NACK:
2881 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002882 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002883 signal.msg_type = foh->msg_type;
2884 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002885 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002886 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002887 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002888 signal.msg_type = foh->msg_type;
2889 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002890 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002891 default:
2892 break;
2893 }
2894
Harald Welte59b04682009-06-10 05:40:52 +08002895 return 0;
2896}
2897
2898/* send an ip-access manufacturer specific message */
2899int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2900 u_int8_t obj_class, u_int8_t bts_nr,
2901 u_int8_t trx_nr, u_int8_t ts_nr,
2902 u_int8_t *attr, int attr_len)
2903{
2904 struct msgb *msg = nm_msgb_alloc();
2905 struct abis_om_hdr *oh;
2906 struct abis_om_fom_hdr *foh;
2907 u_int8_t *data;
2908
2909 /* construct the 12.21 OM header, observe the erroneous length */
2910 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2911 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2912 oh->mdisc = ABIS_OM_MDISC_MANUF;
2913
2914 /* add the ip.access magic */
2915 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2916 *data++ = sizeof(ipaccess_magic);
2917 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2918
2919 /* fill the 12.21 FOM header */
2920 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2921 foh->msg_type = msg_type;
2922 foh->obj_class = obj_class;
2923 foh->obj_inst.bts_nr = bts_nr;
2924 foh->obj_inst.trx_nr = trx_nr;
2925 foh->obj_inst.ts_nr = ts_nr;
2926
2927 if (attr && attr_len) {
2928 data = msgb_put(msg, attr_len);
2929 memcpy(data, attr, attr_len);
2930 }
2931
2932 return abis_nm_sendmsg(bts, msg);
2933}
2934
2935/* set some attributes in NVRAM */
Harald Weltef12c1052010-01-07 20:39:42 +01002936int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002937 int attr_len)
2938{
Harald Weltef12c1052010-01-07 20:39:42 +01002939 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2940 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002941 attr_len);
2942}
2943
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002944int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte5aeedd42009-10-19 22:11:11 +02002945 u_int32_t ip, u_int16_t port, u_int8_t stream)
2946{
2947 struct in_addr ia;
2948 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2949 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2950 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2951
2952 int attr_len = sizeof(attr);
2953
2954 ia.s_addr = htonl(ip);
2955 attr[1] = stream;
2956 attr[3] = port >> 8;
2957 attr[4] = port & 0xff;
2958 *(u_int32_t *)(attr+6) = ia.s_addr;
2959
2960 /* if ip == 0, we use the default IP */
2961 if (ip == 0)
2962 attr_len -= 5;
2963
2964 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002965 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002966
2967 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2968 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2969 trx->nr, 0xff, attr, attr_len);
2970}
2971
Harald Welte59b04682009-06-10 05:40:52 +08002972/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002973int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002974{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002975 struct abis_om_hdr *oh;
2976 struct msgb *msg = nm_msgb_alloc();
2977
2978 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2979 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2980 trx->bts->nr, trx->nr, 0xff);
2981
2982 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002983}
Harald Welte0dfc6232009-10-24 10:20:41 +02002984
2985int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2986 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2987 u_int8_t *attr, u_int8_t attr_len)
2988{
2989 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2990 obj_class, bts_nr, trx_nr, ts_nr,
2991 attr, attr_len);
2992}
Harald Weltebeeae412009-11-12 14:48:42 +01002993
Harald Welte3055e332010-03-14 15:37:43 +08002994void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2995{
2996 /* we simply reuse the GSM48 function and overwrite the RAC
2997 * with the Cell ID */
2998 gsm48_ra_id_by_bts(buf, bts);
2999 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
3000}
3001
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01003002void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
3003{
3004 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
3005
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01003006 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01003007 if (!trx->bts || !trx->bts->oml_link)
3008 return;
3009
3010 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3011 trx->bts->bts_nr, trx->nr, 0xff,
3012 new_state);
3013}
3014
Harald Welte453141f2010-03-25 11:45:30 +08003015static const struct value_string ipacc_testres_names[] = {
3016 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3017 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3018 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3019 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3020 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3021 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01003022};
3023
3024const char *ipacc_testres_name(u_int8_t res)
3025{
Harald Welte453141f2010-03-25 11:45:30 +08003026 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01003027}
3028
Harald Weltebfc21092009-11-13 11:56:05 +01003029void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3030{
3031 cid->mcc = (buf[0] & 0xf) * 100;
3032 cid->mcc += (buf[0] >> 4) * 10;
3033 cid->mcc += (buf[1] & 0xf) * 1;
3034
3035 if (buf[1] >> 4 == 0xf) {
3036 cid->mnc = (buf[2] & 0xf) * 10;
3037 cid->mnc += (buf[2] >> 4) * 1;
3038 } else {
3039 cid->mnc = (buf[2] & 0xf) * 100;
3040 cid->mnc += (buf[2] >> 4) * 10;
3041 cid->mnc += (buf[1] >> 4) * 1;
3042 }
3043
Harald Welte161b4be2009-11-13 14:41:52 +01003044 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3045 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01003046}
3047
Harald Weltebeeae412009-11-12 14:48:42 +01003048/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3049int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3050{
3051 u_int8_t *cur = buf;
3052 u_int16_t len;
3053
Harald Welteb784df82010-07-22 18:14:36 +02003054 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01003055
3056 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3057 return -EINVAL;
3058 cur++;
3059
3060 len = ntohs(*(u_int16_t *)cur);
3061 cur += 2;
3062
3063 binf->info_type = ntohs(*(u_int16_t *)cur);
3064 cur += 2;
3065
3066 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3067 binf->freq_qual = *cur >> 2;
3068
Harald Welteb784df82010-07-22 18:14:36 +02003069 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01003070 binf->arfcn |= *cur++;
3071
3072 if (binf->info_type & IPAC_BINF_RXLEV)
3073 binf->rx_lev = *cur & 0x3f;
3074 cur++;
3075
3076 if (binf->info_type & IPAC_BINF_RXQUAL)
3077 binf->rx_qual = *cur & 0x7;
3078 cur++;
3079
3080 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3081 binf->freq_err = ntohs(*(u_int16_t *)cur);
3082 cur += 2;
3083
3084 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3085 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3086 cur += 2;
3087
3088 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3089 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3090 cur += 4;
3091
Harald Welte22cb81f2010-07-30 22:34:42 +02003092#if 0
3093 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01003094 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02003095#endif
Harald Welte161b4be2009-11-13 14:41:52 +01003096 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01003097 cur++;
3098
Harald Weltebfc21092009-11-13 11:56:05 +01003099 ipac_parse_cgi(&binf->cgi, cur);
3100 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01003101
3102 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3103 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3104 cur += sizeof(binf->ba_list_si2);
3105 }
3106
3107 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3108 memcpy(binf->ba_list_si2bis, cur,
3109 sizeof(binf->ba_list_si2bis));
3110 cur += sizeof(binf->ba_list_si2bis);
3111 }
3112
3113 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3114 memcpy(binf->ba_list_si2ter, cur,
3115 sizeof(binf->ba_list_si2ter));
3116 cur += sizeof(binf->ba_list_si2ter);
3117 }
3118
3119 return 0;
3120}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01003121
3122void abis_nm_clear_queue(struct gsm_bts *bts)
3123{
3124 struct msgb *msg;
3125
3126 while (!llist_empty(&bts->abis_queue)) {
3127 msg = msgb_dequeue(&bts->abis_queue);
3128 msgb_free(msg);
3129 }
3130
3131 bts->abis_nm_pend = 0;
3132}