blob: 686421625f7b578ff3e3d2938ddb77305e4a82e3 [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);
419 return _abis_nm_sendmsg(msg);
420 } 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;
783
784 DEBUGPC(DNM, "Failure Event Report ");
785
Harald Welte59698fb2010-01-10 18:01:52 +0100786 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800787
788 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
789 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
790 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
791 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
792
793 DEBUGPC(DNM, "\n");
794
795 return 0;
796}
797
798static int abis_nm_rcvmsg_report(struct msgb *mb)
799{
800 struct abis_om_fom_hdr *foh = msgb_l3(mb);
801 u_int8_t mt = foh->msg_type;
802
Harald Welteb7284a92009-10-20 09:56:18 +0200803 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800804
805 //nmh->cfg->report_cb(mb, foh);
806
807 switch (mt) {
808 case NM_MT_STATECHG_EVENT_REP:
809 return abis_nm_rx_statechg_rep(mb);
810 break;
811 case NM_MT_SW_ACTIVATED_REP:
812 DEBUGPC(DNM, "Software Activated Report\n");
813 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
814 break;
815 case NM_MT_FAILURE_EVENT_REP:
816 rx_fail_evt_rep(mb);
817 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
818 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200819 case NM_MT_TEST_REP:
820 DEBUGPC(DNM, "Test Report\n");
821 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
822 break;
Harald Welte59b04682009-06-10 05:40:52 +0800823 default:
824 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
825 break;
826
827 };
828
829 return 0;
830}
831
832/* Activate the specified software into the BTS */
833static 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 +0200834 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800835{
836 struct abis_om_hdr *oh;
837 struct msgb *msg = nm_msgb_alloc();
838 u_int8_t len = swdesc_len;
839 u_int8_t *trailer;
840
841 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
842 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
843
844 trailer = msgb_put(msg, swdesc_len);
845 memcpy(trailer, sw_desc, swdesc_len);
846
847 return abis_nm_sendmsg(bts, msg);
848}
849
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100850static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
851{
852 static const struct tlv_definition sw_descr_def = {
853 .def = {
854 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
855 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
856 },
857 };
858
859 u_int8_t tag;
860 u_int16_t tag_len;
861 const u_int8_t *val;
862 int ofs = 0, len;
863
864 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
865 * nested nature and the fact you have to assume it contains only two sub
866 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
867
868 if (sw_descr[0] != NM_ATT_SW_DESCR) {
869 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
870 return -1;
871 }
872 ofs += 1;
873
874 len = tlv_parse_one(&tag, &tag_len, &val,
875 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
876 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
877 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
878 return -2;
879 }
880 ofs += len;
881
882 len = tlv_parse_one(&tag, &tag_len, &val,
883 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
884 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
885 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
886 return -3;
887 }
888 ofs += len;
889
890 return ofs;
891}
892
Harald Welte59b04682009-06-10 05:40:52 +0800893static int abis_nm_rx_sw_act_req(struct msgb *mb)
894{
895 struct abis_om_hdr *oh = msgb_l2(mb);
896 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200897 struct tlv_parsed tp;
898 const u_int8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100899 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800900
Harald Welteb7284a92009-10-20 09:56:18 +0200901 debugp_foh(foh);
902
903 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800904
Harald Welte3055e332010-03-14 15:37:43 +0800905 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800906
907 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
908 foh->obj_inst.bts_nr,
909 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800910 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800911 foh->data, oh->length-sizeof(*foh));
912
Harald Welte59698fb2010-01-10 18:01:52 +0100913 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200914 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
915 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
916 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
917 DEBUGP(DNM, "SW config not found! Can't continue.\n");
918 return -EINVAL;
919 } else {
920 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
921 }
922
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100923 /* Use the first SW_DESCR present in SW config */
924 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
925 if (sw_descr_len < 0)
926 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200927
Harald Welte59b04682009-06-10 05:40:52 +0800928 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
929 foh->obj_inst.bts_nr,
930 foh->obj_inst.trx_nr,
931 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100932 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800933}
934
935/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
936static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
937{
938 struct abis_om_hdr *oh = msgb_l2(mb);
939 struct abis_om_fom_hdr *foh = msgb_l3(mb);
940 struct tlv_parsed tp;
941 u_int8_t adm_state;
942
Harald Welte59698fb2010-01-10 18:01:52 +0100943 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800944 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
945 return -EINVAL;
946
947 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
948
949 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
950}
951
952static int abis_nm_rx_lmt_event(struct msgb *mb)
953{
954 struct abis_om_hdr *oh = msgb_l2(mb);
955 struct abis_om_fom_hdr *foh = msgb_l3(mb);
956 struct tlv_parsed tp;
957
958 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100959 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800960 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
961 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
962 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
963 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
964 }
965 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
966 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
967 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
968 DEBUGPC(DNM, "Level=%u ", level);
969 }
970 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
971 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
972 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
973 DEBUGPC(DNM, "Username=%s ", name);
974 }
975 DEBUGPC(DNM, "\n");
976 /* FIXME: parse LMT LOGON TIME */
977 return 0;
978}
979
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100980static void abis_nm_queue_send_next(struct gsm_bts *bts)
981{
982 int wait = 0;
983 struct msgb *msg;
984 /* the queue is empty */
985 while (!llist_empty(&bts->abis_queue)) {
986 msg = msgb_dequeue(&bts->abis_queue);
987 wait = OBSC_NM_W_ACK_CB(msg);
988 _abis_nm_sendmsg(msg);
989
990 if (wait)
991 break;
992 }
993
994 bts->abis_nm_pend = wait;
995}
996
Harald Welte59b04682009-06-10 05:40:52 +0800997/* Receive a OML NM Message from BTS */
998static int abis_nm_rcvmsg_fom(struct msgb *mb)
999{
1000 struct abis_om_hdr *oh = msgb_l2(mb);
1001 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1002 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001003 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001004
1005 /* check for unsolicited message */
1006 if (is_report(mt))
1007 return abis_nm_rcvmsg_report(mb);
1008
1009 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1010 return abis_nm_rcvmsg_sw(mb);
1011
1012 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001013 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +08001014 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +02001015
Harald Welteb7284a92009-10-20 09:56:18 +02001016 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +02001017
Harald Welte453141f2010-03-25 11:45:30 +08001018 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +08001019
Harald Welte59698fb2010-01-10 18:01:52 +01001020 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08001021 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001022 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08001023 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1024 else
1025 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001026
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001027 nack_data.msg = mb;
1028 nack_data.mt = mt;
1029 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001030 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001031 return 0;
Harald Welte59b04682009-06-10 05:40:52 +08001032 }
1033#if 0
1034 /* check if last message is to be acked */
1035 if (is_ack_nack(nmh->last_msgtype)) {
1036 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +01001037 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001038 /* we got our ACK, continue sending the next msg */
1039 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1040 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +01001041 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001042 /* FIXME: somehow signal this to the caller */
1043 } else {
1044 /* really strange things happen */
1045 return -EINVAL;
1046 }
1047 }
1048#endif
1049
1050 switch (mt) {
1051 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001052 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001053 break;
1054 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001055 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001056 break;
1057 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001058 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001059 break;
Harald Welte204317e2009-08-06 17:58:31 +02001060 case NM_MT_CONN_MDROP_LINK_ACK:
1061 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1062 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001063 case NM_MT_IPACC_RESTART_ACK:
1064 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1065 break;
1066 case NM_MT_IPACC_RESTART_NACK:
1067 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1068 break;
Harald Welte59b04682009-06-10 05:40:52 +08001069 }
1070
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001071 abis_nm_queue_send_next(mb->trx->bts);
1072 return ret;
Harald Welte59b04682009-06-10 05:40:52 +08001073}
1074
1075static int abis_nm_rx_ipacc(struct msgb *mb);
1076
1077static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1078{
1079 int rc;
1080 int bts_type = mb->trx->bts->type;
1081
1082 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001083 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001084 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001085 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001086 break;
1087 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001088 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1089 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001090 rc = 0;
1091 break;
1092 }
1093
1094 return rc;
1095}
1096
1097/* High-Level API */
1098/* Entry-point where L2 OML from BTS enters the NM code */
1099int abis_nm_rcvmsg(struct msgb *msg)
1100{
1101 struct abis_om_hdr *oh = msgb_l2(msg);
1102 int rc = 0;
1103
1104 /* Various consistency checks */
1105 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001106 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001107 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +02001108 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1109 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +08001110 }
1111 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001112 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001113 oh->sequence);
1114 return -EINVAL;
1115 }
1116#if 0
1117 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1118 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1119 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001120 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001121 oh->length + sizeof(*oh), l2_len);
1122 return -EINVAL;
1123 }
1124 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001125 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 +08001126#endif
1127 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1128
1129 switch (oh->mdisc) {
1130 case ABIS_OM_MDISC_FOM:
1131 rc = abis_nm_rcvmsg_fom(msg);
1132 break;
1133 case ABIS_OM_MDISC_MANUF:
1134 rc = abis_nm_rcvmsg_manuf(msg);
1135 break;
1136 case ABIS_OM_MDISC_MMI:
1137 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001138 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001139 oh->mdisc);
1140 break;
1141 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001142 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001143 oh->mdisc);
1144 return -EINVAL;
1145 }
1146
1147 msgb_free(msg);
1148 return rc;
1149}
1150
1151#if 0
1152/* initialized all resources */
1153struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1154{
1155 struct abis_nm_h *nmh;
1156
1157 nmh = malloc(sizeof(*nmh));
1158 if (!nmh)
1159 return NULL;
1160
1161 nmh->cfg = cfg;
1162
1163 return nmh;
1164}
1165
1166/* free all resources */
1167void abis_nm_fini(struct abis_nm_h *nmh)
1168{
1169 free(nmh);
1170}
1171#endif
1172
1173/* Here we are trying to define a high-level API that can be used by
1174 * the actual BSC implementation. However, the architecture is currently
1175 * still under design. Ideally the calls to this API would be synchronous,
1176 * while the underlying stack behind the APi runs in a traditional select
1177 * based state machine.
1178 */
1179
1180/* 6.2 Software Load: */
1181enum sw_state {
1182 SW_STATE_NONE,
1183 SW_STATE_WAIT_INITACK,
1184 SW_STATE_WAIT_SEGACK,
1185 SW_STATE_WAIT_ENDACK,
1186 SW_STATE_WAIT_ACTACK,
1187 SW_STATE_ERROR,
1188};
1189
1190struct abis_nm_sw {
1191 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001192 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +08001193 gsm_cbfn *cbfn;
1194 void *cb_data;
1195 int forced;
1196
1197 /* this will become part of the SW LOAD INITIATE */
1198 u_int8_t obj_class;
1199 u_int8_t obj_instance[3];
1200
1201 u_int8_t file_id[255];
1202 u_int8_t file_id_len;
1203
1204 u_int8_t file_version[255];
1205 u_int8_t file_version_len;
1206
1207 u_int8_t window_size;
1208 u_int8_t seg_in_window;
1209
1210 int fd;
1211 FILE *stream;
1212 enum sw_state state;
1213 int last_seg;
1214};
1215
1216static struct abis_nm_sw g_sw;
1217
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001218static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1219{
1220 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1221 msgb_v_put(msg, NM_ATT_SW_DESCR);
1222 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1223 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1224 sw->file_version);
1225 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1226 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1227 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1228 sw->file_version);
1229 } else {
1230 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1231 }
1232}
1233
Harald Welte59b04682009-06-10 05:40:52 +08001234/* 6.2.1 / 8.3.1: Load Data Initiate */
1235static int sw_load_init(struct abis_nm_sw *sw)
1236{
1237 struct abis_om_hdr *oh;
1238 struct msgb *msg = nm_msgb_alloc();
1239 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1240
1241 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1242 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1243 sw->obj_instance[0], sw->obj_instance[1],
1244 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001245
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001246 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001247 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1248
1249 return abis_nm_sendmsg(sw->bts, msg);
1250}
1251
1252static int is_last_line(FILE *stream)
1253{
1254 char next_seg_buf[256];
1255 long pos;
1256
1257 /* check if we're sending the last line */
1258 pos = ftell(stream);
1259 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1260 fseek(stream, pos, SEEK_SET);
1261 return 1;
1262 }
1263
1264 fseek(stream, pos, SEEK_SET);
1265 return 0;
1266}
1267
1268/* 6.2.2 / 8.3.2 Load Data Segment */
1269static int sw_load_segment(struct abis_nm_sw *sw)
1270{
1271 struct abis_om_hdr *oh;
1272 struct msgb *msg = nm_msgb_alloc();
1273 char seg_buf[256];
1274 char *line_buf = seg_buf+2;
1275 unsigned char *tlv;
1276 u_int8_t len;
1277
1278 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1279
1280 switch (sw->bts->type) {
1281 case GSM_BTS_TYPE_BS11:
1282 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1283 perror("fgets reading segment");
1284 return -EINVAL;
1285 }
1286 seg_buf[0] = 0x00;
1287
1288 /* check if we're sending the last line */
1289 sw->last_seg = is_last_line(sw->stream);
1290 if (sw->last_seg)
1291 seg_buf[1] = 0;
1292 else
1293 seg_buf[1] = 1 + sw->seg_in_window++;
1294
1295 len = strlen(line_buf) + 2;
1296 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1297 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1298 /* BS11 wants CR + LF in excess of the TLV length !?! */
1299 tlv[1] -= 2;
1300
1301 /* we only now know the exact length for the OM hdr */
1302 len = strlen(line_buf)+2;
1303 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001304 case GSM_BTS_TYPE_NANOBTS: {
1305 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1306 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1307 if (len < 0) {
1308 perror("read failed");
1309 return -EINVAL;
1310 }
1311
1312 if (len != IPACC_SEGMENT_SIZE)
1313 sw->last_seg = 1;
1314
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001315 ++sw->seg_in_window;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001316 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1317 len += 3;
1318 break;
1319 }
Harald Welte59b04682009-06-10 05:40:52 +08001320 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001321 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001322 /* FIXME: Other BTS types */
1323 return -1;
1324 }
1325
1326 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1327 sw->obj_instance[0], sw->obj_instance[1],
1328 sw->obj_instance[2]);
1329
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001330 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001331}
1332
1333/* 6.2.4 / 8.3.4 Load Data End */
1334static int sw_load_end(struct abis_nm_sw *sw)
1335{
1336 struct abis_om_hdr *oh;
1337 struct msgb *msg = nm_msgb_alloc();
1338 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1339
1340 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1341 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1342 sw->obj_instance[0], sw->obj_instance[1],
1343 sw->obj_instance[2]);
1344
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001345 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001346 return abis_nm_sendmsg(sw->bts, msg);
1347}
1348
1349/* Activate the specified software into the BTS */
1350static int sw_activate(struct abis_nm_sw *sw)
1351{
1352 struct abis_om_hdr *oh;
1353 struct msgb *msg = nm_msgb_alloc();
1354 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1355
1356 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1357 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1358 sw->obj_instance[0], sw->obj_instance[1],
1359 sw->obj_instance[2]);
1360
1361 /* FIXME: this is BS11 specific format */
1362 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1363 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1364 sw->file_version);
1365
1366 return abis_nm_sendmsg(sw->bts, msg);
1367}
1368
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001369struct sdp_firmware {
1370 char magic[4];
1371 char more_magic[4];
1372 unsigned int header_length;
1373 unsigned int file_length;
1374} __attribute__ ((packed));
1375
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001376static int parse_sdp_header(struct abis_nm_sw *sw)
1377{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001378 struct sdp_firmware firmware_header;
1379 int rc;
1380 struct stat stat;
1381
1382 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1383 if (rc != sizeof(firmware_header)) {
1384 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1385 return -1;
1386 }
1387
1388 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1389 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1390 return -1;
1391 }
1392
1393 if (firmware_header.more_magic[0] != 0x10 ||
1394 firmware_header.more_magic[1] != 0x02 ||
1395 firmware_header.more_magic[2] != 0x00 ||
1396 firmware_header.more_magic[3] != 0x00) {
1397 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1398 return -1;
1399 }
1400
1401
1402 if (fstat(sw->fd, &stat) == -1) {
1403 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1404 return -1;
1405 }
1406
1407 if (ntohl(firmware_header.file_length) != stat.st_size) {
1408 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1409 return -1;
1410 }
1411
1412 /* go back to the start as we checked the whole filesize.. */
1413 lseek(sw->fd, 0l, SEEK_SET);
1414 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1415 "There might be checksums in the file that are not\n"
1416 "verified and incomplete firmware might be flashed.\n"
1417 "There is absolutely no WARRANTY that flashing will\n"
1418 "work.\n");
1419 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001420}
1421
Harald Welte59b04682009-06-10 05:40:52 +08001422static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1423{
1424 char file_id[12+1];
1425 char file_version[80+1];
1426 int rc;
1427
1428 sw->fd = open(fname, O_RDONLY);
1429 if (sw->fd < 0)
1430 return sw->fd;
1431
1432 switch (sw->bts->type) {
1433 case GSM_BTS_TYPE_BS11:
1434 sw->stream = fdopen(sw->fd, "r");
1435 if (!sw->stream) {
1436 perror("fdopen");
1437 return -1;
1438 }
1439 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001440 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001441 file_id, file_version);
1442 if (rc != 2) {
1443 perror("parsing header line of software file");
1444 return -1;
1445 }
1446 strcpy((char *)sw->file_id, file_id);
1447 sw->file_id_len = strlen(file_id);
1448 strcpy((char *)sw->file_version, file_version);
1449 sw->file_version_len = strlen(file_version);
1450 /* rewind to start of file */
1451 rewind(sw->stream);
1452 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001453 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001454 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001455 rc = parse_sdp_header(sw);
1456 if (rc < 0) {
1457 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1458 return -1;
1459 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001460
1461 strcpy((char *)sw->file_id, "id");
1462 sw->file_id_len = 3;
1463 strcpy((char *)sw->file_version, "version");
1464 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001465 break;
Harald Welte59b04682009-06-10 05:40:52 +08001466 default:
1467 /* We don't know how to treat them yet */
1468 close(sw->fd);
1469 return -EINVAL;
1470 }
1471
1472 return 0;
1473}
1474
1475static void sw_close_file(struct abis_nm_sw *sw)
1476{
1477 switch (sw->bts->type) {
1478 case GSM_BTS_TYPE_BS11:
1479 fclose(sw->stream);
1480 break;
1481 default:
1482 close(sw->fd);
1483 break;
1484 }
1485}
1486
1487/* Fill the window */
1488static int sw_fill_window(struct abis_nm_sw *sw)
1489{
1490 int rc;
1491
1492 while (sw->seg_in_window < sw->window_size) {
1493 rc = sw_load_segment(sw);
1494 if (rc < 0)
1495 return rc;
1496 if (sw->last_seg)
1497 break;
1498 }
1499 return 0;
1500}
1501
1502/* callback function from abis_nm_rcvmsg() handler */
1503static int abis_nm_rcvmsg_sw(struct msgb *mb)
1504{
1505 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1506 int rc = -1;
1507 struct abis_nm_sw *sw = &g_sw;
1508 enum sw_state old_state = sw->state;
1509
1510 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1511
1512 switch (sw->state) {
1513 case SW_STATE_WAIT_INITACK:
1514 switch (foh->msg_type) {
1515 case NM_MT_LOAD_INIT_ACK:
1516 /* fill window with segments */
1517 if (sw->cbfn)
1518 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1519 NM_MT_LOAD_INIT_ACK, mb,
1520 sw->cb_data, NULL);
1521 rc = sw_fill_window(sw);
1522 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001523 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001524 break;
1525 case NM_MT_LOAD_INIT_NACK:
1526 if (sw->forced) {
1527 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1528 "Init NACK\n");
1529 if (sw->cbfn)
1530 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1531 NM_MT_LOAD_INIT_ACK, mb,
1532 sw->cb_data, NULL);
1533 rc = sw_fill_window(sw);
1534 sw->state = SW_STATE_WAIT_SEGACK;
1535 } else {
1536 DEBUGP(DNM, "Software Load Init NACK\n");
1537 /* FIXME: cause */
1538 if (sw->cbfn)
1539 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1540 NM_MT_LOAD_INIT_NACK, mb,
1541 sw->cb_data, NULL);
1542 sw->state = SW_STATE_ERROR;
1543 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001544 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001545 break;
1546 }
1547 break;
1548 case SW_STATE_WAIT_SEGACK:
1549 switch (foh->msg_type) {
1550 case NM_MT_LOAD_SEG_ACK:
1551 if (sw->cbfn)
1552 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1553 NM_MT_LOAD_SEG_ACK, mb,
1554 sw->cb_data, NULL);
1555 sw->seg_in_window = 0;
1556 if (!sw->last_seg) {
1557 /* fill window with more segments */
1558 rc = sw_fill_window(sw);
1559 sw->state = SW_STATE_WAIT_SEGACK;
1560 } else {
1561 /* end the transfer */
1562 sw->state = SW_STATE_WAIT_ENDACK;
1563 rc = sw_load_end(sw);
1564 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001565 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001566 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001567 case NM_MT_LOAD_ABORT:
1568 if (sw->cbfn)
1569 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1570 NM_MT_LOAD_ABORT, mb,
1571 sw->cb_data, NULL);
1572 break;
Harald Welte59b04682009-06-10 05:40:52 +08001573 }
1574 break;
1575 case SW_STATE_WAIT_ENDACK:
1576 switch (foh->msg_type) {
1577 case NM_MT_LOAD_END_ACK:
1578 sw_close_file(sw);
1579 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1580 sw->bts->nr);
1581 sw->state = SW_STATE_NONE;
1582 if (sw->cbfn)
1583 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1584 NM_MT_LOAD_END_ACK, mb,
1585 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001586 rc = 0;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001587 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001588 break;
1589 case NM_MT_LOAD_END_NACK:
1590 if (sw->forced) {
1591 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1592 "End NACK\n");
1593 sw->state = SW_STATE_NONE;
1594 if (sw->cbfn)
1595 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1596 NM_MT_LOAD_END_ACK, mb,
1597 sw->cb_data, NULL);
1598 } else {
1599 DEBUGP(DNM, "Software Load End NACK\n");
1600 /* FIXME: cause */
1601 sw->state = SW_STATE_ERROR;
1602 if (sw->cbfn)
1603 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1604 NM_MT_LOAD_END_NACK, mb,
1605 sw->cb_data, NULL);
1606 }
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 }
1610 case SW_STATE_WAIT_ACTACK:
1611 switch (foh->msg_type) {
1612 case NM_MT_ACTIVATE_SW_ACK:
1613 /* we're done */
1614 DEBUGP(DNM, "Activate Software DONE!\n");
1615 sw->state = SW_STATE_NONE;
1616 rc = 0;
1617 if (sw->cbfn)
1618 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1619 NM_MT_ACTIVATE_SW_ACK, mb,
1620 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001621 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001622 break;
1623 case NM_MT_ACTIVATE_SW_NACK:
1624 DEBUGP(DNM, "Activate Software NACK\n");
1625 /* FIXME: cause */
1626 sw->state = SW_STATE_ERROR;
1627 if (sw->cbfn)
1628 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1629 NM_MT_ACTIVATE_SW_NACK, mb,
1630 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001631 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001632 break;
1633 }
1634 case SW_STATE_NONE:
1635 switch (foh->msg_type) {
1636 case NM_MT_ACTIVATE_SW_ACK:
1637 rc = 0;
1638 break;
1639 }
1640 break;
1641 case SW_STATE_ERROR:
1642 break;
1643 }
1644
1645 if (rc)
1646 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1647 foh->msg_type, old_state, sw->state);
1648
1649 return rc;
1650}
1651
1652/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001653int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte59b04682009-06-10 05:40:52 +08001654 u_int8_t win_size, int forced,
1655 gsm_cbfn *cbfn, void *cb_data)
1656{
1657 struct abis_nm_sw *sw = &g_sw;
1658 int rc;
1659
1660 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1661 bts->nr, fname);
1662
1663 if (sw->state != SW_STATE_NONE)
1664 return -EBUSY;
1665
1666 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001667 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001668
1669 switch (bts->type) {
1670 case GSM_BTS_TYPE_BS11:
1671 sw->obj_class = NM_OC_SITE_MANAGER;
1672 sw->obj_instance[0] = 0xff;
1673 sw->obj_instance[1] = 0xff;
1674 sw->obj_instance[2] = 0xff;
1675 break;
1676 case GSM_BTS_TYPE_NANOBTS:
1677 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001678 sw->obj_instance[0] = sw->bts->nr;
1679 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001680 sw->obj_instance[2] = 0xff;
1681 break;
1682 case GSM_BTS_TYPE_UNKNOWN:
1683 default:
1684 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1685 return -1;
1686 break;
1687 }
Harald Welte59b04682009-06-10 05:40:52 +08001688 sw->window_size = win_size;
1689 sw->state = SW_STATE_WAIT_INITACK;
1690 sw->cbfn = cbfn;
1691 sw->cb_data = cb_data;
1692 sw->forced = forced;
1693
1694 rc = sw_open_file(sw, fname);
1695 if (rc < 0) {
1696 sw->state = SW_STATE_NONE;
1697 return rc;
1698 }
1699
1700 return sw_load_init(sw);
1701}
1702
1703int abis_nm_software_load_status(struct gsm_bts *bts)
1704{
1705 struct abis_nm_sw *sw = &g_sw;
1706 struct stat st;
1707 int rc, percent;
1708
1709 rc = fstat(sw->fd, &st);
1710 if (rc < 0) {
1711 perror("ERROR during stat");
1712 return rc;
1713 }
1714
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001715 if (sw->stream)
1716 percent = (ftell(sw->stream) * 100) / st.st_size;
1717 else
1718 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001719 return percent;
1720}
1721
1722/* Activate the specified software into the BTS */
1723int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1724 gsm_cbfn *cbfn, void *cb_data)
1725{
1726 struct abis_nm_sw *sw = &g_sw;
1727 int rc;
1728
1729 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1730 bts->nr, fname);
1731
1732 if (sw->state != SW_STATE_NONE)
1733 return -EBUSY;
1734
1735 sw->bts = bts;
1736 sw->obj_class = NM_OC_SITE_MANAGER;
1737 sw->obj_instance[0] = 0xff;
1738 sw->obj_instance[1] = 0xff;
1739 sw->obj_instance[2] = 0xff;
1740 sw->state = SW_STATE_WAIT_ACTACK;
1741 sw->cbfn = cbfn;
1742 sw->cb_data = cb_data;
1743
1744 /* Open the file in order to fill some sw struct members */
1745 rc = sw_open_file(sw, fname);
1746 if (rc < 0) {
1747 sw->state = SW_STATE_NONE;
1748 return rc;
1749 }
1750 sw_close_file(sw);
1751
1752 return sw_activate(sw);
1753}
1754
1755static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1756 u_int8_t ts_nr, u_int8_t subslot_nr)
1757{
1758 ch->attrib = NM_ATT_ABIS_CHANNEL;
1759 ch->bts_port = bts_port;
1760 ch->timeslot = ts_nr;
1761 ch->subslot = subslot_nr;
1762}
1763
1764int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1765 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1766 u_int8_t tei)
1767{
1768 struct abis_om_hdr *oh;
1769 struct abis_nm_channel *ch;
1770 u_int8_t len = sizeof(*ch) + 2;
1771 struct msgb *msg = nm_msgb_alloc();
1772
1773 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1774 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1775 bts->bts_nr, trx_nr, 0xff);
1776
1777 msgb_tv_put(msg, NM_ATT_TEI, tei);
1778
1779 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1780 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1781
1782 return abis_nm_sendmsg(bts, msg);
1783}
1784
1785/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1786int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1787 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1788{
1789 struct gsm_bts *bts = trx->bts;
1790 struct abis_om_hdr *oh;
1791 struct abis_nm_channel *ch;
1792 struct msgb *msg = nm_msgb_alloc();
1793
1794 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1795 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1796 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1797
1798 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1799 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1800
1801 return abis_nm_sendmsg(bts, msg);
1802}
1803
1804#if 0
1805int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1806 struct abis_nm_abis_channel *chan)
1807{
1808}
1809#endif
1810
1811int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1812 u_int8_t e1_port, u_int8_t e1_timeslot,
1813 u_int8_t e1_subslot)
1814{
1815 struct gsm_bts *bts = ts->trx->bts;
1816 struct abis_om_hdr *oh;
1817 struct abis_nm_channel *ch;
1818 struct msgb *msg = nm_msgb_alloc();
1819
1820 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1821 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1822 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1823
1824 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1825 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1826
1827 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1828 gsm_ts_name(ts),
1829 e1_port, e1_timeslot, e1_subslot);
1830
1831 return abis_nm_sendmsg(bts, msg);
1832}
1833
1834#if 0
1835int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1836 struct abis_nm_abis_channel *chan,
1837 u_int8_t subchan)
1838{
1839}
1840#endif
1841
1842/* Chapter 8.6.1 */
1843int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1844{
1845 struct abis_om_hdr *oh;
1846 struct msgb *msg = nm_msgb_alloc();
1847 u_int8_t *cur;
1848
1849 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1850
1851 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1852 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1853 cur = msgb_put(msg, attr_len);
1854 memcpy(cur, attr, attr_len);
1855
1856 return abis_nm_sendmsg(bts, msg);
1857}
1858
1859/* Chapter 8.6.2 */
1860int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1861{
1862 struct abis_om_hdr *oh;
1863 struct msgb *msg = nm_msgb_alloc();
1864 u_int8_t *cur;
1865
1866 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1867
1868 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1869 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1870 trx->bts->bts_nr, trx->nr, 0xff);
1871 cur = msgb_put(msg, attr_len);
1872 memcpy(cur, attr, attr_len);
1873
1874 return abis_nm_sendmsg(trx->bts, msg);
1875}
1876
Harald Weltef2eb2782009-08-09 21:49:48 +02001877static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1878{
1879 int i;
1880
1881 /* As it turns out, the BS-11 has some very peculiar restrictions
1882 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301883 switch (ts->trx->bts->type) {
1884 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001885 switch (chan_comb) {
1886 case NM_CHANC_TCHHalf:
1887 case NM_CHANC_TCHHalf2:
1888 /* not supported */
1889 return -EINVAL;
1890 case NM_CHANC_SDCCH:
1891 /* only one SDCCH/8 per TRX */
1892 for (i = 0; i < TRX_NR_TS; i++) {
1893 if (i == ts->nr)
1894 continue;
1895 if (ts->trx->ts[i].nm_chan_comb ==
1896 NM_CHANC_SDCCH)
1897 return -EINVAL;
1898 }
1899 /* not allowed for TS0 of BCCH-TRX */
1900 if (ts->trx == ts->trx->bts->c0 &&
1901 ts->nr == 0)
1902 return -EINVAL;
1903 /* not on the same TRX that has a BCCH+SDCCH4
1904 * combination */
1905 if (ts->trx == ts->trx->bts->c0 &&
1906 (ts->trx->ts[0].nm_chan_comb == 5 ||
1907 ts->trx->ts[0].nm_chan_comb == 8))
1908 return -EINVAL;
1909 break;
1910 case NM_CHANC_mainBCCH:
1911 case NM_CHANC_BCCHComb:
1912 /* allowed only for TS0 of C0 */
1913 if (ts->trx != ts->trx->bts->c0 ||
1914 ts->nr != 0)
1915 return -EINVAL;
1916 break;
1917 case NM_CHANC_BCCH:
1918 /* allowed only for TS 2/4/6 of C0 */
1919 if (ts->trx != ts->trx->bts->c0)
1920 return -EINVAL;
1921 if (ts->nr != 2 && ts->nr != 4 &&
1922 ts->nr != 6)
1923 return -EINVAL;
1924 break;
1925 case 8: /* this is not like 08.58, but in fact
1926 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1927 /* FIXME: only one CBCH allowed per cell */
1928 break;
1929 }
Harald Welte76ba8812009-12-02 02:45:23 +05301930 break;
1931 case GSM_BTS_TYPE_NANOBTS:
1932 switch (ts->nr) {
1933 case 0:
1934 if (ts->trx->nr == 0) {
1935 /* only on TRX0 */
1936 switch (chan_comb) {
1937 case NM_CHANC_BCCH:
1938 case NM_CHANC_mainBCCH:
1939 case NM_CHANC_BCCHComb:
1940 return 0;
1941 break;
1942 default:
1943 return -EINVAL;
1944 }
1945 } else {
1946 switch (chan_comb) {
1947 case NM_CHANC_TCHFull:
1948 case NM_CHANC_TCHHalf:
1949 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1950 return 0;
1951 default:
1952 return -EINVAL;
1953 }
1954 }
1955 break;
1956 case 1:
1957 if (ts->trx->nr == 0) {
1958 switch (chan_comb) {
1959 case NM_CHANC_SDCCH_CBCH:
1960 if (ts->trx->ts[0].nm_chan_comb ==
1961 NM_CHANC_mainBCCH)
1962 return 0;
1963 return -EINVAL;
1964 case NM_CHANC_SDCCH:
1965 case NM_CHANC_TCHFull:
1966 case NM_CHANC_TCHHalf:
1967 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1968 case NM_CHANC_IPAC_TCHFull_PDCH:
1969 return 0;
1970 }
1971 } else {
1972 switch (chan_comb) {
1973 case NM_CHANC_SDCCH:
1974 case NM_CHANC_TCHFull:
1975 case NM_CHANC_TCHHalf:
1976 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1977 return 0;
1978 default:
1979 return -EINVAL;
1980 }
1981 }
1982 break;
1983 case 2:
1984 case 3:
1985 case 4:
1986 case 5:
1987 case 6:
1988 case 7:
1989 switch (chan_comb) {
1990 case NM_CHANC_TCHFull:
1991 case NM_CHANC_TCHHalf:
1992 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1993 return 0;
1994 case NM_CHANC_IPAC_PDCH:
1995 case NM_CHANC_IPAC_TCHFull_PDCH:
1996 if (ts->trx->nr == 0)
1997 return 0;
1998 else
1999 return -EINVAL;
2000 }
2001 break;
2002 }
2003 return -EINVAL;
2004 default:
2005 /* unknown BTS type */
2006 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02002007 }
2008 return 0;
2009}
2010
Harald Welte59b04682009-06-10 05:40:52 +08002011/* Chapter 8.6.3 */
2012int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2013{
2014 struct gsm_bts *bts = ts->trx->bts;
2015 struct abis_om_hdr *oh;
2016 u_int16_t arfcn = htons(ts->trx->arfcn);
2017 u_int8_t zero = 0x00;
2018 struct msgb *msg = nm_msgb_alloc();
2019 u_int8_t len = 2 + 2;
2020
2021 if (bts->type == GSM_BTS_TYPE_BS11)
2022 len += 4 + 2 + 2 + 3;
2023
2024 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02002025 if (verify_chan_comb(ts, chan_comb) < 0) {
2026 msgb_free(msg);
2027 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2028 return -EINVAL;
2029 }
2030 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08002031
2032 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2033 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
2034 NM_OC_CHANNEL, bts->bts_nr,
2035 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08002036 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02002037 if (ts->hopping.enabled) {
2038 unsigned int i;
2039 uint8_t *len;
2040
Harald Welte67104d12009-09-12 13:05:33 +02002041 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2042 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02002043
2044 /* build the ARFCN list */
2045 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2046 len = msgb_put(msg, 1);
2047 *len = 0;
2048 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2049 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2050 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02002051 /* At least BS-11 wants a TLV16 here */
2052 if (bts->type == GSM_BTS_TYPE_BS11)
2053 *len += 1;
2054 else
2055 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02002056 }
2057 }
Harald Welte59b04682009-06-10 05:40:52 +08002058 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02002059 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08002060 if (bts->type == GSM_BTS_TYPE_BS11)
2061 msgb_tlv_put(msg, 0x59, 1, &zero);
2062
2063 return abis_nm_sendmsg(bts, msg);
2064}
2065
2066int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
2067 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
2068{
2069 struct abis_om_hdr *oh;
2070 struct msgb *msg = nm_msgb_alloc();
2071 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2072 u_int8_t len = att_len;
2073
2074 if (nack) {
2075 len += 2;
2076 msgtype = NM_MT_SW_ACT_REQ_NACK;
2077 }
2078
2079 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2080 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2081
2082 if (attr) {
2083 u_int8_t *ptr = msgb_put(msg, att_len);
2084 memcpy(ptr, attr, att_len);
2085 }
2086 if (nack)
2087 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2088
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002089 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002090}
2091
2092int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2093{
2094 struct msgb *msg = nm_msgb_alloc();
2095 struct abis_om_hdr *oh;
2096 u_int8_t *data;
2097
2098 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2099 fill_om_hdr(oh, len);
2100 data = msgb_put(msg, len);
2101 memcpy(data, rawmsg, len);
2102
2103 return abis_nm_sendmsg(bts, msg);
2104}
2105
2106/* Siemens specific commands */
2107static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2108{
2109 struct abis_om_hdr *oh;
2110 struct msgb *msg = nm_msgb_alloc();
2111
2112 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2113 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2114 0xff, 0xff, 0xff);
2115
2116 return abis_nm_sendmsg(bts, msg);
2117}
2118
2119/* Chapter 8.9.2 */
2120int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2121{
2122 struct abis_om_hdr *oh;
2123 struct msgb *msg = nm_msgb_alloc();
2124
Harald Welte59b04682009-06-10 05:40:52 +08002125 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2126 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2127
Harald Welteb7284a92009-10-20 09:56:18 +02002128 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2129 DEBUGPC(DNM, "Sending OPSTART\n");
2130
Harald Welte59b04682009-06-10 05:40:52 +08002131 return abis_nm_sendmsg(bts, msg);
2132}
2133
2134/* Chapter 8.8.5 */
2135int 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 +02002136 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002137{
2138 struct abis_om_hdr *oh;
2139 struct msgb *msg = nm_msgb_alloc();
2140
2141 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2142 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2143 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2144
2145 return abis_nm_sendmsg(bts, msg);
2146}
2147
Harald Welte204317e2009-08-06 17:58:31 +02002148int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2149 u_int8_t e1_port1, u_int8_t ts1)
2150{
2151 struct abis_om_hdr *oh;
2152 struct msgb *msg = nm_msgb_alloc();
2153 u_int8_t *attr;
2154
2155 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2156 e1_port0, ts0, e1_port1, ts1);
2157
2158 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2159 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2160 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2161
2162 attr = msgb_put(msg, 3);
2163 attr[0] = NM_ATT_MDROP_LINK;
2164 attr[1] = e1_port0;
2165 attr[2] = ts0;
2166
2167 attr = msgb_put(msg, 3);
2168 attr[0] = NM_ATT_MDROP_NEXT;
2169 attr[1] = e1_port1;
2170 attr[2] = ts1;
2171
2172 return abis_nm_sendmsg(bts, msg);
2173}
Harald Welte59b04682009-06-10 05:40:52 +08002174
Harald Welte0bf8e302009-08-08 00:02:36 +02002175/* Chapter 8.7.1 */
2176int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2177 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welteb31c9df2010-03-06 11:38:05 +01002178 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02002179{
2180 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02002181
2182 DEBUGP(DNM, "PEFORM TEST\n");
Harald Welteb31c9df2010-03-06 11:38:05 +01002183
2184 if (!msg)
2185 msg = nm_msgb_alloc();
2186
2187 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2188 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2189 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2190 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02002191 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02002192
2193 return abis_nm_sendmsg(bts, msg);
2194}
2195
Harald Welte59b04682009-06-10 05:40:52 +08002196int abis_nm_event_reports(struct gsm_bts *bts, int on)
2197{
2198 if (on == 0)
2199 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2200 else
2201 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2202}
2203
2204/* Siemens (or BS-11) specific commands */
2205
2206int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2207{
2208 if (reconnect == 0)
2209 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2210 else
2211 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2212}
2213
2214int abis_nm_bs11_restart(struct gsm_bts *bts)
2215{
2216 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2217}
2218
2219
2220struct bs11_date_time {
2221 u_int16_t year;
2222 u_int8_t month;
2223 u_int8_t day;
2224 u_int8_t hour;
2225 u_int8_t min;
2226 u_int8_t sec;
2227} __attribute__((packed));
2228
2229
2230void get_bs11_date_time(struct bs11_date_time *aet)
2231{
2232 time_t t;
2233 struct tm *tm;
2234
2235 t = time(NULL);
2236 tm = localtime(&t);
2237 aet->sec = tm->tm_sec;
2238 aet->min = tm->tm_min;
2239 aet->hour = tm->tm_hour;
2240 aet->day = tm->tm_mday;
2241 aet->month = tm->tm_mon;
2242 aet->year = htons(1900 + tm->tm_year);
2243}
2244
2245int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2246{
2247 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2248}
2249
2250int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2251{
2252 if (begin)
2253 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2254 else
2255 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2256}
2257
2258int abis_nm_bs11_create_object(struct gsm_bts *bts,
2259 enum abis_bs11_objtype type, u_int8_t idx,
2260 u_int8_t attr_len, const u_int8_t *attr)
2261{
2262 struct abis_om_hdr *oh;
2263 struct msgb *msg = nm_msgb_alloc();
2264 u_int8_t *cur;
2265
2266 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2267 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2268 NM_OC_BS11, type, 0, idx);
2269 cur = msgb_put(msg, attr_len);
2270 memcpy(cur, attr, attr_len);
2271
2272 return abis_nm_sendmsg(bts, msg);
2273}
2274
2275int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2276 enum abis_bs11_objtype type, u_int8_t idx)
2277{
2278 struct abis_om_hdr *oh;
2279 struct msgb *msg = nm_msgb_alloc();
2280
2281 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2282 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2283 NM_OC_BS11, type, 0, idx);
2284
2285 return abis_nm_sendmsg(bts, msg);
2286}
2287
2288int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2289{
2290 struct abis_om_hdr *oh;
2291 struct msgb *msg = nm_msgb_alloc();
2292 u_int8_t zero = 0x00;
2293
2294 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2295 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2296 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2297 msgb_tlv_put(msg, 0x99, 1, &zero);
2298
2299 return abis_nm_sendmsg(bts, msg);
2300}
2301
2302int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2303{
2304 struct abis_om_hdr *oh;
2305 struct msgb *msg = nm_msgb_alloc();
2306
2307 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2308 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002309 idx, 0xff, 0xff);
2310
2311 return abis_nm_sendmsg(bts, msg);
2312}
2313
2314int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2315{
2316 struct abis_om_hdr *oh;
2317 struct msgb *msg = nm_msgb_alloc();
2318
2319 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2320 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2321 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002322
2323 return abis_nm_sendmsg(bts, msg);
2324}
2325
2326static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2327int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2328{
2329 struct abis_om_hdr *oh;
2330 struct msgb *msg = nm_msgb_alloc();
2331
2332 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2333 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2334 0xff, 0xff, 0xff);
2335 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2336
2337 return abis_nm_sendmsg(bts, msg);
2338}
2339
2340/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002341int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welte59b04682009-06-10 05:40:52 +08002342 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2343 u_int8_t tei)
2344{
2345 struct abis_om_hdr *oh;
2346 struct abis_nm_channel *ch;
2347 struct msgb *msg = nm_msgb_alloc();
2348
2349 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2350 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2351 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2352
2353 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2354 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2355 msgb_tv_put(msg, NM_ATT_TEI, tei);
2356
2357 return abis_nm_sendmsg(bts, msg);
2358}
2359
2360int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2361{
2362 struct abis_om_hdr *oh;
2363 struct msgb *msg = nm_msgb_alloc();
2364
2365 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2366 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2367 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2368 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2369
2370 return abis_nm_sendmsg(trx->bts, msg);
2371}
2372
2373int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2374{
2375 struct abis_om_hdr *oh;
2376 struct msgb *msg = nm_msgb_alloc();
2377 u_int8_t attr = NM_ATT_BS11_TXPWR;
2378
2379 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2380 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2381 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2382 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2383
2384 return abis_nm_sendmsg(trx->bts, msg);
2385}
2386
2387int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2388{
2389 struct abis_om_hdr *oh;
2390 struct msgb *msg = nm_msgb_alloc();
2391 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2392
2393 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2394 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2395 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2396 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2397
2398 return abis_nm_sendmsg(bts, msg);
2399}
2400
2401int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2402{
2403 struct abis_om_hdr *oh;
2404 struct msgb *msg = nm_msgb_alloc();
2405 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2406 NM_ATT_BS11_CCLK_TYPE };
2407
2408 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2409 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2410 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2411 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2412
2413 return abis_nm_sendmsg(bts, msg);
2414
2415}
2416
2417//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002418
2419int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2420{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002421 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2422}
2423
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002424int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2425{
2426 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2427}
2428
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002429int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2430{
Harald Welte59b04682009-06-10 05:40:52 +08002431 struct abis_om_hdr *oh;
2432 struct msgb *msg = nm_msgb_alloc();
2433 struct bs11_date_time bdt;
2434
2435 get_bs11_date_time(&bdt);
2436
2437 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2438 if (on) {
2439 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002440 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002441 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2442 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2443 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2444 sizeof(bdt), (u_int8_t *) &bdt);
2445 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002446 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002447 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002448 strlen(name), (u_int8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002449 } else {
2450 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2451 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2452 }
2453
2454 return abis_nm_sendmsg(bts, msg);
2455}
2456
2457int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2458{
2459 struct abis_om_hdr *oh;
2460 struct msgb *msg;
2461
2462 if (strlen(password) != 10)
2463 return -EINVAL;
2464
2465 msg = nm_msgb_alloc();
2466 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2467 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2468 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2469 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2470
2471 return abis_nm_sendmsg(bts, msg);
2472}
2473
2474/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2475int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2476{
2477 struct abis_om_hdr *oh;
2478 struct msgb *msg;
2479 u_int8_t tlv_value;
2480
2481 msg = nm_msgb_alloc();
2482 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2483 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2484 BS11_OBJ_LI, 0x00, 0x00);
2485
2486 if (locked)
2487 tlv_value = BS11_LI_PLL_LOCKED;
2488 else
2489 tlv_value = BS11_LI_PLL_STANDALONE;
2490
2491 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2492
2493 return abis_nm_sendmsg(bts, msg);
2494}
2495
Daniel Willmann10b07db2010-01-07 00:54:01 +01002496/* Set the calibration value of the PLL (work value/set value)
2497 * It depends on the login which one is changed */
2498int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2499{
2500 struct abis_om_hdr *oh;
2501 struct msgb *msg;
2502 u_int8_t tlv_value[2];
2503
2504 msg = nm_msgb_alloc();
2505 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2506 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2507 BS11_OBJ_TRX1, 0x00, 0x00);
2508
2509 tlv_value[0] = value>>8;
2510 tlv_value[1] = value&0xff;
2511
2512 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2513
2514 return abis_nm_sendmsg(bts, msg);
2515}
2516
Harald Welte59b04682009-06-10 05:40:52 +08002517int abis_nm_bs11_get_state(struct gsm_bts *bts)
2518{
2519 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2520}
2521
2522/* BS11 SWL */
2523
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002524void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002525
Harald Welte59b04682009-06-10 05:40:52 +08002526struct abis_nm_bs11_sw {
2527 struct gsm_bts *bts;
2528 char swl_fname[PATH_MAX];
2529 u_int8_t win_size;
2530 int forced;
2531 struct llist_head file_list;
2532 gsm_cbfn *user_cb; /* specified by the user */
2533};
2534static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2535
2536struct file_list_entry {
2537 struct llist_head list;
2538 char fname[PATH_MAX];
2539};
2540
2541struct file_list_entry *fl_dequeue(struct llist_head *queue)
2542{
2543 struct llist_head *lh;
2544
2545 if (llist_empty(queue))
2546 return NULL;
2547
2548 lh = queue->next;
2549 llist_del(lh);
2550
2551 return llist_entry(lh, struct file_list_entry, list);
2552}
2553
2554static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2555{
2556 char linebuf[255];
2557 struct llist_head *lh, *lh2;
2558 FILE *swl;
2559 int rc = 0;
2560
2561 swl = fopen(bs11_sw->swl_fname, "r");
2562 if (!swl)
2563 return -ENODEV;
2564
2565 /* zero the stale file list, if any */
2566 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2567 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002568 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002569 }
2570
2571 while (fgets(linebuf, sizeof(linebuf), swl)) {
2572 char file_id[12+1];
2573 char file_version[80+1];
2574 struct file_list_entry *fle;
2575 static char dir[PATH_MAX];
2576
2577 if (strlen(linebuf) < 4)
2578 continue;
2579
2580 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2581 if (rc < 0) {
2582 perror("ERR parsing SWL file");
2583 rc = -EINVAL;
2584 goto out;
2585 }
2586 if (rc < 2)
2587 continue;
2588
Harald Welte857e00d2009-06-26 20:25:23 +02002589 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002590 if (!fle) {
2591 rc = -ENOMEM;
2592 goto out;
2593 }
Harald Welte59b04682009-06-10 05:40:52 +08002594
2595 /* construct new filename */
2596 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2597 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2598 strcat(fle->fname, "/");
2599 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2600
2601 llist_add_tail(&fle->list, &bs11_sw->file_list);
2602 }
2603
2604out:
2605 fclose(swl);
2606 return rc;
2607}
2608
2609/* bs11 swload specific callback, passed to abis_nm core swload */
2610static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2611 struct msgb *msg, void *data, void *param)
2612{
2613 struct abis_nm_bs11_sw *bs11_sw = data;
2614 struct file_list_entry *fle;
2615 int rc = 0;
2616
2617 switch (event) {
2618 case NM_MT_LOAD_END_ACK:
2619 fle = fl_dequeue(&bs11_sw->file_list);
2620 if (fle) {
2621 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002622 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002623 bs11_sw->win_size,
2624 bs11_sw->forced,
2625 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002626 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002627 } else {
2628 /* activate the SWL */
2629 rc = abis_nm_software_activate(bs11_sw->bts,
2630 bs11_sw->swl_fname,
2631 bs11_swload_cbfn,
2632 bs11_sw);
2633 }
2634 break;
2635 case NM_MT_LOAD_SEG_ACK:
2636 case NM_MT_LOAD_END_NACK:
2637 case NM_MT_LOAD_INIT_ACK:
2638 case NM_MT_LOAD_INIT_NACK:
2639 case NM_MT_ACTIVATE_SW_NACK:
2640 case NM_MT_ACTIVATE_SW_ACK:
2641 default:
2642 /* fallthrough to the user callback */
2643 if (bs11_sw->user_cb)
2644 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2645 break;
2646 }
2647
2648 return rc;
2649}
2650
2651/* Siemens provides a SWL file that is a mere listing of all the other
2652 * files that are part of a software release. We need to upload first
2653 * the list file, and then each file that is listed in the list file */
2654int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2655 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2656{
2657 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2658 struct file_list_entry *fle;
2659 int rc = 0;
2660
2661 INIT_LLIST_HEAD(&bs11_sw->file_list);
2662 bs11_sw->bts = bts;
2663 bs11_sw->win_size = win_size;
2664 bs11_sw->user_cb = cbfn;
2665 bs11_sw->forced = forced;
2666
2667 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2668 rc = bs11_read_swl_file(bs11_sw);
2669 if (rc < 0)
2670 return rc;
2671
2672 /* dequeue next item in file list */
2673 fle = fl_dequeue(&bs11_sw->file_list);
2674 if (!fle)
2675 return -EINVAL;
2676
2677 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002678 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002679 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002680 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002681 return rc;
2682}
2683
2684#if 0
2685static u_int8_t req_attr_btse[] = {
2686 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2687 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2688 NM_ATT_BS11_LMT_USER_NAME,
2689
2690 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2691
2692 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2693
2694 NM_ATT_BS11_SW_LOAD_STORED };
2695
2696static u_int8_t req_attr_btsm[] = {
2697 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2698 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2699 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2700 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2701#endif
2702
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002703static u_int8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002704 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2705 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2706 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2707
2708int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2709{
2710 struct abis_om_hdr *oh;
2711 struct msgb *msg = nm_msgb_alloc();
2712
2713 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2714 /* SiemensHW CCTRL object */
2715 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2716 0x03, 0x00, 0x00);
2717 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2718
2719 return abis_nm_sendmsg(bts, msg);
2720}
2721
2722int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2723{
2724 struct abis_om_hdr *oh;
2725 struct msgb *msg = nm_msgb_alloc();
2726 struct bs11_date_time aet;
2727
2728 get_bs11_date_time(&aet);
2729 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2730 /* SiemensHW CCTRL object */
2731 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2732 0xff, 0xff, 0xff);
2733 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2734
2735 return abis_nm_sendmsg(bts, msg);
2736}
2737
Harald Welte30534c52010-12-14 12:52:16 +01002738int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2739{
2740 struct abis_om_hdr *oh;
2741 struct msgb *msg = nm_msgb_alloc();
2742 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2743
2744 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2745 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2746 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2747 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2748
2749 return abis_nm_sendmsg(bts, msg);
2750}
2751
Daniel Willmann5655afe2009-08-10 11:49:36 +02002752int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2753{
2754 struct abis_om_hdr *oh;
2755 struct msgb *msg = nm_msgb_alloc();
2756 struct bs11_date_time aet;
2757
2758 get_bs11_date_time(&aet);
2759 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2760 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2761 bport, 0xff, 0x02);
2762 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2763
2764 return abis_nm_sendmsg(bts, msg);
2765}
2766
Harald Welte59b04682009-06-10 05:40:52 +08002767/* ip.access nanoBTS specific commands */
2768static const char ipaccess_magic[] = "com.ipaccess";
2769
2770
2771static int abis_nm_rx_ipacc(struct msgb *msg)
2772{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002773 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002774 struct abis_om_hdr *oh = msgb_l2(msg);
2775 struct abis_om_fom_hdr *foh;
2776 u_int8_t idstrlen = oh->data[0];
2777 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002778 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002779
2780 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002781 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002782 return -EINVAL;
2783 }
2784
2785 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002786 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002787
Harald Welteb7284a92009-10-20 09:56:18 +02002788 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002789
Harald Welte5aeedd42009-10-19 22:11:11 +02002790 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002791
2792 switch (foh->msg_type) {
2793 case NM_MT_IPACC_RSL_CONNECT_ACK:
2794 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002795 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2796 memcpy(&addr,
2797 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2798
2799 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2800 }
Harald Welte4206d982009-07-12 09:33:54 +02002801 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002802 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002803 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002804 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002805 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2806 DEBUGPC(DNM, "STREAM=0x%02x ",
2807 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002808 DEBUGPC(DNM, "\n");
2809 break;
2810 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002811 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002812 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002813 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002814 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2815 else
2816 DEBUGPC(DNM, "\n");
2817 break;
2818 case NM_MT_IPACC_SET_NVATTR_ACK:
2819 DEBUGPC(DNM, "SET NVATTR ACK\n");
2820 /* FIXME: decode and show the actual attributes */
2821 break;
2822 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002823 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002824 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002825 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002826 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2827 else
Harald Weltede4477a2009-12-24 12:20:20 +01002828 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002829 break;
Harald Welte21460f02009-07-03 11:26:45 +02002830 case NM_MT_IPACC_GET_NVATTR_ACK:
2831 DEBUGPC(DNM, "GET NVATTR ACK\n");
2832 /* FIXME: decode and show the actual attributes */
2833 break;
2834 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002835 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002836 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002837 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002838 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2839 else
Harald Weltede4477a2009-12-24 12:20:20 +01002840 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002841 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002842 case NM_MT_IPACC_SET_ATTR_ACK:
2843 DEBUGPC(DNM, "SET ATTR ACK\n");
2844 break;
2845 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002846 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002847 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002848 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002849 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2850 else
Harald Weltede4477a2009-12-24 12:20:20 +01002851 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002852 break;
Harald Welte59b04682009-06-10 05:40:52 +08002853 default:
2854 DEBUGPC(DNM, "unknown\n");
2855 break;
2856 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002857
2858 /* signal handling */
2859 switch (foh->msg_type) {
2860 case NM_MT_IPACC_RSL_CONNECT_NACK:
2861 case NM_MT_IPACC_SET_NVATTR_NACK:
2862 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002863 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002864 signal.msg_type = foh->msg_type;
2865 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002866 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002867 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002868 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002869 signal.msg_type = foh->msg_type;
2870 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002871 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002872 default:
2873 break;
2874 }
2875
Harald Welte59b04682009-06-10 05:40:52 +08002876 return 0;
2877}
2878
2879/* send an ip-access manufacturer specific message */
2880int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2881 u_int8_t obj_class, u_int8_t bts_nr,
2882 u_int8_t trx_nr, u_int8_t ts_nr,
2883 u_int8_t *attr, int attr_len)
2884{
2885 struct msgb *msg = nm_msgb_alloc();
2886 struct abis_om_hdr *oh;
2887 struct abis_om_fom_hdr *foh;
2888 u_int8_t *data;
2889
2890 /* construct the 12.21 OM header, observe the erroneous length */
2891 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2892 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2893 oh->mdisc = ABIS_OM_MDISC_MANUF;
2894
2895 /* add the ip.access magic */
2896 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2897 *data++ = sizeof(ipaccess_magic);
2898 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2899
2900 /* fill the 12.21 FOM header */
2901 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2902 foh->msg_type = msg_type;
2903 foh->obj_class = obj_class;
2904 foh->obj_inst.bts_nr = bts_nr;
2905 foh->obj_inst.trx_nr = trx_nr;
2906 foh->obj_inst.ts_nr = ts_nr;
2907
2908 if (attr && attr_len) {
2909 data = msgb_put(msg, attr_len);
2910 memcpy(data, attr, attr_len);
2911 }
2912
2913 return abis_nm_sendmsg(bts, msg);
2914}
2915
2916/* set some attributes in NVRAM */
Harald Weltef12c1052010-01-07 20:39:42 +01002917int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002918 int attr_len)
2919{
Harald Weltef12c1052010-01-07 20:39:42 +01002920 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2921 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002922 attr_len);
2923}
2924
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002925int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte5aeedd42009-10-19 22:11:11 +02002926 u_int32_t ip, u_int16_t port, u_int8_t stream)
2927{
2928 struct in_addr ia;
2929 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2930 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2931 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2932
2933 int attr_len = sizeof(attr);
2934
2935 ia.s_addr = htonl(ip);
2936 attr[1] = stream;
2937 attr[3] = port >> 8;
2938 attr[4] = port & 0xff;
2939 *(u_int32_t *)(attr+6) = ia.s_addr;
2940
2941 /* if ip == 0, we use the default IP */
2942 if (ip == 0)
2943 attr_len -= 5;
2944
2945 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002946 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002947
2948 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2949 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2950 trx->nr, 0xff, attr, attr_len);
2951}
2952
Harald Welte59b04682009-06-10 05:40:52 +08002953/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002954int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002955{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002956 struct abis_om_hdr *oh;
2957 struct msgb *msg = nm_msgb_alloc();
2958
2959 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2960 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2961 trx->bts->nr, trx->nr, 0xff);
2962
2963 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002964}
Harald Welte0dfc6232009-10-24 10:20:41 +02002965
2966int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2967 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2968 u_int8_t *attr, u_int8_t attr_len)
2969{
2970 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2971 obj_class, bts_nr, trx_nr, ts_nr,
2972 attr, attr_len);
2973}
Harald Weltebeeae412009-11-12 14:48:42 +01002974
Harald Welte3055e332010-03-14 15:37:43 +08002975void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2976{
2977 /* we simply reuse the GSM48 function and overwrite the RAC
2978 * with the Cell ID */
2979 gsm48_ra_id_by_bts(buf, bts);
2980 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2981}
2982
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002983void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2984{
2985 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2986
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01002987 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002988 if (!trx->bts || !trx->bts->oml_link)
2989 return;
2990
2991 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2992 trx->bts->bts_nr, trx->nr, 0xff,
2993 new_state);
2994}
2995
Harald Welte453141f2010-03-25 11:45:30 +08002996static const struct value_string ipacc_testres_names[] = {
2997 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2998 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2999 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3000 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3001 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3002 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01003003};
3004
3005const char *ipacc_testres_name(u_int8_t res)
3006{
Harald Welte453141f2010-03-25 11:45:30 +08003007 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01003008}
3009
Harald Weltebfc21092009-11-13 11:56:05 +01003010void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3011{
3012 cid->mcc = (buf[0] & 0xf) * 100;
3013 cid->mcc += (buf[0] >> 4) * 10;
3014 cid->mcc += (buf[1] & 0xf) * 1;
3015
3016 if (buf[1] >> 4 == 0xf) {
3017 cid->mnc = (buf[2] & 0xf) * 10;
3018 cid->mnc += (buf[2] >> 4) * 1;
3019 } else {
3020 cid->mnc = (buf[2] & 0xf) * 100;
3021 cid->mnc += (buf[2] >> 4) * 10;
3022 cid->mnc += (buf[1] >> 4) * 1;
3023 }
3024
Harald Welte161b4be2009-11-13 14:41:52 +01003025 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3026 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01003027}
3028
Harald Weltebeeae412009-11-12 14:48:42 +01003029/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3030int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3031{
3032 u_int8_t *cur = buf;
3033 u_int16_t len;
3034
Harald Welteb784df82010-07-22 18:14:36 +02003035 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01003036
3037 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3038 return -EINVAL;
3039 cur++;
3040
3041 len = ntohs(*(u_int16_t *)cur);
3042 cur += 2;
3043
3044 binf->info_type = ntohs(*(u_int16_t *)cur);
3045 cur += 2;
3046
3047 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3048 binf->freq_qual = *cur >> 2;
3049
Harald Welteb784df82010-07-22 18:14:36 +02003050 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01003051 binf->arfcn |= *cur++;
3052
3053 if (binf->info_type & IPAC_BINF_RXLEV)
3054 binf->rx_lev = *cur & 0x3f;
3055 cur++;
3056
3057 if (binf->info_type & IPAC_BINF_RXQUAL)
3058 binf->rx_qual = *cur & 0x7;
3059 cur++;
3060
3061 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3062 binf->freq_err = ntohs(*(u_int16_t *)cur);
3063 cur += 2;
3064
3065 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3066 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3067 cur += 2;
3068
3069 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3070 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3071 cur += 4;
3072
Harald Welte22cb81f2010-07-30 22:34:42 +02003073#if 0
3074 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01003075 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02003076#endif
Harald Welte161b4be2009-11-13 14:41:52 +01003077 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01003078 cur++;
3079
Harald Weltebfc21092009-11-13 11:56:05 +01003080 ipac_parse_cgi(&binf->cgi, cur);
3081 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01003082
3083 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3084 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3085 cur += sizeof(binf->ba_list_si2);
3086 }
3087
3088 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3089 memcpy(binf->ba_list_si2bis, cur,
3090 sizeof(binf->ba_list_si2bis));
3091 cur += sizeof(binf->ba_list_si2bis);
3092 }
3093
3094 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3095 memcpy(binf->ba_list_si2ter, cur,
3096 sizeof(binf->ba_list_si2ter));
3097 cur += sizeof(binf->ba_list_si2ter);
3098 }
3099
3100 return 0;
3101}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01003102
3103void abis_nm_clear_queue(struct gsm_bts *bts)
3104{
3105 struct msgb *msg;
3106
3107 while (!llist_empty(&bts->abis_queue)) {
3108 msg = msgb_dequeue(&bts->abis_queue);
3109 msgb_free(msg);
3110 }
3111
3112 bts->abis_nm_pend = 0;
3113}