blob: ee0604d3cc35864576a3a2142e5eaad8ed20cf33 [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;
1142 gsm_cbfn *cbfn;
1143 void *cb_data;
1144 int forced;
1145
1146 /* this will become part of the SW LOAD INITIATE */
1147 u_int8_t obj_class;
1148 u_int8_t obj_instance[3];
1149
1150 u_int8_t file_id[255];
1151 u_int8_t file_id_len;
1152
1153 u_int8_t file_version[255];
1154 u_int8_t file_version_len;
1155
1156 u_int8_t window_size;
1157 u_int8_t seg_in_window;
1158
1159 int fd;
1160 FILE *stream;
1161 enum sw_state state;
1162 int last_seg;
1163};
1164
1165static struct abis_nm_sw g_sw;
1166
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001167static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1168{
1169 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1170 msgb_v_put(msg, NM_ATT_SW_DESCR);
1171 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1172 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1173 sw->file_version);
1174 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1175 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1176 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1177 sw->file_version);
1178 } else {
1179 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1180 }
1181}
1182
Harald Welte59b04682009-06-10 05:40:52 +08001183/* 6.2.1 / 8.3.1: Load Data Initiate */
1184static int sw_load_init(struct abis_nm_sw *sw)
1185{
1186 struct abis_om_hdr *oh;
1187 struct msgb *msg = nm_msgb_alloc();
1188 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1189
1190 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1191 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1192 sw->obj_instance[0], sw->obj_instance[1],
1193 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001194
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001195 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001196 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1197
1198 return abis_nm_sendmsg(sw->bts, msg);
1199}
1200
1201static int is_last_line(FILE *stream)
1202{
1203 char next_seg_buf[256];
1204 long pos;
1205
1206 /* check if we're sending the last line */
1207 pos = ftell(stream);
1208 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1209 fseek(stream, pos, SEEK_SET);
1210 return 1;
1211 }
1212
1213 fseek(stream, pos, SEEK_SET);
1214 return 0;
1215}
1216
1217/* 6.2.2 / 8.3.2 Load Data Segment */
1218static int sw_load_segment(struct abis_nm_sw *sw)
1219{
1220 struct abis_om_hdr *oh;
1221 struct msgb *msg = nm_msgb_alloc();
1222 char seg_buf[256];
1223 char *line_buf = seg_buf+2;
1224 unsigned char *tlv;
1225 u_int8_t len;
1226
1227 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1228
1229 switch (sw->bts->type) {
1230 case GSM_BTS_TYPE_BS11:
1231 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1232 perror("fgets reading segment");
1233 return -EINVAL;
1234 }
1235 seg_buf[0] = 0x00;
1236
1237 /* check if we're sending the last line */
1238 sw->last_seg = is_last_line(sw->stream);
1239 if (sw->last_seg)
1240 seg_buf[1] = 0;
1241 else
1242 seg_buf[1] = 1 + sw->seg_in_window++;
1243
1244 len = strlen(line_buf) + 2;
1245 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1246 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1247 /* BS11 wants CR + LF in excess of the TLV length !?! */
1248 tlv[1] -= 2;
1249
1250 /* we only now know the exact length for the OM hdr */
1251 len = strlen(line_buf)+2;
1252 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001253 case GSM_BTS_TYPE_NANOBTS: {
1254 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1255 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1256 if (len < 0) {
1257 perror("read failed");
1258 return -EINVAL;
1259 }
1260
1261 if (len != IPACC_SEGMENT_SIZE)
1262 sw->last_seg = 1;
1263
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001264 ++sw->seg_in_window;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001265 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1266 len += 3;
1267 break;
1268 }
Harald Welte59b04682009-06-10 05:40:52 +08001269 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001270 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001271 /* FIXME: Other BTS types */
1272 return -1;
1273 }
1274
1275 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1276 sw->obj_instance[0], sw->obj_instance[1],
1277 sw->obj_instance[2]);
1278
1279 return abis_nm_sendmsg(sw->bts, msg);
1280}
1281
1282/* 6.2.4 / 8.3.4 Load Data End */
1283static int sw_load_end(struct abis_nm_sw *sw)
1284{
1285 struct abis_om_hdr *oh;
1286 struct msgb *msg = nm_msgb_alloc();
1287 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1288
1289 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1290 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1291 sw->obj_instance[0], sw->obj_instance[1],
1292 sw->obj_instance[2]);
1293
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001294 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001295 return abis_nm_sendmsg(sw->bts, msg);
1296}
1297
1298/* Activate the specified software into the BTS */
1299static int sw_activate(struct abis_nm_sw *sw)
1300{
1301 struct abis_om_hdr *oh;
1302 struct msgb *msg = nm_msgb_alloc();
1303 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1304
1305 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1306 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1307 sw->obj_instance[0], sw->obj_instance[1],
1308 sw->obj_instance[2]);
1309
1310 /* FIXME: this is BS11 specific format */
1311 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1312 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1313 sw->file_version);
1314
1315 return abis_nm_sendmsg(sw->bts, msg);
1316}
1317
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001318struct sdp_firmware {
1319 char magic[4];
1320 char more_magic[4];
1321 unsigned int header_length;
1322 unsigned int file_length;
1323} __attribute__ ((packed));
1324
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001325static int parse_sdp_header(struct abis_nm_sw *sw)
1326{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001327 struct sdp_firmware firmware_header;
1328 int rc;
1329 struct stat stat;
1330
1331 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1332 if (rc != sizeof(firmware_header)) {
1333 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1334 return -1;
1335 }
1336
1337 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1338 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1339 return -1;
1340 }
1341
1342 if (firmware_header.more_magic[0] != 0x10 ||
1343 firmware_header.more_magic[1] != 0x02 ||
1344 firmware_header.more_magic[2] != 0x00 ||
1345 firmware_header.more_magic[3] != 0x00) {
1346 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1347 return -1;
1348 }
1349
1350
1351 if (fstat(sw->fd, &stat) == -1) {
1352 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1353 return -1;
1354 }
1355
1356 if (ntohl(firmware_header.file_length) != stat.st_size) {
1357 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1358 return -1;
1359 }
1360
1361 /* go back to the start as we checked the whole filesize.. */
1362 lseek(sw->fd, 0l, SEEK_SET);
1363 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1364 "There might be checksums in the file that are not\n"
1365 "verified and incomplete firmware might be flashed.\n"
1366 "There is absolutely no WARRANTY that flashing will\n"
1367 "work.\n");
1368 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001369}
1370
Harald Welte59b04682009-06-10 05:40:52 +08001371static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1372{
1373 char file_id[12+1];
1374 char file_version[80+1];
1375 int rc;
1376
1377 sw->fd = open(fname, O_RDONLY);
1378 if (sw->fd < 0)
1379 return sw->fd;
1380
1381 switch (sw->bts->type) {
1382 case GSM_BTS_TYPE_BS11:
1383 sw->stream = fdopen(sw->fd, "r");
1384 if (!sw->stream) {
1385 perror("fdopen");
1386 return -1;
1387 }
1388 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001389 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001390 file_id, file_version);
1391 if (rc != 2) {
1392 perror("parsing header line of software file");
1393 return -1;
1394 }
1395 strcpy((char *)sw->file_id, file_id);
1396 sw->file_id_len = strlen(file_id);
1397 strcpy((char *)sw->file_version, file_version);
1398 sw->file_version_len = strlen(file_version);
1399 /* rewind to start of file */
1400 rewind(sw->stream);
1401 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001402 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001403 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001404 rc = parse_sdp_header(sw);
1405 if (rc < 0) {
1406 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1407 return -1;
1408 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001409
1410 strcpy((char *)sw->file_id, "id");
1411 sw->file_id_len = 3;
1412 strcpy((char *)sw->file_version, "version");
1413 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001414 break;
Harald Welte59b04682009-06-10 05:40:52 +08001415 default:
1416 /* We don't know how to treat them yet */
1417 close(sw->fd);
1418 return -EINVAL;
1419 }
1420
1421 return 0;
1422}
1423
1424static void sw_close_file(struct abis_nm_sw *sw)
1425{
1426 switch (sw->bts->type) {
1427 case GSM_BTS_TYPE_BS11:
1428 fclose(sw->stream);
1429 break;
1430 default:
1431 close(sw->fd);
1432 break;
1433 }
1434}
1435
1436/* Fill the window */
1437static int sw_fill_window(struct abis_nm_sw *sw)
1438{
1439 int rc;
1440
1441 while (sw->seg_in_window < sw->window_size) {
1442 rc = sw_load_segment(sw);
1443 if (rc < 0)
1444 return rc;
1445 if (sw->last_seg)
1446 break;
1447 }
1448 return 0;
1449}
1450
1451/* callback function from abis_nm_rcvmsg() handler */
1452static int abis_nm_rcvmsg_sw(struct msgb *mb)
1453{
1454 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1455 int rc = -1;
1456 struct abis_nm_sw *sw = &g_sw;
1457 enum sw_state old_state = sw->state;
1458
1459 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1460
1461 switch (sw->state) {
1462 case SW_STATE_WAIT_INITACK:
1463 switch (foh->msg_type) {
1464 case NM_MT_LOAD_INIT_ACK:
1465 /* fill window with segments */
1466 if (sw->cbfn)
1467 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1468 NM_MT_LOAD_INIT_ACK, mb,
1469 sw->cb_data, NULL);
1470 rc = sw_fill_window(sw);
1471 sw->state = SW_STATE_WAIT_SEGACK;
1472 break;
1473 case NM_MT_LOAD_INIT_NACK:
1474 if (sw->forced) {
1475 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1476 "Init NACK\n");
1477 if (sw->cbfn)
1478 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1479 NM_MT_LOAD_INIT_ACK, mb,
1480 sw->cb_data, NULL);
1481 rc = sw_fill_window(sw);
1482 sw->state = SW_STATE_WAIT_SEGACK;
1483 } else {
1484 DEBUGP(DNM, "Software Load Init NACK\n");
1485 /* FIXME: cause */
1486 if (sw->cbfn)
1487 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1488 NM_MT_LOAD_INIT_NACK, mb,
1489 sw->cb_data, NULL);
1490 sw->state = SW_STATE_ERROR;
1491 }
1492 break;
1493 }
1494 break;
1495 case SW_STATE_WAIT_SEGACK:
1496 switch (foh->msg_type) {
1497 case NM_MT_LOAD_SEG_ACK:
1498 if (sw->cbfn)
1499 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1500 NM_MT_LOAD_SEG_ACK, mb,
1501 sw->cb_data, NULL);
1502 sw->seg_in_window = 0;
1503 if (!sw->last_seg) {
1504 /* fill window with more segments */
1505 rc = sw_fill_window(sw);
1506 sw->state = SW_STATE_WAIT_SEGACK;
1507 } else {
1508 /* end the transfer */
1509 sw->state = SW_STATE_WAIT_ENDACK;
1510 rc = sw_load_end(sw);
1511 }
1512 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001513 case NM_MT_LOAD_ABORT:
1514 if (sw->cbfn)
1515 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1516 NM_MT_LOAD_ABORT, mb,
1517 sw->cb_data, NULL);
1518 break;
Harald Welte59b04682009-06-10 05:40:52 +08001519 }
1520 break;
1521 case SW_STATE_WAIT_ENDACK:
1522 switch (foh->msg_type) {
1523 case NM_MT_LOAD_END_ACK:
1524 sw_close_file(sw);
1525 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1526 sw->bts->nr);
1527 sw->state = SW_STATE_NONE;
1528 if (sw->cbfn)
1529 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1530 NM_MT_LOAD_END_ACK, mb,
1531 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001532 rc = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001533 break;
1534 case NM_MT_LOAD_END_NACK:
1535 if (sw->forced) {
1536 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1537 "End NACK\n");
1538 sw->state = SW_STATE_NONE;
1539 if (sw->cbfn)
1540 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1541 NM_MT_LOAD_END_ACK, mb,
1542 sw->cb_data, NULL);
1543 } else {
1544 DEBUGP(DNM, "Software Load End NACK\n");
1545 /* FIXME: cause */
1546 sw->state = SW_STATE_ERROR;
1547 if (sw->cbfn)
1548 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1549 NM_MT_LOAD_END_NACK, mb,
1550 sw->cb_data, NULL);
1551 }
1552 break;
1553 }
1554 case SW_STATE_WAIT_ACTACK:
1555 switch (foh->msg_type) {
1556 case NM_MT_ACTIVATE_SW_ACK:
1557 /* we're done */
1558 DEBUGP(DNM, "Activate Software DONE!\n");
1559 sw->state = SW_STATE_NONE;
1560 rc = 0;
1561 if (sw->cbfn)
1562 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1563 NM_MT_ACTIVATE_SW_ACK, mb,
1564 sw->cb_data, NULL);
1565 break;
1566 case NM_MT_ACTIVATE_SW_NACK:
1567 DEBUGP(DNM, "Activate Software NACK\n");
1568 /* FIXME: cause */
1569 sw->state = SW_STATE_ERROR;
1570 if (sw->cbfn)
1571 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1572 NM_MT_ACTIVATE_SW_NACK, mb,
1573 sw->cb_data, NULL);
1574 break;
1575 }
1576 case SW_STATE_NONE:
1577 switch (foh->msg_type) {
1578 case NM_MT_ACTIVATE_SW_ACK:
1579 rc = 0;
1580 break;
1581 }
1582 break;
1583 case SW_STATE_ERROR:
1584 break;
1585 }
1586
1587 if (rc)
1588 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1589 foh->msg_type, old_state, sw->state);
1590
1591 return rc;
1592}
1593
1594/* Load the specified software into the BTS */
1595int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
1596 u_int8_t win_size, int forced,
1597 gsm_cbfn *cbfn, void *cb_data)
1598{
1599 struct abis_nm_sw *sw = &g_sw;
1600 int rc;
1601
1602 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1603 bts->nr, fname);
1604
1605 if (sw->state != SW_STATE_NONE)
1606 return -EBUSY;
1607
1608 sw->bts = bts;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001609
1610 switch (bts->type) {
1611 case GSM_BTS_TYPE_BS11:
1612 sw->obj_class = NM_OC_SITE_MANAGER;
1613 sw->obj_instance[0] = 0xff;
1614 sw->obj_instance[1] = 0xff;
1615 sw->obj_instance[2] = 0xff;
1616 break;
1617 case GSM_BTS_TYPE_NANOBTS:
1618 sw->obj_class = NM_OC_BASEB_TRANSC;
1619 sw->obj_instance[0] = 0x00;
1620 sw->obj_instance[1] = 0x00;
1621 sw->obj_instance[2] = 0xff;
1622 break;
1623 case GSM_BTS_TYPE_UNKNOWN:
1624 default:
1625 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1626 return -1;
1627 break;
1628 }
Harald Welte59b04682009-06-10 05:40:52 +08001629 sw->window_size = win_size;
1630 sw->state = SW_STATE_WAIT_INITACK;
1631 sw->cbfn = cbfn;
1632 sw->cb_data = cb_data;
1633 sw->forced = forced;
1634
1635 rc = sw_open_file(sw, fname);
1636 if (rc < 0) {
1637 sw->state = SW_STATE_NONE;
1638 return rc;
1639 }
1640
1641 return sw_load_init(sw);
1642}
1643
1644int abis_nm_software_load_status(struct gsm_bts *bts)
1645{
1646 struct abis_nm_sw *sw = &g_sw;
1647 struct stat st;
1648 int rc, percent;
1649
1650 rc = fstat(sw->fd, &st);
1651 if (rc < 0) {
1652 perror("ERROR during stat");
1653 return rc;
1654 }
1655
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001656 if (sw->stream)
1657 percent = (ftell(sw->stream) * 100) / st.st_size;
1658 else
1659 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001660 return percent;
1661}
1662
1663/* Activate the specified software into the BTS */
1664int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1665 gsm_cbfn *cbfn, void *cb_data)
1666{
1667 struct abis_nm_sw *sw = &g_sw;
1668 int rc;
1669
1670 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1671 bts->nr, fname);
1672
1673 if (sw->state != SW_STATE_NONE)
1674 return -EBUSY;
1675
1676 sw->bts = bts;
1677 sw->obj_class = NM_OC_SITE_MANAGER;
1678 sw->obj_instance[0] = 0xff;
1679 sw->obj_instance[1] = 0xff;
1680 sw->obj_instance[2] = 0xff;
1681 sw->state = SW_STATE_WAIT_ACTACK;
1682 sw->cbfn = cbfn;
1683 sw->cb_data = cb_data;
1684
1685 /* Open the file in order to fill some sw struct members */
1686 rc = sw_open_file(sw, fname);
1687 if (rc < 0) {
1688 sw->state = SW_STATE_NONE;
1689 return rc;
1690 }
1691 sw_close_file(sw);
1692
1693 return sw_activate(sw);
1694}
1695
1696static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1697 u_int8_t ts_nr, u_int8_t subslot_nr)
1698{
1699 ch->attrib = NM_ATT_ABIS_CHANNEL;
1700 ch->bts_port = bts_port;
1701 ch->timeslot = ts_nr;
1702 ch->subslot = subslot_nr;
1703}
1704
1705int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1706 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1707 u_int8_t tei)
1708{
1709 struct abis_om_hdr *oh;
1710 struct abis_nm_channel *ch;
1711 u_int8_t len = sizeof(*ch) + 2;
1712 struct msgb *msg = nm_msgb_alloc();
1713
1714 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1715 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1716 bts->bts_nr, trx_nr, 0xff);
1717
1718 msgb_tv_put(msg, NM_ATT_TEI, tei);
1719
1720 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1721 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1722
1723 return abis_nm_sendmsg(bts, msg);
1724}
1725
1726/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1727int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1728 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1729{
1730 struct gsm_bts *bts = trx->bts;
1731 struct abis_om_hdr *oh;
1732 struct abis_nm_channel *ch;
1733 struct msgb *msg = nm_msgb_alloc();
1734
1735 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1736 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1737 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1738
1739 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1740 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1741
1742 return abis_nm_sendmsg(bts, msg);
1743}
1744
1745#if 0
1746int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1747 struct abis_nm_abis_channel *chan)
1748{
1749}
1750#endif
1751
1752int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1753 u_int8_t e1_port, u_int8_t e1_timeslot,
1754 u_int8_t e1_subslot)
1755{
1756 struct gsm_bts *bts = ts->trx->bts;
1757 struct abis_om_hdr *oh;
1758 struct abis_nm_channel *ch;
1759 struct msgb *msg = nm_msgb_alloc();
1760
1761 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1762 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1763 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1764
1765 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1766 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1767
1768 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1769 gsm_ts_name(ts),
1770 e1_port, e1_timeslot, e1_subslot);
1771
1772 return abis_nm_sendmsg(bts, msg);
1773}
1774
1775#if 0
1776int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1777 struct abis_nm_abis_channel *chan,
1778 u_int8_t subchan)
1779{
1780}
1781#endif
1782
1783/* Chapter 8.6.1 */
1784int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1785{
1786 struct abis_om_hdr *oh;
1787 struct msgb *msg = nm_msgb_alloc();
1788 u_int8_t *cur;
1789
1790 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1791
1792 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1793 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1794 cur = msgb_put(msg, attr_len);
1795 memcpy(cur, attr, attr_len);
1796
1797 return abis_nm_sendmsg(bts, msg);
1798}
1799
1800/* Chapter 8.6.2 */
1801int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1802{
1803 struct abis_om_hdr *oh;
1804 struct msgb *msg = nm_msgb_alloc();
1805 u_int8_t *cur;
1806
1807 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1808
1809 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1810 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1811 trx->bts->bts_nr, trx->nr, 0xff);
1812 cur = msgb_put(msg, attr_len);
1813 memcpy(cur, attr, attr_len);
1814
1815 return abis_nm_sendmsg(trx->bts, msg);
1816}
1817
Harald Weltef2eb2782009-08-09 21:49:48 +02001818static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1819{
1820 int i;
1821
1822 /* As it turns out, the BS-11 has some very peculiar restrictions
1823 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301824 switch (ts->trx->bts->type) {
1825 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001826 switch (chan_comb) {
1827 case NM_CHANC_TCHHalf:
1828 case NM_CHANC_TCHHalf2:
1829 /* not supported */
1830 return -EINVAL;
1831 case NM_CHANC_SDCCH:
1832 /* only one SDCCH/8 per TRX */
1833 for (i = 0; i < TRX_NR_TS; i++) {
1834 if (i == ts->nr)
1835 continue;
1836 if (ts->trx->ts[i].nm_chan_comb ==
1837 NM_CHANC_SDCCH)
1838 return -EINVAL;
1839 }
1840 /* not allowed for TS0 of BCCH-TRX */
1841 if (ts->trx == ts->trx->bts->c0 &&
1842 ts->nr == 0)
1843 return -EINVAL;
1844 /* not on the same TRX that has a BCCH+SDCCH4
1845 * combination */
1846 if (ts->trx == ts->trx->bts->c0 &&
1847 (ts->trx->ts[0].nm_chan_comb == 5 ||
1848 ts->trx->ts[0].nm_chan_comb == 8))
1849 return -EINVAL;
1850 break;
1851 case NM_CHANC_mainBCCH:
1852 case NM_CHANC_BCCHComb:
1853 /* allowed only for TS0 of C0 */
1854 if (ts->trx != ts->trx->bts->c0 ||
1855 ts->nr != 0)
1856 return -EINVAL;
1857 break;
1858 case NM_CHANC_BCCH:
1859 /* allowed only for TS 2/4/6 of C0 */
1860 if (ts->trx != ts->trx->bts->c0)
1861 return -EINVAL;
1862 if (ts->nr != 2 && ts->nr != 4 &&
1863 ts->nr != 6)
1864 return -EINVAL;
1865 break;
1866 case 8: /* this is not like 08.58, but in fact
1867 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1868 /* FIXME: only one CBCH allowed per cell */
1869 break;
1870 }
Harald Welte76ba8812009-12-02 02:45:23 +05301871 break;
1872 case GSM_BTS_TYPE_NANOBTS:
1873 switch (ts->nr) {
1874 case 0:
1875 if (ts->trx->nr == 0) {
1876 /* only on TRX0 */
1877 switch (chan_comb) {
1878 case NM_CHANC_BCCH:
1879 case NM_CHANC_mainBCCH:
1880 case NM_CHANC_BCCHComb:
1881 return 0;
1882 break;
1883 default:
1884 return -EINVAL;
1885 }
1886 } else {
1887 switch (chan_comb) {
1888 case NM_CHANC_TCHFull:
1889 case NM_CHANC_TCHHalf:
1890 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1891 return 0;
1892 default:
1893 return -EINVAL;
1894 }
1895 }
1896 break;
1897 case 1:
1898 if (ts->trx->nr == 0) {
1899 switch (chan_comb) {
1900 case NM_CHANC_SDCCH_CBCH:
1901 if (ts->trx->ts[0].nm_chan_comb ==
1902 NM_CHANC_mainBCCH)
1903 return 0;
1904 return -EINVAL;
1905 case NM_CHANC_SDCCH:
1906 case NM_CHANC_TCHFull:
1907 case NM_CHANC_TCHHalf:
1908 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1909 case NM_CHANC_IPAC_TCHFull_PDCH:
1910 return 0;
1911 }
1912 } else {
1913 switch (chan_comb) {
1914 case NM_CHANC_SDCCH:
1915 case NM_CHANC_TCHFull:
1916 case NM_CHANC_TCHHalf:
1917 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1918 return 0;
1919 default:
1920 return -EINVAL;
1921 }
1922 }
1923 break;
1924 case 2:
1925 case 3:
1926 case 4:
1927 case 5:
1928 case 6:
1929 case 7:
1930 switch (chan_comb) {
1931 case NM_CHANC_TCHFull:
1932 case NM_CHANC_TCHHalf:
1933 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1934 return 0;
1935 case NM_CHANC_IPAC_PDCH:
1936 case NM_CHANC_IPAC_TCHFull_PDCH:
1937 if (ts->trx->nr == 0)
1938 return 0;
1939 else
1940 return -EINVAL;
1941 }
1942 break;
1943 }
1944 return -EINVAL;
1945 default:
1946 /* unknown BTS type */
1947 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001948 }
1949 return 0;
1950}
1951
Harald Welte59b04682009-06-10 05:40:52 +08001952/* Chapter 8.6.3 */
1953int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1954{
1955 struct gsm_bts *bts = ts->trx->bts;
1956 struct abis_om_hdr *oh;
1957 u_int16_t arfcn = htons(ts->trx->arfcn);
1958 u_int8_t zero = 0x00;
1959 struct msgb *msg = nm_msgb_alloc();
1960 u_int8_t len = 2 + 2;
1961
1962 if (bts->type == GSM_BTS_TYPE_BS11)
1963 len += 4 + 2 + 2 + 3;
1964
1965 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001966 if (verify_chan_comb(ts, chan_comb) < 0) {
1967 msgb_free(msg);
1968 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1969 return -EINVAL;
1970 }
1971 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001972
1973 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1974 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1975 NM_OC_CHANNEL, bts->bts_nr,
1976 ts->trx->nr, ts->nr);
1977 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
1978 if (bts->type == GSM_BTS_TYPE_BS11)
1979 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
1980 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
1981 if (bts->type == GSM_BTS_TYPE_BS11) {
1982 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1983 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1984 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02001985 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001986 if (bts->type == GSM_BTS_TYPE_BS11)
1987 msgb_tlv_put(msg, 0x59, 1, &zero);
1988
1989 return abis_nm_sendmsg(bts, msg);
1990}
1991
1992int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
1993 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
1994{
1995 struct abis_om_hdr *oh;
1996 struct msgb *msg = nm_msgb_alloc();
1997 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1998 u_int8_t len = att_len;
1999
2000 if (nack) {
2001 len += 2;
2002 msgtype = NM_MT_SW_ACT_REQ_NACK;
2003 }
2004
2005 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2006 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2007
2008 if (attr) {
2009 u_int8_t *ptr = msgb_put(msg, att_len);
2010 memcpy(ptr, attr, att_len);
2011 }
2012 if (nack)
2013 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2014
2015 return abis_nm_sendmsg(bts, msg);
2016}
2017
2018int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2019{
2020 struct msgb *msg = nm_msgb_alloc();
2021 struct abis_om_hdr *oh;
2022 u_int8_t *data;
2023
2024 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2025 fill_om_hdr(oh, len);
2026 data = msgb_put(msg, len);
2027 memcpy(data, rawmsg, len);
2028
2029 return abis_nm_sendmsg(bts, msg);
2030}
2031
2032/* Siemens specific commands */
2033static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2034{
2035 struct abis_om_hdr *oh;
2036 struct msgb *msg = nm_msgb_alloc();
2037
2038 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2039 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2040 0xff, 0xff, 0xff);
2041
2042 return abis_nm_sendmsg(bts, msg);
2043}
2044
2045/* Chapter 8.9.2 */
2046int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2047{
2048 struct abis_om_hdr *oh;
2049 struct msgb *msg = nm_msgb_alloc();
2050
Harald Welte59b04682009-06-10 05:40:52 +08002051 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2052 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2053
Harald Welteb7284a92009-10-20 09:56:18 +02002054 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2055 DEBUGPC(DNM, "Sending OPSTART\n");
2056
Harald Welte59b04682009-06-10 05:40:52 +08002057 return abis_nm_sendmsg(bts, msg);
2058}
2059
2060/* Chapter 8.8.5 */
2061int 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 +02002062 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002063{
2064 struct abis_om_hdr *oh;
2065 struct msgb *msg = nm_msgb_alloc();
2066
2067 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2068 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2069 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2070
2071 return abis_nm_sendmsg(bts, msg);
2072}
2073
Harald Welte204317e2009-08-06 17:58:31 +02002074int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2075 u_int8_t e1_port1, u_int8_t ts1)
2076{
2077 struct abis_om_hdr *oh;
2078 struct msgb *msg = nm_msgb_alloc();
2079 u_int8_t *attr;
2080
2081 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2082 e1_port0, ts0, e1_port1, ts1);
2083
2084 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2085 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2086 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2087
2088 attr = msgb_put(msg, 3);
2089 attr[0] = NM_ATT_MDROP_LINK;
2090 attr[1] = e1_port0;
2091 attr[2] = ts0;
2092
2093 attr = msgb_put(msg, 3);
2094 attr[0] = NM_ATT_MDROP_NEXT;
2095 attr[1] = e1_port1;
2096 attr[2] = ts1;
2097
2098 return abis_nm_sendmsg(bts, msg);
2099}
Harald Welte59b04682009-06-10 05:40:52 +08002100
Harald Welte0bf8e302009-08-08 00:02:36 +02002101/* Chapter 8.7.1 */
2102int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2103 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2104 u_int8_t test_nr, u_int8_t auton_report,
2105 u_int8_t *phys_config, u_int16_t phys_config_len)
2106{
2107 struct abis_om_hdr *oh;
2108 struct msgb *msg = nm_msgb_alloc();
2109 int len = 4; /* 2 TV attributes */
2110
2111 DEBUGP(DNM, "PEFORM TEST\n");
2112
2113 if (phys_config_len)
2114 len += 3 + phys_config_len;
2115
2116 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2117 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2118 obj_class, bts_nr, trx_nr, ts_nr);
2119 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2120 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2121 if (phys_config_len)
2122 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2123 phys_config);
2124
2125 return abis_nm_sendmsg(bts, msg);
2126}
2127
Harald Welte59b04682009-06-10 05:40:52 +08002128int abis_nm_event_reports(struct gsm_bts *bts, int on)
2129{
2130 if (on == 0)
2131 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2132 else
2133 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2134}
2135
2136/* Siemens (or BS-11) specific commands */
2137
2138int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2139{
2140 if (reconnect == 0)
2141 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2142 else
2143 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2144}
2145
2146int abis_nm_bs11_restart(struct gsm_bts *bts)
2147{
2148 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2149}
2150
2151
2152struct bs11_date_time {
2153 u_int16_t year;
2154 u_int8_t month;
2155 u_int8_t day;
2156 u_int8_t hour;
2157 u_int8_t min;
2158 u_int8_t sec;
2159} __attribute__((packed));
2160
2161
2162void get_bs11_date_time(struct bs11_date_time *aet)
2163{
2164 time_t t;
2165 struct tm *tm;
2166
2167 t = time(NULL);
2168 tm = localtime(&t);
2169 aet->sec = tm->tm_sec;
2170 aet->min = tm->tm_min;
2171 aet->hour = tm->tm_hour;
2172 aet->day = tm->tm_mday;
2173 aet->month = tm->tm_mon;
2174 aet->year = htons(1900 + tm->tm_year);
2175}
2176
2177int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2178{
2179 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2180}
2181
2182int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2183{
2184 if (begin)
2185 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2186 else
2187 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2188}
2189
2190int abis_nm_bs11_create_object(struct gsm_bts *bts,
2191 enum abis_bs11_objtype type, u_int8_t idx,
2192 u_int8_t attr_len, const u_int8_t *attr)
2193{
2194 struct abis_om_hdr *oh;
2195 struct msgb *msg = nm_msgb_alloc();
2196 u_int8_t *cur;
2197
2198 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2199 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2200 NM_OC_BS11, type, 0, idx);
2201 cur = msgb_put(msg, attr_len);
2202 memcpy(cur, attr, attr_len);
2203
2204 return abis_nm_sendmsg(bts, msg);
2205}
2206
2207int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2208 enum abis_bs11_objtype type, u_int8_t idx)
2209{
2210 struct abis_om_hdr *oh;
2211 struct msgb *msg = nm_msgb_alloc();
2212
2213 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2214 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2215 NM_OC_BS11, type, 0, idx);
2216
2217 return abis_nm_sendmsg(bts, msg);
2218}
2219
2220int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2221{
2222 struct abis_om_hdr *oh;
2223 struct msgb *msg = nm_msgb_alloc();
2224 u_int8_t zero = 0x00;
2225
2226 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2227 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2228 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2229 msgb_tlv_put(msg, 0x99, 1, &zero);
2230
2231 return abis_nm_sendmsg(bts, msg);
2232}
2233
2234int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2235{
2236 struct abis_om_hdr *oh;
2237 struct msgb *msg = nm_msgb_alloc();
2238
2239 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2240 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002241 idx, 0xff, 0xff);
2242
2243 return abis_nm_sendmsg(bts, msg);
2244}
2245
2246int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2247{
2248 struct abis_om_hdr *oh;
2249 struct msgb *msg = nm_msgb_alloc();
2250
2251 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2252 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2253 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002254
2255 return abis_nm_sendmsg(bts, msg);
2256}
2257
2258static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2259int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2260{
2261 struct abis_om_hdr *oh;
2262 struct msgb *msg = nm_msgb_alloc();
2263
2264 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2265 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2266 0xff, 0xff, 0xff);
2267 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2268
2269 return abis_nm_sendmsg(bts, msg);
2270}
2271
2272/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002273int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welte59b04682009-06-10 05:40:52 +08002274 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2275 u_int8_t tei)
2276{
2277 struct abis_om_hdr *oh;
2278 struct abis_nm_channel *ch;
2279 struct msgb *msg = nm_msgb_alloc();
2280
2281 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2282 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2283 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2284
2285 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2286 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2287 msgb_tv_put(msg, NM_ATT_TEI, tei);
2288
2289 return abis_nm_sendmsg(bts, msg);
2290}
2291
2292int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2293{
2294 struct abis_om_hdr *oh;
2295 struct msgb *msg = nm_msgb_alloc();
2296
2297 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2298 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2299 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2300 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2301
2302 return abis_nm_sendmsg(trx->bts, msg);
2303}
2304
2305int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2306{
2307 struct abis_om_hdr *oh;
2308 struct msgb *msg = nm_msgb_alloc();
2309 u_int8_t attr = NM_ATT_BS11_TXPWR;
2310
2311 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2312 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2313 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2314 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2315
2316 return abis_nm_sendmsg(trx->bts, msg);
2317}
2318
2319int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2320{
2321 struct abis_om_hdr *oh;
2322 struct msgb *msg = nm_msgb_alloc();
2323 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2324
2325 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2326 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2327 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2328 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2329
2330 return abis_nm_sendmsg(bts, msg);
2331}
2332
2333int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2334{
2335 struct abis_om_hdr *oh;
2336 struct msgb *msg = nm_msgb_alloc();
2337 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2338 NM_ATT_BS11_CCLK_TYPE };
2339
2340 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2341 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2342 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2343 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2344
2345 return abis_nm_sendmsg(bts, msg);
2346
2347}
2348
2349//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002350
2351int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2352{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002353 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2354}
2355
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002356int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2357{
2358 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2359}
2360
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002361int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2362{
Harald Welte59b04682009-06-10 05:40:52 +08002363 struct abis_om_hdr *oh;
2364 struct msgb *msg = nm_msgb_alloc();
2365 struct bs11_date_time bdt;
2366
2367 get_bs11_date_time(&bdt);
2368
2369 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2370 if (on) {
2371 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002372 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002373 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2374 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2375 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2376 sizeof(bdt), (u_int8_t *) &bdt);
2377 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002378 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002379 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002380 strlen(name), (u_int8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002381 } else {
2382 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2383 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2384 }
2385
2386 return abis_nm_sendmsg(bts, msg);
2387}
2388
2389int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2390{
2391 struct abis_om_hdr *oh;
2392 struct msgb *msg;
2393
2394 if (strlen(password) != 10)
2395 return -EINVAL;
2396
2397 msg = nm_msgb_alloc();
2398 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2399 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2400 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2401 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2402
2403 return abis_nm_sendmsg(bts, msg);
2404}
2405
2406/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2407int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2408{
2409 struct abis_om_hdr *oh;
2410 struct msgb *msg;
2411 u_int8_t tlv_value;
2412
2413 msg = nm_msgb_alloc();
2414 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2415 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2416 BS11_OBJ_LI, 0x00, 0x00);
2417
2418 if (locked)
2419 tlv_value = BS11_LI_PLL_LOCKED;
2420 else
2421 tlv_value = BS11_LI_PLL_STANDALONE;
2422
2423 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2424
2425 return abis_nm_sendmsg(bts, msg);
2426}
2427
Daniel Willmann10b07db2010-01-07 00:54:01 +01002428/* Set the calibration value of the PLL (work value/set value)
2429 * It depends on the login which one is changed */
2430int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2431{
2432 struct abis_om_hdr *oh;
2433 struct msgb *msg;
2434 u_int8_t tlv_value[2];
2435
2436 msg = nm_msgb_alloc();
2437 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2438 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2439 BS11_OBJ_TRX1, 0x00, 0x00);
2440
2441 tlv_value[0] = value>>8;
2442 tlv_value[1] = value&0xff;
2443
2444 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2445
2446 return abis_nm_sendmsg(bts, msg);
2447}
2448
Harald Welte59b04682009-06-10 05:40:52 +08002449int abis_nm_bs11_get_state(struct gsm_bts *bts)
2450{
2451 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2452}
2453
2454/* BS11 SWL */
2455
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002456void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002457
Harald Welte59b04682009-06-10 05:40:52 +08002458struct abis_nm_bs11_sw {
2459 struct gsm_bts *bts;
2460 char swl_fname[PATH_MAX];
2461 u_int8_t win_size;
2462 int forced;
2463 struct llist_head file_list;
2464 gsm_cbfn *user_cb; /* specified by the user */
2465};
2466static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2467
2468struct file_list_entry {
2469 struct llist_head list;
2470 char fname[PATH_MAX];
2471};
2472
2473struct file_list_entry *fl_dequeue(struct llist_head *queue)
2474{
2475 struct llist_head *lh;
2476
2477 if (llist_empty(queue))
2478 return NULL;
2479
2480 lh = queue->next;
2481 llist_del(lh);
2482
2483 return llist_entry(lh, struct file_list_entry, list);
2484}
2485
2486static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2487{
2488 char linebuf[255];
2489 struct llist_head *lh, *lh2;
2490 FILE *swl;
2491 int rc = 0;
2492
2493 swl = fopen(bs11_sw->swl_fname, "r");
2494 if (!swl)
2495 return -ENODEV;
2496
2497 /* zero the stale file list, if any */
2498 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2499 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002500 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002501 }
2502
2503 while (fgets(linebuf, sizeof(linebuf), swl)) {
2504 char file_id[12+1];
2505 char file_version[80+1];
2506 struct file_list_entry *fle;
2507 static char dir[PATH_MAX];
2508
2509 if (strlen(linebuf) < 4)
2510 continue;
2511
2512 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2513 if (rc < 0) {
2514 perror("ERR parsing SWL file");
2515 rc = -EINVAL;
2516 goto out;
2517 }
2518 if (rc < 2)
2519 continue;
2520
Harald Welte857e00d2009-06-26 20:25:23 +02002521 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002522 if (!fle) {
2523 rc = -ENOMEM;
2524 goto out;
2525 }
Harald Welte59b04682009-06-10 05:40:52 +08002526
2527 /* construct new filename */
2528 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2529 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2530 strcat(fle->fname, "/");
2531 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2532
2533 llist_add_tail(&fle->list, &bs11_sw->file_list);
2534 }
2535
2536out:
2537 fclose(swl);
2538 return rc;
2539}
2540
2541/* bs11 swload specific callback, passed to abis_nm core swload */
2542static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2543 struct msgb *msg, void *data, void *param)
2544{
2545 struct abis_nm_bs11_sw *bs11_sw = data;
2546 struct file_list_entry *fle;
2547 int rc = 0;
2548
2549 switch (event) {
2550 case NM_MT_LOAD_END_ACK:
2551 fle = fl_dequeue(&bs11_sw->file_list);
2552 if (fle) {
2553 /* start download the next file of our file list */
2554 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
2555 bs11_sw->win_size,
2556 bs11_sw->forced,
2557 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002558 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002559 } else {
2560 /* activate the SWL */
2561 rc = abis_nm_software_activate(bs11_sw->bts,
2562 bs11_sw->swl_fname,
2563 bs11_swload_cbfn,
2564 bs11_sw);
2565 }
2566 break;
2567 case NM_MT_LOAD_SEG_ACK:
2568 case NM_MT_LOAD_END_NACK:
2569 case NM_MT_LOAD_INIT_ACK:
2570 case NM_MT_LOAD_INIT_NACK:
2571 case NM_MT_ACTIVATE_SW_NACK:
2572 case NM_MT_ACTIVATE_SW_ACK:
2573 default:
2574 /* fallthrough to the user callback */
2575 if (bs11_sw->user_cb)
2576 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2577 break;
2578 }
2579
2580 return rc;
2581}
2582
2583/* Siemens provides a SWL file that is a mere listing of all the other
2584 * files that are part of a software release. We need to upload first
2585 * the list file, and then each file that is listed in the list file */
2586int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2587 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2588{
2589 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2590 struct file_list_entry *fle;
2591 int rc = 0;
2592
2593 INIT_LLIST_HEAD(&bs11_sw->file_list);
2594 bs11_sw->bts = bts;
2595 bs11_sw->win_size = win_size;
2596 bs11_sw->user_cb = cbfn;
2597 bs11_sw->forced = forced;
2598
2599 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2600 rc = bs11_read_swl_file(bs11_sw);
2601 if (rc < 0)
2602 return rc;
2603
2604 /* dequeue next item in file list */
2605 fle = fl_dequeue(&bs11_sw->file_list);
2606 if (!fle)
2607 return -EINVAL;
2608
2609 /* start download the next file of our file list */
2610 rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
2611 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002612 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002613 return rc;
2614}
2615
2616#if 0
2617static u_int8_t req_attr_btse[] = {
2618 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2619 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2620 NM_ATT_BS11_LMT_USER_NAME,
2621
2622 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2623
2624 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2625
2626 NM_ATT_BS11_SW_LOAD_STORED };
2627
2628static u_int8_t req_attr_btsm[] = {
2629 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2630 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2631 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2632 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2633#endif
2634
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002635static u_int8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002636 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2637 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2638 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2639
2640int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2641{
2642 struct abis_om_hdr *oh;
2643 struct msgb *msg = nm_msgb_alloc();
2644
2645 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2646 /* SiemensHW CCTRL object */
2647 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2648 0x03, 0x00, 0x00);
2649 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2650
2651 return abis_nm_sendmsg(bts, msg);
2652}
2653
2654int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2655{
2656 struct abis_om_hdr *oh;
2657 struct msgb *msg = nm_msgb_alloc();
2658 struct bs11_date_time aet;
2659
2660 get_bs11_date_time(&aet);
2661 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2662 /* SiemensHW CCTRL object */
2663 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2664 0xff, 0xff, 0xff);
2665 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2666
2667 return abis_nm_sendmsg(bts, msg);
2668}
2669
Daniel Willmann5655afe2009-08-10 11:49:36 +02002670int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2671{
2672 struct abis_om_hdr *oh;
2673 struct msgb *msg = nm_msgb_alloc();
2674 struct bs11_date_time aet;
2675
2676 get_bs11_date_time(&aet);
2677 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2678 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2679 bport, 0xff, 0x02);
2680 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2681
2682 return abis_nm_sendmsg(bts, msg);
2683}
2684
Harald Welte59b04682009-06-10 05:40:52 +08002685/* ip.access nanoBTS specific commands */
2686static const char ipaccess_magic[] = "com.ipaccess";
2687
2688
2689static int abis_nm_rx_ipacc(struct msgb *msg)
2690{
2691 struct abis_om_hdr *oh = msgb_l2(msg);
2692 struct abis_om_fom_hdr *foh;
2693 u_int8_t idstrlen = oh->data[0];
2694 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002695 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002696
2697 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002698 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002699 return -EINVAL;
2700 }
2701
2702 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002703 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002704
Harald Welteb7284a92009-10-20 09:56:18 +02002705 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002706
Harald Welte5aeedd42009-10-19 22:11:11 +02002707 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002708
2709 switch (foh->msg_type) {
2710 case NM_MT_IPACC_RSL_CONNECT_ACK:
2711 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte4206d982009-07-12 09:33:54 +02002712 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte59b04682009-06-10 05:40:52 +08002713 DEBUGPC(DNM, "IP=%s ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002714 inet_ntoa(*((struct in_addr *)
Harald Welte4206d982009-07-12 09:33:54 +02002715 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2716 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002717 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002718 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002719 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002720 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2721 DEBUGPC(DNM, "STREAM=0x%02x ",
2722 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002723 DEBUGPC(DNM, "\n");
2724 break;
2725 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002726 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002727 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002728 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002729 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2730 else
2731 DEBUGPC(DNM, "\n");
2732 break;
2733 case NM_MT_IPACC_SET_NVATTR_ACK:
2734 DEBUGPC(DNM, "SET NVATTR ACK\n");
2735 /* FIXME: decode and show the actual attributes */
2736 break;
2737 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002738 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002739 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002740 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002741 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2742 else
Harald Weltede4477a2009-12-24 12:20:20 +01002743 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002744 break;
Harald Welte21460f02009-07-03 11:26:45 +02002745 case NM_MT_IPACC_GET_NVATTR_ACK:
2746 DEBUGPC(DNM, "GET NVATTR ACK\n");
2747 /* FIXME: decode and show the actual attributes */
2748 break;
2749 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002750 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002751 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002752 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002753 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2754 else
Harald Weltede4477a2009-12-24 12:20:20 +01002755 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002756 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002757 case NM_MT_IPACC_SET_ATTR_ACK:
2758 DEBUGPC(DNM, "SET ATTR ACK\n");
2759 break;
2760 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002761 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002762 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002763 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002764 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2765 else
Harald Weltede4477a2009-12-24 12:20:20 +01002766 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002767 break;
Harald Welte59b04682009-06-10 05:40:52 +08002768 default:
2769 DEBUGPC(DNM, "unknown\n");
2770 break;
2771 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002772
2773 /* signal handling */
2774 switch (foh->msg_type) {
2775 case NM_MT_IPACC_RSL_CONNECT_NACK:
2776 case NM_MT_IPACC_SET_NVATTR_NACK:
2777 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002778 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002779 signal.msg_type = foh->msg_type;
2780 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002781 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002782 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002783 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002784 signal.msg_type = foh->msg_type;
2785 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002786 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002787 default:
2788 break;
2789 }
2790
Harald Welte59b04682009-06-10 05:40:52 +08002791 return 0;
2792}
2793
2794/* send an ip-access manufacturer specific message */
2795int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2796 u_int8_t obj_class, u_int8_t bts_nr,
2797 u_int8_t trx_nr, u_int8_t ts_nr,
2798 u_int8_t *attr, int attr_len)
2799{
2800 struct msgb *msg = nm_msgb_alloc();
2801 struct abis_om_hdr *oh;
2802 struct abis_om_fom_hdr *foh;
2803 u_int8_t *data;
2804
2805 /* construct the 12.21 OM header, observe the erroneous length */
2806 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2807 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2808 oh->mdisc = ABIS_OM_MDISC_MANUF;
2809
2810 /* add the ip.access magic */
2811 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2812 *data++ = sizeof(ipaccess_magic);
2813 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2814
2815 /* fill the 12.21 FOM header */
2816 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2817 foh->msg_type = msg_type;
2818 foh->obj_class = obj_class;
2819 foh->obj_inst.bts_nr = bts_nr;
2820 foh->obj_inst.trx_nr = trx_nr;
2821 foh->obj_inst.ts_nr = ts_nr;
2822
2823 if (attr && attr_len) {
2824 data = msgb_put(msg, attr_len);
2825 memcpy(data, attr, attr_len);
2826 }
2827
2828 return abis_nm_sendmsg(bts, msg);
2829}
2830
2831/* set some attributes in NVRAM */
Harald Weltef12c1052010-01-07 20:39:42 +01002832int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002833 int attr_len)
2834{
Harald Weltef12c1052010-01-07 20:39:42 +01002835 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2836 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002837 attr_len);
2838}
2839
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002840int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte5aeedd42009-10-19 22:11:11 +02002841 u_int32_t ip, u_int16_t port, u_int8_t stream)
2842{
2843 struct in_addr ia;
2844 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2845 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2846 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2847
2848 int attr_len = sizeof(attr);
2849
2850 ia.s_addr = htonl(ip);
2851 attr[1] = stream;
2852 attr[3] = port >> 8;
2853 attr[4] = port & 0xff;
2854 *(u_int32_t *)(attr+6) = ia.s_addr;
2855
2856 /* if ip == 0, we use the default IP */
2857 if (ip == 0)
2858 attr_len -= 5;
2859
2860 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002861 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002862
2863 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2864 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2865 trx->nr, 0xff, attr, attr_len);
2866}
2867
Harald Welte59b04682009-06-10 05:40:52 +08002868/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002869int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002870{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002871 struct abis_om_hdr *oh;
2872 struct msgb *msg = nm_msgb_alloc();
2873
2874 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2875 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2876 trx->bts->nr, trx->nr, 0xff);
2877
2878 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002879}
Harald Welte0dfc6232009-10-24 10:20:41 +02002880
2881int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2882 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2883 u_int8_t *attr, u_int8_t attr_len)
2884{
2885 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2886 obj_class, bts_nr, trx_nr, ts_nr,
2887 attr, attr_len);
2888}
Harald Weltebeeae412009-11-12 14:48:42 +01002889
Harald Welte3055e332010-03-14 15:37:43 +08002890void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2891{
2892 /* we simply reuse the GSM48 function and overwrite the RAC
2893 * with the Cell ID */
2894 gsm48_ra_id_by_bts(buf, bts);
2895 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2896}
2897
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002898void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2899{
2900 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2901
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01002902 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002903 if (!trx->bts || !trx->bts->oml_link)
2904 return;
2905
2906 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2907 trx->bts->bts_nr, trx->nr, 0xff,
2908 new_state);
2909}
2910
Harald Welte453141f2010-03-25 11:45:30 +08002911static const struct value_string ipacc_testres_names[] = {
2912 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2913 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2914 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2915 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2916 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2917 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002918};
2919
2920const char *ipacc_testres_name(u_int8_t res)
2921{
Harald Welte453141f2010-03-25 11:45:30 +08002922 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002923}
2924
Harald Weltebfc21092009-11-13 11:56:05 +01002925void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2926{
2927 cid->mcc = (buf[0] & 0xf) * 100;
2928 cid->mcc += (buf[0] >> 4) * 10;
2929 cid->mcc += (buf[1] & 0xf) * 1;
2930
2931 if (buf[1] >> 4 == 0xf) {
2932 cid->mnc = (buf[2] & 0xf) * 10;
2933 cid->mnc += (buf[2] >> 4) * 1;
2934 } else {
2935 cid->mnc = (buf[2] & 0xf) * 100;
2936 cid->mnc += (buf[2] >> 4) * 10;
2937 cid->mnc += (buf[1] >> 4) * 1;
2938 }
2939
Harald Welte161b4be2009-11-13 14:41:52 +01002940 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2941 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002942}
2943
Harald Weltebeeae412009-11-12 14:48:42 +01002944/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2945int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2946{
2947 u_int8_t *cur = buf;
2948 u_int16_t len;
2949
2950 memset(binf, 0, sizeof(binf));
2951
2952 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2953 return -EINVAL;
2954 cur++;
2955
2956 len = ntohs(*(u_int16_t *)cur);
2957 cur += 2;
2958
2959 binf->info_type = ntohs(*(u_int16_t *)cur);
2960 cur += 2;
2961
2962 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2963 binf->freq_qual = *cur >> 2;
2964
2965 binf->arfcn = *cur++ & 3 << 8;
2966 binf->arfcn |= *cur++;
2967
2968 if (binf->info_type & IPAC_BINF_RXLEV)
2969 binf->rx_lev = *cur & 0x3f;
2970 cur++;
2971
2972 if (binf->info_type & IPAC_BINF_RXQUAL)
2973 binf->rx_qual = *cur & 0x7;
2974 cur++;
2975
2976 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2977 binf->freq_err = ntohs(*(u_int16_t *)cur);
2978 cur += 2;
2979
2980 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2981 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2982 cur += 2;
2983
2984 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2985 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2986 cur += 4;
2987
2988 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte161b4be2009-11-13 14:41:52 +01002989 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002990 cur++;
2991
Harald Weltebfc21092009-11-13 11:56:05 +01002992 ipac_parse_cgi(&binf->cgi, cur);
2993 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002994
2995 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2996 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2997 cur += sizeof(binf->ba_list_si2);
2998 }
2999
3000 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3001 memcpy(binf->ba_list_si2bis, cur,
3002 sizeof(binf->ba_list_si2bis));
3003 cur += sizeof(binf->ba_list_si2bis);
3004 }
3005
3006 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3007 memcpy(binf->ba_list_si2ter, cur,
3008 sizeof(binf->ba_list_si2ter));
3009 cur += sizeof(binf->ba_list_si2ter);
3010 }
3011
3012 return 0;
3013}