blob: 09285bd434cd020053d3ffc06fef3626bac1d12e [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
Holger Hans Peter Freyther9aec6db2010-05-13 00:37:48 +0800681 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800682
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);
Holger Hans Peter Freyther9aec6db2010-05-13 00:37:48 +0800735 rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +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
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100825static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
826{
827 static const struct tlv_definition sw_descr_def = {
828 .def = {
829 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
830 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
831 },
832 };
833
834 u_int8_t tag;
835 u_int16_t tag_len;
836 const u_int8_t *val;
837 int ofs = 0, len;
838
839 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
840 * nested nature and the fact you have to assume it contains only two sub
841 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
842
843 if (sw_descr[0] != NM_ATT_SW_DESCR) {
844 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
845 return -1;
846 }
847 ofs += 1;
848
849 len = tlv_parse_one(&tag, &tag_len, &val,
850 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
851 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
852 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
853 return -2;
854 }
855 ofs += len;
856
857 len = tlv_parse_one(&tag, &tag_len, &val,
858 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
859 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
860 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
861 return -3;
862 }
863 ofs += len;
864
865 return ofs;
866}
867
Harald Welte59b04682009-06-10 05:40:52 +0800868static int abis_nm_rx_sw_act_req(struct msgb *mb)
869{
870 struct abis_om_hdr *oh = msgb_l2(mb);
871 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200872 struct tlv_parsed tp;
873 const u_int8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100874 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800875
Harald Welteb7284a92009-10-20 09:56:18 +0200876 debugp_foh(foh);
877
878 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800879
Harald Welte3055e332010-03-14 15:37:43 +0800880 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800881
882 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
883 foh->obj_inst.bts_nr,
884 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800885 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800886 foh->data, oh->length-sizeof(*foh));
887
Harald Welte59698fb2010-01-10 18:01:52 +0100888 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200889 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
890 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
891 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
892 DEBUGP(DNM, "SW config not found! Can't continue.\n");
893 return -EINVAL;
894 } else {
895 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
896 }
897
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100898 /* Use the first SW_DESCR present in SW config */
899 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
900 if (sw_descr_len < 0)
901 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200902
Harald Welte59b04682009-06-10 05:40:52 +0800903 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
904 foh->obj_inst.bts_nr,
905 foh->obj_inst.trx_nr,
906 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100907 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800908}
909
910/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
911static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
912{
913 struct abis_om_hdr *oh = msgb_l2(mb);
914 struct abis_om_fom_hdr *foh = msgb_l3(mb);
915 struct tlv_parsed tp;
916 u_int8_t adm_state;
917
Harald Welte59698fb2010-01-10 18:01:52 +0100918 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800919 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
920 return -EINVAL;
921
922 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
923
924 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
925}
926
927static int abis_nm_rx_lmt_event(struct msgb *mb)
928{
929 struct abis_om_hdr *oh = msgb_l2(mb);
930 struct abis_om_fom_hdr *foh = msgb_l3(mb);
931 struct tlv_parsed tp;
932
933 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100934 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800935 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
936 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
937 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
938 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
939 }
940 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
941 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
942 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
943 DEBUGPC(DNM, "Level=%u ", level);
944 }
945 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
946 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
947 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
948 DEBUGPC(DNM, "Username=%s ", name);
949 }
950 DEBUGPC(DNM, "\n");
951 /* FIXME: parse LMT LOGON TIME */
952 return 0;
953}
954
955/* Receive a OML NM Message from BTS */
956static int abis_nm_rcvmsg_fom(struct msgb *mb)
957{
958 struct abis_om_hdr *oh = msgb_l2(mb);
959 struct abis_om_fom_hdr *foh = msgb_l3(mb);
960 u_int8_t mt = foh->msg_type;
961
962 /* check for unsolicited message */
963 if (is_report(mt))
964 return abis_nm_rcvmsg_report(mb);
965
966 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
967 return abis_nm_rcvmsg_sw(mb);
968
969 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
970 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200971
Harald Welteb7284a92009-10-20 09:56:18 +0200972 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200973
Harald Welte453141f2010-03-25 11:45:30 +0800974 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +0800975
Harald Welte59698fb2010-01-10 18:01:52 +0100976 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800977 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200978 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +0800979 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
980 else
981 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200982
Harald Welte6a21c732009-11-17 06:09:56 +0100983 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200984 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800985 }
986#if 0
987 /* check if last message is to be acked */
988 if (is_ack_nack(nmh->last_msgtype)) {
989 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100990 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800991 /* we got our ACK, continue sending the next msg */
992 } else if (mt == MT_NACK(nmh->last_msgtype)) {
993 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100994 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800995 /* FIXME: somehow signal this to the caller */
996 } else {
997 /* really strange things happen */
998 return -EINVAL;
999 }
1000 }
1001#endif
1002
1003 switch (mt) {
1004 case NM_MT_CHG_ADM_STATE_ACK:
1005 return abis_nm_rx_chg_adm_state_ack(mb);
1006 break;
1007 case NM_MT_SW_ACT_REQ:
1008 return abis_nm_rx_sw_act_req(mb);
1009 break;
1010 case NM_MT_BS11_LMT_SESSION:
1011 return abis_nm_rx_lmt_event(mb);
1012 break;
Harald Welte204317e2009-08-06 17:58:31 +02001013 case NM_MT_CONN_MDROP_LINK_ACK:
1014 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1015 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001016 case NM_MT_IPACC_RESTART_ACK:
1017 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1018 break;
1019 case NM_MT_IPACC_RESTART_NACK:
1020 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1021 break;
Harald Welte59b04682009-06-10 05:40:52 +08001022 }
1023
1024 return 0;
1025}
1026
1027static int abis_nm_rx_ipacc(struct msgb *mb);
1028
1029static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1030{
1031 int rc;
1032 int bts_type = mb->trx->bts->type;
1033
1034 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001035 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001036 rc = abis_nm_rx_ipacc(mb);
1037 break;
1038 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001039 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1040 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001041 rc = 0;
1042 break;
1043 }
1044
1045 return rc;
1046}
1047
1048/* High-Level API */
1049/* Entry-point where L2 OML from BTS enters the NM code */
1050int abis_nm_rcvmsg(struct msgb *msg)
1051{
1052 struct abis_om_hdr *oh = msgb_l2(msg);
1053 int rc = 0;
1054
1055 /* Various consistency checks */
1056 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001057 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001058 oh->placement);
1059 return -EINVAL;
1060 }
1061 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001062 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001063 oh->sequence);
1064 return -EINVAL;
1065 }
1066#if 0
1067 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1068 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1069 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001070 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001071 oh->length + sizeof(*oh), l2_len);
1072 return -EINVAL;
1073 }
1074 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001075 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 +08001076#endif
1077 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1078
1079 switch (oh->mdisc) {
1080 case ABIS_OM_MDISC_FOM:
1081 rc = abis_nm_rcvmsg_fom(msg);
1082 break;
1083 case ABIS_OM_MDISC_MANUF:
1084 rc = abis_nm_rcvmsg_manuf(msg);
1085 break;
1086 case ABIS_OM_MDISC_MMI:
1087 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001088 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001089 oh->mdisc);
1090 break;
1091 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001092 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001093 oh->mdisc);
1094 return -EINVAL;
1095 }
1096
1097 msgb_free(msg);
1098 return rc;
1099}
1100
1101#if 0
1102/* initialized all resources */
1103struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1104{
1105 struct abis_nm_h *nmh;
1106
1107 nmh = malloc(sizeof(*nmh));
1108 if (!nmh)
1109 return NULL;
1110
1111 nmh->cfg = cfg;
1112
1113 return nmh;
1114}
1115
1116/* free all resources */
1117void abis_nm_fini(struct abis_nm_h *nmh)
1118{
1119 free(nmh);
1120}
1121#endif
1122
1123/* Here we are trying to define a high-level API that can be used by
1124 * the actual BSC implementation. However, the architecture is currently
1125 * still under design. Ideally the calls to this API would be synchronous,
1126 * while the underlying stack behind the APi runs in a traditional select
1127 * based state machine.
1128 */
1129
1130/* 6.2 Software Load: */
1131enum sw_state {
1132 SW_STATE_NONE,
1133 SW_STATE_WAIT_INITACK,
1134 SW_STATE_WAIT_SEGACK,
1135 SW_STATE_WAIT_ENDACK,
1136 SW_STATE_WAIT_ACTACK,
1137 SW_STATE_ERROR,
1138};
1139
1140struct abis_nm_sw {
1141 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001142 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +08001143 gsm_cbfn *cbfn;
1144 void *cb_data;
1145 int forced;
1146
1147 /* this will become part of the SW LOAD INITIATE */
1148 u_int8_t obj_class;
1149 u_int8_t obj_instance[3];
1150
1151 u_int8_t file_id[255];
1152 u_int8_t file_id_len;
1153
1154 u_int8_t file_version[255];
1155 u_int8_t file_version_len;
1156
1157 u_int8_t window_size;
1158 u_int8_t seg_in_window;
1159
1160 int fd;
1161 FILE *stream;
1162 enum sw_state state;
1163 int last_seg;
1164};
1165
1166static struct abis_nm_sw g_sw;
1167
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001168static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1169{
1170 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1171 msgb_v_put(msg, NM_ATT_SW_DESCR);
1172 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1173 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1174 sw->file_version);
1175 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1176 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1177 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1178 sw->file_version);
1179 } else {
1180 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1181 }
1182}
1183
Harald Welte59b04682009-06-10 05:40:52 +08001184/* 6.2.1 / 8.3.1: Load Data Initiate */
1185static int sw_load_init(struct abis_nm_sw *sw)
1186{
1187 struct abis_om_hdr *oh;
1188 struct msgb *msg = nm_msgb_alloc();
1189 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1190
1191 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1192 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1193 sw->obj_instance[0], sw->obj_instance[1],
1194 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001195
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001196 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001197 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1198
1199 return abis_nm_sendmsg(sw->bts, msg);
1200}
1201
1202static int is_last_line(FILE *stream)
1203{
1204 char next_seg_buf[256];
1205 long pos;
1206
1207 /* check if we're sending the last line */
1208 pos = ftell(stream);
1209 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1210 fseek(stream, pos, SEEK_SET);
1211 return 1;
1212 }
1213
1214 fseek(stream, pos, SEEK_SET);
1215 return 0;
1216}
1217
1218/* 6.2.2 / 8.3.2 Load Data Segment */
1219static int sw_load_segment(struct abis_nm_sw *sw)
1220{
1221 struct abis_om_hdr *oh;
1222 struct msgb *msg = nm_msgb_alloc();
1223 char seg_buf[256];
1224 char *line_buf = seg_buf+2;
1225 unsigned char *tlv;
1226 u_int8_t len;
1227
1228 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1229
1230 switch (sw->bts->type) {
1231 case GSM_BTS_TYPE_BS11:
1232 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1233 perror("fgets reading segment");
1234 return -EINVAL;
1235 }
1236 seg_buf[0] = 0x00;
1237
1238 /* check if we're sending the last line */
1239 sw->last_seg = is_last_line(sw->stream);
1240 if (sw->last_seg)
1241 seg_buf[1] = 0;
1242 else
1243 seg_buf[1] = 1 + sw->seg_in_window++;
1244
1245 len = strlen(line_buf) + 2;
1246 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1247 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1248 /* BS11 wants CR + LF in excess of the TLV length !?! */
1249 tlv[1] -= 2;
1250
1251 /* we only now know the exact length for the OM hdr */
1252 len = strlen(line_buf)+2;
1253 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001254 case GSM_BTS_TYPE_NANOBTS: {
1255 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1256 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1257 if (len < 0) {
1258 perror("read failed");
1259 return -EINVAL;
1260 }
1261
1262 if (len != IPACC_SEGMENT_SIZE)
1263 sw->last_seg = 1;
1264
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001265 ++sw->seg_in_window;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001266 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1267 len += 3;
1268 break;
1269 }
Harald Welte59b04682009-06-10 05:40:52 +08001270 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001271 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001272 /* FIXME: Other BTS types */
1273 return -1;
1274 }
1275
1276 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1277 sw->obj_instance[0], sw->obj_instance[1],
1278 sw->obj_instance[2]);
1279
1280 return abis_nm_sendmsg(sw->bts, msg);
1281}
1282
1283/* 6.2.4 / 8.3.4 Load Data End */
1284static int sw_load_end(struct abis_nm_sw *sw)
1285{
1286 struct abis_om_hdr *oh;
1287 struct msgb *msg = nm_msgb_alloc();
1288 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1289
1290 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1291 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1292 sw->obj_instance[0], sw->obj_instance[1],
1293 sw->obj_instance[2]);
1294
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001295 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001296 return abis_nm_sendmsg(sw->bts, msg);
1297}
1298
1299/* Activate the specified software into the BTS */
1300static int sw_activate(struct abis_nm_sw *sw)
1301{
1302 struct abis_om_hdr *oh;
1303 struct msgb *msg = nm_msgb_alloc();
1304 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1305
1306 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1307 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1308 sw->obj_instance[0], sw->obj_instance[1],
1309 sw->obj_instance[2]);
1310
1311 /* FIXME: this is BS11 specific format */
1312 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1313 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1314 sw->file_version);
1315
1316 return abis_nm_sendmsg(sw->bts, msg);
1317}
1318
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001319struct sdp_firmware {
1320 char magic[4];
1321 char more_magic[4];
1322 unsigned int header_length;
1323 unsigned int file_length;
1324} __attribute__ ((packed));
1325
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001326static int parse_sdp_header(struct abis_nm_sw *sw)
1327{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001328 struct sdp_firmware firmware_header;
1329 int rc;
1330 struct stat stat;
1331
1332 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1333 if (rc != sizeof(firmware_header)) {
1334 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1335 return -1;
1336 }
1337
1338 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1339 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1340 return -1;
1341 }
1342
1343 if (firmware_header.more_magic[0] != 0x10 ||
1344 firmware_header.more_magic[1] != 0x02 ||
1345 firmware_header.more_magic[2] != 0x00 ||
1346 firmware_header.more_magic[3] != 0x00) {
1347 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1348 return -1;
1349 }
1350
1351
1352 if (fstat(sw->fd, &stat) == -1) {
1353 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1354 return -1;
1355 }
1356
1357 if (ntohl(firmware_header.file_length) != stat.st_size) {
1358 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1359 return -1;
1360 }
1361
1362 /* go back to the start as we checked the whole filesize.. */
1363 lseek(sw->fd, 0l, SEEK_SET);
1364 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1365 "There might be checksums in the file that are not\n"
1366 "verified and incomplete firmware might be flashed.\n"
1367 "There is absolutely no WARRANTY that flashing will\n"
1368 "work.\n");
1369 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001370}
1371
Harald Welte59b04682009-06-10 05:40:52 +08001372static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1373{
1374 char file_id[12+1];
1375 char file_version[80+1];
1376 int rc;
1377
1378 sw->fd = open(fname, O_RDONLY);
1379 if (sw->fd < 0)
1380 return sw->fd;
1381
1382 switch (sw->bts->type) {
1383 case GSM_BTS_TYPE_BS11:
1384 sw->stream = fdopen(sw->fd, "r");
1385 if (!sw->stream) {
1386 perror("fdopen");
1387 return -1;
1388 }
1389 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001390 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001391 file_id, file_version);
1392 if (rc != 2) {
1393 perror("parsing header line of software file");
1394 return -1;
1395 }
1396 strcpy((char *)sw->file_id, file_id);
1397 sw->file_id_len = strlen(file_id);
1398 strcpy((char *)sw->file_version, file_version);
1399 sw->file_version_len = strlen(file_version);
1400 /* rewind to start of file */
1401 rewind(sw->stream);
1402 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001403 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001404 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001405 rc = parse_sdp_header(sw);
1406 if (rc < 0) {
1407 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1408 return -1;
1409 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001410
1411 strcpy((char *)sw->file_id, "id");
1412 sw->file_id_len = 3;
1413 strcpy((char *)sw->file_version, "version");
1414 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001415 break;
Harald Welte59b04682009-06-10 05:40:52 +08001416 default:
1417 /* We don't know how to treat them yet */
1418 close(sw->fd);
1419 return -EINVAL;
1420 }
1421
1422 return 0;
1423}
1424
1425static void sw_close_file(struct abis_nm_sw *sw)
1426{
1427 switch (sw->bts->type) {
1428 case GSM_BTS_TYPE_BS11:
1429 fclose(sw->stream);
1430 break;
1431 default:
1432 close(sw->fd);
1433 break;
1434 }
1435}
1436
1437/* Fill the window */
1438static int sw_fill_window(struct abis_nm_sw *sw)
1439{
1440 int rc;
1441
1442 while (sw->seg_in_window < sw->window_size) {
1443 rc = sw_load_segment(sw);
1444 if (rc < 0)
1445 return rc;
1446 if (sw->last_seg)
1447 break;
1448 }
1449 return 0;
1450}
1451
1452/* callback function from abis_nm_rcvmsg() handler */
1453static int abis_nm_rcvmsg_sw(struct msgb *mb)
1454{
1455 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1456 int rc = -1;
1457 struct abis_nm_sw *sw = &g_sw;
1458 enum sw_state old_state = sw->state;
1459
1460 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1461
1462 switch (sw->state) {
1463 case SW_STATE_WAIT_INITACK:
1464 switch (foh->msg_type) {
1465 case NM_MT_LOAD_INIT_ACK:
1466 /* fill window with segments */
1467 if (sw->cbfn)
1468 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1469 NM_MT_LOAD_INIT_ACK, mb,
1470 sw->cb_data, NULL);
1471 rc = sw_fill_window(sw);
1472 sw->state = SW_STATE_WAIT_SEGACK;
1473 break;
1474 case NM_MT_LOAD_INIT_NACK:
1475 if (sw->forced) {
1476 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1477 "Init NACK\n");
1478 if (sw->cbfn)
1479 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1480 NM_MT_LOAD_INIT_ACK, mb,
1481 sw->cb_data, NULL);
1482 rc = sw_fill_window(sw);
1483 sw->state = SW_STATE_WAIT_SEGACK;
1484 } else {
1485 DEBUGP(DNM, "Software Load Init NACK\n");
1486 /* FIXME: cause */
1487 if (sw->cbfn)
1488 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1489 NM_MT_LOAD_INIT_NACK, mb,
1490 sw->cb_data, NULL);
1491 sw->state = SW_STATE_ERROR;
1492 }
1493 break;
1494 }
1495 break;
1496 case SW_STATE_WAIT_SEGACK:
1497 switch (foh->msg_type) {
1498 case NM_MT_LOAD_SEG_ACK:
1499 if (sw->cbfn)
1500 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1501 NM_MT_LOAD_SEG_ACK, mb,
1502 sw->cb_data, NULL);
1503 sw->seg_in_window = 0;
1504 if (!sw->last_seg) {
1505 /* fill window with more segments */
1506 rc = sw_fill_window(sw);
1507 sw->state = SW_STATE_WAIT_SEGACK;
1508 } else {
1509 /* end the transfer */
1510 sw->state = SW_STATE_WAIT_ENDACK;
1511 rc = sw_load_end(sw);
1512 }
1513 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001514 case NM_MT_LOAD_ABORT:
1515 if (sw->cbfn)
1516 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1517 NM_MT_LOAD_ABORT, mb,
1518 sw->cb_data, NULL);
1519 break;
Harald Welte59b04682009-06-10 05:40:52 +08001520 }
1521 break;
1522 case SW_STATE_WAIT_ENDACK:
1523 switch (foh->msg_type) {
1524 case NM_MT_LOAD_END_ACK:
1525 sw_close_file(sw);
1526 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1527 sw->bts->nr);
1528 sw->state = SW_STATE_NONE;
1529 if (sw->cbfn)
1530 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1531 NM_MT_LOAD_END_ACK, mb,
1532 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001533 rc = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001534 break;
1535 case NM_MT_LOAD_END_NACK:
1536 if (sw->forced) {
1537 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1538 "End NACK\n");
1539 sw->state = SW_STATE_NONE;
1540 if (sw->cbfn)
1541 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1542 NM_MT_LOAD_END_ACK, mb,
1543 sw->cb_data, NULL);
1544 } else {
1545 DEBUGP(DNM, "Software Load End NACK\n");
1546 /* FIXME: cause */
1547 sw->state = SW_STATE_ERROR;
1548 if (sw->cbfn)
1549 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1550 NM_MT_LOAD_END_NACK, mb,
1551 sw->cb_data, NULL);
1552 }
1553 break;
1554 }
1555 case SW_STATE_WAIT_ACTACK:
1556 switch (foh->msg_type) {
1557 case NM_MT_ACTIVATE_SW_ACK:
1558 /* we're done */
1559 DEBUGP(DNM, "Activate Software DONE!\n");
1560 sw->state = SW_STATE_NONE;
1561 rc = 0;
1562 if (sw->cbfn)
1563 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1564 NM_MT_ACTIVATE_SW_ACK, mb,
1565 sw->cb_data, NULL);
1566 break;
1567 case NM_MT_ACTIVATE_SW_NACK:
1568 DEBUGP(DNM, "Activate Software NACK\n");
1569 /* FIXME: cause */
1570 sw->state = SW_STATE_ERROR;
1571 if (sw->cbfn)
1572 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1573 NM_MT_ACTIVATE_SW_NACK, mb,
1574 sw->cb_data, NULL);
1575 break;
1576 }
1577 case SW_STATE_NONE:
1578 switch (foh->msg_type) {
1579 case NM_MT_ACTIVATE_SW_ACK:
1580 rc = 0;
1581 break;
1582 }
1583 break;
1584 case SW_STATE_ERROR:
1585 break;
1586 }
1587
1588 if (rc)
1589 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1590 foh->msg_type, old_state, sw->state);
1591
1592 return rc;
1593}
1594
1595/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001596int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte59b04682009-06-10 05:40:52 +08001597 u_int8_t win_size, int forced,
1598 gsm_cbfn *cbfn, void *cb_data)
1599{
1600 struct abis_nm_sw *sw = &g_sw;
1601 int rc;
1602
1603 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1604 bts->nr, fname);
1605
1606 if (sw->state != SW_STATE_NONE)
1607 return -EBUSY;
1608
1609 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001610 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001611
1612 switch (bts->type) {
1613 case GSM_BTS_TYPE_BS11:
1614 sw->obj_class = NM_OC_SITE_MANAGER;
1615 sw->obj_instance[0] = 0xff;
1616 sw->obj_instance[1] = 0xff;
1617 sw->obj_instance[2] = 0xff;
1618 break;
1619 case GSM_BTS_TYPE_NANOBTS:
1620 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001621 sw->obj_instance[0] = sw->bts->nr;
1622 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001623 sw->obj_instance[2] = 0xff;
1624 break;
1625 case GSM_BTS_TYPE_UNKNOWN:
1626 default:
1627 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1628 return -1;
1629 break;
1630 }
Harald Welte59b04682009-06-10 05:40:52 +08001631 sw->window_size = win_size;
1632 sw->state = SW_STATE_WAIT_INITACK;
1633 sw->cbfn = cbfn;
1634 sw->cb_data = cb_data;
1635 sw->forced = forced;
1636
1637 rc = sw_open_file(sw, fname);
1638 if (rc < 0) {
1639 sw->state = SW_STATE_NONE;
1640 return rc;
1641 }
1642
1643 return sw_load_init(sw);
1644}
1645
1646int abis_nm_software_load_status(struct gsm_bts *bts)
1647{
1648 struct abis_nm_sw *sw = &g_sw;
1649 struct stat st;
1650 int rc, percent;
1651
1652 rc = fstat(sw->fd, &st);
1653 if (rc < 0) {
1654 perror("ERROR during stat");
1655 return rc;
1656 }
1657
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001658 if (sw->stream)
1659 percent = (ftell(sw->stream) * 100) / st.st_size;
1660 else
1661 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001662 return percent;
1663}
1664
1665/* Activate the specified software into the BTS */
1666int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1667 gsm_cbfn *cbfn, void *cb_data)
1668{
1669 struct abis_nm_sw *sw = &g_sw;
1670 int rc;
1671
1672 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1673 bts->nr, fname);
1674
1675 if (sw->state != SW_STATE_NONE)
1676 return -EBUSY;
1677
1678 sw->bts = bts;
1679 sw->obj_class = NM_OC_SITE_MANAGER;
1680 sw->obj_instance[0] = 0xff;
1681 sw->obj_instance[1] = 0xff;
1682 sw->obj_instance[2] = 0xff;
1683 sw->state = SW_STATE_WAIT_ACTACK;
1684 sw->cbfn = cbfn;
1685 sw->cb_data = cb_data;
1686
1687 /* Open the file in order to fill some sw struct members */
1688 rc = sw_open_file(sw, fname);
1689 if (rc < 0) {
1690 sw->state = SW_STATE_NONE;
1691 return rc;
1692 }
1693 sw_close_file(sw);
1694
1695 return sw_activate(sw);
1696}
1697
1698static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1699 u_int8_t ts_nr, u_int8_t subslot_nr)
1700{
1701 ch->attrib = NM_ATT_ABIS_CHANNEL;
1702 ch->bts_port = bts_port;
1703 ch->timeslot = ts_nr;
1704 ch->subslot = subslot_nr;
1705}
1706
1707int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1708 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1709 u_int8_t tei)
1710{
1711 struct abis_om_hdr *oh;
1712 struct abis_nm_channel *ch;
1713 u_int8_t len = sizeof(*ch) + 2;
1714 struct msgb *msg = nm_msgb_alloc();
1715
1716 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1717 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1718 bts->bts_nr, trx_nr, 0xff);
1719
1720 msgb_tv_put(msg, NM_ATT_TEI, tei);
1721
1722 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1723 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1724
1725 return abis_nm_sendmsg(bts, msg);
1726}
1727
1728/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1729int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1730 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1731{
1732 struct gsm_bts *bts = trx->bts;
1733 struct abis_om_hdr *oh;
1734 struct abis_nm_channel *ch;
1735 struct msgb *msg = nm_msgb_alloc();
1736
1737 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1738 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1739 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1740
1741 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1742 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1743
1744 return abis_nm_sendmsg(bts, msg);
1745}
1746
1747#if 0
1748int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1749 struct abis_nm_abis_channel *chan)
1750{
1751}
1752#endif
1753
1754int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1755 u_int8_t e1_port, u_int8_t e1_timeslot,
1756 u_int8_t e1_subslot)
1757{
1758 struct gsm_bts *bts = ts->trx->bts;
1759 struct abis_om_hdr *oh;
1760 struct abis_nm_channel *ch;
1761 struct msgb *msg = nm_msgb_alloc();
1762
1763 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1764 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1765 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1766
1767 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1768 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1769
1770 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1771 gsm_ts_name(ts),
1772 e1_port, e1_timeslot, e1_subslot);
1773
1774 return abis_nm_sendmsg(bts, msg);
1775}
1776
1777#if 0
1778int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1779 struct abis_nm_abis_channel *chan,
1780 u_int8_t subchan)
1781{
1782}
1783#endif
1784
1785/* Chapter 8.6.1 */
1786int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1787{
1788 struct abis_om_hdr *oh;
1789 struct msgb *msg = nm_msgb_alloc();
1790 u_int8_t *cur;
1791
1792 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1793
1794 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1795 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1796 cur = msgb_put(msg, attr_len);
1797 memcpy(cur, attr, attr_len);
1798
1799 return abis_nm_sendmsg(bts, msg);
1800}
1801
1802/* Chapter 8.6.2 */
1803int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1804{
1805 struct abis_om_hdr *oh;
1806 struct msgb *msg = nm_msgb_alloc();
1807 u_int8_t *cur;
1808
1809 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1810
1811 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1812 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1813 trx->bts->bts_nr, trx->nr, 0xff);
1814 cur = msgb_put(msg, attr_len);
1815 memcpy(cur, attr, attr_len);
1816
1817 return abis_nm_sendmsg(trx->bts, msg);
1818}
1819
Harald Weltef2eb2782009-08-09 21:49:48 +02001820static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1821{
1822 int i;
1823
1824 /* As it turns out, the BS-11 has some very peculiar restrictions
1825 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301826 switch (ts->trx->bts->type) {
1827 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001828 switch (chan_comb) {
1829 case NM_CHANC_TCHHalf:
1830 case NM_CHANC_TCHHalf2:
1831 /* not supported */
1832 return -EINVAL;
1833 case NM_CHANC_SDCCH:
1834 /* only one SDCCH/8 per TRX */
1835 for (i = 0; i < TRX_NR_TS; i++) {
1836 if (i == ts->nr)
1837 continue;
1838 if (ts->trx->ts[i].nm_chan_comb ==
1839 NM_CHANC_SDCCH)
1840 return -EINVAL;
1841 }
1842 /* not allowed for TS0 of BCCH-TRX */
1843 if (ts->trx == ts->trx->bts->c0 &&
1844 ts->nr == 0)
1845 return -EINVAL;
1846 /* not on the same TRX that has a BCCH+SDCCH4
1847 * combination */
1848 if (ts->trx == ts->trx->bts->c0 &&
1849 (ts->trx->ts[0].nm_chan_comb == 5 ||
1850 ts->trx->ts[0].nm_chan_comb == 8))
1851 return -EINVAL;
1852 break;
1853 case NM_CHANC_mainBCCH:
1854 case NM_CHANC_BCCHComb:
1855 /* allowed only for TS0 of C0 */
1856 if (ts->trx != ts->trx->bts->c0 ||
1857 ts->nr != 0)
1858 return -EINVAL;
1859 break;
1860 case NM_CHANC_BCCH:
1861 /* allowed only for TS 2/4/6 of C0 */
1862 if (ts->trx != ts->trx->bts->c0)
1863 return -EINVAL;
1864 if (ts->nr != 2 && ts->nr != 4 &&
1865 ts->nr != 6)
1866 return -EINVAL;
1867 break;
1868 case 8: /* this is not like 08.58, but in fact
1869 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1870 /* FIXME: only one CBCH allowed per cell */
1871 break;
1872 }
Harald Welte76ba8812009-12-02 02:45:23 +05301873 break;
1874 case GSM_BTS_TYPE_NANOBTS:
1875 switch (ts->nr) {
1876 case 0:
1877 if (ts->trx->nr == 0) {
1878 /* only on TRX0 */
1879 switch (chan_comb) {
1880 case NM_CHANC_BCCH:
1881 case NM_CHANC_mainBCCH:
1882 case NM_CHANC_BCCHComb:
1883 return 0;
1884 break;
1885 default:
1886 return -EINVAL;
1887 }
1888 } else {
1889 switch (chan_comb) {
1890 case NM_CHANC_TCHFull:
1891 case NM_CHANC_TCHHalf:
1892 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1893 return 0;
1894 default:
1895 return -EINVAL;
1896 }
1897 }
1898 break;
1899 case 1:
1900 if (ts->trx->nr == 0) {
1901 switch (chan_comb) {
1902 case NM_CHANC_SDCCH_CBCH:
1903 if (ts->trx->ts[0].nm_chan_comb ==
1904 NM_CHANC_mainBCCH)
1905 return 0;
1906 return -EINVAL;
1907 case NM_CHANC_SDCCH:
1908 case NM_CHANC_TCHFull:
1909 case NM_CHANC_TCHHalf:
1910 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1911 case NM_CHANC_IPAC_TCHFull_PDCH:
1912 return 0;
1913 }
1914 } else {
1915 switch (chan_comb) {
1916 case NM_CHANC_SDCCH:
1917 case NM_CHANC_TCHFull:
1918 case NM_CHANC_TCHHalf:
1919 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1920 return 0;
1921 default:
1922 return -EINVAL;
1923 }
1924 }
1925 break;
1926 case 2:
1927 case 3:
1928 case 4:
1929 case 5:
1930 case 6:
1931 case 7:
1932 switch (chan_comb) {
1933 case NM_CHANC_TCHFull:
1934 case NM_CHANC_TCHHalf:
1935 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1936 return 0;
1937 case NM_CHANC_IPAC_PDCH:
1938 case NM_CHANC_IPAC_TCHFull_PDCH:
1939 if (ts->trx->nr == 0)
1940 return 0;
1941 else
1942 return -EINVAL;
1943 }
1944 break;
1945 }
1946 return -EINVAL;
1947 default:
1948 /* unknown BTS type */
1949 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001950 }
1951 return 0;
1952}
1953
Harald Welte59b04682009-06-10 05:40:52 +08001954/* Chapter 8.6.3 */
1955int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1956{
1957 struct gsm_bts *bts = ts->trx->bts;
1958 struct abis_om_hdr *oh;
1959 u_int16_t arfcn = htons(ts->trx->arfcn);
1960 u_int8_t zero = 0x00;
1961 struct msgb *msg = nm_msgb_alloc();
1962 u_int8_t len = 2 + 2;
1963
1964 if (bts->type == GSM_BTS_TYPE_BS11)
1965 len += 4 + 2 + 2 + 3;
1966
1967 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001968 if (verify_chan_comb(ts, chan_comb) < 0) {
1969 msgb_free(msg);
1970 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1971 return -EINVAL;
1972 }
1973 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001974
1975 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1976 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1977 NM_OC_CHANNEL, bts->bts_nr,
1978 ts->trx->nr, ts->nr);
1979 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
1980 if (bts->type == GSM_BTS_TYPE_BS11)
1981 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
1982 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
1983 if (bts->type == GSM_BTS_TYPE_BS11) {
1984 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1985 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1986 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02001987 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001988 if (bts->type == GSM_BTS_TYPE_BS11)
1989 msgb_tlv_put(msg, 0x59, 1, &zero);
1990
1991 return abis_nm_sendmsg(bts, msg);
1992}
1993
1994int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
1995 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
1996{
1997 struct abis_om_hdr *oh;
1998 struct msgb *msg = nm_msgb_alloc();
1999 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2000 u_int8_t len = att_len;
2001
2002 if (nack) {
2003 len += 2;
2004 msgtype = NM_MT_SW_ACT_REQ_NACK;
2005 }
2006
2007 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2008 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2009
2010 if (attr) {
2011 u_int8_t *ptr = msgb_put(msg, att_len);
2012 memcpy(ptr, attr, att_len);
2013 }
2014 if (nack)
2015 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2016
2017 return abis_nm_sendmsg(bts, msg);
2018}
2019
2020int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2021{
2022 struct msgb *msg = nm_msgb_alloc();
2023 struct abis_om_hdr *oh;
2024 u_int8_t *data;
2025
2026 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2027 fill_om_hdr(oh, len);
2028 data = msgb_put(msg, len);
2029 memcpy(data, rawmsg, len);
2030
2031 return abis_nm_sendmsg(bts, msg);
2032}
2033
2034/* Siemens specific commands */
2035static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2036{
2037 struct abis_om_hdr *oh;
2038 struct msgb *msg = nm_msgb_alloc();
2039
2040 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2041 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2042 0xff, 0xff, 0xff);
2043
2044 return abis_nm_sendmsg(bts, msg);
2045}
2046
2047/* Chapter 8.9.2 */
2048int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2049{
2050 struct abis_om_hdr *oh;
2051 struct msgb *msg = nm_msgb_alloc();
2052
Harald Welte59b04682009-06-10 05:40:52 +08002053 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2054 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2055
Harald Welteb7284a92009-10-20 09:56:18 +02002056 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2057 DEBUGPC(DNM, "Sending OPSTART\n");
2058
Harald Welte59b04682009-06-10 05:40:52 +08002059 return abis_nm_sendmsg(bts, msg);
2060}
2061
2062/* Chapter 8.8.5 */
2063int 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 +02002064 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002065{
2066 struct abis_om_hdr *oh;
2067 struct msgb *msg = nm_msgb_alloc();
2068
2069 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2070 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2071 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2072
2073 return abis_nm_sendmsg(bts, msg);
2074}
2075
Harald Welte204317e2009-08-06 17:58:31 +02002076int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2077 u_int8_t e1_port1, u_int8_t ts1)
2078{
2079 struct abis_om_hdr *oh;
2080 struct msgb *msg = nm_msgb_alloc();
2081 u_int8_t *attr;
2082
2083 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2084 e1_port0, ts0, e1_port1, ts1);
2085
2086 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2087 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2088 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2089
2090 attr = msgb_put(msg, 3);
2091 attr[0] = NM_ATT_MDROP_LINK;
2092 attr[1] = e1_port0;
2093 attr[2] = ts0;
2094
2095 attr = msgb_put(msg, 3);
2096 attr[0] = NM_ATT_MDROP_NEXT;
2097 attr[1] = e1_port1;
2098 attr[2] = ts1;
2099
2100 return abis_nm_sendmsg(bts, msg);
2101}
Harald Welte59b04682009-06-10 05:40:52 +08002102
Harald Welte0bf8e302009-08-08 00:02:36 +02002103/* Chapter 8.7.1 */
2104int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2105 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2106 u_int8_t test_nr, u_int8_t auton_report,
2107 u_int8_t *phys_config, u_int16_t phys_config_len)
2108{
2109 struct abis_om_hdr *oh;
2110 struct msgb *msg = nm_msgb_alloc();
2111 int len = 4; /* 2 TV attributes */
2112
2113 DEBUGP(DNM, "PEFORM TEST\n");
2114
2115 if (phys_config_len)
2116 len += 3 + phys_config_len;
2117
2118 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2119 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2120 obj_class, bts_nr, trx_nr, ts_nr);
2121 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2122 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2123 if (phys_config_len)
2124 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2125 phys_config);
2126
2127 return abis_nm_sendmsg(bts, msg);
2128}
2129
Harald Welte59b04682009-06-10 05:40:52 +08002130int abis_nm_event_reports(struct gsm_bts *bts, int on)
2131{
2132 if (on == 0)
2133 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2134 else
2135 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2136}
2137
2138/* Siemens (or BS-11) specific commands */
2139
2140int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2141{
2142 if (reconnect == 0)
2143 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2144 else
2145 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2146}
2147
2148int abis_nm_bs11_restart(struct gsm_bts *bts)
2149{
2150 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2151}
2152
2153
2154struct bs11_date_time {
2155 u_int16_t year;
2156 u_int8_t month;
2157 u_int8_t day;
2158 u_int8_t hour;
2159 u_int8_t min;
2160 u_int8_t sec;
2161} __attribute__((packed));
2162
2163
2164void get_bs11_date_time(struct bs11_date_time *aet)
2165{
2166 time_t t;
2167 struct tm *tm;
2168
2169 t = time(NULL);
2170 tm = localtime(&t);
2171 aet->sec = tm->tm_sec;
2172 aet->min = tm->tm_min;
2173 aet->hour = tm->tm_hour;
2174 aet->day = tm->tm_mday;
2175 aet->month = tm->tm_mon;
2176 aet->year = htons(1900 + tm->tm_year);
2177}
2178
2179int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2180{
2181 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2182}
2183
2184int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2185{
2186 if (begin)
2187 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2188 else
2189 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2190}
2191
2192int abis_nm_bs11_create_object(struct gsm_bts *bts,
2193 enum abis_bs11_objtype type, u_int8_t idx,
2194 u_int8_t attr_len, const u_int8_t *attr)
2195{
2196 struct abis_om_hdr *oh;
2197 struct msgb *msg = nm_msgb_alloc();
2198 u_int8_t *cur;
2199
2200 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2201 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2202 NM_OC_BS11, type, 0, idx);
2203 cur = msgb_put(msg, attr_len);
2204 memcpy(cur, attr, attr_len);
2205
2206 return abis_nm_sendmsg(bts, msg);
2207}
2208
2209int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2210 enum abis_bs11_objtype type, u_int8_t idx)
2211{
2212 struct abis_om_hdr *oh;
2213 struct msgb *msg = nm_msgb_alloc();
2214
2215 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2216 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2217 NM_OC_BS11, type, 0, idx);
2218
2219 return abis_nm_sendmsg(bts, msg);
2220}
2221
2222int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2223{
2224 struct abis_om_hdr *oh;
2225 struct msgb *msg = nm_msgb_alloc();
2226 u_int8_t zero = 0x00;
2227
2228 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2229 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2230 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2231 msgb_tlv_put(msg, 0x99, 1, &zero);
2232
2233 return abis_nm_sendmsg(bts, msg);
2234}
2235
2236int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2237{
2238 struct abis_om_hdr *oh;
2239 struct msgb *msg = nm_msgb_alloc();
2240
2241 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2242 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002243 idx, 0xff, 0xff);
2244
2245 return abis_nm_sendmsg(bts, msg);
2246}
2247
2248int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2249{
2250 struct abis_om_hdr *oh;
2251 struct msgb *msg = nm_msgb_alloc();
2252
2253 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2254 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2255 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002256
2257 return abis_nm_sendmsg(bts, msg);
2258}
2259
2260static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2261int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2262{
2263 struct abis_om_hdr *oh;
2264 struct msgb *msg = nm_msgb_alloc();
2265
2266 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2267 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2268 0xff, 0xff, 0xff);
2269 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2270
2271 return abis_nm_sendmsg(bts, msg);
2272}
2273
2274/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002275int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welte59b04682009-06-10 05:40:52 +08002276 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2277 u_int8_t tei)
2278{
2279 struct abis_om_hdr *oh;
2280 struct abis_nm_channel *ch;
2281 struct msgb *msg = nm_msgb_alloc();
2282
2283 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2284 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2285 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2286
2287 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2288 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2289 msgb_tv_put(msg, NM_ATT_TEI, tei);
2290
2291 return abis_nm_sendmsg(bts, msg);
2292}
2293
2294int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2295{
2296 struct abis_om_hdr *oh;
2297 struct msgb *msg = nm_msgb_alloc();
2298
2299 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2300 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2301 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2302 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2303
2304 return abis_nm_sendmsg(trx->bts, msg);
2305}
2306
2307int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2308{
2309 struct abis_om_hdr *oh;
2310 struct msgb *msg = nm_msgb_alloc();
2311 u_int8_t attr = NM_ATT_BS11_TXPWR;
2312
2313 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2314 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2315 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2316 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2317
2318 return abis_nm_sendmsg(trx->bts, msg);
2319}
2320
2321int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2322{
2323 struct abis_om_hdr *oh;
2324 struct msgb *msg = nm_msgb_alloc();
2325 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2326
2327 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2328 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2329 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2330 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2331
2332 return abis_nm_sendmsg(bts, msg);
2333}
2334
2335int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2336{
2337 struct abis_om_hdr *oh;
2338 struct msgb *msg = nm_msgb_alloc();
2339 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2340 NM_ATT_BS11_CCLK_TYPE };
2341
2342 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2343 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2344 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2345 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2346
2347 return abis_nm_sendmsg(bts, msg);
2348
2349}
2350
2351//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002352
2353int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2354{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002355 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2356}
2357
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002358int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2359{
2360 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2361}
2362
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002363int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2364{
Harald Welte59b04682009-06-10 05:40:52 +08002365 struct abis_om_hdr *oh;
2366 struct msgb *msg = nm_msgb_alloc();
2367 struct bs11_date_time bdt;
2368
2369 get_bs11_date_time(&bdt);
2370
2371 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2372 if (on) {
2373 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002374 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002375 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2376 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2377 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2378 sizeof(bdt), (u_int8_t *) &bdt);
2379 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002380 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002381 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002382 strlen(name), (u_int8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002383 } else {
2384 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2385 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2386 }
2387
2388 return abis_nm_sendmsg(bts, msg);
2389}
2390
2391int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2392{
2393 struct abis_om_hdr *oh;
2394 struct msgb *msg;
2395
2396 if (strlen(password) != 10)
2397 return -EINVAL;
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, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2402 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2403 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2404
2405 return abis_nm_sendmsg(bts, msg);
2406}
2407
2408/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2409int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2410{
2411 struct abis_om_hdr *oh;
2412 struct msgb *msg;
2413 u_int8_t tlv_value;
2414
2415 msg = nm_msgb_alloc();
2416 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2417 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2418 BS11_OBJ_LI, 0x00, 0x00);
2419
2420 if (locked)
2421 tlv_value = BS11_LI_PLL_LOCKED;
2422 else
2423 tlv_value = BS11_LI_PLL_STANDALONE;
2424
2425 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2426
2427 return abis_nm_sendmsg(bts, msg);
2428}
2429
Daniel Willmann10b07db2010-01-07 00:54:01 +01002430/* Set the calibration value of the PLL (work value/set value)
2431 * It depends on the login which one is changed */
2432int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2433{
2434 struct abis_om_hdr *oh;
2435 struct msgb *msg;
2436 u_int8_t tlv_value[2];
2437
2438 msg = nm_msgb_alloc();
2439 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2440 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2441 BS11_OBJ_TRX1, 0x00, 0x00);
2442
2443 tlv_value[0] = value>>8;
2444 tlv_value[1] = value&0xff;
2445
2446 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2447
2448 return abis_nm_sendmsg(bts, msg);
2449}
2450
Harald Welte59b04682009-06-10 05:40:52 +08002451int abis_nm_bs11_get_state(struct gsm_bts *bts)
2452{
2453 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2454}
2455
2456/* BS11 SWL */
2457
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002458void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002459
Harald Welte59b04682009-06-10 05:40:52 +08002460struct abis_nm_bs11_sw {
2461 struct gsm_bts *bts;
2462 char swl_fname[PATH_MAX];
2463 u_int8_t win_size;
2464 int forced;
2465 struct llist_head file_list;
2466 gsm_cbfn *user_cb; /* specified by the user */
2467};
2468static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2469
2470struct file_list_entry {
2471 struct llist_head list;
2472 char fname[PATH_MAX];
2473};
2474
2475struct file_list_entry *fl_dequeue(struct llist_head *queue)
2476{
2477 struct llist_head *lh;
2478
2479 if (llist_empty(queue))
2480 return NULL;
2481
2482 lh = queue->next;
2483 llist_del(lh);
2484
2485 return llist_entry(lh, struct file_list_entry, list);
2486}
2487
2488static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2489{
2490 char linebuf[255];
2491 struct llist_head *lh, *lh2;
2492 FILE *swl;
2493 int rc = 0;
2494
2495 swl = fopen(bs11_sw->swl_fname, "r");
2496 if (!swl)
2497 return -ENODEV;
2498
2499 /* zero the stale file list, if any */
2500 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2501 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002502 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002503 }
2504
2505 while (fgets(linebuf, sizeof(linebuf), swl)) {
2506 char file_id[12+1];
2507 char file_version[80+1];
2508 struct file_list_entry *fle;
2509 static char dir[PATH_MAX];
2510
2511 if (strlen(linebuf) < 4)
2512 continue;
2513
2514 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2515 if (rc < 0) {
2516 perror("ERR parsing SWL file");
2517 rc = -EINVAL;
2518 goto out;
2519 }
2520 if (rc < 2)
2521 continue;
2522
Harald Welte857e00d2009-06-26 20:25:23 +02002523 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002524 if (!fle) {
2525 rc = -ENOMEM;
2526 goto out;
2527 }
Harald Welte59b04682009-06-10 05:40:52 +08002528
2529 /* construct new filename */
2530 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2531 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2532 strcat(fle->fname, "/");
2533 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2534
2535 llist_add_tail(&fle->list, &bs11_sw->file_list);
2536 }
2537
2538out:
2539 fclose(swl);
2540 return rc;
2541}
2542
2543/* bs11 swload specific callback, passed to abis_nm core swload */
2544static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2545 struct msgb *msg, void *data, void *param)
2546{
2547 struct abis_nm_bs11_sw *bs11_sw = data;
2548 struct file_list_entry *fle;
2549 int rc = 0;
2550
2551 switch (event) {
2552 case NM_MT_LOAD_END_ACK:
2553 fle = fl_dequeue(&bs11_sw->file_list);
2554 if (fle) {
2555 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002556 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002557 bs11_sw->win_size,
2558 bs11_sw->forced,
2559 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002560 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002561 } else {
2562 /* activate the SWL */
2563 rc = abis_nm_software_activate(bs11_sw->bts,
2564 bs11_sw->swl_fname,
2565 bs11_swload_cbfn,
2566 bs11_sw);
2567 }
2568 break;
2569 case NM_MT_LOAD_SEG_ACK:
2570 case NM_MT_LOAD_END_NACK:
2571 case NM_MT_LOAD_INIT_ACK:
2572 case NM_MT_LOAD_INIT_NACK:
2573 case NM_MT_ACTIVATE_SW_NACK:
2574 case NM_MT_ACTIVATE_SW_ACK:
2575 default:
2576 /* fallthrough to the user callback */
2577 if (bs11_sw->user_cb)
2578 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2579 break;
2580 }
2581
2582 return rc;
2583}
2584
2585/* Siemens provides a SWL file that is a mere listing of all the other
2586 * files that are part of a software release. We need to upload first
2587 * the list file, and then each file that is listed in the list file */
2588int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2589 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2590{
2591 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2592 struct file_list_entry *fle;
2593 int rc = 0;
2594
2595 INIT_LLIST_HEAD(&bs11_sw->file_list);
2596 bs11_sw->bts = bts;
2597 bs11_sw->win_size = win_size;
2598 bs11_sw->user_cb = cbfn;
2599 bs11_sw->forced = forced;
2600
2601 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2602 rc = bs11_read_swl_file(bs11_sw);
2603 if (rc < 0)
2604 return rc;
2605
2606 /* dequeue next item in file list */
2607 fle = fl_dequeue(&bs11_sw->file_list);
2608 if (!fle)
2609 return -EINVAL;
2610
2611 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002612 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002613 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002614 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002615 return rc;
2616}
2617
2618#if 0
2619static u_int8_t req_attr_btse[] = {
2620 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2621 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2622 NM_ATT_BS11_LMT_USER_NAME,
2623
2624 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2625
2626 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2627
2628 NM_ATT_BS11_SW_LOAD_STORED };
2629
2630static u_int8_t req_attr_btsm[] = {
2631 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2632 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2633 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2634 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2635#endif
2636
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002637static u_int8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002638 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2639 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2640 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2641
2642int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2643{
2644 struct abis_om_hdr *oh;
2645 struct msgb *msg = nm_msgb_alloc();
2646
2647 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2648 /* SiemensHW CCTRL object */
2649 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2650 0x03, 0x00, 0x00);
2651 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2652
2653 return abis_nm_sendmsg(bts, msg);
2654}
2655
2656int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2657{
2658 struct abis_om_hdr *oh;
2659 struct msgb *msg = nm_msgb_alloc();
2660 struct bs11_date_time aet;
2661
2662 get_bs11_date_time(&aet);
2663 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2664 /* SiemensHW CCTRL object */
2665 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2666 0xff, 0xff, 0xff);
2667 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2668
2669 return abis_nm_sendmsg(bts, msg);
2670}
2671
Daniel Willmann5655afe2009-08-10 11:49:36 +02002672int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2673{
2674 struct abis_om_hdr *oh;
2675 struct msgb *msg = nm_msgb_alloc();
2676 struct bs11_date_time aet;
2677
2678 get_bs11_date_time(&aet);
2679 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2680 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2681 bport, 0xff, 0x02);
2682 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2683
2684 return abis_nm_sendmsg(bts, msg);
2685}
2686
Harald Welte59b04682009-06-10 05:40:52 +08002687/* ip.access nanoBTS specific commands */
2688static const char ipaccess_magic[] = "com.ipaccess";
2689
2690
2691static int abis_nm_rx_ipacc(struct msgb *msg)
2692{
2693 struct abis_om_hdr *oh = msgb_l2(msg);
2694 struct abis_om_fom_hdr *foh;
2695 u_int8_t idstrlen = oh->data[0];
2696 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002697 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002698
2699 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002700 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002701 return -EINVAL;
2702 }
2703
2704 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002705 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002706
Harald Welteb7284a92009-10-20 09:56:18 +02002707 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002708
Harald Welte5aeedd42009-10-19 22:11:11 +02002709 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002710
2711 switch (foh->msg_type) {
2712 case NM_MT_IPACC_RSL_CONNECT_ACK:
2713 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte4206d982009-07-12 09:33:54 +02002714 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte59b04682009-06-10 05:40:52 +08002715 DEBUGPC(DNM, "IP=%s ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002716 inet_ntoa(*((struct in_addr *)
Harald Welte4206d982009-07-12 09:33:54 +02002717 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2718 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002719 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002720 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002721 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002722 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2723 DEBUGPC(DNM, "STREAM=0x%02x ",
2724 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002725 DEBUGPC(DNM, "\n");
2726 break;
2727 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002728 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002729 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002730 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002731 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2732 else
2733 DEBUGPC(DNM, "\n");
2734 break;
2735 case NM_MT_IPACC_SET_NVATTR_ACK:
2736 DEBUGPC(DNM, "SET NVATTR ACK\n");
2737 /* FIXME: decode and show the actual attributes */
2738 break;
2739 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002740 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002741 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002742 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002743 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2744 else
Harald Weltede4477a2009-12-24 12:20:20 +01002745 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002746 break;
Harald Welte21460f02009-07-03 11:26:45 +02002747 case NM_MT_IPACC_GET_NVATTR_ACK:
2748 DEBUGPC(DNM, "GET NVATTR ACK\n");
2749 /* FIXME: decode and show the actual attributes */
2750 break;
2751 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002752 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002753 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002754 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002755 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2756 else
Harald Weltede4477a2009-12-24 12:20:20 +01002757 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002758 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002759 case NM_MT_IPACC_SET_ATTR_ACK:
2760 DEBUGPC(DNM, "SET ATTR ACK\n");
2761 break;
2762 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002763 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002764 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002765 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002766 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2767 else
Harald Weltede4477a2009-12-24 12:20:20 +01002768 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002769 break;
Harald Welte59b04682009-06-10 05:40:52 +08002770 default:
2771 DEBUGPC(DNM, "unknown\n");
2772 break;
2773 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002774
2775 /* signal handling */
2776 switch (foh->msg_type) {
2777 case NM_MT_IPACC_RSL_CONNECT_NACK:
2778 case NM_MT_IPACC_SET_NVATTR_NACK:
2779 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002780 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002781 signal.msg_type = foh->msg_type;
2782 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002783 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002784 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002785 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002786 signal.msg_type = foh->msg_type;
2787 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002788 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002789 default:
2790 break;
2791 }
2792
Harald Welte59b04682009-06-10 05:40:52 +08002793 return 0;
2794}
2795
2796/* send an ip-access manufacturer specific message */
2797int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2798 u_int8_t obj_class, u_int8_t bts_nr,
2799 u_int8_t trx_nr, u_int8_t ts_nr,
2800 u_int8_t *attr, int attr_len)
2801{
2802 struct msgb *msg = nm_msgb_alloc();
2803 struct abis_om_hdr *oh;
2804 struct abis_om_fom_hdr *foh;
2805 u_int8_t *data;
2806
2807 /* construct the 12.21 OM header, observe the erroneous length */
2808 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2809 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2810 oh->mdisc = ABIS_OM_MDISC_MANUF;
2811
2812 /* add the ip.access magic */
2813 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2814 *data++ = sizeof(ipaccess_magic);
2815 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2816
2817 /* fill the 12.21 FOM header */
2818 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2819 foh->msg_type = msg_type;
2820 foh->obj_class = obj_class;
2821 foh->obj_inst.bts_nr = bts_nr;
2822 foh->obj_inst.trx_nr = trx_nr;
2823 foh->obj_inst.ts_nr = ts_nr;
2824
2825 if (attr && attr_len) {
2826 data = msgb_put(msg, attr_len);
2827 memcpy(data, attr, attr_len);
2828 }
2829
2830 return abis_nm_sendmsg(bts, msg);
2831}
2832
2833/* set some attributes in NVRAM */
Harald Weltef12c1052010-01-07 20:39:42 +01002834int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002835 int attr_len)
2836{
Harald Weltef12c1052010-01-07 20:39:42 +01002837 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2838 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002839 attr_len);
2840}
2841
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002842int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte5aeedd42009-10-19 22:11:11 +02002843 u_int32_t ip, u_int16_t port, u_int8_t stream)
2844{
2845 struct in_addr ia;
2846 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2847 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2848 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2849
2850 int attr_len = sizeof(attr);
2851
2852 ia.s_addr = htonl(ip);
2853 attr[1] = stream;
2854 attr[3] = port >> 8;
2855 attr[4] = port & 0xff;
2856 *(u_int32_t *)(attr+6) = ia.s_addr;
2857
2858 /* if ip == 0, we use the default IP */
2859 if (ip == 0)
2860 attr_len -= 5;
2861
2862 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002863 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002864
2865 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2866 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2867 trx->nr, 0xff, attr, attr_len);
2868}
2869
Harald Welte59b04682009-06-10 05:40:52 +08002870/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002871int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002872{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002873 struct abis_om_hdr *oh;
2874 struct msgb *msg = nm_msgb_alloc();
2875
2876 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2877 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2878 trx->bts->nr, trx->nr, 0xff);
2879
2880 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002881}
Harald Welte0dfc6232009-10-24 10:20:41 +02002882
2883int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2884 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2885 u_int8_t *attr, u_int8_t attr_len)
2886{
2887 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2888 obj_class, bts_nr, trx_nr, ts_nr,
2889 attr, attr_len);
2890}
Harald Weltebeeae412009-11-12 14:48:42 +01002891
Harald Welte3055e332010-03-14 15:37:43 +08002892void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2893{
2894 /* we simply reuse the GSM48 function and overwrite the RAC
2895 * with the Cell ID */
2896 gsm48_ra_id_by_bts(buf, bts);
2897 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2898}
2899
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002900void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2901{
2902 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2903
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01002904 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002905 if (!trx->bts || !trx->bts->oml_link)
2906 return;
2907
2908 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2909 trx->bts->bts_nr, trx->nr, 0xff,
2910 new_state);
2911}
2912
Harald Welte453141f2010-03-25 11:45:30 +08002913static const struct value_string ipacc_testres_names[] = {
2914 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2915 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2916 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2917 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2918 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2919 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002920};
2921
2922const char *ipacc_testres_name(u_int8_t res)
2923{
Harald Welte453141f2010-03-25 11:45:30 +08002924 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002925}
2926
Harald Weltebfc21092009-11-13 11:56:05 +01002927void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2928{
2929 cid->mcc = (buf[0] & 0xf) * 100;
2930 cid->mcc += (buf[0] >> 4) * 10;
2931 cid->mcc += (buf[1] & 0xf) * 1;
2932
2933 if (buf[1] >> 4 == 0xf) {
2934 cid->mnc = (buf[2] & 0xf) * 10;
2935 cid->mnc += (buf[2] >> 4) * 1;
2936 } else {
2937 cid->mnc = (buf[2] & 0xf) * 100;
2938 cid->mnc += (buf[2] >> 4) * 10;
2939 cid->mnc += (buf[1] >> 4) * 1;
2940 }
2941
Harald Welte161b4be2009-11-13 14:41:52 +01002942 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2943 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002944}
2945
Harald Weltebeeae412009-11-12 14:48:42 +01002946/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2947int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2948{
2949 u_int8_t *cur = buf;
2950 u_int16_t len;
2951
2952 memset(binf, 0, sizeof(binf));
2953
2954 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2955 return -EINVAL;
2956 cur++;
2957
2958 len = ntohs(*(u_int16_t *)cur);
2959 cur += 2;
2960
2961 binf->info_type = ntohs(*(u_int16_t *)cur);
2962 cur += 2;
2963
2964 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2965 binf->freq_qual = *cur >> 2;
2966
2967 binf->arfcn = *cur++ & 3 << 8;
2968 binf->arfcn |= *cur++;
2969
2970 if (binf->info_type & IPAC_BINF_RXLEV)
2971 binf->rx_lev = *cur & 0x3f;
2972 cur++;
2973
2974 if (binf->info_type & IPAC_BINF_RXQUAL)
2975 binf->rx_qual = *cur & 0x7;
2976 cur++;
2977
2978 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2979 binf->freq_err = ntohs(*(u_int16_t *)cur);
2980 cur += 2;
2981
2982 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2983 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2984 cur += 2;
2985
2986 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2987 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2988 cur += 4;
2989
2990 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte161b4be2009-11-13 14:41:52 +01002991 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002992 cur++;
2993
Harald Weltebfc21092009-11-13 11:56:05 +01002994 ipac_parse_cgi(&binf->cgi, cur);
2995 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002996
2997 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2998 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2999 cur += sizeof(binf->ba_list_si2);
3000 }
3001
3002 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3003 memcpy(binf->ba_list_si2bis, cur,
3004 sizeof(binf->ba_list_si2bis));
3005 cur += sizeof(binf->ba_list_si2bis);
3006 }
3007
3008 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3009 memcpy(binf->ba_list_si2ter, cur,
3010 sizeof(binf->ba_list_si2ter));
3011 cur += sizeof(binf->ba_list_si2ter);
3012 }
3013
3014 return 0;
3015}