blob: c2541dfc5408d1ca4e2fee364bb1b14ff6d5b135 [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;
686 void *obj;
687 int rc;
688
689 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte3d9ecf72009-11-13 12:10:18 +0100690 if (!obj)
691 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800692 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
693 if (!nm_state)
694 return -1;
695
696 new_state = *nm_state;
697 new_state.administrative = adm_state;
698
Holger Hans Peter Freyther9aec6db2010-05-13 00:37:48 +0800699 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800700
701 nm_state->administrative = adm_state;
702
703 return rc;
704}
705
706static int abis_nm_rx_statechg_rep(struct msgb *mb)
707{
708 struct abis_om_hdr *oh = msgb_l2(mb);
709 struct abis_om_fom_hdr *foh = msgb_l3(mb);
710 struct gsm_bts *bts = mb->trx->bts;
711 struct tlv_parsed tp;
712 struct gsm_nm_state *nm_state, new_state;
713 int rc;
714
715 DEBUGPC(DNM, "STATE CHG: ");
716
717 memset(&new_state, 0, sizeof(new_state));
718
719 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
720 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100721 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800722 return -EINVAL;
723 }
724
725 new_state = *nm_state;
726
Harald Welte59698fb2010-01-10 18:01:52 +0100727 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800728 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
729 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
730 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
731 }
732 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
733 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
734 new_state.availability = 0xff;
735 else
736 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
737 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
738 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100739 } else
740 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800741 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
742 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther460fb3b2009-10-22 15:44:30 +0200743 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800744 }
745 DEBUGPC(DNM, "\n");
746
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100747 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
748 new_state.operational != nm_state->operational ||
749 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800750 /* Update the operational state of a given object in our in-memory data
751 * structures and send an event to the higher layer */
752 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Holger Hans Peter Freyther9aec6db2010-05-13 00:37:48 +0800753 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100754 nm_state->operational = new_state.operational;
755 nm_state->availability = new_state.availability;
756 if (nm_state->administrative == 0)
757 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800758 }
759#if 0
760 if (op_state == 1) {
761 /* try to enable objects that are disabled */
762 abis_nm_opstart(bts, foh->obj_class,
763 foh->obj_inst.bts_nr,
764 foh->obj_inst.trx_nr,
765 foh->obj_inst.ts_nr);
766 }
767#endif
768 return 0;
769}
770
771static int rx_fail_evt_rep(struct msgb *mb)
772{
773 struct abis_om_hdr *oh = msgb_l2(mb);
774 struct abis_om_fom_hdr *foh = msgb_l3(mb);
775 struct tlv_parsed tp;
776
777 DEBUGPC(DNM, "Failure Event Report ");
778
Harald Welte59698fb2010-01-10 18:01:52 +0100779 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800780
781 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
782 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
783 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
784 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
785
786 DEBUGPC(DNM, "\n");
787
788 return 0;
789}
790
791static int abis_nm_rcvmsg_report(struct msgb *mb)
792{
793 struct abis_om_fom_hdr *foh = msgb_l3(mb);
794 u_int8_t mt = foh->msg_type;
795
Harald Welteb7284a92009-10-20 09:56:18 +0200796 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800797
798 //nmh->cfg->report_cb(mb, foh);
799
800 switch (mt) {
801 case NM_MT_STATECHG_EVENT_REP:
802 return abis_nm_rx_statechg_rep(mb);
803 break;
804 case NM_MT_SW_ACTIVATED_REP:
805 DEBUGPC(DNM, "Software Activated Report\n");
806 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
807 break;
808 case NM_MT_FAILURE_EVENT_REP:
809 rx_fail_evt_rep(mb);
810 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
811 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200812 case NM_MT_TEST_REP:
813 DEBUGPC(DNM, "Test Report\n");
814 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
815 break;
Harald Welte59b04682009-06-10 05:40:52 +0800816 default:
817 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
818 break;
819
820 };
821
822 return 0;
823}
824
825/* Activate the specified software into the BTS */
826static 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 +0200827 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800828{
829 struct abis_om_hdr *oh;
830 struct msgb *msg = nm_msgb_alloc();
831 u_int8_t len = swdesc_len;
832 u_int8_t *trailer;
833
834 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
835 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
836
837 trailer = msgb_put(msg, swdesc_len);
838 memcpy(trailer, sw_desc, swdesc_len);
839
840 return abis_nm_sendmsg(bts, msg);
841}
842
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100843static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
844{
845 static const struct tlv_definition sw_descr_def = {
846 .def = {
847 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
848 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
849 },
850 };
851
852 u_int8_t tag;
853 u_int16_t tag_len;
854 const u_int8_t *val;
855 int ofs = 0, len;
856
857 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
858 * nested nature and the fact you have to assume it contains only two sub
859 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
860
861 if (sw_descr[0] != NM_ATT_SW_DESCR) {
862 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
863 return -1;
864 }
865 ofs += 1;
866
867 len = tlv_parse_one(&tag, &tag_len, &val,
868 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
869 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
870 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
871 return -2;
872 }
873 ofs += len;
874
875 len = tlv_parse_one(&tag, &tag_len, &val,
876 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
877 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
878 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
879 return -3;
880 }
881 ofs += len;
882
883 return ofs;
884}
885
Harald Welte59b04682009-06-10 05:40:52 +0800886static int abis_nm_rx_sw_act_req(struct msgb *mb)
887{
888 struct abis_om_hdr *oh = msgb_l2(mb);
889 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200890 struct tlv_parsed tp;
891 const u_int8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100892 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800893
Harald Welteb7284a92009-10-20 09:56:18 +0200894 debugp_foh(foh);
895
896 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800897
Harald Welte3055e332010-03-14 15:37:43 +0800898 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800899
900 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
901 foh->obj_inst.bts_nr,
902 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800903 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800904 foh->data, oh->length-sizeof(*foh));
905
Harald Welte59698fb2010-01-10 18:01:52 +0100906 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200907 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
908 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
909 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
910 DEBUGP(DNM, "SW config not found! Can't continue.\n");
911 return -EINVAL;
912 } else {
913 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
914 }
915
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100916 /* Use the first SW_DESCR present in SW config */
917 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
918 if (sw_descr_len < 0)
919 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200920
Harald Welte59b04682009-06-10 05:40:52 +0800921 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
922 foh->obj_inst.bts_nr,
923 foh->obj_inst.trx_nr,
924 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100925 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800926}
927
928/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
929static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
930{
931 struct abis_om_hdr *oh = msgb_l2(mb);
932 struct abis_om_fom_hdr *foh = msgb_l3(mb);
933 struct tlv_parsed tp;
934 u_int8_t adm_state;
935
Harald Welte59698fb2010-01-10 18:01:52 +0100936 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800937 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
938 return -EINVAL;
939
940 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
941
942 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
943}
944
945static int abis_nm_rx_lmt_event(struct msgb *mb)
946{
947 struct abis_om_hdr *oh = msgb_l2(mb);
948 struct abis_om_fom_hdr *foh = msgb_l3(mb);
949 struct tlv_parsed tp;
950
951 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100952 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800953 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
954 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
955 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
956 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
957 }
958 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
959 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
960 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
961 DEBUGPC(DNM, "Level=%u ", level);
962 }
963 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
964 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
965 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
966 DEBUGPC(DNM, "Username=%s ", name);
967 }
968 DEBUGPC(DNM, "\n");
969 /* FIXME: parse LMT LOGON TIME */
970 return 0;
971}
972
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100973static void abis_nm_queue_send_next(struct gsm_bts *bts)
974{
975 int wait = 0;
976 struct msgb *msg;
977 /* the queue is empty */
978 while (!llist_empty(&bts->abis_queue)) {
979 msg = msgb_dequeue(&bts->abis_queue);
980 wait = OBSC_NM_W_ACK_CB(msg);
981 _abis_nm_sendmsg(msg);
982
983 if (wait)
984 break;
985 }
986
987 bts->abis_nm_pend = wait;
988}
989
Harald Welte59b04682009-06-10 05:40:52 +0800990/* Receive a OML NM Message from BTS */
991static int abis_nm_rcvmsg_fom(struct msgb *mb)
992{
993 struct abis_om_hdr *oh = msgb_l2(mb);
994 struct abis_om_fom_hdr *foh = msgb_l3(mb);
995 u_int8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100996 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800997
998 /* check for unsolicited message */
999 if (is_report(mt))
1000 return abis_nm_rcvmsg_report(mb);
1001
1002 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1003 return abis_nm_rcvmsg_sw(mb);
1004
1005 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001006 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +08001007 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +02001008
Harald Welteb7284a92009-10-20 09:56:18 +02001009 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +02001010
Harald Welte453141f2010-03-25 11:45:30 +08001011 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +08001012
Harald Welte59698fb2010-01-10 18:01:52 +01001013 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08001014 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001015 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08001016 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1017 else
1018 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001019
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001020 nack_data.msg = mb;
1021 nack_data.mt = mt;
1022 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001023 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001024 return 0;
Harald Welte59b04682009-06-10 05:40:52 +08001025 }
1026#if 0
1027 /* check if last message is to be acked */
1028 if (is_ack_nack(nmh->last_msgtype)) {
1029 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +01001030 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001031 /* we got our ACK, continue sending the next msg */
1032 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1033 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +01001034 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001035 /* FIXME: somehow signal this to the caller */
1036 } else {
1037 /* really strange things happen */
1038 return -EINVAL;
1039 }
1040 }
1041#endif
1042
1043 switch (mt) {
1044 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001045 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001046 break;
1047 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001048 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001049 break;
1050 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001051 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001052 break;
Harald Welte204317e2009-08-06 17:58:31 +02001053 case NM_MT_CONN_MDROP_LINK_ACK:
1054 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1055 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001056 case NM_MT_IPACC_RESTART_ACK:
1057 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1058 break;
1059 case NM_MT_IPACC_RESTART_NACK:
1060 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1061 break;
Harald Welte59b04682009-06-10 05:40:52 +08001062 }
1063
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001064 abis_nm_queue_send_next(mb->trx->bts);
1065 return ret;
Harald Welte59b04682009-06-10 05:40:52 +08001066}
1067
1068static int abis_nm_rx_ipacc(struct msgb *mb);
1069
1070static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1071{
1072 int rc;
1073 int bts_type = mb->trx->bts->type;
1074
1075 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001076 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001077 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001078 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001079 break;
1080 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001081 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1082 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001083 rc = 0;
1084 break;
1085 }
1086
1087 return rc;
1088}
1089
1090/* High-Level API */
1091/* Entry-point where L2 OML from BTS enters the NM code */
1092int abis_nm_rcvmsg(struct msgb *msg)
1093{
1094 struct abis_om_hdr *oh = msgb_l2(msg);
1095 int rc = 0;
1096
1097 /* Various consistency checks */
1098 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001099 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001100 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +02001101 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1102 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +08001103 }
1104 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001105 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001106 oh->sequence);
1107 return -EINVAL;
1108 }
1109#if 0
1110 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1111 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1112 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001113 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001114 oh->length + sizeof(*oh), l2_len);
1115 return -EINVAL;
1116 }
1117 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001118 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 +08001119#endif
1120 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1121
1122 switch (oh->mdisc) {
1123 case ABIS_OM_MDISC_FOM:
1124 rc = abis_nm_rcvmsg_fom(msg);
1125 break;
1126 case ABIS_OM_MDISC_MANUF:
1127 rc = abis_nm_rcvmsg_manuf(msg);
1128 break;
1129 case ABIS_OM_MDISC_MMI:
1130 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001131 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001132 oh->mdisc);
1133 break;
1134 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001135 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001136 oh->mdisc);
1137 return -EINVAL;
1138 }
1139
1140 msgb_free(msg);
1141 return rc;
1142}
1143
1144#if 0
1145/* initialized all resources */
1146struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1147{
1148 struct abis_nm_h *nmh;
1149
1150 nmh = malloc(sizeof(*nmh));
1151 if (!nmh)
1152 return NULL;
1153
1154 nmh->cfg = cfg;
1155
1156 return nmh;
1157}
1158
1159/* free all resources */
1160void abis_nm_fini(struct abis_nm_h *nmh)
1161{
1162 free(nmh);
1163}
1164#endif
1165
1166/* Here we are trying to define a high-level API that can be used by
1167 * the actual BSC implementation. However, the architecture is currently
1168 * still under design. Ideally the calls to this API would be synchronous,
1169 * while the underlying stack behind the APi runs in a traditional select
1170 * based state machine.
1171 */
1172
1173/* 6.2 Software Load: */
1174enum sw_state {
1175 SW_STATE_NONE,
1176 SW_STATE_WAIT_INITACK,
1177 SW_STATE_WAIT_SEGACK,
1178 SW_STATE_WAIT_ENDACK,
1179 SW_STATE_WAIT_ACTACK,
1180 SW_STATE_ERROR,
1181};
1182
1183struct abis_nm_sw {
1184 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001185 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +08001186 gsm_cbfn *cbfn;
1187 void *cb_data;
1188 int forced;
1189
1190 /* this will become part of the SW LOAD INITIATE */
1191 u_int8_t obj_class;
1192 u_int8_t obj_instance[3];
1193
1194 u_int8_t file_id[255];
1195 u_int8_t file_id_len;
1196
1197 u_int8_t file_version[255];
1198 u_int8_t file_version_len;
1199
1200 u_int8_t window_size;
1201 u_int8_t seg_in_window;
1202
1203 int fd;
1204 FILE *stream;
1205 enum sw_state state;
1206 int last_seg;
1207};
1208
1209static struct abis_nm_sw g_sw;
1210
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001211static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1212{
1213 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1214 msgb_v_put(msg, NM_ATT_SW_DESCR);
1215 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1216 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1217 sw->file_version);
1218 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1219 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1220 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1221 sw->file_version);
1222 } else {
1223 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1224 }
1225}
1226
Harald Welte59b04682009-06-10 05:40:52 +08001227/* 6.2.1 / 8.3.1: Load Data Initiate */
1228static int sw_load_init(struct abis_nm_sw *sw)
1229{
1230 struct abis_om_hdr *oh;
1231 struct msgb *msg = nm_msgb_alloc();
1232 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1233
1234 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1235 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1236 sw->obj_instance[0], sw->obj_instance[1],
1237 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001238
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001239 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001240 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1241
1242 return abis_nm_sendmsg(sw->bts, msg);
1243}
1244
1245static int is_last_line(FILE *stream)
1246{
1247 char next_seg_buf[256];
1248 long pos;
1249
1250 /* check if we're sending the last line */
1251 pos = ftell(stream);
1252 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1253 fseek(stream, pos, SEEK_SET);
1254 return 1;
1255 }
1256
1257 fseek(stream, pos, SEEK_SET);
1258 return 0;
1259}
1260
1261/* 6.2.2 / 8.3.2 Load Data Segment */
1262static int sw_load_segment(struct abis_nm_sw *sw)
1263{
1264 struct abis_om_hdr *oh;
1265 struct msgb *msg = nm_msgb_alloc();
1266 char seg_buf[256];
1267 char *line_buf = seg_buf+2;
1268 unsigned char *tlv;
1269 u_int8_t len;
1270
1271 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1272
1273 switch (sw->bts->type) {
1274 case GSM_BTS_TYPE_BS11:
1275 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1276 perror("fgets reading segment");
1277 return -EINVAL;
1278 }
1279 seg_buf[0] = 0x00;
1280
1281 /* check if we're sending the last line */
1282 sw->last_seg = is_last_line(sw->stream);
1283 if (sw->last_seg)
1284 seg_buf[1] = 0;
1285 else
1286 seg_buf[1] = 1 + sw->seg_in_window++;
1287
1288 len = strlen(line_buf) + 2;
1289 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1290 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1291 /* BS11 wants CR + LF in excess of the TLV length !?! */
1292 tlv[1] -= 2;
1293
1294 /* we only now know the exact length for the OM hdr */
1295 len = strlen(line_buf)+2;
1296 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001297 case GSM_BTS_TYPE_NANOBTS: {
1298 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1299 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1300 if (len < 0) {
1301 perror("read failed");
1302 return -EINVAL;
1303 }
1304
1305 if (len != IPACC_SEGMENT_SIZE)
1306 sw->last_seg = 1;
1307
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001308 ++sw->seg_in_window;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001309 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1310 len += 3;
1311 break;
1312 }
Harald Welte59b04682009-06-10 05:40:52 +08001313 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001314 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001315 /* FIXME: Other BTS types */
1316 return -1;
1317 }
1318
1319 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1320 sw->obj_instance[0], sw->obj_instance[1],
1321 sw->obj_instance[2]);
1322
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001323 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001324}
1325
1326/* 6.2.4 / 8.3.4 Load Data End */
1327static int sw_load_end(struct abis_nm_sw *sw)
1328{
1329 struct abis_om_hdr *oh;
1330 struct msgb *msg = nm_msgb_alloc();
1331 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1332
1333 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1334 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1335 sw->obj_instance[0], sw->obj_instance[1],
1336 sw->obj_instance[2]);
1337
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001338 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001339 return abis_nm_sendmsg(sw->bts, msg);
1340}
1341
1342/* Activate the specified software into the BTS */
1343static int sw_activate(struct abis_nm_sw *sw)
1344{
1345 struct abis_om_hdr *oh;
1346 struct msgb *msg = nm_msgb_alloc();
1347 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1348
1349 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1350 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1351 sw->obj_instance[0], sw->obj_instance[1],
1352 sw->obj_instance[2]);
1353
1354 /* FIXME: this is BS11 specific format */
1355 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1356 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1357 sw->file_version);
1358
1359 return abis_nm_sendmsg(sw->bts, msg);
1360}
1361
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001362struct sdp_firmware {
1363 char magic[4];
1364 char more_magic[4];
1365 unsigned int header_length;
1366 unsigned int file_length;
1367} __attribute__ ((packed));
1368
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001369static int parse_sdp_header(struct abis_nm_sw *sw)
1370{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001371 struct sdp_firmware firmware_header;
1372 int rc;
1373 struct stat stat;
1374
1375 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1376 if (rc != sizeof(firmware_header)) {
1377 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1378 return -1;
1379 }
1380
1381 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1382 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1383 return -1;
1384 }
1385
1386 if (firmware_header.more_magic[0] != 0x10 ||
1387 firmware_header.more_magic[1] != 0x02 ||
1388 firmware_header.more_magic[2] != 0x00 ||
1389 firmware_header.more_magic[3] != 0x00) {
1390 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1391 return -1;
1392 }
1393
1394
1395 if (fstat(sw->fd, &stat) == -1) {
1396 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1397 return -1;
1398 }
1399
1400 if (ntohl(firmware_header.file_length) != stat.st_size) {
1401 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1402 return -1;
1403 }
1404
1405 /* go back to the start as we checked the whole filesize.. */
1406 lseek(sw->fd, 0l, SEEK_SET);
1407 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1408 "There might be checksums in the file that are not\n"
1409 "verified and incomplete firmware might be flashed.\n"
1410 "There is absolutely no WARRANTY that flashing will\n"
1411 "work.\n");
1412 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001413}
1414
Harald Welte59b04682009-06-10 05:40:52 +08001415static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1416{
1417 char file_id[12+1];
1418 char file_version[80+1];
1419 int rc;
1420
1421 sw->fd = open(fname, O_RDONLY);
1422 if (sw->fd < 0)
1423 return sw->fd;
1424
1425 switch (sw->bts->type) {
1426 case GSM_BTS_TYPE_BS11:
1427 sw->stream = fdopen(sw->fd, "r");
1428 if (!sw->stream) {
1429 perror("fdopen");
1430 return -1;
1431 }
1432 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001433 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001434 file_id, file_version);
1435 if (rc != 2) {
1436 perror("parsing header line of software file");
1437 return -1;
1438 }
1439 strcpy((char *)sw->file_id, file_id);
1440 sw->file_id_len = strlen(file_id);
1441 strcpy((char *)sw->file_version, file_version);
1442 sw->file_version_len = strlen(file_version);
1443 /* rewind to start of file */
1444 rewind(sw->stream);
1445 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001446 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001447 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001448 rc = parse_sdp_header(sw);
1449 if (rc < 0) {
1450 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1451 return -1;
1452 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001453
1454 strcpy((char *)sw->file_id, "id");
1455 sw->file_id_len = 3;
1456 strcpy((char *)sw->file_version, "version");
1457 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001458 break;
Harald Welte59b04682009-06-10 05:40:52 +08001459 default:
1460 /* We don't know how to treat them yet */
1461 close(sw->fd);
1462 return -EINVAL;
1463 }
1464
1465 return 0;
1466}
1467
1468static void sw_close_file(struct abis_nm_sw *sw)
1469{
1470 switch (sw->bts->type) {
1471 case GSM_BTS_TYPE_BS11:
1472 fclose(sw->stream);
1473 break;
1474 default:
1475 close(sw->fd);
1476 break;
1477 }
1478}
1479
1480/* Fill the window */
1481static int sw_fill_window(struct abis_nm_sw *sw)
1482{
1483 int rc;
1484
1485 while (sw->seg_in_window < sw->window_size) {
1486 rc = sw_load_segment(sw);
1487 if (rc < 0)
1488 return rc;
1489 if (sw->last_seg)
1490 break;
1491 }
1492 return 0;
1493}
1494
1495/* callback function from abis_nm_rcvmsg() handler */
1496static int abis_nm_rcvmsg_sw(struct msgb *mb)
1497{
1498 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1499 int rc = -1;
1500 struct abis_nm_sw *sw = &g_sw;
1501 enum sw_state old_state = sw->state;
1502
1503 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1504
1505 switch (sw->state) {
1506 case SW_STATE_WAIT_INITACK:
1507 switch (foh->msg_type) {
1508 case NM_MT_LOAD_INIT_ACK:
1509 /* fill window with segments */
1510 if (sw->cbfn)
1511 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1512 NM_MT_LOAD_INIT_ACK, mb,
1513 sw->cb_data, NULL);
1514 rc = sw_fill_window(sw);
1515 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001516 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001517 break;
1518 case NM_MT_LOAD_INIT_NACK:
1519 if (sw->forced) {
1520 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1521 "Init NACK\n");
1522 if (sw->cbfn)
1523 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1524 NM_MT_LOAD_INIT_ACK, mb,
1525 sw->cb_data, NULL);
1526 rc = sw_fill_window(sw);
1527 sw->state = SW_STATE_WAIT_SEGACK;
1528 } else {
1529 DEBUGP(DNM, "Software Load Init NACK\n");
1530 /* FIXME: cause */
1531 if (sw->cbfn)
1532 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1533 NM_MT_LOAD_INIT_NACK, mb,
1534 sw->cb_data, NULL);
1535 sw->state = SW_STATE_ERROR;
1536 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001537 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001538 break;
1539 }
1540 break;
1541 case SW_STATE_WAIT_SEGACK:
1542 switch (foh->msg_type) {
1543 case NM_MT_LOAD_SEG_ACK:
1544 if (sw->cbfn)
1545 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1546 NM_MT_LOAD_SEG_ACK, mb,
1547 sw->cb_data, NULL);
1548 sw->seg_in_window = 0;
1549 if (!sw->last_seg) {
1550 /* fill window with more segments */
1551 rc = sw_fill_window(sw);
1552 sw->state = SW_STATE_WAIT_SEGACK;
1553 } else {
1554 /* end the transfer */
1555 sw->state = SW_STATE_WAIT_ENDACK;
1556 rc = sw_load_end(sw);
1557 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001558 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001559 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001560 case NM_MT_LOAD_ABORT:
1561 if (sw->cbfn)
1562 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1563 NM_MT_LOAD_ABORT, mb,
1564 sw->cb_data, NULL);
1565 break;
Harald Welte59b04682009-06-10 05:40:52 +08001566 }
1567 break;
1568 case SW_STATE_WAIT_ENDACK:
1569 switch (foh->msg_type) {
1570 case NM_MT_LOAD_END_ACK:
1571 sw_close_file(sw);
1572 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1573 sw->bts->nr);
1574 sw->state = SW_STATE_NONE;
1575 if (sw->cbfn)
1576 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1577 NM_MT_LOAD_END_ACK, mb,
1578 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001579 rc = 0;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001580 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001581 break;
1582 case NM_MT_LOAD_END_NACK:
1583 if (sw->forced) {
1584 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1585 "End NACK\n");
1586 sw->state = SW_STATE_NONE;
1587 if (sw->cbfn)
1588 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1589 NM_MT_LOAD_END_ACK, mb,
1590 sw->cb_data, NULL);
1591 } else {
1592 DEBUGP(DNM, "Software Load End NACK\n");
1593 /* FIXME: cause */
1594 sw->state = SW_STATE_ERROR;
1595 if (sw->cbfn)
1596 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1597 NM_MT_LOAD_END_NACK, mb,
1598 sw->cb_data, NULL);
1599 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001600 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001601 break;
1602 }
1603 case SW_STATE_WAIT_ACTACK:
1604 switch (foh->msg_type) {
1605 case NM_MT_ACTIVATE_SW_ACK:
1606 /* we're done */
1607 DEBUGP(DNM, "Activate Software DONE!\n");
1608 sw->state = SW_STATE_NONE;
1609 rc = 0;
1610 if (sw->cbfn)
1611 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1612 NM_MT_ACTIVATE_SW_ACK, mb,
1613 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001614 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001615 break;
1616 case NM_MT_ACTIVATE_SW_NACK:
1617 DEBUGP(DNM, "Activate Software NACK\n");
1618 /* FIXME: cause */
1619 sw->state = SW_STATE_ERROR;
1620 if (sw->cbfn)
1621 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1622 NM_MT_ACTIVATE_SW_NACK, mb,
1623 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001624 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001625 break;
1626 }
1627 case SW_STATE_NONE:
1628 switch (foh->msg_type) {
1629 case NM_MT_ACTIVATE_SW_ACK:
1630 rc = 0;
1631 break;
1632 }
1633 break;
1634 case SW_STATE_ERROR:
1635 break;
1636 }
1637
1638 if (rc)
1639 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1640 foh->msg_type, old_state, sw->state);
1641
1642 return rc;
1643}
1644
1645/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001646int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte59b04682009-06-10 05:40:52 +08001647 u_int8_t win_size, int forced,
1648 gsm_cbfn *cbfn, void *cb_data)
1649{
1650 struct abis_nm_sw *sw = &g_sw;
1651 int rc;
1652
1653 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1654 bts->nr, fname);
1655
1656 if (sw->state != SW_STATE_NONE)
1657 return -EBUSY;
1658
1659 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001660 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001661
1662 switch (bts->type) {
1663 case GSM_BTS_TYPE_BS11:
1664 sw->obj_class = NM_OC_SITE_MANAGER;
1665 sw->obj_instance[0] = 0xff;
1666 sw->obj_instance[1] = 0xff;
1667 sw->obj_instance[2] = 0xff;
1668 break;
1669 case GSM_BTS_TYPE_NANOBTS:
1670 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001671 sw->obj_instance[0] = sw->bts->nr;
1672 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001673 sw->obj_instance[2] = 0xff;
1674 break;
1675 case GSM_BTS_TYPE_UNKNOWN:
1676 default:
1677 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1678 return -1;
1679 break;
1680 }
Harald Welte59b04682009-06-10 05:40:52 +08001681 sw->window_size = win_size;
1682 sw->state = SW_STATE_WAIT_INITACK;
1683 sw->cbfn = cbfn;
1684 sw->cb_data = cb_data;
1685 sw->forced = forced;
1686
1687 rc = sw_open_file(sw, fname);
1688 if (rc < 0) {
1689 sw->state = SW_STATE_NONE;
1690 return rc;
1691 }
1692
1693 return sw_load_init(sw);
1694}
1695
1696int abis_nm_software_load_status(struct gsm_bts *bts)
1697{
1698 struct abis_nm_sw *sw = &g_sw;
1699 struct stat st;
1700 int rc, percent;
1701
1702 rc = fstat(sw->fd, &st);
1703 if (rc < 0) {
1704 perror("ERROR during stat");
1705 return rc;
1706 }
1707
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001708 if (sw->stream)
1709 percent = (ftell(sw->stream) * 100) / st.st_size;
1710 else
1711 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001712 return percent;
1713}
1714
1715/* Activate the specified software into the BTS */
1716int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1717 gsm_cbfn *cbfn, void *cb_data)
1718{
1719 struct abis_nm_sw *sw = &g_sw;
1720 int rc;
1721
1722 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1723 bts->nr, fname);
1724
1725 if (sw->state != SW_STATE_NONE)
1726 return -EBUSY;
1727
1728 sw->bts = bts;
1729 sw->obj_class = NM_OC_SITE_MANAGER;
1730 sw->obj_instance[0] = 0xff;
1731 sw->obj_instance[1] = 0xff;
1732 sw->obj_instance[2] = 0xff;
1733 sw->state = SW_STATE_WAIT_ACTACK;
1734 sw->cbfn = cbfn;
1735 sw->cb_data = cb_data;
1736
1737 /* Open the file in order to fill some sw struct members */
1738 rc = sw_open_file(sw, fname);
1739 if (rc < 0) {
1740 sw->state = SW_STATE_NONE;
1741 return rc;
1742 }
1743 sw_close_file(sw);
1744
1745 return sw_activate(sw);
1746}
1747
1748static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1749 u_int8_t ts_nr, u_int8_t subslot_nr)
1750{
1751 ch->attrib = NM_ATT_ABIS_CHANNEL;
1752 ch->bts_port = bts_port;
1753 ch->timeslot = ts_nr;
1754 ch->subslot = subslot_nr;
1755}
1756
1757int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1758 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1759 u_int8_t tei)
1760{
1761 struct abis_om_hdr *oh;
1762 struct abis_nm_channel *ch;
1763 u_int8_t len = sizeof(*ch) + 2;
1764 struct msgb *msg = nm_msgb_alloc();
1765
1766 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1767 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1768 bts->bts_nr, trx_nr, 0xff);
1769
1770 msgb_tv_put(msg, NM_ATT_TEI, tei);
1771
1772 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1773 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1774
1775 return abis_nm_sendmsg(bts, msg);
1776}
1777
1778/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1779int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1780 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1781{
1782 struct gsm_bts *bts = trx->bts;
1783 struct abis_om_hdr *oh;
1784 struct abis_nm_channel *ch;
1785 struct msgb *msg = nm_msgb_alloc();
1786
1787 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1788 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1789 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1790
1791 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1792 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1793
1794 return abis_nm_sendmsg(bts, msg);
1795}
1796
1797#if 0
1798int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1799 struct abis_nm_abis_channel *chan)
1800{
1801}
1802#endif
1803
1804int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1805 u_int8_t e1_port, u_int8_t e1_timeslot,
1806 u_int8_t e1_subslot)
1807{
1808 struct gsm_bts *bts = ts->trx->bts;
1809 struct abis_om_hdr *oh;
1810 struct abis_nm_channel *ch;
1811 struct msgb *msg = nm_msgb_alloc();
1812
1813 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1814 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1815 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1816
1817 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1818 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1819
1820 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1821 gsm_ts_name(ts),
1822 e1_port, e1_timeslot, e1_subslot);
1823
1824 return abis_nm_sendmsg(bts, msg);
1825}
1826
1827#if 0
1828int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1829 struct abis_nm_abis_channel *chan,
1830 u_int8_t subchan)
1831{
1832}
1833#endif
1834
1835/* Chapter 8.6.1 */
1836int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1837{
1838 struct abis_om_hdr *oh;
1839 struct msgb *msg = nm_msgb_alloc();
1840 u_int8_t *cur;
1841
1842 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1843
1844 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1845 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1846 cur = msgb_put(msg, attr_len);
1847 memcpy(cur, attr, attr_len);
1848
1849 return abis_nm_sendmsg(bts, msg);
1850}
1851
1852/* Chapter 8.6.2 */
1853int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1854{
1855 struct abis_om_hdr *oh;
1856 struct msgb *msg = nm_msgb_alloc();
1857 u_int8_t *cur;
1858
1859 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1860
1861 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1862 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1863 trx->bts->bts_nr, trx->nr, 0xff);
1864 cur = msgb_put(msg, attr_len);
1865 memcpy(cur, attr, attr_len);
1866
1867 return abis_nm_sendmsg(trx->bts, msg);
1868}
1869
Harald Weltef2eb2782009-08-09 21:49:48 +02001870static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1871{
1872 int i;
1873
1874 /* As it turns out, the BS-11 has some very peculiar restrictions
1875 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301876 switch (ts->trx->bts->type) {
1877 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001878 switch (chan_comb) {
1879 case NM_CHANC_TCHHalf:
1880 case NM_CHANC_TCHHalf2:
1881 /* not supported */
1882 return -EINVAL;
1883 case NM_CHANC_SDCCH:
1884 /* only one SDCCH/8 per TRX */
1885 for (i = 0; i < TRX_NR_TS; i++) {
1886 if (i == ts->nr)
1887 continue;
1888 if (ts->trx->ts[i].nm_chan_comb ==
1889 NM_CHANC_SDCCH)
1890 return -EINVAL;
1891 }
1892 /* not allowed for TS0 of BCCH-TRX */
1893 if (ts->trx == ts->trx->bts->c0 &&
1894 ts->nr == 0)
1895 return -EINVAL;
1896 /* not on the same TRX that has a BCCH+SDCCH4
1897 * combination */
1898 if (ts->trx == ts->trx->bts->c0 &&
1899 (ts->trx->ts[0].nm_chan_comb == 5 ||
1900 ts->trx->ts[0].nm_chan_comb == 8))
1901 return -EINVAL;
1902 break;
1903 case NM_CHANC_mainBCCH:
1904 case NM_CHANC_BCCHComb:
1905 /* allowed only for TS0 of C0 */
1906 if (ts->trx != ts->trx->bts->c0 ||
1907 ts->nr != 0)
1908 return -EINVAL;
1909 break;
1910 case NM_CHANC_BCCH:
1911 /* allowed only for TS 2/4/6 of C0 */
1912 if (ts->trx != ts->trx->bts->c0)
1913 return -EINVAL;
1914 if (ts->nr != 2 && ts->nr != 4 &&
1915 ts->nr != 6)
1916 return -EINVAL;
1917 break;
1918 case 8: /* this is not like 08.58, but in fact
1919 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1920 /* FIXME: only one CBCH allowed per cell */
1921 break;
1922 }
Harald Welte76ba8812009-12-02 02:45:23 +05301923 break;
1924 case GSM_BTS_TYPE_NANOBTS:
1925 switch (ts->nr) {
1926 case 0:
1927 if (ts->trx->nr == 0) {
1928 /* only on TRX0 */
1929 switch (chan_comb) {
1930 case NM_CHANC_BCCH:
1931 case NM_CHANC_mainBCCH:
1932 case NM_CHANC_BCCHComb:
1933 return 0;
1934 break;
1935 default:
1936 return -EINVAL;
1937 }
1938 } else {
1939 switch (chan_comb) {
1940 case NM_CHANC_TCHFull:
1941 case NM_CHANC_TCHHalf:
1942 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1943 return 0;
1944 default:
1945 return -EINVAL;
1946 }
1947 }
1948 break;
1949 case 1:
1950 if (ts->trx->nr == 0) {
1951 switch (chan_comb) {
1952 case NM_CHANC_SDCCH_CBCH:
1953 if (ts->trx->ts[0].nm_chan_comb ==
1954 NM_CHANC_mainBCCH)
1955 return 0;
1956 return -EINVAL;
1957 case NM_CHANC_SDCCH:
1958 case NM_CHANC_TCHFull:
1959 case NM_CHANC_TCHHalf:
1960 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1961 case NM_CHANC_IPAC_TCHFull_PDCH:
1962 return 0;
1963 }
1964 } else {
1965 switch (chan_comb) {
1966 case NM_CHANC_SDCCH:
1967 case NM_CHANC_TCHFull:
1968 case NM_CHANC_TCHHalf:
1969 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1970 return 0;
1971 default:
1972 return -EINVAL;
1973 }
1974 }
1975 break;
1976 case 2:
1977 case 3:
1978 case 4:
1979 case 5:
1980 case 6:
1981 case 7:
1982 switch (chan_comb) {
1983 case NM_CHANC_TCHFull:
1984 case NM_CHANC_TCHHalf:
1985 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1986 return 0;
1987 case NM_CHANC_IPAC_PDCH:
1988 case NM_CHANC_IPAC_TCHFull_PDCH:
1989 if (ts->trx->nr == 0)
1990 return 0;
1991 else
1992 return -EINVAL;
1993 }
1994 break;
1995 }
1996 return -EINVAL;
1997 default:
1998 /* unknown BTS type */
1999 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02002000 }
2001 return 0;
2002}
2003
Harald Welte59b04682009-06-10 05:40:52 +08002004/* Chapter 8.6.3 */
2005int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2006{
2007 struct gsm_bts *bts = ts->trx->bts;
2008 struct abis_om_hdr *oh;
2009 u_int16_t arfcn = htons(ts->trx->arfcn);
2010 u_int8_t zero = 0x00;
2011 struct msgb *msg = nm_msgb_alloc();
2012 u_int8_t len = 2 + 2;
2013
2014 if (bts->type == GSM_BTS_TYPE_BS11)
2015 len += 4 + 2 + 2 + 3;
2016
2017 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02002018 if (verify_chan_comb(ts, chan_comb) < 0) {
2019 msgb_free(msg);
2020 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2021 return -EINVAL;
2022 }
2023 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08002024
2025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2026 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
2027 NM_OC_CHANNEL, bts->bts_nr,
2028 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08002029 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02002030 if (ts->hopping.enabled) {
2031 unsigned int i;
2032 uint8_t *len;
2033
Harald Welte67104d12009-09-12 13:05:33 +02002034 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2035 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02002036
2037 /* build the ARFCN list */
2038 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2039 len = msgb_put(msg, 1);
2040 *len = 0;
2041 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2042 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2043 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02002044 /* At least BS-11 wants a TLV16 here */
2045 if (bts->type == GSM_BTS_TYPE_BS11)
2046 *len += 1;
2047 else
2048 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02002049 }
2050 }
Harald Welte59b04682009-06-10 05:40:52 +08002051 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02002052 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08002053 if (bts->type == GSM_BTS_TYPE_BS11)
2054 msgb_tlv_put(msg, 0x59, 1, &zero);
2055
2056 return abis_nm_sendmsg(bts, msg);
2057}
2058
2059int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
2060 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
2061{
2062 struct abis_om_hdr *oh;
2063 struct msgb *msg = nm_msgb_alloc();
2064 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2065 u_int8_t len = att_len;
2066
2067 if (nack) {
2068 len += 2;
2069 msgtype = NM_MT_SW_ACT_REQ_NACK;
2070 }
2071
2072 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2073 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2074
2075 if (attr) {
2076 u_int8_t *ptr = msgb_put(msg, att_len);
2077 memcpy(ptr, attr, att_len);
2078 }
2079 if (nack)
2080 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2081
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002082 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002083}
2084
2085int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2086{
2087 struct msgb *msg = nm_msgb_alloc();
2088 struct abis_om_hdr *oh;
2089 u_int8_t *data;
2090
2091 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2092 fill_om_hdr(oh, len);
2093 data = msgb_put(msg, len);
2094 memcpy(data, rawmsg, len);
2095
2096 return abis_nm_sendmsg(bts, msg);
2097}
2098
2099/* Siemens specific commands */
2100static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2101{
2102 struct abis_om_hdr *oh;
2103 struct msgb *msg = nm_msgb_alloc();
2104
2105 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2106 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2107 0xff, 0xff, 0xff);
2108
2109 return abis_nm_sendmsg(bts, msg);
2110}
2111
2112/* Chapter 8.9.2 */
2113int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2114{
2115 struct abis_om_hdr *oh;
2116 struct msgb *msg = nm_msgb_alloc();
2117
Harald Welte59b04682009-06-10 05:40:52 +08002118 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2119 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2120
Harald Welteb7284a92009-10-20 09:56:18 +02002121 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2122 DEBUGPC(DNM, "Sending OPSTART\n");
2123
Harald Welte59b04682009-06-10 05:40:52 +08002124 return abis_nm_sendmsg(bts, msg);
2125}
2126
2127/* Chapter 8.8.5 */
2128int 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 +02002129 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002130{
2131 struct abis_om_hdr *oh;
2132 struct msgb *msg = nm_msgb_alloc();
2133
2134 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2135 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2136 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2137
2138 return abis_nm_sendmsg(bts, msg);
2139}
2140
Harald Welte204317e2009-08-06 17:58:31 +02002141int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2142 u_int8_t e1_port1, u_int8_t ts1)
2143{
2144 struct abis_om_hdr *oh;
2145 struct msgb *msg = nm_msgb_alloc();
2146 u_int8_t *attr;
2147
2148 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2149 e1_port0, ts0, e1_port1, ts1);
2150
2151 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2152 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2153 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2154
2155 attr = msgb_put(msg, 3);
2156 attr[0] = NM_ATT_MDROP_LINK;
2157 attr[1] = e1_port0;
2158 attr[2] = ts0;
2159
2160 attr = msgb_put(msg, 3);
2161 attr[0] = NM_ATT_MDROP_NEXT;
2162 attr[1] = e1_port1;
2163 attr[2] = ts1;
2164
2165 return abis_nm_sendmsg(bts, msg);
2166}
Harald Welte59b04682009-06-10 05:40:52 +08002167
Harald Welte0bf8e302009-08-08 00:02:36 +02002168/* Chapter 8.7.1 */
2169int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2170 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
Harald Welteb31c9df2010-03-06 11:38:05 +01002171 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02002172{
2173 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02002174
2175 DEBUGP(DNM, "PEFORM TEST\n");
Harald Welteb31c9df2010-03-06 11:38:05 +01002176
2177 if (!msg)
2178 msg = nm_msgb_alloc();
2179
2180 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2181 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2182 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2183 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02002184 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02002185
2186 return abis_nm_sendmsg(bts, msg);
2187}
2188
Harald Welte59b04682009-06-10 05:40:52 +08002189int abis_nm_event_reports(struct gsm_bts *bts, int on)
2190{
2191 if (on == 0)
2192 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2193 else
2194 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2195}
2196
2197/* Siemens (or BS-11) specific commands */
2198
2199int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2200{
2201 if (reconnect == 0)
2202 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2203 else
2204 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2205}
2206
2207int abis_nm_bs11_restart(struct gsm_bts *bts)
2208{
2209 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2210}
2211
2212
2213struct bs11_date_time {
2214 u_int16_t year;
2215 u_int8_t month;
2216 u_int8_t day;
2217 u_int8_t hour;
2218 u_int8_t min;
2219 u_int8_t sec;
2220} __attribute__((packed));
2221
2222
2223void get_bs11_date_time(struct bs11_date_time *aet)
2224{
2225 time_t t;
2226 struct tm *tm;
2227
2228 t = time(NULL);
2229 tm = localtime(&t);
2230 aet->sec = tm->tm_sec;
2231 aet->min = tm->tm_min;
2232 aet->hour = tm->tm_hour;
2233 aet->day = tm->tm_mday;
2234 aet->month = tm->tm_mon;
2235 aet->year = htons(1900 + tm->tm_year);
2236}
2237
2238int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2239{
2240 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2241}
2242
2243int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2244{
2245 if (begin)
2246 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2247 else
2248 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2249}
2250
2251int abis_nm_bs11_create_object(struct gsm_bts *bts,
2252 enum abis_bs11_objtype type, u_int8_t idx,
2253 u_int8_t attr_len, const u_int8_t *attr)
2254{
2255 struct abis_om_hdr *oh;
2256 struct msgb *msg = nm_msgb_alloc();
2257 u_int8_t *cur;
2258
2259 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2260 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2261 NM_OC_BS11, type, 0, idx);
2262 cur = msgb_put(msg, attr_len);
2263 memcpy(cur, attr, attr_len);
2264
2265 return abis_nm_sendmsg(bts, msg);
2266}
2267
2268int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2269 enum abis_bs11_objtype type, u_int8_t idx)
2270{
2271 struct abis_om_hdr *oh;
2272 struct msgb *msg = nm_msgb_alloc();
2273
2274 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2275 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2276 NM_OC_BS11, type, 0, idx);
2277
2278 return abis_nm_sendmsg(bts, msg);
2279}
2280
2281int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2282{
2283 struct abis_om_hdr *oh;
2284 struct msgb *msg = nm_msgb_alloc();
2285 u_int8_t zero = 0x00;
2286
2287 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2288 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2289 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2290 msgb_tlv_put(msg, 0x99, 1, &zero);
2291
2292 return abis_nm_sendmsg(bts, msg);
2293}
2294
2295int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2296{
2297 struct abis_om_hdr *oh;
2298 struct msgb *msg = nm_msgb_alloc();
2299
2300 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2301 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002302 idx, 0xff, 0xff);
2303
2304 return abis_nm_sendmsg(bts, msg);
2305}
2306
2307int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2308{
2309 struct abis_om_hdr *oh;
2310 struct msgb *msg = nm_msgb_alloc();
2311
2312 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2313 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2314 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002315
2316 return abis_nm_sendmsg(bts, msg);
2317}
2318
2319static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2320int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2321{
2322 struct abis_om_hdr *oh;
2323 struct msgb *msg = nm_msgb_alloc();
2324
2325 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2326 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2327 0xff, 0xff, 0xff);
2328 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2329
2330 return abis_nm_sendmsg(bts, msg);
2331}
2332
2333/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002334int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welte59b04682009-06-10 05:40:52 +08002335 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2336 u_int8_t tei)
2337{
2338 struct abis_om_hdr *oh;
2339 struct abis_nm_channel *ch;
2340 struct msgb *msg = nm_msgb_alloc();
2341
2342 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2343 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2344 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2345
2346 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2347 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2348 msgb_tv_put(msg, NM_ATT_TEI, tei);
2349
2350 return abis_nm_sendmsg(bts, msg);
2351}
2352
2353int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2354{
2355 struct abis_om_hdr *oh;
2356 struct msgb *msg = nm_msgb_alloc();
2357
2358 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2359 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2360 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2361 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2362
2363 return abis_nm_sendmsg(trx->bts, msg);
2364}
2365
2366int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2367{
2368 struct abis_om_hdr *oh;
2369 struct msgb *msg = nm_msgb_alloc();
2370 u_int8_t attr = NM_ATT_BS11_TXPWR;
2371
2372 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2373 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2374 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2375 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2376
2377 return abis_nm_sendmsg(trx->bts, msg);
2378}
2379
2380int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2381{
2382 struct abis_om_hdr *oh;
2383 struct msgb *msg = nm_msgb_alloc();
2384 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2385
2386 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2387 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2388 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2389 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2390
2391 return abis_nm_sendmsg(bts, msg);
2392}
2393
2394int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2395{
2396 struct abis_om_hdr *oh;
2397 struct msgb *msg = nm_msgb_alloc();
2398 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2399 NM_ATT_BS11_CCLK_TYPE };
2400
2401 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2402 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2403 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2404 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2405
2406 return abis_nm_sendmsg(bts, msg);
2407
2408}
2409
2410//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002411
2412int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2413{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002414 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2415}
2416
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002417int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2418{
2419 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2420}
2421
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002422int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2423{
Harald Welte59b04682009-06-10 05:40:52 +08002424 struct abis_om_hdr *oh;
2425 struct msgb *msg = nm_msgb_alloc();
2426 struct bs11_date_time bdt;
2427
2428 get_bs11_date_time(&bdt);
2429
2430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2431 if (on) {
2432 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002433 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002434 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2435 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2436 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2437 sizeof(bdt), (u_int8_t *) &bdt);
2438 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002439 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002440 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002441 strlen(name), (u_int8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002442 } else {
2443 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2444 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2445 }
2446
2447 return abis_nm_sendmsg(bts, msg);
2448}
2449
2450int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2451{
2452 struct abis_om_hdr *oh;
2453 struct msgb *msg;
2454
2455 if (strlen(password) != 10)
2456 return -EINVAL;
2457
2458 msg = nm_msgb_alloc();
2459 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2460 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2461 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2462 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2463
2464 return abis_nm_sendmsg(bts, msg);
2465}
2466
2467/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2468int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2469{
2470 struct abis_om_hdr *oh;
2471 struct msgb *msg;
2472 u_int8_t tlv_value;
2473
2474 msg = nm_msgb_alloc();
2475 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2476 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2477 BS11_OBJ_LI, 0x00, 0x00);
2478
2479 if (locked)
2480 tlv_value = BS11_LI_PLL_LOCKED;
2481 else
2482 tlv_value = BS11_LI_PLL_STANDALONE;
2483
2484 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2485
2486 return abis_nm_sendmsg(bts, msg);
2487}
2488
Daniel Willmann10b07db2010-01-07 00:54:01 +01002489/* Set the calibration value of the PLL (work value/set value)
2490 * It depends on the login which one is changed */
2491int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2492{
2493 struct abis_om_hdr *oh;
2494 struct msgb *msg;
2495 u_int8_t tlv_value[2];
2496
2497 msg = nm_msgb_alloc();
2498 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2499 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2500 BS11_OBJ_TRX1, 0x00, 0x00);
2501
2502 tlv_value[0] = value>>8;
2503 tlv_value[1] = value&0xff;
2504
2505 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2506
2507 return abis_nm_sendmsg(bts, msg);
2508}
2509
Harald Welte59b04682009-06-10 05:40:52 +08002510int abis_nm_bs11_get_state(struct gsm_bts *bts)
2511{
2512 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2513}
2514
2515/* BS11 SWL */
2516
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002517void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002518
Harald Welte59b04682009-06-10 05:40:52 +08002519struct abis_nm_bs11_sw {
2520 struct gsm_bts *bts;
2521 char swl_fname[PATH_MAX];
2522 u_int8_t win_size;
2523 int forced;
2524 struct llist_head file_list;
2525 gsm_cbfn *user_cb; /* specified by the user */
2526};
2527static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2528
2529struct file_list_entry {
2530 struct llist_head list;
2531 char fname[PATH_MAX];
2532};
2533
2534struct file_list_entry *fl_dequeue(struct llist_head *queue)
2535{
2536 struct llist_head *lh;
2537
2538 if (llist_empty(queue))
2539 return NULL;
2540
2541 lh = queue->next;
2542 llist_del(lh);
2543
2544 return llist_entry(lh, struct file_list_entry, list);
2545}
2546
2547static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2548{
2549 char linebuf[255];
2550 struct llist_head *lh, *lh2;
2551 FILE *swl;
2552 int rc = 0;
2553
2554 swl = fopen(bs11_sw->swl_fname, "r");
2555 if (!swl)
2556 return -ENODEV;
2557
2558 /* zero the stale file list, if any */
2559 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2560 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002561 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002562 }
2563
2564 while (fgets(linebuf, sizeof(linebuf), swl)) {
2565 char file_id[12+1];
2566 char file_version[80+1];
2567 struct file_list_entry *fle;
2568 static char dir[PATH_MAX];
2569
2570 if (strlen(linebuf) < 4)
2571 continue;
2572
2573 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2574 if (rc < 0) {
2575 perror("ERR parsing SWL file");
2576 rc = -EINVAL;
2577 goto out;
2578 }
2579 if (rc < 2)
2580 continue;
2581
Harald Welte857e00d2009-06-26 20:25:23 +02002582 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002583 if (!fle) {
2584 rc = -ENOMEM;
2585 goto out;
2586 }
Harald Welte59b04682009-06-10 05:40:52 +08002587
2588 /* construct new filename */
2589 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2590 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2591 strcat(fle->fname, "/");
2592 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2593
2594 llist_add_tail(&fle->list, &bs11_sw->file_list);
2595 }
2596
2597out:
2598 fclose(swl);
2599 return rc;
2600}
2601
2602/* bs11 swload specific callback, passed to abis_nm core swload */
2603static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2604 struct msgb *msg, void *data, void *param)
2605{
2606 struct abis_nm_bs11_sw *bs11_sw = data;
2607 struct file_list_entry *fle;
2608 int rc = 0;
2609
2610 switch (event) {
2611 case NM_MT_LOAD_END_ACK:
2612 fle = fl_dequeue(&bs11_sw->file_list);
2613 if (fle) {
2614 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002615 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002616 bs11_sw->win_size,
2617 bs11_sw->forced,
2618 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002619 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002620 } else {
2621 /* activate the SWL */
2622 rc = abis_nm_software_activate(bs11_sw->bts,
2623 bs11_sw->swl_fname,
2624 bs11_swload_cbfn,
2625 bs11_sw);
2626 }
2627 break;
2628 case NM_MT_LOAD_SEG_ACK:
2629 case NM_MT_LOAD_END_NACK:
2630 case NM_MT_LOAD_INIT_ACK:
2631 case NM_MT_LOAD_INIT_NACK:
2632 case NM_MT_ACTIVATE_SW_NACK:
2633 case NM_MT_ACTIVATE_SW_ACK:
2634 default:
2635 /* fallthrough to the user callback */
2636 if (bs11_sw->user_cb)
2637 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2638 break;
2639 }
2640
2641 return rc;
2642}
2643
2644/* Siemens provides a SWL file that is a mere listing of all the other
2645 * files that are part of a software release. We need to upload first
2646 * the list file, and then each file that is listed in the list file */
2647int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2648 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2649{
2650 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2651 struct file_list_entry *fle;
2652 int rc = 0;
2653
2654 INIT_LLIST_HEAD(&bs11_sw->file_list);
2655 bs11_sw->bts = bts;
2656 bs11_sw->win_size = win_size;
2657 bs11_sw->user_cb = cbfn;
2658 bs11_sw->forced = forced;
2659
2660 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2661 rc = bs11_read_swl_file(bs11_sw);
2662 if (rc < 0)
2663 return rc;
2664
2665 /* dequeue next item in file list */
2666 fle = fl_dequeue(&bs11_sw->file_list);
2667 if (!fle)
2668 return -EINVAL;
2669
2670 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002671 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002672 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002673 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002674 return rc;
2675}
2676
2677#if 0
2678static u_int8_t req_attr_btse[] = {
2679 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2680 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2681 NM_ATT_BS11_LMT_USER_NAME,
2682
2683 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2684
2685 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2686
2687 NM_ATT_BS11_SW_LOAD_STORED };
2688
2689static u_int8_t req_attr_btsm[] = {
2690 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2691 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2692 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2693 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2694#endif
2695
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002696static u_int8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002697 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2698 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2699 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2700
2701int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2702{
2703 struct abis_om_hdr *oh;
2704 struct msgb *msg = nm_msgb_alloc();
2705
2706 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2707 /* SiemensHW CCTRL object */
2708 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2709 0x03, 0x00, 0x00);
2710 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2711
2712 return abis_nm_sendmsg(bts, msg);
2713}
2714
2715int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2716{
2717 struct abis_om_hdr *oh;
2718 struct msgb *msg = nm_msgb_alloc();
2719 struct bs11_date_time aet;
2720
2721 get_bs11_date_time(&aet);
2722 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2723 /* SiemensHW CCTRL object */
2724 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2725 0xff, 0xff, 0xff);
2726 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2727
2728 return abis_nm_sendmsg(bts, msg);
2729}
2730
Harald Welte30534c52010-12-14 12:52:16 +01002731int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2732{
2733 struct abis_om_hdr *oh;
2734 struct msgb *msg = nm_msgb_alloc();
2735 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2736
2737 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2738 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2739 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2740 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2741
2742 return abis_nm_sendmsg(bts, msg);
2743}
2744
Daniel Willmann5655afe2009-08-10 11:49:36 +02002745int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2746{
2747 struct abis_om_hdr *oh;
2748 struct msgb *msg = nm_msgb_alloc();
2749 struct bs11_date_time aet;
2750
2751 get_bs11_date_time(&aet);
2752 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2753 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2754 bport, 0xff, 0x02);
2755 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2756
2757 return abis_nm_sendmsg(bts, msg);
2758}
2759
Harald Welte59b04682009-06-10 05:40:52 +08002760/* ip.access nanoBTS specific commands */
2761static const char ipaccess_magic[] = "com.ipaccess";
2762
2763
2764static int abis_nm_rx_ipacc(struct msgb *msg)
2765{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002766 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002767 struct abis_om_hdr *oh = msgb_l2(msg);
2768 struct abis_om_fom_hdr *foh;
2769 u_int8_t idstrlen = oh->data[0];
2770 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002771 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002772
2773 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002774 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002775 return -EINVAL;
2776 }
2777
2778 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002779 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002780
Harald Welteb7284a92009-10-20 09:56:18 +02002781 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002782
Harald Welte5aeedd42009-10-19 22:11:11 +02002783 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002784
2785 switch (foh->msg_type) {
2786 case NM_MT_IPACC_RSL_CONNECT_ACK:
2787 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002788 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2789 memcpy(&addr,
2790 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2791
2792 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2793 }
Harald Welte4206d982009-07-12 09:33:54 +02002794 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002795 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002796 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002797 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002798 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2799 DEBUGPC(DNM, "STREAM=0x%02x ",
2800 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002801 DEBUGPC(DNM, "\n");
2802 break;
2803 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002804 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002805 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002806 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002807 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2808 else
2809 DEBUGPC(DNM, "\n");
2810 break;
2811 case NM_MT_IPACC_SET_NVATTR_ACK:
2812 DEBUGPC(DNM, "SET NVATTR ACK\n");
2813 /* FIXME: decode and show the actual attributes */
2814 break;
2815 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002816 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002817 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002818 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002819 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2820 else
Harald Weltede4477a2009-12-24 12:20:20 +01002821 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002822 break;
Harald Welte21460f02009-07-03 11:26:45 +02002823 case NM_MT_IPACC_GET_NVATTR_ACK:
2824 DEBUGPC(DNM, "GET NVATTR ACK\n");
2825 /* FIXME: decode and show the actual attributes */
2826 break;
2827 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002828 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002829 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002830 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002831 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2832 else
Harald Weltede4477a2009-12-24 12:20:20 +01002833 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002834 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002835 case NM_MT_IPACC_SET_ATTR_ACK:
2836 DEBUGPC(DNM, "SET ATTR ACK\n");
2837 break;
2838 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002839 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002840 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002841 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002842 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2843 else
Harald Weltede4477a2009-12-24 12:20:20 +01002844 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002845 break;
Harald Welte59b04682009-06-10 05:40:52 +08002846 default:
2847 DEBUGPC(DNM, "unknown\n");
2848 break;
2849 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002850
2851 /* signal handling */
2852 switch (foh->msg_type) {
2853 case NM_MT_IPACC_RSL_CONNECT_NACK:
2854 case NM_MT_IPACC_SET_NVATTR_NACK:
2855 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002856 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002857 signal.msg_type = foh->msg_type;
2858 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002859 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002860 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002861 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002862 signal.msg_type = foh->msg_type;
2863 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002864 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002865 default:
2866 break;
2867 }
2868
Harald Welte59b04682009-06-10 05:40:52 +08002869 return 0;
2870}
2871
2872/* send an ip-access manufacturer specific message */
2873int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2874 u_int8_t obj_class, u_int8_t bts_nr,
2875 u_int8_t trx_nr, u_int8_t ts_nr,
2876 u_int8_t *attr, int attr_len)
2877{
2878 struct msgb *msg = nm_msgb_alloc();
2879 struct abis_om_hdr *oh;
2880 struct abis_om_fom_hdr *foh;
2881 u_int8_t *data;
2882
2883 /* construct the 12.21 OM header, observe the erroneous length */
2884 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2885 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2886 oh->mdisc = ABIS_OM_MDISC_MANUF;
2887
2888 /* add the ip.access magic */
2889 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2890 *data++ = sizeof(ipaccess_magic);
2891 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2892
2893 /* fill the 12.21 FOM header */
2894 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2895 foh->msg_type = msg_type;
2896 foh->obj_class = obj_class;
2897 foh->obj_inst.bts_nr = bts_nr;
2898 foh->obj_inst.trx_nr = trx_nr;
2899 foh->obj_inst.ts_nr = ts_nr;
2900
2901 if (attr && attr_len) {
2902 data = msgb_put(msg, attr_len);
2903 memcpy(data, attr, attr_len);
2904 }
2905
2906 return abis_nm_sendmsg(bts, msg);
2907}
2908
2909/* set some attributes in NVRAM */
Harald Weltef12c1052010-01-07 20:39:42 +01002910int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002911 int attr_len)
2912{
Harald Weltef12c1052010-01-07 20:39:42 +01002913 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2914 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002915 attr_len);
2916}
2917
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002918int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte5aeedd42009-10-19 22:11:11 +02002919 u_int32_t ip, u_int16_t port, u_int8_t stream)
2920{
2921 struct in_addr ia;
2922 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2923 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2924 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2925
2926 int attr_len = sizeof(attr);
2927
2928 ia.s_addr = htonl(ip);
2929 attr[1] = stream;
2930 attr[3] = port >> 8;
2931 attr[4] = port & 0xff;
2932 *(u_int32_t *)(attr+6) = ia.s_addr;
2933
2934 /* if ip == 0, we use the default IP */
2935 if (ip == 0)
2936 attr_len -= 5;
2937
2938 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002939 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002940
2941 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2942 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2943 trx->nr, 0xff, attr, attr_len);
2944}
2945
Harald Welte59b04682009-06-10 05:40:52 +08002946/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002947int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002948{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002949 struct abis_om_hdr *oh;
2950 struct msgb *msg = nm_msgb_alloc();
2951
2952 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2953 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2954 trx->bts->nr, trx->nr, 0xff);
2955
2956 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002957}
Harald Welte0dfc6232009-10-24 10:20:41 +02002958
2959int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2960 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2961 u_int8_t *attr, u_int8_t attr_len)
2962{
2963 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2964 obj_class, bts_nr, trx_nr, ts_nr,
2965 attr, attr_len);
2966}
Harald Weltebeeae412009-11-12 14:48:42 +01002967
Harald Welte3055e332010-03-14 15:37:43 +08002968void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2969{
2970 /* we simply reuse the GSM48 function and overwrite the RAC
2971 * with the Cell ID */
2972 gsm48_ra_id_by_bts(buf, bts);
2973 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2974}
2975
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002976void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2977{
2978 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2979
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01002980 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002981 if (!trx->bts || !trx->bts->oml_link)
2982 return;
2983
2984 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2985 trx->bts->bts_nr, trx->nr, 0xff,
2986 new_state);
2987}
2988
Harald Welte453141f2010-03-25 11:45:30 +08002989static const struct value_string ipacc_testres_names[] = {
2990 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2991 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2992 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2993 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2994 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2995 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002996};
2997
2998const char *ipacc_testres_name(u_int8_t res)
2999{
Harald Welte453141f2010-03-25 11:45:30 +08003000 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01003001}
3002
Harald Weltebfc21092009-11-13 11:56:05 +01003003void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3004{
3005 cid->mcc = (buf[0] & 0xf) * 100;
3006 cid->mcc += (buf[0] >> 4) * 10;
3007 cid->mcc += (buf[1] & 0xf) * 1;
3008
3009 if (buf[1] >> 4 == 0xf) {
3010 cid->mnc = (buf[2] & 0xf) * 10;
3011 cid->mnc += (buf[2] >> 4) * 1;
3012 } else {
3013 cid->mnc = (buf[2] & 0xf) * 100;
3014 cid->mnc += (buf[2] >> 4) * 10;
3015 cid->mnc += (buf[1] >> 4) * 1;
3016 }
3017
Harald Welte161b4be2009-11-13 14:41:52 +01003018 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3019 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01003020}
3021
Harald Weltebeeae412009-11-12 14:48:42 +01003022/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3023int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3024{
3025 u_int8_t *cur = buf;
3026 u_int16_t len;
3027
Harald Welteb784df82010-07-22 18:14:36 +02003028 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01003029
3030 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3031 return -EINVAL;
3032 cur++;
3033
3034 len = ntohs(*(u_int16_t *)cur);
3035 cur += 2;
3036
3037 binf->info_type = ntohs(*(u_int16_t *)cur);
3038 cur += 2;
3039
3040 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3041 binf->freq_qual = *cur >> 2;
3042
Harald Welteb784df82010-07-22 18:14:36 +02003043 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01003044 binf->arfcn |= *cur++;
3045
3046 if (binf->info_type & IPAC_BINF_RXLEV)
3047 binf->rx_lev = *cur & 0x3f;
3048 cur++;
3049
3050 if (binf->info_type & IPAC_BINF_RXQUAL)
3051 binf->rx_qual = *cur & 0x7;
3052 cur++;
3053
3054 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3055 binf->freq_err = ntohs(*(u_int16_t *)cur);
3056 cur += 2;
3057
3058 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3059 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3060 cur += 2;
3061
3062 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3063 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3064 cur += 4;
3065
Harald Welte22cb81f2010-07-30 22:34:42 +02003066#if 0
3067 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01003068 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02003069#endif
Harald Welte161b4be2009-11-13 14:41:52 +01003070 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01003071 cur++;
3072
Harald Weltebfc21092009-11-13 11:56:05 +01003073 ipac_parse_cgi(&binf->cgi, cur);
3074 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01003075
3076 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3077 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3078 cur += sizeof(binf->ba_list_si2);
3079 }
3080
3081 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3082 memcpy(binf->ba_list_si2bis, cur,
3083 sizeof(binf->ba_list_si2bis));
3084 cur += sizeof(binf->ba_list_si2bis);
3085 }
3086
3087 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3088 memcpy(binf->ba_list_si2ter, cur,
3089 sizeof(binf->ba_list_si2ter));
3090 cur += sizeof(binf->ba_list_si2ter);
3091 }
3092
3093 return 0;
3094}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01003095
3096void abis_nm_clear_queue(struct gsm_bts *bts)
3097{
3098 struct msgb *msg;
3099
3100 while (!llist_empty(&bts->abis_queue)) {
3101 msg = msgb_dequeue(&bts->abis_queue);
3102 msgb_free(msg);
3103 }
3104
3105 bts->abis_nm_pend = 0;
3106}