blob: 5e6e8196c9323d08fe8f0918416c8a5caa334e1d [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
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25#include <errno.h>
26#include <unistd.h>
27#include <stdio.h>
28#include <fcntl.h>
29#include <stdlib.h>
30#include <libgen.h>
31#include <time.h>
32#include <limits.h>
33
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38
39#include <openbsc/gsm_data.h>
40#include <openbsc/debug.h>
Harald Weltef4625b12010-02-20 16:24:02 +010041#include <osmocore/msgb.h>
42#include <osmocore/tlv.h>
43#include <osmocore/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080044#include <openbsc/abis_nm.h>
45#include <openbsc/misdn.h>
46#include <openbsc/signal.h>
47
48#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080051
52/* unidirectional messages from BTS to BSC */
53static const enum abis_nm_msgtype reports[] = {
54 NM_MT_SW_ACTIVATED_REP,
55 NM_MT_TEST_REP,
56 NM_MT_STATECHG_EVENT_REP,
57 NM_MT_FAILURE_EVENT_REP,
58};
59
60/* messages without ACK/NACK */
61static const enum abis_nm_msgtype no_ack_nack[] = {
62 NM_MT_MEAS_RES_REQ,
63 NM_MT_STOP_MEAS,
64 NM_MT_START_MEAS,
65};
66
67/* Messages related to software load */
68static const enum abis_nm_msgtype sw_load_msgs[] = {
69 NM_MT_LOAD_INIT_ACK,
70 NM_MT_LOAD_INIT_NACK,
71 NM_MT_LOAD_SEG_ACK,
72 NM_MT_LOAD_ABORT,
73 NM_MT_LOAD_END_ACK,
74 NM_MT_LOAD_END_NACK,
75 //NM_MT_SW_ACT_REQ,
76 NM_MT_ACTIVATE_SW_ACK,
77 NM_MT_ACTIVATE_SW_NACK,
78 NM_MT_SW_ACTIVATED_REP,
79};
80
81static const enum abis_nm_msgtype nacks[] = {
82 NM_MT_LOAD_INIT_NACK,
83 NM_MT_LOAD_END_NACK,
84 NM_MT_SW_ACT_REQ_NACK,
85 NM_MT_ACTIVATE_SW_NACK,
86 NM_MT_ESTABLISH_TEI_NACK,
87 NM_MT_CONN_TERR_SIGN_NACK,
88 NM_MT_DISC_TERR_SIGN_NACK,
89 NM_MT_CONN_TERR_TRAF_NACK,
90 NM_MT_DISC_TERR_TRAF_NACK,
91 NM_MT_CONN_MDROP_LINK_NACK,
92 NM_MT_DISC_MDROP_LINK_NACK,
93 NM_MT_SET_BTS_ATTR_NACK,
94 NM_MT_SET_RADIO_ATTR_NACK,
95 NM_MT_SET_CHAN_ATTR_NACK,
96 NM_MT_PERF_TEST_NACK,
97 NM_MT_SEND_TEST_REP_NACK,
98 NM_MT_STOP_TEST_NACK,
99 NM_MT_STOP_EVENT_REP_NACK,
100 NM_MT_REST_EVENT_REP_NACK,
101 NM_MT_CHG_ADM_STATE_NACK,
102 NM_MT_CHG_ADM_STATE_REQ_NACK,
103 NM_MT_REP_OUTST_ALARMS_NACK,
104 NM_MT_CHANGEOVER_NACK,
105 NM_MT_OPSTART_NACK,
106 NM_MT_REINIT_NACK,
107 NM_MT_SET_SITE_OUT_NACK,
108 NM_MT_CHG_HW_CONF_NACK,
109 NM_MT_GET_ATTR_NACK,
110 NM_MT_SET_ALARM_THRES_NACK,
111 NM_MT_BS11_BEGIN_DB_TX_NACK,
112 NM_MT_BS11_END_DB_TX_NACK,
113 NM_MT_BS11_CREATE_OBJ_NACK,
114 NM_MT_BS11_DELETE_OBJ_NACK,
115};
116
Harald Welte453141f2010-03-25 11:45:30 +0800117static const struct value_string nack_names[] = {
118 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
119 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
120 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
121 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
122 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
123 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
124 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
125 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
126 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
127 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
128 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
129 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
130 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
131 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
132 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
133 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
134 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
135 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
136 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
137 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
138 { NM_MT_CHG_ADM_STATE_REQ_NACK,
139 "CHANGE ADMINISTRATIVE STATE REQUEST" },
140 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
141 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
142 { NM_MT_OPSTART_NACK, "OPSTART" },
143 { NM_MT_REINIT_NACK, "REINIT" },
144 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
145 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
146 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
147 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
148 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
149 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
150 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
151 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
152 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800153};
154
155/* Chapter 9.4.36 */
Harald Welte453141f2010-03-25 11:45:30 +0800156static const struct value_string nack_cause_names[] = {
Harald Welte59b04682009-06-10 05:40:52 +0800157 /* General Nack Causes */
Harald Welte453141f2010-03-25 11:45:30 +0800158 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
159 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
160 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
161 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
162 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
163 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
164 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
165 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
166 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
167 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
168 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
169 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
170 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte59b04682009-06-10 05:40:52 +0800171 /* Specific Nack Causes */
Harald Welte453141f2010-03-25 11:45:30 +0800172 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
173 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
174 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
175 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
176 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
177 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
178 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
179 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
180 { NM_NACK_TEST_NOSUCH, "No such test" },
181 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
182 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
183 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
184 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
185 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
186 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
187 { NM_NACK_WAIT, "Wait" },
188 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
189 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
190 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
191 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800192};
193
Harald Welte59b04682009-06-10 05:40:52 +0800194static const char *nack_cause_name(u_int8_t cause)
195{
Harald Welte453141f2010-03-25 11:45:30 +0800196 return get_value_string(nack_cause_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800197}
198
199/* Chapter 9.4.16: Event Type */
Harald Welte453141f2010-03-25 11:45:30 +0800200static const struct value_string event_type_names[] = {
201 { NM_EVT_COMM_FAIL, "communication failure" },
202 { NM_EVT_QOS_FAIL, "quality of service failure" },
203 { NM_EVT_PROC_FAIL, "processing failure" },
204 { NM_EVT_EQUIP_FAIL, "equipment failure" },
205 { NM_EVT_ENV_FAIL, "environment failure" },
206 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800207};
208
209static const char *event_type_name(u_int8_t cause)
210{
Harald Welte453141f2010-03-25 11:45:30 +0800211 return get_value_string(event_type_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800212}
213
214/* Chapter 9.4.63: Perceived Severity */
Harald Welte453141f2010-03-25 11:45:30 +0800215static const struct value_string severity_names[] = {
216 { NM_SEVER_CEASED, "failure ceased" },
217 { NM_SEVER_CRITICAL, "critical failure" },
218 { NM_SEVER_MAJOR, "major failure" },
219 { NM_SEVER_MINOR, "minor failure" },
220 { NM_SEVER_WARNING, "warning level failure" },
221 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
222 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800223};
224
225static const char *severity_name(u_int8_t cause)
226{
Harald Welte453141f2010-03-25 11:45:30 +0800227 return get_value_string(severity_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800228}
229
230/* Attributes that the BSC can set, not only get, according to Section 9.4 */
231static const enum abis_nm_attr nm_att_settable[] = {
232 NM_ATT_ADD_INFO,
233 NM_ATT_ADD_TEXT,
234 NM_ATT_DEST,
235 NM_ATT_EVENT_TYPE,
236 NM_ATT_FILE_DATA,
237 NM_ATT_GET_ARI,
238 NM_ATT_HW_CONF_CHG,
239 NM_ATT_LIST_REQ_ATTR,
240 NM_ATT_MDROP_LINK,
241 NM_ATT_MDROP_NEXT,
242 NM_ATT_NACK_CAUSES,
243 NM_ATT_OUTST_ALARM,
244 NM_ATT_PHYS_CONF,
245 NM_ATT_PROB_CAUSE,
246 NM_ATT_RAD_SUBC,
247 NM_ATT_SOURCE,
248 NM_ATT_SPEC_PROB,
249 NM_ATT_START_TIME,
250 NM_ATT_TEST_DUR,
251 NM_ATT_TEST_NO,
252 NM_ATT_TEST_REPORT,
253 NM_ATT_WINDOW_SIZE,
254 NM_ATT_SEVERITY,
255 NM_ATT_MEAS_RES,
256 NM_ATT_MEAS_TYPE,
257};
258
Harald Welte59698fb2010-01-10 18:01:52 +0100259const struct tlv_definition nm_att_tlvdef = {
Harald Welte59b04682009-06-10 05:40:52 +0800260 .def = {
261 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
262 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
264 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
265 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
266 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
267 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
268 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
269 [NM_ATT_BSIC] = { TLV_TYPE_TV },
270 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
272 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
273 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
274 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
275 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
276 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
277 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
279 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
280 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
281 [NM_ATT_HSN] = { TLV_TYPE_TV },
282 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
283 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
284 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
285 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
286 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
287 [NM_ATT_MAIO] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
289 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
290 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
291 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
292 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
294 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
295 [NM_ATT_NY1] = { TLV_TYPE_TV },
296 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
297 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
298 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
299 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
300 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
302 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
303 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
304 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
305 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
306 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
308 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
309 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
310 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
311 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
312 [NM_ATT_TEI] = { TLV_TYPE_TV },
313 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
314 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
315 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
316 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
317 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
318 [NM_ATT_TSC] = { TLV_TYPE_TV },
319 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
320 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
321 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
322 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
323 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Welte59b04682009-06-10 05:40:52 +0800324 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Welte59b04682009-06-10 05:40:52 +0800325 },
326};
327
Harald Welte35cd5e92009-08-10 12:21:22 +0200328static const enum abis_nm_chan_comb chcomb4pchan[] = {
329 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
330 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
331 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
332 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
333 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Welte37884ed2009-10-24 10:25:50 +0200334 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
335 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte35cd5e92009-08-10 12:21:22 +0200336 /* FIXME: bounds check */
337};
338
339int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
340{
341 if (pchan < ARRAY_SIZE(chcomb4pchan))
342 return chcomb4pchan[pchan];
343
344 return -EINVAL;
345}
346
Harald Welte59698fb2010-01-10 18:01:52 +0100347int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
Harald Welte59b04682009-06-10 05:40:52 +0800348{
Harald Welte59698fb2010-01-10 18:01:52 +0100349 if (!bts->model)
350 return -EIO;
351 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +0800352}
353
354static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
355{
356 int i;
357
358 for (i = 0; i < size; i++) {
359 if (arr[i] == mt)
360 return 1;
361 }
362
363 return 0;
364}
365
366#if 0
367/* is this msgtype the usual ACK/NACK type ? */
368static int is_ack_nack(enum abis_nm_msgtype mt)
369{
370 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
371}
372#endif
373
374/* is this msgtype a report ? */
375static int is_report(enum abis_nm_msgtype mt)
376{
377 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
378}
379
380#define MT_ACK(x) (x+1)
381#define MT_NACK(x) (x+2)
382
383static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
384{
385 oh->mdisc = ABIS_OM_MDISC_FOM;
386 oh->placement = ABIS_OM_PLACEMENT_ONLY;
387 oh->sequence = 0;
388 oh->length = len;
389}
390
391static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
392 u_int8_t msg_type, u_int8_t obj_class,
393 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
394{
395 struct abis_om_fom_hdr *foh =
396 (struct abis_om_fom_hdr *) oh->data;
397
398 fill_om_hdr(oh, len+sizeof(*foh));
399 foh->msg_type = msg_type;
400 foh->obj_class = obj_class;
401 foh->obj_inst.bts_nr = bts_nr;
402 foh->obj_inst.trx_nr = trx_nr;
403 foh->obj_inst.ts_nr = ts_nr;
404}
405
406static struct msgb *nm_msgb_alloc(void)
407{
Harald Welte9cfc9352009-06-26 19:39:35 +0200408 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
409 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800410}
411
412/* Send a OML NM Message from BSC to BTS */
413int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
414{
415 msg->trx = bts->c0;
416
417 return _abis_nm_sendmsg(msg);
418}
419
420static int abis_nm_rcvmsg_sw(struct msgb *mb);
421
Harald Welte453141f2010-03-25 11:45:30 +0800422static struct value_string obj_class_names[] = {
423 { NM_OC_SITE_MANAGER, "SITE MANAGER" },
424 { NM_OC_BTS, "BTS" },
425 { NM_OC_RADIO_CARRIER, "RADIO CARRIER" },
426 { NM_OC_BASEB_TRANSC, "BASEBAND TRANSCEIVER" },
427 { NM_OC_CHANNEL, "CHANNEL" },
428 { NM_OC_BS11_ADJC, "ADJC" },
429 { NM_OC_BS11_HANDOVER, "HANDOVER" },
430 { NM_OC_BS11_PWR_CTRL, "POWER CONTROL" },
431 { NM_OC_BS11_BTSE, "BTSE" },
432 { NM_OC_BS11_RACK, "RACK" },
433 { NM_OC_BS11_TEST, "TEST" },
434 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
435 { NM_OC_BS11_BPORT, "BPORT" },
436 { NM_OC_GPRS_NSE, "GPRS NSE" },
437 { NM_OC_GPRS_CELL, "GPRS CELL" },
438 { NM_OC_GPRS_NSVC, "GPRS NSVC" },
439 { NM_OC_BS11, "SIEMENSHW" },
440 { 0, NULL }
441};
442
Harald Welte59b04682009-06-10 05:40:52 +0800443static const char *obj_class_name(u_int8_t oc)
444{
Harald Welte453141f2010-03-25 11:45:30 +0800445 return get_value_string(obj_class_names, oc);
Harald Welte59b04682009-06-10 05:40:52 +0800446}
447
448const char *nm_opstate_name(u_int8_t os)
449{
450 switch (os) {
Harald Welte2c87ec12009-12-24 10:06:33 +0100451 case NM_OPSTATE_DISABLED:
Harald Welte59b04682009-06-10 05:40:52 +0800452 return "Disabled";
Harald Welte2c87ec12009-12-24 10:06:33 +0100453 case NM_OPSTATE_ENABLED:
Harald Welte59b04682009-06-10 05:40:52 +0800454 return "Enabled";
Harald Welte2c87ec12009-12-24 10:06:33 +0100455 case NM_OPSTATE_NULL:
Harald Welte59b04682009-06-10 05:40:52 +0800456 return "NULL";
457 default:
458 return "RFU";
459 }
460}
461
462/* Chapter 9.4.7 */
Harald Welte453141f2010-03-25 11:45:30 +0800463static const struct value_string avail_names[] = {
464 { 0, "In test" },
465 { 1, "Failed" },
466 { 2, "Power off" },
467 { 3, "Off line" },
468 /* Not used */
469 { 5, "Dependency" },
470 { 6, "Degraded" },
471 { 7, "Not installed" },
472 { 0xff, "OK" },
473 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800474};
475
476const char *nm_avail_name(u_int8_t avail)
477{
Harald Welte453141f2010-03-25 11:45:30 +0800478 return get_value_string(avail_names, avail);
Harald Welte59b04682009-06-10 05:40:52 +0800479}
480
Harald Weltebeeae412009-11-12 14:48:42 +0100481static struct value_string test_names[] = {
482 /* FIXME: standard test names */
483 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
484 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
485 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
486 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
487 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
488 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
489 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
490 { 0, NULL }
491};
492
Harald Welte59b04682009-06-10 05:40:52 +0800493const char *nm_adm_name(u_int8_t adm)
494{
495 switch (adm) {
496 case 1:
497 return "Locked";
498 case 2:
499 return "Unlocked";
500 case 3:
501 return "Shutdown";
502 default:
503 return "<not used>";
504 }
505}
506
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100507int nm_is_running(struct gsm_nm_state *s) {
508 return (s->operational == NM_OPSTATE_ENABLED) && (
509 (s->availability == NM_AVSTATE_OK) ||
510 (s->availability == 0xff)
511 );
512}
513
Harald Welteb7284a92009-10-20 09:56:18 +0200514static void debugp_foh(struct abis_om_fom_hdr *foh)
515{
516 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200517 obj_class_name(foh->obj_class), foh->obj_class,
Harald Welteb7284a92009-10-20 09:56:18 +0200518 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
519 foh->obj_inst.ts_nr);
520}
521
Harald Welte59b04682009-06-10 05:40:52 +0800522/* obtain the gsm_nm_state data structure for a given object instance */
523static struct gsm_nm_state *
524objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
525 struct abis_om_obj_inst *obj_inst)
526{
527 struct gsm_bts_trx *trx;
528 struct gsm_nm_state *nm_state = NULL;
529
530 switch (obj_class) {
531 case NM_OC_BTS:
532 nm_state = &bts->nm_state;
533 break;
534 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100535 if (obj_inst->trx_nr >= bts->num_trx) {
536 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800537 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100538 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200539 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800540 nm_state = &trx->nm_state;
541 break;
542 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100543 if (obj_inst->trx_nr >= bts->num_trx) {
544 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800545 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100546 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200547 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800548 nm_state = &trx->bb_transc.nm_state;
549 break;
550 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100551 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100552 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800553 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100554 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200555 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800556 if (obj_inst->ts_nr >= TRX_NR_TS)
557 return NULL;
558 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
559 break;
560 case NM_OC_SITE_MANAGER:
561 nm_state = &bts->site_mgr.nm_state;
562 break;
563 case NM_OC_BS11:
564 switch (obj_inst->bts_nr) {
565 case BS11_OBJ_CCLK:
566 nm_state = &bts->bs11.cclk.nm_state;
567 break;
568 case BS11_OBJ_BBSIG:
569 if (obj_inst->ts_nr > bts->num_trx)
570 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200571 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800572 nm_state = &trx->bs11.bbsig.nm_state;
573 break;
574 case BS11_OBJ_PA:
575 if (obj_inst->ts_nr > bts->num_trx)
576 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200577 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800578 nm_state = &trx->bs11.pa.nm_state;
579 break;
580 default:
581 return NULL;
582 }
583 case NM_OC_BS11_RACK:
584 nm_state = &bts->bs11.rack.nm_state;
585 break;
586 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100587 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte59b04682009-06-10 05:40:52 +0800588 return NULL;
589 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
590 break;
Harald Welte439e1282009-10-24 10:19:14 +0200591 case NM_OC_GPRS_NSE:
592 nm_state = &bts->gprs.nse.nm_state;
593 break;
594 case NM_OC_GPRS_CELL:
595 nm_state = &bts->gprs.cell.nm_state;
596 break;
597 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100598 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200599 return NULL;
600 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
601 break;
Harald Welte59b04682009-06-10 05:40:52 +0800602 }
603 return nm_state;
604}
605
606/* obtain the in-memory data structure of a given object instance */
607static void *
608objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
609 struct abis_om_obj_inst *obj_inst)
610{
611 struct gsm_bts_trx *trx;
612 void *obj = NULL;
613
614 switch (obj_class) {
615 case NM_OC_BTS:
616 obj = bts;
617 break;
618 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100619 if (obj_inst->trx_nr >= bts->num_trx) {
620 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800621 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100622 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200623 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800624 obj = trx;
625 break;
626 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100627 if (obj_inst->trx_nr >= bts->num_trx) {
628 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800629 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100630 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200631 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800632 obj = &trx->bb_transc;
633 break;
634 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100635 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100636 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800637 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100638 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200639 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800640 if (obj_inst->ts_nr >= TRX_NR_TS)
641 return NULL;
642 obj = &trx->ts[obj_inst->ts_nr];
643 break;
644 case NM_OC_SITE_MANAGER:
645 obj = &bts->site_mgr;
646 break;
Harald Welte439e1282009-10-24 10:19:14 +0200647 case NM_OC_GPRS_NSE:
648 obj = &bts->gprs.nse;
649 break;
650 case NM_OC_GPRS_CELL:
651 obj = &bts->gprs.cell;
652 break;
653 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100654 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200655 return NULL;
656 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
657 break;
Harald Welte59b04682009-06-10 05:40:52 +0800658 }
659 return obj;
660}
661
662/* Update the administrative state of a given object in our in-memory data
663 * structures and send an event to the higher layer */
664static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
665 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
666{
667 struct gsm_nm_state *nm_state, new_state;
668 void *obj;
669 int rc;
670
671 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte3d9ecf72009-11-13 12:10:18 +0100672 if (!obj)
673 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800674 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
675 if (!nm_state)
676 return -1;
677
678 new_state = *nm_state;
679 new_state.administrative = adm_state;
680
681 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
682
683 nm_state->administrative = adm_state;
684
685 return rc;
686}
687
688static int abis_nm_rx_statechg_rep(struct msgb *mb)
689{
690 struct abis_om_hdr *oh = msgb_l2(mb);
691 struct abis_om_fom_hdr *foh = msgb_l3(mb);
692 struct gsm_bts *bts = mb->trx->bts;
693 struct tlv_parsed tp;
694 struct gsm_nm_state *nm_state, new_state;
695 int rc;
696
697 DEBUGPC(DNM, "STATE CHG: ");
698
699 memset(&new_state, 0, sizeof(new_state));
700
701 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
702 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100703 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800704 return -EINVAL;
705 }
706
707 new_state = *nm_state;
708
Harald Welte59698fb2010-01-10 18:01:52 +0100709 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800710 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
711 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
712 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
713 }
714 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
715 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
716 new_state.availability = 0xff;
717 else
718 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
719 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
720 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100721 } else
722 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800723 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
724 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther460fb3b2009-10-22 15:44:30 +0200725 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800726 }
727 DEBUGPC(DNM, "\n");
728
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100729 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
730 new_state.operational != nm_state->operational ||
731 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800732 /* Update the operational state of a given object in our in-memory data
733 * structures and send an event to the higher layer */
734 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
735 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100736 nm_state->operational = new_state.operational;
737 nm_state->availability = new_state.availability;
738 if (nm_state->administrative == 0)
739 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800740 }
741#if 0
742 if (op_state == 1) {
743 /* try to enable objects that are disabled */
744 abis_nm_opstart(bts, foh->obj_class,
745 foh->obj_inst.bts_nr,
746 foh->obj_inst.trx_nr,
747 foh->obj_inst.ts_nr);
748 }
749#endif
750 return 0;
751}
752
753static int rx_fail_evt_rep(struct msgb *mb)
754{
755 struct abis_om_hdr *oh = msgb_l2(mb);
756 struct abis_om_fom_hdr *foh = msgb_l3(mb);
757 struct tlv_parsed tp;
758
759 DEBUGPC(DNM, "Failure Event Report ");
760
Harald Welte59698fb2010-01-10 18:01:52 +0100761 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800762
763 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
764 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
765 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
766 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
767
768 DEBUGPC(DNM, "\n");
769
770 return 0;
771}
772
773static int abis_nm_rcvmsg_report(struct msgb *mb)
774{
775 struct abis_om_fom_hdr *foh = msgb_l3(mb);
776 u_int8_t mt = foh->msg_type;
777
Harald Welteb7284a92009-10-20 09:56:18 +0200778 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800779
780 //nmh->cfg->report_cb(mb, foh);
781
782 switch (mt) {
783 case NM_MT_STATECHG_EVENT_REP:
784 return abis_nm_rx_statechg_rep(mb);
785 break;
786 case NM_MT_SW_ACTIVATED_REP:
787 DEBUGPC(DNM, "Software Activated Report\n");
788 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
789 break;
790 case NM_MT_FAILURE_EVENT_REP:
791 rx_fail_evt_rep(mb);
792 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
793 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200794 case NM_MT_TEST_REP:
795 DEBUGPC(DNM, "Test Report\n");
796 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
797 break;
Harald Welte59b04682009-06-10 05:40:52 +0800798 default:
799 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
800 break;
801
802 };
803
804 return 0;
805}
806
807/* Activate the specified software into the BTS */
808static 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 +0200809 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800810{
811 struct abis_om_hdr *oh;
812 struct msgb *msg = nm_msgb_alloc();
813 u_int8_t len = swdesc_len;
814 u_int8_t *trailer;
815
816 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
817 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
818
819 trailer = msgb_put(msg, swdesc_len);
820 memcpy(trailer, sw_desc, swdesc_len);
821
822 return abis_nm_sendmsg(bts, msg);
823}
824
825static int abis_nm_rx_sw_act_req(struct msgb *mb)
826{
827 struct abis_om_hdr *oh = msgb_l2(mb);
828 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200829 struct tlv_parsed tp;
830 const u_int8_t *sw_config;
831 int sw_config_len;
832 int file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800833 int ret;
834
Harald Welteb7284a92009-10-20 09:56:18 +0200835 debugp_foh(foh);
836
837 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800838
Harald Welte3055e332010-03-14 15:37:43 +0800839 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800840
841 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
842 foh->obj_inst.bts_nr,
843 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800844 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800845 foh->data, oh->length-sizeof(*foh));
846
Harald Welte59698fb2010-01-10 18:01:52 +0100847 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200848 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
849 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
850 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
851 DEBUGP(DNM, "SW config not found! Can't continue.\n");
852 return -EINVAL;
853 } else {
854 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
855 }
856
857 if (sw_config[0] != NM_ATT_SW_DESCR)
858 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
859 if (sw_config[1] != NM_ATT_FILE_ID)
860 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
861 file_id_len = sw_config[2] * 256 + sw_config[3];
862
863 /* Assumes first SW file in list is the one to be activated */
864 /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
Harald Welte59b04682009-06-10 05:40:52 +0800865 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
866 foh->obj_inst.bts_nr,
867 foh->obj_inst.trx_nr,
868 foh->obj_inst.ts_nr,
Mike Haben322fc582009-10-01 14:56:13 +0200869 sw_config + 4,
870 file_id_len);
Harald Welte59b04682009-06-10 05:40:52 +0800871}
872
873/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
874static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
875{
876 struct abis_om_hdr *oh = msgb_l2(mb);
877 struct abis_om_fom_hdr *foh = msgb_l3(mb);
878 struct tlv_parsed tp;
879 u_int8_t adm_state;
880
Harald Welte59698fb2010-01-10 18:01:52 +0100881 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800882 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
883 return -EINVAL;
884
885 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
886
887 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
888}
889
890static int abis_nm_rx_lmt_event(struct msgb *mb)
891{
892 struct abis_om_hdr *oh = msgb_l2(mb);
893 struct abis_om_fom_hdr *foh = msgb_l3(mb);
894 struct tlv_parsed tp;
895
896 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100897 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800898 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
899 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
900 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
901 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
902 }
903 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
904 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
905 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
906 DEBUGPC(DNM, "Level=%u ", level);
907 }
908 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
909 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
910 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
911 DEBUGPC(DNM, "Username=%s ", name);
912 }
913 DEBUGPC(DNM, "\n");
914 /* FIXME: parse LMT LOGON TIME */
915 return 0;
916}
917
918/* Receive a OML NM Message from BTS */
919static int abis_nm_rcvmsg_fom(struct msgb *mb)
920{
921 struct abis_om_hdr *oh = msgb_l2(mb);
922 struct abis_om_fom_hdr *foh = msgb_l3(mb);
923 u_int8_t mt = foh->msg_type;
924
925 /* check for unsolicited message */
926 if (is_report(mt))
927 return abis_nm_rcvmsg_report(mb);
928
929 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
930 return abis_nm_rcvmsg_sw(mb);
931
932 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
933 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200934
Harald Welteb7284a92009-10-20 09:56:18 +0200935 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200936
Harald Welte453141f2010-03-25 11:45:30 +0800937 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +0800938
Harald Welte59698fb2010-01-10 18:01:52 +0100939 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800940 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200941 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +0800942 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
943 else
944 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200945
Harald Welte6a21c732009-11-17 06:09:56 +0100946 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200947 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800948 }
949#if 0
950 /* check if last message is to be acked */
951 if (is_ack_nack(nmh->last_msgtype)) {
952 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100953 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800954 /* we got our ACK, continue sending the next msg */
955 } else if (mt == MT_NACK(nmh->last_msgtype)) {
956 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100957 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800958 /* FIXME: somehow signal this to the caller */
959 } else {
960 /* really strange things happen */
961 return -EINVAL;
962 }
963 }
964#endif
965
966 switch (mt) {
967 case NM_MT_CHG_ADM_STATE_ACK:
968 return abis_nm_rx_chg_adm_state_ack(mb);
969 break;
970 case NM_MT_SW_ACT_REQ:
971 return abis_nm_rx_sw_act_req(mb);
972 break;
973 case NM_MT_BS11_LMT_SESSION:
974 return abis_nm_rx_lmt_event(mb);
975 break;
Harald Welte204317e2009-08-06 17:58:31 +0200976 case NM_MT_CONN_MDROP_LINK_ACK:
977 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
978 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100979 case NM_MT_IPACC_RESTART_ACK:
980 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
981 break;
982 case NM_MT_IPACC_RESTART_NACK:
983 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
984 break;
Harald Welte59b04682009-06-10 05:40:52 +0800985 }
986
987 return 0;
988}
989
990static int abis_nm_rx_ipacc(struct msgb *mb);
991
992static int abis_nm_rcvmsg_manuf(struct msgb *mb)
993{
994 int rc;
995 int bts_type = mb->trx->bts->type;
996
997 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100998 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +0800999 rc = abis_nm_rx_ipacc(mb);
1000 break;
1001 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001002 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1003 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001004 rc = 0;
1005 break;
1006 }
1007
1008 return rc;
1009}
1010
1011/* High-Level API */
1012/* Entry-point where L2 OML from BTS enters the NM code */
1013int abis_nm_rcvmsg(struct msgb *msg)
1014{
1015 struct abis_om_hdr *oh = msgb_l2(msg);
1016 int rc = 0;
1017
1018 /* Various consistency checks */
1019 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001020 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001021 oh->placement);
1022 return -EINVAL;
1023 }
1024 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001025 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001026 oh->sequence);
1027 return -EINVAL;
1028 }
1029#if 0
1030 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1031 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1032 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001033 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001034 oh->length + sizeof(*oh), l2_len);
1035 return -EINVAL;
1036 }
1037 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001038 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 +08001039#endif
1040 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1041
1042 switch (oh->mdisc) {
1043 case ABIS_OM_MDISC_FOM:
1044 rc = abis_nm_rcvmsg_fom(msg);
1045 break;
1046 case ABIS_OM_MDISC_MANUF:
1047 rc = abis_nm_rcvmsg_manuf(msg);
1048 break;
1049 case ABIS_OM_MDISC_MMI:
1050 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001051 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001052 oh->mdisc);
1053 break;
1054 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001055 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001056 oh->mdisc);
1057 return -EINVAL;
1058 }
1059
1060 msgb_free(msg);
1061 return rc;
1062}
1063
1064#if 0
1065/* initialized all resources */
1066struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1067{
1068 struct abis_nm_h *nmh;
1069
1070 nmh = malloc(sizeof(*nmh));
1071 if (!nmh)
1072 return NULL;
1073
1074 nmh->cfg = cfg;
1075
1076 return nmh;
1077}
1078
1079/* free all resources */
1080void abis_nm_fini(struct abis_nm_h *nmh)
1081{
1082 free(nmh);
1083}
1084#endif
1085
1086/* Here we are trying to define a high-level API that can be used by
1087 * the actual BSC implementation. However, the architecture is currently
1088 * still under design. Ideally the calls to this API would be synchronous,
1089 * while the underlying stack behind the APi runs in a traditional select
1090 * based state machine.
1091 */
1092
1093/* 6.2 Software Load: */
1094enum sw_state {
1095 SW_STATE_NONE,
1096 SW_STATE_WAIT_INITACK,
1097 SW_STATE_WAIT_SEGACK,
1098 SW_STATE_WAIT_ENDACK,
1099 SW_STATE_WAIT_ACTACK,
1100 SW_STATE_ERROR,
1101};
1102
1103struct abis_nm_sw {
1104 struct gsm_bts *bts;
1105 gsm_cbfn *cbfn;
1106 void *cb_data;
1107 int forced;
1108
1109 /* this will become part of the SW LOAD INITIATE */
1110 u_int8_t obj_class;
1111 u_int8_t obj_instance[3];
1112
1113 u_int8_t file_id[255];
1114 u_int8_t file_id_len;
1115
1116 u_int8_t file_version[255];
1117 u_int8_t file_version_len;
1118
1119 u_int8_t window_size;
1120 u_int8_t seg_in_window;
1121
1122 int fd;
1123 FILE *stream;
1124 enum sw_state state;
1125 int last_seg;
1126};
1127
1128static struct abis_nm_sw g_sw;
1129
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001130static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1131{
1132 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1133 msgb_v_put(msg, NM_ATT_SW_DESCR);
1134 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1135 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1136 sw->file_version);
1137 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1138 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1139 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1140 sw->file_version);
1141 } else {
1142 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1143 }
1144}
1145
Harald Welte59b04682009-06-10 05:40:52 +08001146/* 6.2.1 / 8.3.1: Load Data Initiate */
1147static int sw_load_init(struct abis_nm_sw *sw)
1148{
1149 struct abis_om_hdr *oh;
1150 struct msgb *msg = nm_msgb_alloc();
1151 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1152
1153 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1154 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1155 sw->obj_instance[0], sw->obj_instance[1],
1156 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001157
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001158 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001159 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1160
1161 return abis_nm_sendmsg(sw->bts, msg);
1162}
1163
1164static int is_last_line(FILE *stream)
1165{
1166 char next_seg_buf[256];
1167 long pos;
1168
1169 /* check if we're sending the last line */
1170 pos = ftell(stream);
1171 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1172 fseek(stream, pos, SEEK_SET);
1173 return 1;
1174 }
1175
1176 fseek(stream, pos, SEEK_SET);
1177 return 0;
1178}
1179
1180/* 6.2.2 / 8.3.2 Load Data Segment */
1181static int sw_load_segment(struct abis_nm_sw *sw)
1182{
1183 struct abis_om_hdr *oh;
1184 struct msgb *msg = nm_msgb_alloc();
1185 char seg_buf[256];
1186 char *line_buf = seg_buf+2;
1187 unsigned char *tlv;
1188 u_int8_t len;
1189
1190 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1191
1192 switch (sw->bts->type) {
1193 case GSM_BTS_TYPE_BS11:
1194 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1195 perror("fgets reading segment");
1196 return -EINVAL;
1197 }
1198 seg_buf[0] = 0x00;
1199
1200 /* check if we're sending the last line */
1201 sw->last_seg = is_last_line(sw->stream);
1202 if (sw->last_seg)
1203 seg_buf[1] = 0;
1204 else
1205 seg_buf[1] = 1 + sw->seg_in_window++;
1206
1207 len = strlen(line_buf) + 2;
1208 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1209 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1210 /* BS11 wants CR + LF in excess of the TLV length !?! */
1211 tlv[1] -= 2;
1212
1213 /* we only now know the exact length for the OM hdr */
1214 len = strlen(line_buf)+2;
1215 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001216 case GSM_BTS_TYPE_NANOBTS: {
1217 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1218 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1219 if (len < 0) {
1220 perror("read failed");
1221 return -EINVAL;
1222 }
1223
1224 if (len != IPACC_SEGMENT_SIZE)
1225 sw->last_seg = 1;
1226
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001227 ++sw->seg_in_window;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001228 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1229 len += 3;
1230 break;
1231 }
Harald Welte59b04682009-06-10 05:40:52 +08001232 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001233 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001234 /* FIXME: Other BTS types */
1235 return -1;
1236 }
1237
1238 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1239 sw->obj_instance[0], sw->obj_instance[1],
1240 sw->obj_instance[2]);
1241
1242 return abis_nm_sendmsg(sw->bts, msg);
1243}
1244
1245/* 6.2.4 / 8.3.4 Load Data End */
1246static int sw_load_end(struct abis_nm_sw *sw)
1247{
1248 struct abis_om_hdr *oh;
1249 struct msgb *msg = nm_msgb_alloc();
1250 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1251
1252 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1253 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1254 sw->obj_instance[0], sw->obj_instance[1],
1255 sw->obj_instance[2]);
1256
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001257 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001258 return abis_nm_sendmsg(sw->bts, msg);
1259}
1260
1261/* Activate the specified software into the BTS */
1262static int sw_activate(struct abis_nm_sw *sw)
1263{
1264 struct abis_om_hdr *oh;
1265 struct msgb *msg = nm_msgb_alloc();
1266 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1267
1268 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1269 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1270 sw->obj_instance[0], sw->obj_instance[1],
1271 sw->obj_instance[2]);
1272
1273 /* FIXME: this is BS11 specific format */
1274 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1275 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1276 sw->file_version);
1277
1278 return abis_nm_sendmsg(sw->bts, msg);
1279}
1280
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001281struct sdp_firmware {
1282 char magic[4];
1283 char more_magic[4];
1284 unsigned int header_length;
1285 unsigned int file_length;
1286} __attribute__ ((packed));
1287
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001288static int parse_sdp_header(struct abis_nm_sw *sw)
1289{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001290 struct sdp_firmware firmware_header;
1291 int rc;
1292 struct stat stat;
1293
1294 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1295 if (rc != sizeof(firmware_header)) {
1296 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1297 return -1;
1298 }
1299
1300 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1301 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1302 return -1;
1303 }
1304
1305 if (firmware_header.more_magic[0] != 0x10 ||
1306 firmware_header.more_magic[1] != 0x02 ||
1307 firmware_header.more_magic[2] != 0x00 ||
1308 firmware_header.more_magic[3] != 0x00) {
1309 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1310 return -1;
1311 }
1312
1313
1314 if (fstat(sw->fd, &stat) == -1) {
1315 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1316 return -1;
1317 }
1318
1319 if (ntohl(firmware_header.file_length) != stat.st_size) {
1320 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1321 return -1;
1322 }
1323
1324 /* go back to the start as we checked the whole filesize.. */
1325 lseek(sw->fd, 0l, SEEK_SET);
1326 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1327 "There might be checksums in the file that are not\n"
1328 "verified and incomplete firmware might be flashed.\n"
1329 "There is absolutely no WARRANTY that flashing will\n"
1330 "work.\n");
1331 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001332}
1333
Harald Welte59b04682009-06-10 05:40:52 +08001334static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1335{
1336 char file_id[12+1];
1337 char file_version[80+1];
1338 int rc;
1339
1340 sw->fd = open(fname, O_RDONLY);
1341 if (sw->fd < 0)
1342 return sw->fd;
1343
1344 switch (sw->bts->type) {
1345 case GSM_BTS_TYPE_BS11:
1346 sw->stream = fdopen(sw->fd, "r");
1347 if (!sw->stream) {
1348 perror("fdopen");
1349 return -1;
1350 }
1351 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001352 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001353 file_id, file_version);
1354 if (rc != 2) {
1355 perror("parsing header line of software file");
1356 return -1;
1357 }
1358 strcpy((char *)sw->file_id, file_id);
1359 sw->file_id_len = strlen(file_id);
1360 strcpy((char *)sw->file_version, file_version);
1361 sw->file_version_len = strlen(file_version);
1362 /* rewind to start of file */
1363 rewind(sw->stream);
1364 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001365 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001366 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001367 rc = parse_sdp_header(sw);
1368 if (rc < 0) {
1369 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1370 return -1;
1371 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001372
1373 strcpy((char *)sw->file_id, "id");
1374 sw->file_id_len = 3;
1375 strcpy((char *)sw->file_version, "version");
1376 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001377 break;
Harald Welte59b04682009-06-10 05:40:52 +08001378 default:
1379 /* We don't know how to treat them yet */
1380 close(sw->fd);
1381 return -EINVAL;
1382 }
1383
1384 return 0;
1385}
1386
1387static void sw_close_file(struct abis_nm_sw *sw)
1388{
1389 switch (sw->bts->type) {
1390 case GSM_BTS_TYPE_BS11:
1391 fclose(sw->stream);
1392 break;
1393 default:
1394 close(sw->fd);
1395 break;
1396 }
1397}
1398
1399/* Fill the window */
1400static int sw_fill_window(struct abis_nm_sw *sw)
1401{
1402 int rc;
1403
1404 while (sw->seg_in_window < sw->window_size) {
1405 rc = sw_load_segment(sw);
1406 if (rc < 0)
1407 return rc;
1408 if (sw->last_seg)
1409 break;
1410 }
1411 return 0;
1412}
1413
1414/* callback function from abis_nm_rcvmsg() handler */
1415static int abis_nm_rcvmsg_sw(struct msgb *mb)
1416{
1417 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1418 int rc = -1;
1419 struct abis_nm_sw *sw = &g_sw;
1420 enum sw_state old_state = sw->state;
1421
1422 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1423
1424 switch (sw->state) {
1425 case SW_STATE_WAIT_INITACK:
1426 switch (foh->msg_type) {
1427 case NM_MT_LOAD_INIT_ACK:
1428 /* fill window with segments */
1429 if (sw->cbfn)
1430 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1431 NM_MT_LOAD_INIT_ACK, mb,
1432 sw->cb_data, NULL);
1433 rc = sw_fill_window(sw);
1434 sw->state = SW_STATE_WAIT_SEGACK;
1435 break;
1436 case NM_MT_LOAD_INIT_NACK:
1437 if (sw->forced) {
1438 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1439 "Init NACK\n");
1440 if (sw->cbfn)
1441 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1442 NM_MT_LOAD_INIT_ACK, mb,
1443 sw->cb_data, NULL);
1444 rc = sw_fill_window(sw);
1445 sw->state = SW_STATE_WAIT_SEGACK;
1446 } else {
1447 DEBUGP(DNM, "Software Load Init NACK\n");
1448 /* FIXME: cause */
1449 if (sw->cbfn)
1450 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1451 NM_MT_LOAD_INIT_NACK, mb,
1452 sw->cb_data, NULL);
1453 sw->state = SW_STATE_ERROR;
1454 }
1455 break;
1456 }
1457 break;
1458 case SW_STATE_WAIT_SEGACK:
1459 switch (foh->msg_type) {
1460 case NM_MT_LOAD_SEG_ACK:
1461 if (sw->cbfn)
1462 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1463 NM_MT_LOAD_SEG_ACK, mb,
1464 sw->cb_data, NULL);
1465 sw->seg_in_window = 0;
1466 if (!sw->last_seg) {
1467 /* fill window with more segments */
1468 rc = sw_fill_window(sw);
1469 sw->state = SW_STATE_WAIT_SEGACK;
1470 } else {
1471 /* end the transfer */
1472 sw->state = SW_STATE_WAIT_ENDACK;
1473 rc = sw_load_end(sw);
1474 }
1475 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001476 case NM_MT_LOAD_ABORT:
1477 if (sw->cbfn)
1478 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1479 NM_MT_LOAD_ABORT, mb,
1480 sw->cb_data, NULL);
1481 break;
Harald Welte59b04682009-06-10 05:40:52 +08001482 }
1483 break;
1484 case SW_STATE_WAIT_ENDACK:
1485 switch (foh->msg_type) {
1486 case NM_MT_LOAD_END_ACK:
1487 sw_close_file(sw);
1488 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1489 sw->bts->nr);
1490 sw->state = SW_STATE_NONE;
1491 if (sw->cbfn)
1492 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1493 NM_MT_LOAD_END_ACK, mb,
1494 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001495 rc = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001496 break;
1497 case NM_MT_LOAD_END_NACK:
1498 if (sw->forced) {
1499 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1500 "End NACK\n");
1501 sw->state = SW_STATE_NONE;
1502 if (sw->cbfn)
1503 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1504 NM_MT_LOAD_END_ACK, mb,
1505 sw->cb_data, NULL);
1506 } else {
1507 DEBUGP(DNM, "Software Load End NACK\n");
1508 /* FIXME: cause */
1509 sw->state = SW_STATE_ERROR;
1510 if (sw->cbfn)
1511 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1512 NM_MT_LOAD_END_NACK, mb,
1513 sw->cb_data, NULL);
1514 }
1515 break;
1516 }
1517 case SW_STATE_WAIT_ACTACK:
1518 switch (foh->msg_type) {
1519 case NM_MT_ACTIVATE_SW_ACK:
1520 /* we're done */
1521 DEBUGP(DNM, "Activate Software DONE!\n");
1522 sw->state = SW_STATE_NONE;
1523 rc = 0;
1524 if (sw->cbfn)
1525 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1526 NM_MT_ACTIVATE_SW_ACK, mb,
1527 sw->cb_data, NULL);
1528 break;
1529 case NM_MT_ACTIVATE_SW_NACK:
1530 DEBUGP(DNM, "Activate Software NACK\n");
1531 /* FIXME: cause */
1532 sw->state = SW_STATE_ERROR;
1533 if (sw->cbfn)
1534 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1535 NM_MT_ACTIVATE_SW_NACK, mb,
1536 sw->cb_data, NULL);
1537 break;
1538 }
1539 case SW_STATE_NONE:
1540 switch (foh->msg_type) {
1541 case NM_MT_ACTIVATE_SW_ACK:
1542 rc = 0;
1543 break;
1544 }
1545 break;
1546 case SW_STATE_ERROR:
1547 break;
1548 }
1549
1550 if (rc)
1551 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1552 foh->msg_type, old_state, sw->state);
1553
1554 return rc;
1555}
1556
1557/* Load the specified software into the BTS */
1558int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
1559 u_int8_t win_size, int forced,
1560 gsm_cbfn *cbfn, void *cb_data)
1561{
1562 struct abis_nm_sw *sw = &g_sw;
1563 int rc;
1564
1565 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1566 bts->nr, fname);
1567
1568 if (sw->state != SW_STATE_NONE)
1569 return -EBUSY;
1570
1571 sw->bts = bts;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001572
1573 switch (bts->type) {
1574 case GSM_BTS_TYPE_BS11:
1575 sw->obj_class = NM_OC_SITE_MANAGER;
1576 sw->obj_instance[0] = 0xff;
1577 sw->obj_instance[1] = 0xff;
1578 sw->obj_instance[2] = 0xff;
1579 break;
1580 case GSM_BTS_TYPE_NANOBTS:
1581 sw->obj_class = NM_OC_BASEB_TRANSC;
1582 sw->obj_instance[0] = 0x00;
1583 sw->obj_instance[1] = 0x00;
1584 sw->obj_instance[2] = 0xff;
1585 break;
1586 case GSM_BTS_TYPE_UNKNOWN:
1587 default:
1588 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1589 return -1;
1590 break;
1591 }
Harald Welte59b04682009-06-10 05:40:52 +08001592 sw->window_size = win_size;
1593 sw->state = SW_STATE_WAIT_INITACK;
1594 sw->cbfn = cbfn;
1595 sw->cb_data = cb_data;
1596 sw->forced = forced;
1597
1598 rc = sw_open_file(sw, fname);
1599 if (rc < 0) {
1600 sw->state = SW_STATE_NONE;
1601 return rc;
1602 }
1603
1604 return sw_load_init(sw);
1605}
1606
1607int abis_nm_software_load_status(struct gsm_bts *bts)
1608{
1609 struct abis_nm_sw *sw = &g_sw;
1610 struct stat st;
1611 int rc, percent;
1612
1613 rc = fstat(sw->fd, &st);
1614 if (rc < 0) {
1615 perror("ERROR during stat");
1616 return rc;
1617 }
1618
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001619 if (sw->stream)
1620 percent = (ftell(sw->stream) * 100) / st.st_size;
1621 else
1622 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001623 return percent;
1624}
1625
1626/* Activate the specified software into the BTS */
1627int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1628 gsm_cbfn *cbfn, void *cb_data)
1629{
1630 struct abis_nm_sw *sw = &g_sw;
1631 int rc;
1632
1633 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1634 bts->nr, fname);
1635
1636 if (sw->state != SW_STATE_NONE)
1637 return -EBUSY;
1638
1639 sw->bts = bts;
1640 sw->obj_class = NM_OC_SITE_MANAGER;
1641 sw->obj_instance[0] = 0xff;
1642 sw->obj_instance[1] = 0xff;
1643 sw->obj_instance[2] = 0xff;
1644 sw->state = SW_STATE_WAIT_ACTACK;
1645 sw->cbfn = cbfn;
1646 sw->cb_data = cb_data;
1647
1648 /* Open the file in order to fill some sw struct members */
1649 rc = sw_open_file(sw, fname);
1650 if (rc < 0) {
1651 sw->state = SW_STATE_NONE;
1652 return rc;
1653 }
1654 sw_close_file(sw);
1655
1656 return sw_activate(sw);
1657}
1658
1659static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1660 u_int8_t ts_nr, u_int8_t subslot_nr)
1661{
1662 ch->attrib = NM_ATT_ABIS_CHANNEL;
1663 ch->bts_port = bts_port;
1664 ch->timeslot = ts_nr;
1665 ch->subslot = subslot_nr;
1666}
1667
1668int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1669 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1670 u_int8_t tei)
1671{
1672 struct abis_om_hdr *oh;
1673 struct abis_nm_channel *ch;
1674 u_int8_t len = sizeof(*ch) + 2;
1675 struct msgb *msg = nm_msgb_alloc();
1676
1677 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1678 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1679 bts->bts_nr, trx_nr, 0xff);
1680
1681 msgb_tv_put(msg, NM_ATT_TEI, tei);
1682
1683 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1684 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1685
1686 return abis_nm_sendmsg(bts, msg);
1687}
1688
1689/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1690int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1691 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1692{
1693 struct gsm_bts *bts = trx->bts;
1694 struct abis_om_hdr *oh;
1695 struct abis_nm_channel *ch;
1696 struct msgb *msg = nm_msgb_alloc();
1697
1698 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1699 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1700 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1701
1702 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1703 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1704
1705 return abis_nm_sendmsg(bts, msg);
1706}
1707
1708#if 0
1709int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1710 struct abis_nm_abis_channel *chan)
1711{
1712}
1713#endif
1714
1715int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1716 u_int8_t e1_port, u_int8_t e1_timeslot,
1717 u_int8_t e1_subslot)
1718{
1719 struct gsm_bts *bts = ts->trx->bts;
1720 struct abis_om_hdr *oh;
1721 struct abis_nm_channel *ch;
1722 struct msgb *msg = nm_msgb_alloc();
1723
1724 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1725 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1726 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1727
1728 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1729 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1730
1731 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1732 gsm_ts_name(ts),
1733 e1_port, e1_timeslot, e1_subslot);
1734
1735 return abis_nm_sendmsg(bts, msg);
1736}
1737
1738#if 0
1739int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1740 struct abis_nm_abis_channel *chan,
1741 u_int8_t subchan)
1742{
1743}
1744#endif
1745
1746/* Chapter 8.6.1 */
1747int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1748{
1749 struct abis_om_hdr *oh;
1750 struct msgb *msg = nm_msgb_alloc();
1751 u_int8_t *cur;
1752
1753 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1754
1755 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1756 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1757 cur = msgb_put(msg, attr_len);
1758 memcpy(cur, attr, attr_len);
1759
1760 return abis_nm_sendmsg(bts, msg);
1761}
1762
1763/* Chapter 8.6.2 */
1764int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1765{
1766 struct abis_om_hdr *oh;
1767 struct msgb *msg = nm_msgb_alloc();
1768 u_int8_t *cur;
1769
1770 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1771
1772 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1773 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1774 trx->bts->bts_nr, trx->nr, 0xff);
1775 cur = msgb_put(msg, attr_len);
1776 memcpy(cur, attr, attr_len);
1777
1778 return abis_nm_sendmsg(trx->bts, msg);
1779}
1780
Harald Weltef2eb2782009-08-09 21:49:48 +02001781static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1782{
1783 int i;
1784
1785 /* As it turns out, the BS-11 has some very peculiar restrictions
1786 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301787 switch (ts->trx->bts->type) {
1788 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001789 switch (chan_comb) {
1790 case NM_CHANC_TCHHalf:
1791 case NM_CHANC_TCHHalf2:
1792 /* not supported */
1793 return -EINVAL;
1794 case NM_CHANC_SDCCH:
1795 /* only one SDCCH/8 per TRX */
1796 for (i = 0; i < TRX_NR_TS; i++) {
1797 if (i == ts->nr)
1798 continue;
1799 if (ts->trx->ts[i].nm_chan_comb ==
1800 NM_CHANC_SDCCH)
1801 return -EINVAL;
1802 }
1803 /* not allowed for TS0 of BCCH-TRX */
1804 if (ts->trx == ts->trx->bts->c0 &&
1805 ts->nr == 0)
1806 return -EINVAL;
1807 /* not on the same TRX that has a BCCH+SDCCH4
1808 * combination */
1809 if (ts->trx == ts->trx->bts->c0 &&
1810 (ts->trx->ts[0].nm_chan_comb == 5 ||
1811 ts->trx->ts[0].nm_chan_comb == 8))
1812 return -EINVAL;
1813 break;
1814 case NM_CHANC_mainBCCH:
1815 case NM_CHANC_BCCHComb:
1816 /* allowed only for TS0 of C0 */
1817 if (ts->trx != ts->trx->bts->c0 ||
1818 ts->nr != 0)
1819 return -EINVAL;
1820 break;
1821 case NM_CHANC_BCCH:
1822 /* allowed only for TS 2/4/6 of C0 */
1823 if (ts->trx != ts->trx->bts->c0)
1824 return -EINVAL;
1825 if (ts->nr != 2 && ts->nr != 4 &&
1826 ts->nr != 6)
1827 return -EINVAL;
1828 break;
1829 case 8: /* this is not like 08.58, but in fact
1830 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1831 /* FIXME: only one CBCH allowed per cell */
1832 break;
1833 }
Harald Welte76ba8812009-12-02 02:45:23 +05301834 break;
1835 case GSM_BTS_TYPE_NANOBTS:
1836 switch (ts->nr) {
1837 case 0:
1838 if (ts->trx->nr == 0) {
1839 /* only on TRX0 */
1840 switch (chan_comb) {
1841 case NM_CHANC_BCCH:
1842 case NM_CHANC_mainBCCH:
1843 case NM_CHANC_BCCHComb:
1844 return 0;
1845 break;
1846 default:
1847 return -EINVAL;
1848 }
1849 } else {
1850 switch (chan_comb) {
1851 case NM_CHANC_TCHFull:
1852 case NM_CHANC_TCHHalf:
1853 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1854 return 0;
1855 default:
1856 return -EINVAL;
1857 }
1858 }
1859 break;
1860 case 1:
1861 if (ts->trx->nr == 0) {
1862 switch (chan_comb) {
1863 case NM_CHANC_SDCCH_CBCH:
1864 if (ts->trx->ts[0].nm_chan_comb ==
1865 NM_CHANC_mainBCCH)
1866 return 0;
1867 return -EINVAL;
1868 case NM_CHANC_SDCCH:
1869 case NM_CHANC_TCHFull:
1870 case NM_CHANC_TCHHalf:
1871 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1872 case NM_CHANC_IPAC_TCHFull_PDCH:
1873 return 0;
1874 }
1875 } else {
1876 switch (chan_comb) {
1877 case NM_CHANC_SDCCH:
1878 case NM_CHANC_TCHFull:
1879 case NM_CHANC_TCHHalf:
1880 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1881 return 0;
1882 default:
1883 return -EINVAL;
1884 }
1885 }
1886 break;
1887 case 2:
1888 case 3:
1889 case 4:
1890 case 5:
1891 case 6:
1892 case 7:
1893 switch (chan_comb) {
1894 case NM_CHANC_TCHFull:
1895 case NM_CHANC_TCHHalf:
1896 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1897 return 0;
1898 case NM_CHANC_IPAC_PDCH:
1899 case NM_CHANC_IPAC_TCHFull_PDCH:
1900 if (ts->trx->nr == 0)
1901 return 0;
1902 else
1903 return -EINVAL;
1904 }
1905 break;
1906 }
1907 return -EINVAL;
1908 default:
1909 /* unknown BTS type */
1910 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001911 }
1912 return 0;
1913}
1914
Harald Welte59b04682009-06-10 05:40:52 +08001915/* Chapter 8.6.3 */
1916int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1917{
1918 struct gsm_bts *bts = ts->trx->bts;
1919 struct abis_om_hdr *oh;
1920 u_int16_t arfcn = htons(ts->trx->arfcn);
1921 u_int8_t zero = 0x00;
1922 struct msgb *msg = nm_msgb_alloc();
1923 u_int8_t len = 2 + 2;
1924
1925 if (bts->type == GSM_BTS_TYPE_BS11)
1926 len += 4 + 2 + 2 + 3;
1927
1928 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001929 if (verify_chan_comb(ts, chan_comb) < 0) {
1930 msgb_free(msg);
1931 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1932 return -EINVAL;
1933 }
1934 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001935
1936 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1937 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1938 NM_OC_CHANNEL, bts->bts_nr,
1939 ts->trx->nr, ts->nr);
1940 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
1941 if (bts->type == GSM_BTS_TYPE_BS11)
1942 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
1943 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
1944 if (bts->type == GSM_BTS_TYPE_BS11) {
1945 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1946 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1947 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02001948 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001949 if (bts->type == GSM_BTS_TYPE_BS11)
1950 msgb_tlv_put(msg, 0x59, 1, &zero);
1951
1952 return abis_nm_sendmsg(bts, msg);
1953}
1954
1955int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
1956 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
1957{
1958 struct abis_om_hdr *oh;
1959 struct msgb *msg = nm_msgb_alloc();
1960 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1961 u_int8_t len = att_len;
1962
1963 if (nack) {
1964 len += 2;
1965 msgtype = NM_MT_SW_ACT_REQ_NACK;
1966 }
1967
1968 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1969 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1970
1971 if (attr) {
1972 u_int8_t *ptr = msgb_put(msg, att_len);
1973 memcpy(ptr, attr, att_len);
1974 }
1975 if (nack)
1976 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1977
1978 return abis_nm_sendmsg(bts, msg);
1979}
1980
1981int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
1982{
1983 struct msgb *msg = nm_msgb_alloc();
1984 struct abis_om_hdr *oh;
1985 u_int8_t *data;
1986
1987 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1988 fill_om_hdr(oh, len);
1989 data = msgb_put(msg, len);
1990 memcpy(data, rawmsg, len);
1991
1992 return abis_nm_sendmsg(bts, msg);
1993}
1994
1995/* Siemens specific commands */
1996static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
1997{
1998 struct abis_om_hdr *oh;
1999 struct msgb *msg = nm_msgb_alloc();
2000
2001 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2002 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2003 0xff, 0xff, 0xff);
2004
2005 return abis_nm_sendmsg(bts, msg);
2006}
2007
2008/* Chapter 8.9.2 */
2009int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2010{
2011 struct abis_om_hdr *oh;
2012 struct msgb *msg = nm_msgb_alloc();
2013
Harald Welte59b04682009-06-10 05:40:52 +08002014 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2015 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2016
Harald Welteb7284a92009-10-20 09:56:18 +02002017 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2018 DEBUGPC(DNM, "Sending OPSTART\n");
2019
Harald Welte59b04682009-06-10 05:40:52 +08002020 return abis_nm_sendmsg(bts, msg);
2021}
2022
2023/* Chapter 8.8.5 */
2024int 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 +02002025 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002026{
2027 struct abis_om_hdr *oh;
2028 struct msgb *msg = nm_msgb_alloc();
2029
2030 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2031 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2032 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2033
2034 return abis_nm_sendmsg(bts, msg);
2035}
2036
Harald Welte204317e2009-08-06 17:58:31 +02002037int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2038 u_int8_t e1_port1, u_int8_t ts1)
2039{
2040 struct abis_om_hdr *oh;
2041 struct msgb *msg = nm_msgb_alloc();
2042 u_int8_t *attr;
2043
2044 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2045 e1_port0, ts0, e1_port1, ts1);
2046
2047 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2048 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2049 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2050
2051 attr = msgb_put(msg, 3);
2052 attr[0] = NM_ATT_MDROP_LINK;
2053 attr[1] = e1_port0;
2054 attr[2] = ts0;
2055
2056 attr = msgb_put(msg, 3);
2057 attr[0] = NM_ATT_MDROP_NEXT;
2058 attr[1] = e1_port1;
2059 attr[2] = ts1;
2060
2061 return abis_nm_sendmsg(bts, msg);
2062}
Harald Welte59b04682009-06-10 05:40:52 +08002063
Harald Welte0bf8e302009-08-08 00:02:36 +02002064/* Chapter 8.7.1 */
2065int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2066 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2067 u_int8_t test_nr, u_int8_t auton_report,
2068 u_int8_t *phys_config, u_int16_t phys_config_len)
2069{
2070 struct abis_om_hdr *oh;
2071 struct msgb *msg = nm_msgb_alloc();
2072 int len = 4; /* 2 TV attributes */
2073
2074 DEBUGP(DNM, "PEFORM TEST\n");
2075
2076 if (phys_config_len)
2077 len += 3 + phys_config_len;
2078
2079 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2080 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2081 obj_class, bts_nr, trx_nr, ts_nr);
2082 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2083 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2084 if (phys_config_len)
2085 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2086 phys_config);
2087
2088 return abis_nm_sendmsg(bts, msg);
2089}
2090
Harald Welte59b04682009-06-10 05:40:52 +08002091int abis_nm_event_reports(struct gsm_bts *bts, int on)
2092{
2093 if (on == 0)
2094 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2095 else
2096 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2097}
2098
2099/* Siemens (or BS-11) specific commands */
2100
2101int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2102{
2103 if (reconnect == 0)
2104 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2105 else
2106 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2107}
2108
2109int abis_nm_bs11_restart(struct gsm_bts *bts)
2110{
2111 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2112}
2113
2114
2115struct bs11_date_time {
2116 u_int16_t year;
2117 u_int8_t month;
2118 u_int8_t day;
2119 u_int8_t hour;
2120 u_int8_t min;
2121 u_int8_t sec;
2122} __attribute__((packed));
2123
2124
2125void get_bs11_date_time(struct bs11_date_time *aet)
2126{
2127 time_t t;
2128 struct tm *tm;
2129
2130 t = time(NULL);
2131 tm = localtime(&t);
2132 aet->sec = tm->tm_sec;
2133 aet->min = tm->tm_min;
2134 aet->hour = tm->tm_hour;
2135 aet->day = tm->tm_mday;
2136 aet->month = tm->tm_mon;
2137 aet->year = htons(1900 + tm->tm_year);
2138}
2139
2140int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2141{
2142 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2143}
2144
2145int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2146{
2147 if (begin)
2148 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2149 else
2150 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2151}
2152
2153int abis_nm_bs11_create_object(struct gsm_bts *bts,
2154 enum abis_bs11_objtype type, u_int8_t idx,
2155 u_int8_t attr_len, const u_int8_t *attr)
2156{
2157 struct abis_om_hdr *oh;
2158 struct msgb *msg = nm_msgb_alloc();
2159 u_int8_t *cur;
2160
2161 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2162 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2163 NM_OC_BS11, type, 0, idx);
2164 cur = msgb_put(msg, attr_len);
2165 memcpy(cur, attr, attr_len);
2166
2167 return abis_nm_sendmsg(bts, msg);
2168}
2169
2170int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2171 enum abis_bs11_objtype type, u_int8_t idx)
2172{
2173 struct abis_om_hdr *oh;
2174 struct msgb *msg = nm_msgb_alloc();
2175
2176 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2177 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2178 NM_OC_BS11, type, 0, idx);
2179
2180 return abis_nm_sendmsg(bts, msg);
2181}
2182
2183int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2184{
2185 struct abis_om_hdr *oh;
2186 struct msgb *msg = nm_msgb_alloc();
2187 u_int8_t zero = 0x00;
2188
2189 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2190 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2191 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2192 msgb_tlv_put(msg, 0x99, 1, &zero);
2193
2194 return abis_nm_sendmsg(bts, msg);
2195}
2196
2197int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2198{
2199 struct abis_om_hdr *oh;
2200 struct msgb *msg = nm_msgb_alloc();
2201
2202 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2203 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002204 idx, 0xff, 0xff);
2205
2206 return abis_nm_sendmsg(bts, msg);
2207}
2208
2209int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2210{
2211 struct abis_om_hdr *oh;
2212 struct msgb *msg = nm_msgb_alloc();
2213
2214 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2215 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2216 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002217
2218 return abis_nm_sendmsg(bts, msg);
2219}
2220
2221static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2222int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2223{
2224 struct abis_om_hdr *oh;
2225 struct msgb *msg = nm_msgb_alloc();
2226
2227 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2228 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2229 0xff, 0xff, 0xff);
2230 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2231
2232 return abis_nm_sendmsg(bts, msg);
2233}
2234
2235/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002236int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welte59b04682009-06-10 05:40:52 +08002237 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2238 u_int8_t tei)
2239{
2240 struct abis_om_hdr *oh;
2241 struct abis_nm_channel *ch;
2242 struct msgb *msg = nm_msgb_alloc();
2243
2244 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2245 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2246 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2247
2248 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2249 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2250 msgb_tv_put(msg, NM_ATT_TEI, tei);
2251
2252 return abis_nm_sendmsg(bts, msg);
2253}
2254
2255int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2256{
2257 struct abis_om_hdr *oh;
2258 struct msgb *msg = nm_msgb_alloc();
2259
2260 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2261 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2262 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2263 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2264
2265 return abis_nm_sendmsg(trx->bts, msg);
2266}
2267
2268int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2269{
2270 struct abis_om_hdr *oh;
2271 struct msgb *msg = nm_msgb_alloc();
2272 u_int8_t attr = NM_ATT_BS11_TXPWR;
2273
2274 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2275 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2276 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2277 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2278
2279 return abis_nm_sendmsg(trx->bts, msg);
2280}
2281
2282int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2283{
2284 struct abis_om_hdr *oh;
2285 struct msgb *msg = nm_msgb_alloc();
2286 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2287
2288 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2289 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2290 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2291 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2292
2293 return abis_nm_sendmsg(bts, msg);
2294}
2295
2296int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2297{
2298 struct abis_om_hdr *oh;
2299 struct msgb *msg = nm_msgb_alloc();
2300 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2301 NM_ATT_BS11_CCLK_TYPE };
2302
2303 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2304 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2305 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2306 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2307
2308 return abis_nm_sendmsg(bts, msg);
2309
2310}
2311
2312//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002313
2314int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2315{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002316 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2317}
2318
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002319int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2320{
2321 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2322}
2323
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002324int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2325{
Harald Welte59b04682009-06-10 05:40:52 +08002326 struct abis_om_hdr *oh;
2327 struct msgb *msg = nm_msgb_alloc();
2328 struct bs11_date_time bdt;
2329
2330 get_bs11_date_time(&bdt);
2331
2332 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2333 if (on) {
2334 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002335 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002336 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2337 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2338 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2339 sizeof(bdt), (u_int8_t *) &bdt);
2340 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002341 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002342 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002343 strlen(name), (u_int8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002344 } else {
2345 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2346 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2347 }
2348
2349 return abis_nm_sendmsg(bts, msg);
2350}
2351
2352int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2353{
2354 struct abis_om_hdr *oh;
2355 struct msgb *msg;
2356
2357 if (strlen(password) != 10)
2358 return -EINVAL;
2359
2360 msg = nm_msgb_alloc();
2361 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2362 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2363 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2364 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2365
2366 return abis_nm_sendmsg(bts, msg);
2367}
2368
2369/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2370int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2371{
2372 struct abis_om_hdr *oh;
2373 struct msgb *msg;
2374 u_int8_t tlv_value;
2375
2376 msg = nm_msgb_alloc();
2377 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2378 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2379 BS11_OBJ_LI, 0x00, 0x00);
2380
2381 if (locked)
2382 tlv_value = BS11_LI_PLL_LOCKED;
2383 else
2384 tlv_value = BS11_LI_PLL_STANDALONE;
2385
2386 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2387
2388 return abis_nm_sendmsg(bts, msg);
2389}
2390
Daniel Willmann10b07db2010-01-07 00:54:01 +01002391/* Set the calibration value of the PLL (work value/set value)
2392 * It depends on the login which one is changed */
2393int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2394{
2395 struct abis_om_hdr *oh;
2396 struct msgb *msg;
2397 u_int8_t tlv_value[2];
2398
2399 msg = nm_msgb_alloc();
2400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2401 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2402 BS11_OBJ_TRX1, 0x00, 0x00);
2403
2404 tlv_value[0] = value>>8;
2405 tlv_value[1] = value&0xff;
2406
2407 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2408
2409 return abis_nm_sendmsg(bts, msg);
2410}
2411
Harald Welte59b04682009-06-10 05:40:52 +08002412int abis_nm_bs11_get_state(struct gsm_bts *bts)
2413{
2414 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2415}
2416
2417/* BS11 SWL */
2418
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002419void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002420
Harald Welte59b04682009-06-10 05:40:52 +08002421struct abis_nm_bs11_sw {
2422 struct gsm_bts *bts;
2423 char swl_fname[PATH_MAX];
2424 u_int8_t win_size;
2425 int forced;
2426 struct llist_head file_list;
2427 gsm_cbfn *user_cb; /* specified by the user */
2428};
2429static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2430
2431struct file_list_entry {
2432 struct llist_head list;
2433 char fname[PATH_MAX];
2434};
2435
2436struct file_list_entry *fl_dequeue(struct llist_head *queue)
2437{
2438 struct llist_head *lh;
2439
2440 if (llist_empty(queue))
2441 return NULL;
2442
2443 lh = queue->next;
2444 llist_del(lh);
2445
2446 return llist_entry(lh, struct file_list_entry, list);
2447}
2448
2449static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2450{
2451 char linebuf[255];
2452 struct llist_head *lh, *lh2;
2453 FILE *swl;
2454 int rc = 0;
2455
2456 swl = fopen(bs11_sw->swl_fname, "r");
2457 if (!swl)
2458 return -ENODEV;
2459
2460 /* zero the stale file list, if any */
2461 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2462 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002463 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002464 }
2465
2466 while (fgets(linebuf, sizeof(linebuf), swl)) {
2467 char file_id[12+1];
2468 char file_version[80+1];
2469 struct file_list_entry *fle;
2470 static char dir[PATH_MAX];
2471
2472 if (strlen(linebuf) < 4)
2473 continue;
2474
2475 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2476 if (rc < 0) {
2477 perror("ERR parsing SWL file");
2478 rc = -EINVAL;
2479 goto out;
2480 }
2481 if (rc < 2)
2482 continue;
2483
Harald Welte857e00d2009-06-26 20:25:23 +02002484 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002485 if (!fle) {
2486 rc = -ENOMEM;
2487 goto out;
2488 }
Harald Welte59b04682009-06-10 05:40:52 +08002489
2490 /* construct new filename */
2491 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2492 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2493 strcat(fle->fname, "/");
2494 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2495
2496 llist_add_tail(&fle->list, &bs11_sw->file_list);
2497 }
2498
2499out:
2500 fclose(swl);
2501 return rc;
2502}
2503
2504/* bs11 swload specific callback, passed to abis_nm core swload */
2505static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2506 struct msgb *msg, void *data, void *param)
2507{
2508 struct abis_nm_bs11_sw *bs11_sw = data;
2509 struct file_list_entry *fle;
2510 int rc = 0;
2511
2512 switch (event) {
2513 case NM_MT_LOAD_END_ACK:
2514 fle = fl_dequeue(&bs11_sw->file_list);
2515 if (fle) {
2516 /* start download the next file of our file list */
2517 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2518 bs11_sw->win_size,
2519 bs11_sw->forced,
2520 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002521 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002522 } else {
2523 /* activate the SWL */
2524 rc = abis_nm_software_activate(bs11_sw->bts,
2525 bs11_sw->swl_fname,
2526 bs11_swload_cbfn,
2527 bs11_sw);
2528 }
2529 break;
2530 case NM_MT_LOAD_SEG_ACK:
2531 case NM_MT_LOAD_END_NACK:
2532 case NM_MT_LOAD_INIT_ACK:
2533 case NM_MT_LOAD_INIT_NACK:
2534 case NM_MT_ACTIVATE_SW_NACK:
2535 case NM_MT_ACTIVATE_SW_ACK:
2536 default:
2537 /* fallthrough to the user callback */
2538 if (bs11_sw->user_cb)
2539 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2540 break;
2541 }
2542
2543 return rc;
2544}
2545
2546/* Siemens provides a SWL file that is a mere listing of all the other
2547 * files that are part of a software release. We need to upload first
2548 * the list file, and then each file that is listed in the list file */
2549int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2550 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2551{
2552 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2553 struct file_list_entry *fle;
2554 int rc = 0;
2555
2556 INIT_LLIST_HEAD(&bs11_sw->file_list);
2557 bs11_sw->bts = bts;
2558 bs11_sw->win_size = win_size;
2559 bs11_sw->user_cb = cbfn;
2560 bs11_sw->forced = forced;
2561
2562 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2563 rc = bs11_read_swl_file(bs11_sw);
2564 if (rc < 0)
2565 return rc;
2566
2567 /* dequeue next item in file list */
2568 fle = fl_dequeue(&bs11_sw->file_list);
2569 if (!fle)
2570 return -EINVAL;
2571
2572 /* start download the next file of our file list */
2573 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
2574 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002575 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002576 return rc;
2577}
2578
2579#if 0
2580static u_int8_t req_attr_btse[] = {
2581 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2582 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2583 NM_ATT_BS11_LMT_USER_NAME,
2584
2585 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2586
2587 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2588
2589 NM_ATT_BS11_SW_LOAD_STORED };
2590
2591static u_int8_t req_attr_btsm[] = {
2592 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2593 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2594 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2595 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2596#endif
2597
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002598static u_int8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002599 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2600 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2601 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2602
2603int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2604{
2605 struct abis_om_hdr *oh;
2606 struct msgb *msg = nm_msgb_alloc();
2607
2608 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2609 /* SiemensHW CCTRL object */
2610 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2611 0x03, 0x00, 0x00);
2612 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2613
2614 return abis_nm_sendmsg(bts, msg);
2615}
2616
2617int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2618{
2619 struct abis_om_hdr *oh;
2620 struct msgb *msg = nm_msgb_alloc();
2621 struct bs11_date_time aet;
2622
2623 get_bs11_date_time(&aet);
2624 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2625 /* SiemensHW CCTRL object */
2626 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2627 0xff, 0xff, 0xff);
2628 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2629
2630 return abis_nm_sendmsg(bts, msg);
2631}
2632
Daniel Willmann5655afe2009-08-10 11:49:36 +02002633int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2634{
2635 struct abis_om_hdr *oh;
2636 struct msgb *msg = nm_msgb_alloc();
2637 struct bs11_date_time aet;
2638
2639 get_bs11_date_time(&aet);
2640 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2641 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2642 bport, 0xff, 0x02);
2643 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2644
2645 return abis_nm_sendmsg(bts, msg);
2646}
2647
Harald Welte59b04682009-06-10 05:40:52 +08002648/* ip.access nanoBTS specific commands */
2649static const char ipaccess_magic[] = "com.ipaccess";
2650
2651
2652static int abis_nm_rx_ipacc(struct msgb *msg)
2653{
2654 struct abis_om_hdr *oh = msgb_l2(msg);
2655 struct abis_om_fom_hdr *foh;
2656 u_int8_t idstrlen = oh->data[0];
2657 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002658 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002659
2660 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002661 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002662 return -EINVAL;
2663 }
2664
2665 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002666 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002667
Harald Welteb7284a92009-10-20 09:56:18 +02002668 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002669
Harald Welte5aeedd42009-10-19 22:11:11 +02002670 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002671
2672 switch (foh->msg_type) {
2673 case NM_MT_IPACC_RSL_CONNECT_ACK:
2674 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte4206d982009-07-12 09:33:54 +02002675 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte59b04682009-06-10 05:40:52 +08002676 DEBUGPC(DNM, "IP=%s ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002677 inet_ntoa(*((struct in_addr *)
Harald Welte4206d982009-07-12 09:33:54 +02002678 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2679 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002680 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002681 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002682 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002683 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2684 DEBUGPC(DNM, "STREAM=0x%02x ",
2685 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002686 DEBUGPC(DNM, "\n");
2687 break;
2688 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002689 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002690 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002691 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002692 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2693 else
2694 DEBUGPC(DNM, "\n");
2695 break;
2696 case NM_MT_IPACC_SET_NVATTR_ACK:
2697 DEBUGPC(DNM, "SET NVATTR ACK\n");
2698 /* FIXME: decode and show the actual attributes */
2699 break;
2700 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002701 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002702 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002703 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002704 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2705 else
Harald Weltede4477a2009-12-24 12:20:20 +01002706 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002707 break;
Harald Welte21460f02009-07-03 11:26:45 +02002708 case NM_MT_IPACC_GET_NVATTR_ACK:
2709 DEBUGPC(DNM, "GET NVATTR ACK\n");
2710 /* FIXME: decode and show the actual attributes */
2711 break;
2712 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002713 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002714 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002715 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002716 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2717 else
Harald Weltede4477a2009-12-24 12:20:20 +01002718 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002719 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002720 case NM_MT_IPACC_SET_ATTR_ACK:
2721 DEBUGPC(DNM, "SET ATTR ACK\n");
2722 break;
2723 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002724 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002725 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002726 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002727 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2728 else
Harald Weltede4477a2009-12-24 12:20:20 +01002729 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002730 break;
Harald Welte59b04682009-06-10 05:40:52 +08002731 default:
2732 DEBUGPC(DNM, "unknown\n");
2733 break;
2734 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002735
2736 /* signal handling */
2737 switch (foh->msg_type) {
2738 case NM_MT_IPACC_RSL_CONNECT_NACK:
2739 case NM_MT_IPACC_SET_NVATTR_NACK:
2740 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002741 signal.bts = msg->trx->bts;
2742 signal.msg_type = foh->msg_type;
2743 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002744 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002745 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002746 signal.bts = msg->trx->bts;
2747 signal.msg_type = foh->msg_type;
2748 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002749 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002750 default:
2751 break;
2752 }
2753
Harald Welte59b04682009-06-10 05:40:52 +08002754 return 0;
2755}
2756
2757/* send an ip-access manufacturer specific message */
2758int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2759 u_int8_t obj_class, u_int8_t bts_nr,
2760 u_int8_t trx_nr, u_int8_t ts_nr,
2761 u_int8_t *attr, int attr_len)
2762{
2763 struct msgb *msg = nm_msgb_alloc();
2764 struct abis_om_hdr *oh;
2765 struct abis_om_fom_hdr *foh;
2766 u_int8_t *data;
2767
2768 /* construct the 12.21 OM header, observe the erroneous length */
2769 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2770 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2771 oh->mdisc = ABIS_OM_MDISC_MANUF;
2772
2773 /* add the ip.access magic */
2774 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2775 *data++ = sizeof(ipaccess_magic);
2776 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2777
2778 /* fill the 12.21 FOM header */
2779 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2780 foh->msg_type = msg_type;
2781 foh->obj_class = obj_class;
2782 foh->obj_inst.bts_nr = bts_nr;
2783 foh->obj_inst.trx_nr = trx_nr;
2784 foh->obj_inst.ts_nr = ts_nr;
2785
2786 if (attr && attr_len) {
2787 data = msgb_put(msg, attr_len);
2788 memcpy(data, attr, attr_len);
2789 }
2790
2791 return abis_nm_sendmsg(bts, msg);
2792}
2793
2794/* set some attributes in NVRAM */
Harald Weltef12c1052010-01-07 20:39:42 +01002795int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002796 int attr_len)
2797{
Harald Weltef12c1052010-01-07 20:39:42 +01002798 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2799 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002800 attr_len);
2801}
2802
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002803int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte5aeedd42009-10-19 22:11:11 +02002804 u_int32_t ip, u_int16_t port, u_int8_t stream)
2805{
2806 struct in_addr ia;
2807 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2808 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2809 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2810
2811 int attr_len = sizeof(attr);
2812
2813 ia.s_addr = htonl(ip);
2814 attr[1] = stream;
2815 attr[3] = port >> 8;
2816 attr[4] = port & 0xff;
2817 *(u_int32_t *)(attr+6) = ia.s_addr;
2818
2819 /* if ip == 0, we use the default IP */
2820 if (ip == 0)
2821 attr_len -= 5;
2822
2823 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002824 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002825
2826 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2827 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2828 trx->nr, 0xff, attr, attr_len);
2829}
2830
Harald Welte59b04682009-06-10 05:40:52 +08002831/* restart / reboot an ip.access nanoBTS */
2832int abis_nm_ipaccess_restart(struct gsm_bts *bts)
2833{
2834 return __simple_cmd(bts, NM_MT_IPACC_RESTART);
2835}
Harald Welte0dfc6232009-10-24 10:20:41 +02002836
2837int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2838 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2839 u_int8_t *attr, u_int8_t attr_len)
2840{
2841 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2842 obj_class, bts_nr, trx_nr, ts_nr,
2843 attr, attr_len);
2844}
Harald Weltebeeae412009-11-12 14:48:42 +01002845
Harald Welte3055e332010-03-14 15:37:43 +08002846void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2847{
2848 /* we simply reuse the GSM48 function and overwrite the RAC
2849 * with the Cell ID */
2850 gsm48_ra_id_by_bts(buf, bts);
2851 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2852}
2853
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002854void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2855{
2856 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2857
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01002858 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002859 if (!trx->bts || !trx->bts->oml_link)
2860 return;
2861
2862 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2863 trx->bts->bts_nr, trx->nr, 0xff,
2864 new_state);
2865}
2866
Harald Welte453141f2010-03-25 11:45:30 +08002867static const struct value_string ipacc_testres_names[] = {
2868 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2869 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2870 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2871 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2872 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2873 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002874};
2875
2876const char *ipacc_testres_name(u_int8_t res)
2877{
Harald Welte453141f2010-03-25 11:45:30 +08002878 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002879}
2880
Harald Weltebfc21092009-11-13 11:56:05 +01002881void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2882{
2883 cid->mcc = (buf[0] & 0xf) * 100;
2884 cid->mcc += (buf[0] >> 4) * 10;
2885 cid->mcc += (buf[1] & 0xf) * 1;
2886
2887 if (buf[1] >> 4 == 0xf) {
2888 cid->mnc = (buf[2] & 0xf) * 10;
2889 cid->mnc += (buf[2] >> 4) * 1;
2890 } else {
2891 cid->mnc = (buf[2] & 0xf) * 100;
2892 cid->mnc += (buf[2] >> 4) * 10;
2893 cid->mnc += (buf[1] >> 4) * 1;
2894 }
2895
Harald Welte161b4be2009-11-13 14:41:52 +01002896 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2897 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002898}
2899
Harald Weltebeeae412009-11-12 14:48:42 +01002900/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2901int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2902{
2903 u_int8_t *cur = buf;
2904 u_int16_t len;
2905
2906 memset(binf, 0, sizeof(binf));
2907
2908 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2909 return -EINVAL;
2910 cur++;
2911
2912 len = ntohs(*(u_int16_t *)cur);
2913 cur += 2;
2914
2915 binf->info_type = ntohs(*(u_int16_t *)cur);
2916 cur += 2;
2917
2918 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2919 binf->freq_qual = *cur >> 2;
2920
2921 binf->arfcn = *cur++ & 3 << 8;
2922 binf->arfcn |= *cur++;
2923
2924 if (binf->info_type & IPAC_BINF_RXLEV)
2925 binf->rx_lev = *cur & 0x3f;
2926 cur++;
2927
2928 if (binf->info_type & IPAC_BINF_RXQUAL)
2929 binf->rx_qual = *cur & 0x7;
2930 cur++;
2931
2932 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2933 binf->freq_err = ntohs(*(u_int16_t *)cur);
2934 cur += 2;
2935
2936 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2937 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2938 cur += 2;
2939
2940 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2941 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2942 cur += 4;
2943
2944 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte161b4be2009-11-13 14:41:52 +01002945 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002946 cur++;
2947
Harald Weltebfc21092009-11-13 11:56:05 +01002948 ipac_parse_cgi(&binf->cgi, cur);
2949 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002950
2951 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2952 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2953 cur += sizeof(binf->ba_list_si2);
2954 }
2955
2956 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2957 memcpy(binf->ba_list_si2bis, cur,
2958 sizeof(binf->ba_list_si2bis));
2959 cur += sizeof(binf->ba_list_si2bis);
2960 }
2961
2962 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2963 memcpy(binf->ba_list_si2ter, cur,
2964 sizeof(binf->ba_list_si2ter));
2965 cur += sizeof(binf->ba_list_si2ter);
2966 }
2967
2968 return 0;
2969}