blob: 68373050a01c9506f1bf6e05a8256fcf78e4633c [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 Welte63b964e2010-05-31 16:40:40 +0200422const struct value_string abis_nm_obj_class_names[] = {
423 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte453141f2010-03-25 11:45:30 +0800424 { NM_OC_BTS, "BTS" },
Harald Welte63b964e2010-05-31 16:40:40 +0200425 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
426 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte453141f2010-03-25 11:45:30 +0800427 { NM_OC_CHANNEL, "CHANNEL" },
428 { NM_OC_BS11_ADJC, "ADJC" },
429 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte63b964e2010-05-31 16:40:40 +0200430 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte453141f2010-03-25 11:45:30 +0800431 { 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" },
Harald Welte63b964e2010-05-31 16:40:40 +0200436 { NM_OC_GPRS_NSE, "GPRS-NSE" },
437 { NM_OC_GPRS_CELL, "GPRS-CELL" },
438 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte453141f2010-03-25 11:45:30 +0800439 { 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 Welte63b964e2010-05-31 16:40:40 +0200445 return get_value_string(abis_nm_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 Welte63b964e2010-05-31 16:40:40 +0200493const struct value_string abis_nm_adm_state_names[] = {
494 { NM_STATE_LOCKED, "Locked" },
495 { NM_STATE_UNLOCKED, "Unlocked" },
496 { NM_STATE_SHUTDOWN, "Shutdown" },
497 { NM_STATE_NULL, "NULL" },
498 { 0, NULL }
499};
500
Harald Welte59b04682009-06-10 05:40:52 +0800501const char *nm_adm_name(u_int8_t adm)
502{
Harald Welte63b964e2010-05-31 16:40:40 +0200503 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte59b04682009-06-10 05:40:52 +0800504}
505
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100506int nm_is_running(struct gsm_nm_state *s) {
507 return (s->operational == NM_OPSTATE_ENABLED) && (
508 (s->availability == NM_AVSTATE_OK) ||
509 (s->availability == 0xff)
510 );
511}
512
Harald Welteb7284a92009-10-20 09:56:18 +0200513static void debugp_foh(struct abis_om_fom_hdr *foh)
514{
515 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200516 obj_class_name(foh->obj_class), foh->obj_class,
Harald Welteb7284a92009-10-20 09:56:18 +0200517 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
518 foh->obj_inst.ts_nr);
519}
520
Harald Welte59b04682009-06-10 05:40:52 +0800521/* obtain the gsm_nm_state data structure for a given object instance */
522static struct gsm_nm_state *
523objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
524 struct abis_om_obj_inst *obj_inst)
525{
526 struct gsm_bts_trx *trx;
527 struct gsm_nm_state *nm_state = NULL;
528
529 switch (obj_class) {
530 case NM_OC_BTS:
531 nm_state = &bts->nm_state;
532 break;
533 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100534 if (obj_inst->trx_nr >= bts->num_trx) {
535 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800536 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100537 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200538 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800539 nm_state = &trx->nm_state;
540 break;
541 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100542 if (obj_inst->trx_nr >= bts->num_trx) {
543 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800544 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100545 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200546 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800547 nm_state = &trx->bb_transc.nm_state;
548 break;
549 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100550 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100551 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800552 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100553 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200554 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800555 if (obj_inst->ts_nr >= TRX_NR_TS)
556 return NULL;
557 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
558 break;
559 case NM_OC_SITE_MANAGER:
560 nm_state = &bts->site_mgr.nm_state;
561 break;
562 case NM_OC_BS11:
563 switch (obj_inst->bts_nr) {
564 case BS11_OBJ_CCLK:
565 nm_state = &bts->bs11.cclk.nm_state;
566 break;
567 case BS11_OBJ_BBSIG:
568 if (obj_inst->ts_nr > bts->num_trx)
569 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200570 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800571 nm_state = &trx->bs11.bbsig.nm_state;
572 break;
573 case BS11_OBJ_PA:
574 if (obj_inst->ts_nr > bts->num_trx)
575 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200576 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800577 nm_state = &trx->bs11.pa.nm_state;
578 break;
579 default:
580 return NULL;
581 }
582 case NM_OC_BS11_RACK:
583 nm_state = &bts->bs11.rack.nm_state;
584 break;
585 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100586 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte59b04682009-06-10 05:40:52 +0800587 return NULL;
588 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
589 break;
Harald Welte439e1282009-10-24 10:19:14 +0200590 case NM_OC_GPRS_NSE:
591 nm_state = &bts->gprs.nse.nm_state;
592 break;
593 case NM_OC_GPRS_CELL:
594 nm_state = &bts->gprs.cell.nm_state;
595 break;
596 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100597 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200598 return NULL;
599 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
600 break;
Harald Welte59b04682009-06-10 05:40:52 +0800601 }
602 return nm_state;
603}
604
605/* obtain the in-memory data structure of a given object instance */
606static void *
607objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
608 struct abis_om_obj_inst *obj_inst)
609{
610 struct gsm_bts_trx *trx;
611 void *obj = NULL;
612
613 switch (obj_class) {
614 case NM_OC_BTS:
615 obj = bts;
616 break;
617 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100618 if (obj_inst->trx_nr >= bts->num_trx) {
619 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800620 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100621 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200622 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800623 obj = trx;
624 break;
625 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100626 if (obj_inst->trx_nr >= bts->num_trx) {
627 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800628 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100629 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200630 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800631 obj = &trx->bb_transc;
632 break;
633 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100634 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100635 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800636 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100637 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200638 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800639 if (obj_inst->ts_nr >= TRX_NR_TS)
640 return NULL;
641 obj = &trx->ts[obj_inst->ts_nr];
642 break;
643 case NM_OC_SITE_MANAGER:
644 obj = &bts->site_mgr;
645 break;
Harald Welte439e1282009-10-24 10:19:14 +0200646 case NM_OC_GPRS_NSE:
647 obj = &bts->gprs.nse;
648 break;
649 case NM_OC_GPRS_CELL:
650 obj = &bts->gprs.cell;
651 break;
652 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100653 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200654 return NULL;
655 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
656 break;
Harald Welte59b04682009-06-10 05:40:52 +0800657 }
658 return obj;
659}
660
661/* Update the administrative state of a given object in our in-memory data
662 * structures and send an event to the higher layer */
663static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
664 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
665{
666 struct gsm_nm_state *nm_state, new_state;
667 void *obj;
668 int rc;
669
670 obj = objclass2obj(bts, obj_class, obj_inst);
Harald Welte3d9ecf72009-11-13 12:10:18 +0100671 if (!obj)
672 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800673 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
674 if (!nm_state)
675 return -1;
676
677 new_state = *nm_state;
678 new_state.administrative = adm_state;
679
Holger Hans Peter Freyther9aec6db2010-05-13 00:37:48 +0800680 rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800681
682 nm_state->administrative = adm_state;
683
684 return rc;
685}
686
687static int abis_nm_rx_statechg_rep(struct msgb *mb)
688{
689 struct abis_om_hdr *oh = msgb_l2(mb);
690 struct abis_om_fom_hdr *foh = msgb_l3(mb);
691 struct gsm_bts *bts = mb->trx->bts;
692 struct tlv_parsed tp;
693 struct gsm_nm_state *nm_state, new_state;
694 int rc;
695
696 DEBUGPC(DNM, "STATE CHG: ");
697
698 memset(&new_state, 0, sizeof(new_state));
699
700 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
701 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100702 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800703 return -EINVAL;
704 }
705
706 new_state = *nm_state;
707
Harald Welte59698fb2010-01-10 18:01:52 +0100708 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800709 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
710 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
711 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
712 }
713 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
714 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
715 new_state.availability = 0xff;
716 else
717 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
718 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
719 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100720 } else
721 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800722 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
723 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther460fb3b2009-10-22 15:44:30 +0200724 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800725 }
726 DEBUGPC(DNM, "\n");
727
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100728 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
729 new_state.operational != nm_state->operational ||
730 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800731 /* Update the operational state of a given object in our in-memory data
732 * structures and send an event to the higher layer */
733 void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Holger Hans Peter Freyther9aec6db2010-05-13 00:37:48 +0800734 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 +0100735 nm_state->operational = new_state.operational;
736 nm_state->availability = new_state.availability;
737 if (nm_state->administrative == 0)
738 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800739 }
740#if 0
741 if (op_state == 1) {
742 /* try to enable objects that are disabled */
743 abis_nm_opstart(bts, foh->obj_class,
744 foh->obj_inst.bts_nr,
745 foh->obj_inst.trx_nr,
746 foh->obj_inst.ts_nr);
747 }
748#endif
749 return 0;
750}
751
752static int rx_fail_evt_rep(struct msgb *mb)
753{
754 struct abis_om_hdr *oh = msgb_l2(mb);
755 struct abis_om_fom_hdr *foh = msgb_l3(mb);
756 struct tlv_parsed tp;
757
758 DEBUGPC(DNM, "Failure Event Report ");
759
Harald Welte59698fb2010-01-10 18:01:52 +0100760 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800761
762 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
763 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
764 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
765 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
766
767 DEBUGPC(DNM, "\n");
768
769 return 0;
770}
771
772static int abis_nm_rcvmsg_report(struct msgb *mb)
773{
774 struct abis_om_fom_hdr *foh = msgb_l3(mb);
775 u_int8_t mt = foh->msg_type;
776
Harald Welteb7284a92009-10-20 09:56:18 +0200777 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800778
779 //nmh->cfg->report_cb(mb, foh);
780
781 switch (mt) {
782 case NM_MT_STATECHG_EVENT_REP:
783 return abis_nm_rx_statechg_rep(mb);
784 break;
785 case NM_MT_SW_ACTIVATED_REP:
786 DEBUGPC(DNM, "Software Activated Report\n");
787 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
788 break;
789 case NM_MT_FAILURE_EVENT_REP:
790 rx_fail_evt_rep(mb);
791 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
792 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200793 case NM_MT_TEST_REP:
794 DEBUGPC(DNM, "Test Report\n");
795 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
796 break;
Harald Welte59b04682009-06-10 05:40:52 +0800797 default:
798 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
799 break;
800
801 };
802
803 return 0;
804}
805
806/* Activate the specified software into the BTS */
807static 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 +0200808 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800809{
810 struct abis_om_hdr *oh;
811 struct msgb *msg = nm_msgb_alloc();
812 u_int8_t len = swdesc_len;
813 u_int8_t *trailer;
814
815 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
816 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
817
818 trailer = msgb_put(msg, swdesc_len);
819 memcpy(trailer, sw_desc, swdesc_len);
820
821 return abis_nm_sendmsg(bts, msg);
822}
823
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100824static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
825{
826 static const struct tlv_definition sw_descr_def = {
827 .def = {
828 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
829 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
830 },
831 };
832
833 u_int8_t tag;
834 u_int16_t tag_len;
835 const u_int8_t *val;
836 int ofs = 0, len;
837
838 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
839 * nested nature and the fact you have to assume it contains only two sub
840 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
841
842 if (sw_descr[0] != NM_ATT_SW_DESCR) {
843 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
844 return -1;
845 }
846 ofs += 1;
847
848 len = tlv_parse_one(&tag, &tag_len, &val,
849 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
850 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
851 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
852 return -2;
853 }
854 ofs += len;
855
856 len = tlv_parse_one(&tag, &tag_len, &val,
857 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
858 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
859 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
860 return -3;
861 }
862 ofs += len;
863
864 return ofs;
865}
866
Harald Welte59b04682009-06-10 05:40:52 +0800867static int abis_nm_rx_sw_act_req(struct msgb *mb)
868{
869 struct abis_om_hdr *oh = msgb_l2(mb);
870 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200871 struct tlv_parsed tp;
872 const u_int8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100873 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800874
Harald Welteb7284a92009-10-20 09:56:18 +0200875 debugp_foh(foh);
876
877 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800878
Harald Welte3055e332010-03-14 15:37:43 +0800879 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800880
881 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
882 foh->obj_inst.bts_nr,
883 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800884 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800885 foh->data, oh->length-sizeof(*foh));
886
Harald Welte59698fb2010-01-10 18:01:52 +0100887 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200888 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
889 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
890 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
891 DEBUGP(DNM, "SW config not found! Can't continue.\n");
892 return -EINVAL;
893 } else {
894 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
895 }
896
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100897 /* Use the first SW_DESCR present in SW config */
898 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
899 if (sw_descr_len < 0)
900 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200901
Harald Welte59b04682009-06-10 05:40:52 +0800902 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
903 foh->obj_inst.bts_nr,
904 foh->obj_inst.trx_nr,
905 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100906 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800907}
908
909/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
910static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
911{
912 struct abis_om_hdr *oh = msgb_l2(mb);
913 struct abis_om_fom_hdr *foh = msgb_l3(mb);
914 struct tlv_parsed tp;
915 u_int8_t adm_state;
916
Harald Welte59698fb2010-01-10 18:01:52 +0100917 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800918 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
919 return -EINVAL;
920
921 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
922
923 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
924}
925
926static int abis_nm_rx_lmt_event(struct msgb *mb)
927{
928 struct abis_om_hdr *oh = msgb_l2(mb);
929 struct abis_om_fom_hdr *foh = msgb_l3(mb);
930 struct tlv_parsed tp;
931
932 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100933 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800934 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
935 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
936 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
937 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
938 }
939 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
940 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
941 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
942 DEBUGPC(DNM, "Level=%u ", level);
943 }
944 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
945 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
946 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
947 DEBUGPC(DNM, "Username=%s ", name);
948 }
949 DEBUGPC(DNM, "\n");
950 /* FIXME: parse LMT LOGON TIME */
951 return 0;
952}
953
954/* Receive a OML NM Message from BTS */
955static int abis_nm_rcvmsg_fom(struct msgb *mb)
956{
957 struct abis_om_hdr *oh = msgb_l2(mb);
958 struct abis_om_fom_hdr *foh = msgb_l3(mb);
959 u_int8_t mt = foh->msg_type;
960
961 /* check for unsolicited message */
962 if (is_report(mt))
963 return abis_nm_rcvmsg_report(mb);
964
965 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
966 return abis_nm_rcvmsg_sw(mb);
967
968 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
969 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200970
Harald Welteb7284a92009-10-20 09:56:18 +0200971 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200972
Harald Welte453141f2010-03-25 11:45:30 +0800973 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +0800974
Harald Welte59698fb2010-01-10 18:01:52 +0100975 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800976 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200977 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +0800978 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
979 else
980 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200981
Harald Welte6a21c732009-11-17 06:09:56 +0100982 dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200983 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800984 }
985#if 0
986 /* check if last message is to be acked */
987 if (is_ack_nack(nmh->last_msgtype)) {
988 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100989 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800990 /* we got our ACK, continue sending the next msg */
991 } else if (mt == MT_NACK(nmh->last_msgtype)) {
992 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100993 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800994 /* FIXME: somehow signal this to the caller */
995 } else {
996 /* really strange things happen */
997 return -EINVAL;
998 }
999 }
1000#endif
1001
1002 switch (mt) {
1003 case NM_MT_CHG_ADM_STATE_ACK:
1004 return abis_nm_rx_chg_adm_state_ack(mb);
1005 break;
1006 case NM_MT_SW_ACT_REQ:
1007 return abis_nm_rx_sw_act_req(mb);
1008 break;
1009 case NM_MT_BS11_LMT_SESSION:
1010 return abis_nm_rx_lmt_event(mb);
1011 break;
Harald Welte204317e2009-08-06 17:58:31 +02001012 case NM_MT_CONN_MDROP_LINK_ACK:
1013 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1014 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001015 case NM_MT_IPACC_RESTART_ACK:
1016 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1017 break;
1018 case NM_MT_IPACC_RESTART_NACK:
1019 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1020 break;
Harald Welte59b04682009-06-10 05:40:52 +08001021 }
1022
1023 return 0;
1024}
1025
1026static int abis_nm_rx_ipacc(struct msgb *mb);
1027
1028static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1029{
1030 int rc;
1031 int bts_type = mb->trx->bts->type;
1032
1033 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001034 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001035 rc = abis_nm_rx_ipacc(mb);
1036 break;
1037 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001038 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1039 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001040 rc = 0;
1041 break;
1042 }
1043
1044 return rc;
1045}
1046
1047/* High-Level API */
1048/* Entry-point where L2 OML from BTS enters the NM code */
1049int abis_nm_rcvmsg(struct msgb *msg)
1050{
1051 struct abis_om_hdr *oh = msgb_l2(msg);
1052 int rc = 0;
1053
1054 /* Various consistency checks */
1055 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001056 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001057 oh->placement);
1058 return -EINVAL;
1059 }
1060 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001061 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001062 oh->sequence);
1063 return -EINVAL;
1064 }
1065#if 0
1066 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1067 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1068 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001069 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001070 oh->length + sizeof(*oh), l2_len);
1071 return -EINVAL;
1072 }
1073 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001074 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 +08001075#endif
1076 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1077
1078 switch (oh->mdisc) {
1079 case ABIS_OM_MDISC_FOM:
1080 rc = abis_nm_rcvmsg_fom(msg);
1081 break;
1082 case ABIS_OM_MDISC_MANUF:
1083 rc = abis_nm_rcvmsg_manuf(msg);
1084 break;
1085 case ABIS_OM_MDISC_MMI:
1086 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001087 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001088 oh->mdisc);
1089 break;
1090 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001091 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001092 oh->mdisc);
1093 return -EINVAL;
1094 }
1095
1096 msgb_free(msg);
1097 return rc;
1098}
1099
1100#if 0
1101/* initialized all resources */
1102struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1103{
1104 struct abis_nm_h *nmh;
1105
1106 nmh = malloc(sizeof(*nmh));
1107 if (!nmh)
1108 return NULL;
1109
1110 nmh->cfg = cfg;
1111
1112 return nmh;
1113}
1114
1115/* free all resources */
1116void abis_nm_fini(struct abis_nm_h *nmh)
1117{
1118 free(nmh);
1119}
1120#endif
1121
1122/* Here we are trying to define a high-level API that can be used by
1123 * the actual BSC implementation. However, the architecture is currently
1124 * still under design. Ideally the calls to this API would be synchronous,
1125 * while the underlying stack behind the APi runs in a traditional select
1126 * based state machine.
1127 */
1128
1129/* 6.2 Software Load: */
1130enum sw_state {
1131 SW_STATE_NONE,
1132 SW_STATE_WAIT_INITACK,
1133 SW_STATE_WAIT_SEGACK,
1134 SW_STATE_WAIT_ENDACK,
1135 SW_STATE_WAIT_ACTACK,
1136 SW_STATE_ERROR,
1137};
1138
1139struct abis_nm_sw {
1140 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001141 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +08001142 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 */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001595int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Harald Welte59b04682009-06-10 05:40:52 +08001596 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 Freyther2b4083a2010-05-12 23:51:46 +08001609 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001610
1611 switch (bts->type) {
1612 case GSM_BTS_TYPE_BS11:
1613 sw->obj_class = NM_OC_SITE_MANAGER;
1614 sw->obj_instance[0] = 0xff;
1615 sw->obj_instance[1] = 0xff;
1616 sw->obj_instance[2] = 0xff;
1617 break;
1618 case GSM_BTS_TYPE_NANOBTS:
1619 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001620 sw->obj_instance[0] = sw->bts->nr;
1621 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001622 sw->obj_instance[2] = 0xff;
1623 break;
1624 case GSM_BTS_TYPE_UNKNOWN:
1625 default:
1626 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1627 return -1;
1628 break;
1629 }
Harald Welte59b04682009-06-10 05:40:52 +08001630 sw->window_size = win_size;
1631 sw->state = SW_STATE_WAIT_INITACK;
1632 sw->cbfn = cbfn;
1633 sw->cb_data = cb_data;
1634 sw->forced = forced;
1635
1636 rc = sw_open_file(sw, fname);
1637 if (rc < 0) {
1638 sw->state = SW_STATE_NONE;
1639 return rc;
1640 }
1641
1642 return sw_load_init(sw);
1643}
1644
1645int abis_nm_software_load_status(struct gsm_bts *bts)
1646{
1647 struct abis_nm_sw *sw = &g_sw;
1648 struct stat st;
1649 int rc, percent;
1650
1651 rc = fstat(sw->fd, &st);
1652 if (rc < 0) {
1653 perror("ERROR during stat");
1654 return rc;
1655 }
1656
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001657 if (sw->stream)
1658 percent = (ftell(sw->stream) * 100) / st.st_size;
1659 else
1660 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001661 return percent;
1662}
1663
1664/* Activate the specified software into the BTS */
1665int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1666 gsm_cbfn *cbfn, void *cb_data)
1667{
1668 struct abis_nm_sw *sw = &g_sw;
1669 int rc;
1670
1671 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1672 bts->nr, fname);
1673
1674 if (sw->state != SW_STATE_NONE)
1675 return -EBUSY;
1676
1677 sw->bts = bts;
1678 sw->obj_class = NM_OC_SITE_MANAGER;
1679 sw->obj_instance[0] = 0xff;
1680 sw->obj_instance[1] = 0xff;
1681 sw->obj_instance[2] = 0xff;
1682 sw->state = SW_STATE_WAIT_ACTACK;
1683 sw->cbfn = cbfn;
1684 sw->cb_data = cb_data;
1685
1686 /* Open the file in order to fill some sw struct members */
1687 rc = sw_open_file(sw, fname);
1688 if (rc < 0) {
1689 sw->state = SW_STATE_NONE;
1690 return rc;
1691 }
1692 sw_close_file(sw);
1693
1694 return sw_activate(sw);
1695}
1696
1697static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1698 u_int8_t ts_nr, u_int8_t subslot_nr)
1699{
1700 ch->attrib = NM_ATT_ABIS_CHANNEL;
1701 ch->bts_port = bts_port;
1702 ch->timeslot = ts_nr;
1703 ch->subslot = subslot_nr;
1704}
1705
1706int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1707 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1708 u_int8_t tei)
1709{
1710 struct abis_om_hdr *oh;
1711 struct abis_nm_channel *ch;
1712 u_int8_t len = sizeof(*ch) + 2;
1713 struct msgb *msg = nm_msgb_alloc();
1714
1715 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1716 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1717 bts->bts_nr, trx_nr, 0xff);
1718
1719 msgb_tv_put(msg, NM_ATT_TEI, tei);
1720
1721 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1722 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1723
1724 return abis_nm_sendmsg(bts, msg);
1725}
1726
1727/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1728int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1729 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1730{
1731 struct gsm_bts *bts = trx->bts;
1732 struct abis_om_hdr *oh;
1733 struct abis_nm_channel *ch;
1734 struct msgb *msg = nm_msgb_alloc();
1735
1736 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1737 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1738 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1739
1740 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1741 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1742
1743 return abis_nm_sendmsg(bts, msg);
1744}
1745
1746#if 0
1747int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1748 struct abis_nm_abis_channel *chan)
1749{
1750}
1751#endif
1752
1753int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1754 u_int8_t e1_port, u_int8_t e1_timeslot,
1755 u_int8_t e1_subslot)
1756{
1757 struct gsm_bts *bts = ts->trx->bts;
1758 struct abis_om_hdr *oh;
1759 struct abis_nm_channel *ch;
1760 struct msgb *msg = nm_msgb_alloc();
1761
1762 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1763 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1764 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1765
1766 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1767 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1768
1769 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1770 gsm_ts_name(ts),
1771 e1_port, e1_timeslot, e1_subslot);
1772
1773 return abis_nm_sendmsg(bts, msg);
1774}
1775
1776#if 0
1777int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1778 struct abis_nm_abis_channel *chan,
1779 u_int8_t subchan)
1780{
1781}
1782#endif
1783
1784/* Chapter 8.6.1 */
1785int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1786{
1787 struct abis_om_hdr *oh;
1788 struct msgb *msg = nm_msgb_alloc();
1789 u_int8_t *cur;
1790
1791 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1792
1793 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1794 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1795 cur = msgb_put(msg, attr_len);
1796 memcpy(cur, attr, attr_len);
1797
1798 return abis_nm_sendmsg(bts, msg);
1799}
1800
1801/* Chapter 8.6.2 */
1802int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1803{
1804 struct abis_om_hdr *oh;
1805 struct msgb *msg = nm_msgb_alloc();
1806 u_int8_t *cur;
1807
1808 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1809
1810 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1811 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1812 trx->bts->bts_nr, trx->nr, 0xff);
1813 cur = msgb_put(msg, attr_len);
1814 memcpy(cur, attr, attr_len);
1815
1816 return abis_nm_sendmsg(trx->bts, msg);
1817}
1818
Harald Weltef2eb2782009-08-09 21:49:48 +02001819static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1820{
1821 int i;
1822
1823 /* As it turns out, the BS-11 has some very peculiar restrictions
1824 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301825 switch (ts->trx->bts->type) {
1826 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001827 switch (chan_comb) {
1828 case NM_CHANC_TCHHalf:
1829 case NM_CHANC_TCHHalf2:
1830 /* not supported */
1831 return -EINVAL;
1832 case NM_CHANC_SDCCH:
1833 /* only one SDCCH/8 per TRX */
1834 for (i = 0; i < TRX_NR_TS; i++) {
1835 if (i == ts->nr)
1836 continue;
1837 if (ts->trx->ts[i].nm_chan_comb ==
1838 NM_CHANC_SDCCH)
1839 return -EINVAL;
1840 }
1841 /* not allowed for TS0 of BCCH-TRX */
1842 if (ts->trx == ts->trx->bts->c0 &&
1843 ts->nr == 0)
1844 return -EINVAL;
1845 /* not on the same TRX that has a BCCH+SDCCH4
1846 * combination */
1847 if (ts->trx == ts->trx->bts->c0 &&
1848 (ts->trx->ts[0].nm_chan_comb == 5 ||
1849 ts->trx->ts[0].nm_chan_comb == 8))
1850 return -EINVAL;
1851 break;
1852 case NM_CHANC_mainBCCH:
1853 case NM_CHANC_BCCHComb:
1854 /* allowed only for TS0 of C0 */
1855 if (ts->trx != ts->trx->bts->c0 ||
1856 ts->nr != 0)
1857 return -EINVAL;
1858 break;
1859 case NM_CHANC_BCCH:
1860 /* allowed only for TS 2/4/6 of C0 */
1861 if (ts->trx != ts->trx->bts->c0)
1862 return -EINVAL;
1863 if (ts->nr != 2 && ts->nr != 4 &&
1864 ts->nr != 6)
1865 return -EINVAL;
1866 break;
1867 case 8: /* this is not like 08.58, but in fact
1868 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1869 /* FIXME: only one CBCH allowed per cell */
1870 break;
1871 }
Harald Welte76ba8812009-12-02 02:45:23 +05301872 break;
1873 case GSM_BTS_TYPE_NANOBTS:
1874 switch (ts->nr) {
1875 case 0:
1876 if (ts->trx->nr == 0) {
1877 /* only on TRX0 */
1878 switch (chan_comb) {
1879 case NM_CHANC_BCCH:
1880 case NM_CHANC_mainBCCH:
1881 case NM_CHANC_BCCHComb:
1882 return 0;
1883 break;
1884 default:
1885 return -EINVAL;
1886 }
1887 } else {
1888 switch (chan_comb) {
1889 case NM_CHANC_TCHFull:
1890 case NM_CHANC_TCHHalf:
1891 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1892 return 0;
1893 default:
1894 return -EINVAL;
1895 }
1896 }
1897 break;
1898 case 1:
1899 if (ts->trx->nr == 0) {
1900 switch (chan_comb) {
1901 case NM_CHANC_SDCCH_CBCH:
1902 if (ts->trx->ts[0].nm_chan_comb ==
1903 NM_CHANC_mainBCCH)
1904 return 0;
1905 return -EINVAL;
1906 case NM_CHANC_SDCCH:
1907 case NM_CHANC_TCHFull:
1908 case NM_CHANC_TCHHalf:
1909 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1910 case NM_CHANC_IPAC_TCHFull_PDCH:
1911 return 0;
1912 }
1913 } else {
1914 switch (chan_comb) {
1915 case NM_CHANC_SDCCH:
1916 case NM_CHANC_TCHFull:
1917 case NM_CHANC_TCHHalf:
1918 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1919 return 0;
1920 default:
1921 return -EINVAL;
1922 }
1923 }
1924 break;
1925 case 2:
1926 case 3:
1927 case 4:
1928 case 5:
1929 case 6:
1930 case 7:
1931 switch (chan_comb) {
1932 case NM_CHANC_TCHFull:
1933 case NM_CHANC_TCHHalf:
1934 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1935 return 0;
1936 case NM_CHANC_IPAC_PDCH:
1937 case NM_CHANC_IPAC_TCHFull_PDCH:
1938 if (ts->trx->nr == 0)
1939 return 0;
1940 else
1941 return -EINVAL;
1942 }
1943 break;
1944 }
1945 return -EINVAL;
1946 default:
1947 /* unknown BTS type */
1948 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001949 }
1950 return 0;
1951}
1952
Harald Welte59b04682009-06-10 05:40:52 +08001953/* Chapter 8.6.3 */
1954int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1955{
1956 struct gsm_bts *bts = ts->trx->bts;
1957 struct abis_om_hdr *oh;
1958 u_int16_t arfcn = htons(ts->trx->arfcn);
1959 u_int8_t zero = 0x00;
1960 struct msgb *msg = nm_msgb_alloc();
1961 u_int8_t len = 2 + 2;
1962
1963 if (bts->type == GSM_BTS_TYPE_BS11)
1964 len += 4 + 2 + 2 + 3;
1965
1966 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001967 if (verify_chan_comb(ts, chan_comb) < 0) {
1968 msgb_free(msg);
1969 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1970 return -EINVAL;
1971 }
1972 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001973
1974 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1975 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1976 NM_OC_CHANNEL, bts->bts_nr,
1977 ts->trx->nr, ts->nr);
1978 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
1979 if (bts->type == GSM_BTS_TYPE_BS11)
1980 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
1981 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
1982 if (bts->type == GSM_BTS_TYPE_BS11) {
1983 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
1984 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
1985 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02001986 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001987 if (bts->type == GSM_BTS_TYPE_BS11)
1988 msgb_tlv_put(msg, 0x59, 1, &zero);
1989
1990 return abis_nm_sendmsg(bts, msg);
1991}
1992
1993int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
1994 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
1995{
1996 struct abis_om_hdr *oh;
1997 struct msgb *msg = nm_msgb_alloc();
1998 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1999 u_int8_t len = att_len;
2000
2001 if (nack) {
2002 len += 2;
2003 msgtype = NM_MT_SW_ACT_REQ_NACK;
2004 }
2005
2006 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2007 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2008
2009 if (attr) {
2010 u_int8_t *ptr = msgb_put(msg, att_len);
2011 memcpy(ptr, attr, att_len);
2012 }
2013 if (nack)
2014 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2015
2016 return abis_nm_sendmsg(bts, msg);
2017}
2018
2019int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2020{
2021 struct msgb *msg = nm_msgb_alloc();
2022 struct abis_om_hdr *oh;
2023 u_int8_t *data;
2024
2025 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2026 fill_om_hdr(oh, len);
2027 data = msgb_put(msg, len);
2028 memcpy(data, rawmsg, len);
2029
2030 return abis_nm_sendmsg(bts, msg);
2031}
2032
2033/* Siemens specific commands */
2034static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2035{
2036 struct abis_om_hdr *oh;
2037 struct msgb *msg = nm_msgb_alloc();
2038
2039 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2040 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2041 0xff, 0xff, 0xff);
2042
2043 return abis_nm_sendmsg(bts, msg);
2044}
2045
2046/* Chapter 8.9.2 */
2047int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2048{
2049 struct abis_om_hdr *oh;
2050 struct msgb *msg = nm_msgb_alloc();
2051
Harald Welte59b04682009-06-10 05:40:52 +08002052 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2053 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2054
Harald Welteb7284a92009-10-20 09:56:18 +02002055 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2056 DEBUGPC(DNM, "Sending OPSTART\n");
2057
Harald Welte59b04682009-06-10 05:40:52 +08002058 return abis_nm_sendmsg(bts, msg);
2059}
2060
2061/* Chapter 8.8.5 */
2062int 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 +02002063 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002064{
2065 struct abis_om_hdr *oh;
2066 struct msgb *msg = nm_msgb_alloc();
2067
2068 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2069 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2070 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2071
2072 return abis_nm_sendmsg(bts, msg);
2073}
2074
Harald Welte204317e2009-08-06 17:58:31 +02002075int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2076 u_int8_t e1_port1, u_int8_t ts1)
2077{
2078 struct abis_om_hdr *oh;
2079 struct msgb *msg = nm_msgb_alloc();
2080 u_int8_t *attr;
2081
2082 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2083 e1_port0, ts0, e1_port1, ts1);
2084
2085 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2086 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2087 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2088
2089 attr = msgb_put(msg, 3);
2090 attr[0] = NM_ATT_MDROP_LINK;
2091 attr[1] = e1_port0;
2092 attr[2] = ts0;
2093
2094 attr = msgb_put(msg, 3);
2095 attr[0] = NM_ATT_MDROP_NEXT;
2096 attr[1] = e1_port1;
2097 attr[2] = ts1;
2098
2099 return abis_nm_sendmsg(bts, msg);
2100}
Harald Welte59b04682009-06-10 05:40:52 +08002101
Harald Welte0bf8e302009-08-08 00:02:36 +02002102/* Chapter 8.7.1 */
2103int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2104 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2105 u_int8_t test_nr, u_int8_t auton_report,
2106 u_int8_t *phys_config, u_int16_t phys_config_len)
2107{
2108 struct abis_om_hdr *oh;
2109 struct msgb *msg = nm_msgb_alloc();
2110 int len = 4; /* 2 TV attributes */
2111
2112 DEBUGP(DNM, "PEFORM TEST\n");
2113
2114 if (phys_config_len)
2115 len += 3 + phys_config_len;
2116
2117 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2118 fill_om_fom_hdr(oh, len, NM_MT_PERF_TEST,
2119 obj_class, bts_nr, trx_nr, ts_nr);
2120 msgb_tv_put(msg, NM_ATT_TEST_NO, test_nr);
2121 msgb_tv_put(msg, NM_ATT_AUTON_REPORT, auton_report);
2122 if (phys_config_len)
2123 msgb_tl16v_put(msg, NM_ATT_PHYS_CONF, phys_config_len,
2124 phys_config);
2125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
Harald Welte59b04682009-06-10 05:40:52 +08002129int abis_nm_event_reports(struct gsm_bts *bts, int on)
2130{
2131 if (on == 0)
2132 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2133 else
2134 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2135}
2136
2137/* Siemens (or BS-11) specific commands */
2138
2139int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2140{
2141 if (reconnect == 0)
2142 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2143 else
2144 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2145}
2146
2147int abis_nm_bs11_restart(struct gsm_bts *bts)
2148{
2149 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2150}
2151
2152
2153struct bs11_date_time {
2154 u_int16_t year;
2155 u_int8_t month;
2156 u_int8_t day;
2157 u_int8_t hour;
2158 u_int8_t min;
2159 u_int8_t sec;
2160} __attribute__((packed));
2161
2162
2163void get_bs11_date_time(struct bs11_date_time *aet)
2164{
2165 time_t t;
2166 struct tm *tm;
2167
2168 t = time(NULL);
2169 tm = localtime(&t);
2170 aet->sec = tm->tm_sec;
2171 aet->min = tm->tm_min;
2172 aet->hour = tm->tm_hour;
2173 aet->day = tm->tm_mday;
2174 aet->month = tm->tm_mon;
2175 aet->year = htons(1900 + tm->tm_year);
2176}
2177
2178int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2179{
2180 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2181}
2182
2183int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2184{
2185 if (begin)
2186 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2187 else
2188 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2189}
2190
2191int abis_nm_bs11_create_object(struct gsm_bts *bts,
2192 enum abis_bs11_objtype type, u_int8_t idx,
2193 u_int8_t attr_len, const u_int8_t *attr)
2194{
2195 struct abis_om_hdr *oh;
2196 struct msgb *msg = nm_msgb_alloc();
2197 u_int8_t *cur;
2198
2199 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2200 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2201 NM_OC_BS11, type, 0, idx);
2202 cur = msgb_put(msg, attr_len);
2203 memcpy(cur, attr, attr_len);
2204
2205 return abis_nm_sendmsg(bts, msg);
2206}
2207
2208int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2209 enum abis_bs11_objtype type, u_int8_t idx)
2210{
2211 struct abis_om_hdr *oh;
2212 struct msgb *msg = nm_msgb_alloc();
2213
2214 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2215 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2216 NM_OC_BS11, type, 0, idx);
2217
2218 return abis_nm_sendmsg(bts, msg);
2219}
2220
2221int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2222{
2223 struct abis_om_hdr *oh;
2224 struct msgb *msg = nm_msgb_alloc();
2225 u_int8_t zero = 0x00;
2226
2227 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2228 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2229 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2230 msgb_tlv_put(msg, 0x99, 1, &zero);
2231
2232 return abis_nm_sendmsg(bts, msg);
2233}
2234
2235int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2236{
2237 struct abis_om_hdr *oh;
2238 struct msgb *msg = nm_msgb_alloc();
2239
2240 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2241 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002242 idx, 0xff, 0xff);
2243
2244 return abis_nm_sendmsg(bts, msg);
2245}
2246
2247int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2248{
2249 struct abis_om_hdr *oh;
2250 struct msgb *msg = nm_msgb_alloc();
2251
2252 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2253 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2254 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002255
2256 return abis_nm_sendmsg(bts, msg);
2257}
2258
2259static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2260int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2261{
2262 struct abis_om_hdr *oh;
2263 struct msgb *msg = nm_msgb_alloc();
2264
2265 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2266 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2267 0xff, 0xff, 0xff);
2268 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2269
2270 return abis_nm_sendmsg(bts, msg);
2271}
2272
2273/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002274int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
Harald Welte59b04682009-06-10 05:40:52 +08002275 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2276 u_int8_t tei)
2277{
2278 struct abis_om_hdr *oh;
2279 struct abis_nm_channel *ch;
2280 struct msgb *msg = nm_msgb_alloc();
2281
2282 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2283 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2284 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2285
2286 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2287 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2288 msgb_tv_put(msg, NM_ATT_TEI, tei);
2289
2290 return abis_nm_sendmsg(bts, msg);
2291}
2292
2293int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2294{
2295 struct abis_om_hdr *oh;
2296 struct msgb *msg = nm_msgb_alloc();
2297
2298 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2299 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2300 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2301 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2302
2303 return abis_nm_sendmsg(trx->bts, msg);
2304}
2305
2306int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2307{
2308 struct abis_om_hdr *oh;
2309 struct msgb *msg = nm_msgb_alloc();
2310 u_int8_t attr = NM_ATT_BS11_TXPWR;
2311
2312 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2313 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2314 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2315 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2316
2317 return abis_nm_sendmsg(trx->bts, msg);
2318}
2319
2320int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2321{
2322 struct abis_om_hdr *oh;
2323 struct msgb *msg = nm_msgb_alloc();
2324 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2327 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2328 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2329 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2330
2331 return abis_nm_sendmsg(bts, msg);
2332}
2333
2334int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2335{
2336 struct abis_om_hdr *oh;
2337 struct msgb *msg = nm_msgb_alloc();
2338 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2339 NM_ATT_BS11_CCLK_TYPE };
2340
2341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2342 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2343 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2344 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2345
2346 return abis_nm_sendmsg(bts, msg);
2347
2348}
2349
2350//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002351
2352int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2353{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002354 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2355}
2356
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002357int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2358{
2359 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2360}
2361
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002362int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2363{
Harald Welte59b04682009-06-10 05:40:52 +08002364 struct abis_om_hdr *oh;
2365 struct msgb *msg = nm_msgb_alloc();
2366 struct bs11_date_time bdt;
2367
2368 get_bs11_date_time(&bdt);
2369
2370 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2371 if (on) {
2372 u_int8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002373 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002374 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2375 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2376 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2377 sizeof(bdt), (u_int8_t *) &bdt);
2378 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002379 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002380 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002381 strlen(name), (u_int8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002382 } else {
2383 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2384 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2385 }
2386
2387 return abis_nm_sendmsg(bts, msg);
2388}
2389
2390int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2391{
2392 struct abis_om_hdr *oh;
2393 struct msgb *msg;
2394
2395 if (strlen(password) != 10)
2396 return -EINVAL;
2397
2398 msg = nm_msgb_alloc();
2399 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2400 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2401 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2402 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2403
2404 return abis_nm_sendmsg(bts, msg);
2405}
2406
2407/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2408int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2409{
2410 struct abis_om_hdr *oh;
2411 struct msgb *msg;
2412 u_int8_t tlv_value;
2413
2414 msg = nm_msgb_alloc();
2415 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2416 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2417 BS11_OBJ_LI, 0x00, 0x00);
2418
2419 if (locked)
2420 tlv_value = BS11_LI_PLL_LOCKED;
2421 else
2422 tlv_value = BS11_LI_PLL_STANDALONE;
2423
2424 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2425
2426 return abis_nm_sendmsg(bts, msg);
2427}
2428
Daniel Willmann10b07db2010-01-07 00:54:01 +01002429/* Set the calibration value of the PLL (work value/set value)
2430 * It depends on the login which one is changed */
2431int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2432{
2433 struct abis_om_hdr *oh;
2434 struct msgb *msg;
2435 u_int8_t tlv_value[2];
2436
2437 msg = nm_msgb_alloc();
2438 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2439 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2440 BS11_OBJ_TRX1, 0x00, 0x00);
2441
2442 tlv_value[0] = value>>8;
2443 tlv_value[1] = value&0xff;
2444
2445 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2446
2447 return abis_nm_sendmsg(bts, msg);
2448}
2449
Harald Welte59b04682009-06-10 05:40:52 +08002450int abis_nm_bs11_get_state(struct gsm_bts *bts)
2451{
2452 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2453}
2454
2455/* BS11 SWL */
2456
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002457void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002458
Harald Welte59b04682009-06-10 05:40:52 +08002459struct abis_nm_bs11_sw {
2460 struct gsm_bts *bts;
2461 char swl_fname[PATH_MAX];
2462 u_int8_t win_size;
2463 int forced;
2464 struct llist_head file_list;
2465 gsm_cbfn *user_cb; /* specified by the user */
2466};
2467static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2468
2469struct file_list_entry {
2470 struct llist_head list;
2471 char fname[PATH_MAX];
2472};
2473
2474struct file_list_entry *fl_dequeue(struct llist_head *queue)
2475{
2476 struct llist_head *lh;
2477
2478 if (llist_empty(queue))
2479 return NULL;
2480
2481 lh = queue->next;
2482 llist_del(lh);
2483
2484 return llist_entry(lh, struct file_list_entry, list);
2485}
2486
2487static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2488{
2489 char linebuf[255];
2490 struct llist_head *lh, *lh2;
2491 FILE *swl;
2492 int rc = 0;
2493
2494 swl = fopen(bs11_sw->swl_fname, "r");
2495 if (!swl)
2496 return -ENODEV;
2497
2498 /* zero the stale file list, if any */
2499 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2500 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002501 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002502 }
2503
2504 while (fgets(linebuf, sizeof(linebuf), swl)) {
2505 char file_id[12+1];
2506 char file_version[80+1];
2507 struct file_list_entry *fle;
2508 static char dir[PATH_MAX];
2509
2510 if (strlen(linebuf) < 4)
2511 continue;
2512
2513 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2514 if (rc < 0) {
2515 perror("ERR parsing SWL file");
2516 rc = -EINVAL;
2517 goto out;
2518 }
2519 if (rc < 2)
2520 continue;
2521
Harald Welte857e00d2009-06-26 20:25:23 +02002522 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002523 if (!fle) {
2524 rc = -ENOMEM;
2525 goto out;
2526 }
Harald Welte59b04682009-06-10 05:40:52 +08002527
2528 /* construct new filename */
2529 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2530 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2531 strcat(fle->fname, "/");
2532 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2533
2534 llist_add_tail(&fle->list, &bs11_sw->file_list);
2535 }
2536
2537out:
2538 fclose(swl);
2539 return rc;
2540}
2541
2542/* bs11 swload specific callback, passed to abis_nm core swload */
2543static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2544 struct msgb *msg, void *data, void *param)
2545{
2546 struct abis_nm_bs11_sw *bs11_sw = data;
2547 struct file_list_entry *fle;
2548 int rc = 0;
2549
2550 switch (event) {
2551 case NM_MT_LOAD_END_ACK:
2552 fle = fl_dequeue(&bs11_sw->file_list);
2553 if (fle) {
2554 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002555 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002556 bs11_sw->win_size,
2557 bs11_sw->forced,
2558 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002559 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002560 } else {
2561 /* activate the SWL */
2562 rc = abis_nm_software_activate(bs11_sw->bts,
2563 bs11_sw->swl_fname,
2564 bs11_swload_cbfn,
2565 bs11_sw);
2566 }
2567 break;
2568 case NM_MT_LOAD_SEG_ACK:
2569 case NM_MT_LOAD_END_NACK:
2570 case NM_MT_LOAD_INIT_ACK:
2571 case NM_MT_LOAD_INIT_NACK:
2572 case NM_MT_ACTIVATE_SW_NACK:
2573 case NM_MT_ACTIVATE_SW_ACK:
2574 default:
2575 /* fallthrough to the user callback */
2576 if (bs11_sw->user_cb)
2577 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2578 break;
2579 }
2580
2581 return rc;
2582}
2583
2584/* Siemens provides a SWL file that is a mere listing of all the other
2585 * files that are part of a software release. We need to upload first
2586 * the list file, and then each file that is listed in the list file */
2587int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2588 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2589{
2590 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2591 struct file_list_entry *fle;
2592 int rc = 0;
2593
2594 INIT_LLIST_HEAD(&bs11_sw->file_list);
2595 bs11_sw->bts = bts;
2596 bs11_sw->win_size = win_size;
2597 bs11_sw->user_cb = cbfn;
2598 bs11_sw->forced = forced;
2599
2600 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2601 rc = bs11_read_swl_file(bs11_sw);
2602 if (rc < 0)
2603 return rc;
2604
2605 /* dequeue next item in file list */
2606 fle = fl_dequeue(&bs11_sw->file_list);
2607 if (!fle)
2608 return -EINVAL;
2609
2610 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002611 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002612 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002613 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002614 return rc;
2615}
2616
2617#if 0
2618static u_int8_t req_attr_btse[] = {
2619 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2620 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2621 NM_ATT_BS11_LMT_USER_NAME,
2622
2623 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2624
2625 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2626
2627 NM_ATT_BS11_SW_LOAD_STORED };
2628
2629static u_int8_t req_attr_btsm[] = {
2630 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2631 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2632 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2633 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2634#endif
2635
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002636static u_int8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002637 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2638 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2639 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2640
2641int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2642{
2643 struct abis_om_hdr *oh;
2644 struct msgb *msg = nm_msgb_alloc();
2645
2646 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2647 /* SiemensHW CCTRL object */
2648 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2649 0x03, 0x00, 0x00);
2650 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2651
2652 return abis_nm_sendmsg(bts, msg);
2653}
2654
2655int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2656{
2657 struct abis_om_hdr *oh;
2658 struct msgb *msg = nm_msgb_alloc();
2659 struct bs11_date_time aet;
2660
2661 get_bs11_date_time(&aet);
2662 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2663 /* SiemensHW CCTRL object */
2664 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2665 0xff, 0xff, 0xff);
2666 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2667
2668 return abis_nm_sendmsg(bts, msg);
2669}
2670
Daniel Willmann5655afe2009-08-10 11:49:36 +02002671int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2672{
2673 struct abis_om_hdr *oh;
2674 struct msgb *msg = nm_msgb_alloc();
2675 struct bs11_date_time aet;
2676
2677 get_bs11_date_time(&aet);
2678 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2679 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2680 bport, 0xff, 0x02);
2681 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2682
2683 return abis_nm_sendmsg(bts, msg);
2684}
2685
Harald Welte59b04682009-06-10 05:40:52 +08002686/* ip.access nanoBTS specific commands */
2687static const char ipaccess_magic[] = "com.ipaccess";
2688
2689
2690static int abis_nm_rx_ipacc(struct msgb *msg)
2691{
2692 struct abis_om_hdr *oh = msgb_l2(msg);
2693 struct abis_om_fom_hdr *foh;
2694 u_int8_t idstrlen = oh->data[0];
2695 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002696 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002697
2698 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002699 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002700 return -EINVAL;
2701 }
2702
2703 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002704 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002705
Harald Welteb7284a92009-10-20 09:56:18 +02002706 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002707
Harald Welte5aeedd42009-10-19 22:11:11 +02002708 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002709
2710 switch (foh->msg_type) {
2711 case NM_MT_IPACC_RSL_CONNECT_ACK:
2712 DEBUGPC(DNM, "RSL CONNECT ACK ");
Harald Welte4206d982009-07-12 09:33:54 +02002713 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
Harald Welte59b04682009-06-10 05:40:52 +08002714 DEBUGPC(DNM, "IP=%s ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002715 inet_ntoa(*((struct in_addr *)
Harald Welte4206d982009-07-12 09:33:54 +02002716 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
2717 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002718 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002719 ntohs(*((u_int16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002720 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002721 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2722 DEBUGPC(DNM, "STREAM=0x%02x ",
2723 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002724 DEBUGPC(DNM, "\n");
2725 break;
2726 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002727 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002728 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002729 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002730 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2731 else
2732 DEBUGPC(DNM, "\n");
2733 break;
2734 case NM_MT_IPACC_SET_NVATTR_ACK:
2735 DEBUGPC(DNM, "SET NVATTR ACK\n");
2736 /* FIXME: decode and show the actual attributes */
2737 break;
2738 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002739 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002740 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002741 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002742 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2743 else
Harald Weltede4477a2009-12-24 12:20:20 +01002744 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002745 break;
Harald Welte21460f02009-07-03 11:26:45 +02002746 case NM_MT_IPACC_GET_NVATTR_ACK:
2747 DEBUGPC(DNM, "GET NVATTR ACK\n");
2748 /* FIXME: decode and show the actual attributes */
2749 break;
2750 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002751 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002752 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002753 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002754 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2755 else
Harald Weltede4477a2009-12-24 12:20:20 +01002756 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002757 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002758 case NM_MT_IPACC_SET_ATTR_ACK:
2759 DEBUGPC(DNM, "SET ATTR ACK\n");
2760 break;
2761 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002762 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002763 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002764 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002765 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2766 else
Harald Weltede4477a2009-12-24 12:20:20 +01002767 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002768 break;
Harald Welte59b04682009-06-10 05:40:52 +08002769 default:
2770 DEBUGPC(DNM, "unknown\n");
2771 break;
2772 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002773
2774 /* signal handling */
2775 switch (foh->msg_type) {
2776 case NM_MT_IPACC_RSL_CONNECT_NACK:
2777 case NM_MT_IPACC_SET_NVATTR_NACK:
2778 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002779 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002780 signal.msg_type = foh->msg_type;
2781 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002782 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002783 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002784 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002785 signal.msg_type = foh->msg_type;
2786 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002787 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002788 default:
2789 break;
2790 }
2791
Harald Welte59b04682009-06-10 05:40:52 +08002792 return 0;
2793}
2794
2795/* send an ip-access manufacturer specific message */
2796int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2797 u_int8_t obj_class, u_int8_t bts_nr,
2798 u_int8_t trx_nr, u_int8_t ts_nr,
2799 u_int8_t *attr, int attr_len)
2800{
2801 struct msgb *msg = nm_msgb_alloc();
2802 struct abis_om_hdr *oh;
2803 struct abis_om_fom_hdr *foh;
2804 u_int8_t *data;
2805
2806 /* construct the 12.21 OM header, observe the erroneous length */
2807 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2808 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2809 oh->mdisc = ABIS_OM_MDISC_MANUF;
2810
2811 /* add the ip.access magic */
2812 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2813 *data++ = sizeof(ipaccess_magic);
2814 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2815
2816 /* fill the 12.21 FOM header */
2817 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2818 foh->msg_type = msg_type;
2819 foh->obj_class = obj_class;
2820 foh->obj_inst.bts_nr = bts_nr;
2821 foh->obj_inst.trx_nr = trx_nr;
2822 foh->obj_inst.ts_nr = ts_nr;
2823
2824 if (attr && attr_len) {
2825 data = msgb_put(msg, attr_len);
2826 memcpy(data, attr, attr_len);
2827 }
2828
2829 return abis_nm_sendmsg(bts, msg);
2830}
2831
2832/* set some attributes in NVRAM */
Harald Weltef12c1052010-01-07 20:39:42 +01002833int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002834 int attr_len)
2835{
Harald Weltef12c1052010-01-07 20:39:42 +01002836 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2837 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002838 attr_len);
2839}
2840
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002841int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Harald Welte5aeedd42009-10-19 22:11:11 +02002842 u_int32_t ip, u_int16_t port, u_int8_t stream)
2843{
2844 struct in_addr ia;
2845 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2846 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2847 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2848
2849 int attr_len = sizeof(attr);
2850
2851 ia.s_addr = htonl(ip);
2852 attr[1] = stream;
2853 attr[3] = port >> 8;
2854 attr[4] = port & 0xff;
2855 *(u_int32_t *)(attr+6) = ia.s_addr;
2856
2857 /* if ip == 0, we use the default IP */
2858 if (ip == 0)
2859 attr_len -= 5;
2860
2861 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002862 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002863
2864 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2865 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2866 trx->nr, 0xff, attr, attr_len);
2867}
2868
Harald Welte59b04682009-06-10 05:40:52 +08002869/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002870int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002871{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002872 struct abis_om_hdr *oh;
2873 struct msgb *msg = nm_msgb_alloc();
2874
2875 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2876 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2877 trx->bts->nr, trx->nr, 0xff);
2878
2879 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002880}
Harald Welte0dfc6232009-10-24 10:20:41 +02002881
2882int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2883 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2884 u_int8_t *attr, u_int8_t attr_len)
2885{
2886 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2887 obj_class, bts_nr, trx_nr, ts_nr,
2888 attr, attr_len);
2889}
Harald Weltebeeae412009-11-12 14:48:42 +01002890
Harald Welte3055e332010-03-14 15:37:43 +08002891void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2892{
2893 /* we simply reuse the GSM48 function and overwrite the RAC
2894 * with the Cell ID */
2895 gsm48_ra_id_by_bts(buf, bts);
2896 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
2897}
2898
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002899void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2900{
2901 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2902
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01002903 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002904 if (!trx->bts || !trx->bts->oml_link)
2905 return;
2906
2907 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2908 trx->bts->bts_nr, trx->nr, 0xff,
2909 new_state);
2910}
2911
Harald Welte453141f2010-03-25 11:45:30 +08002912static const struct value_string ipacc_testres_names[] = {
2913 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2914 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2915 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2916 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2917 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2918 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002919};
2920
2921const char *ipacc_testres_name(u_int8_t res)
2922{
Harald Welte453141f2010-03-25 11:45:30 +08002923 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002924}
2925
Harald Weltebfc21092009-11-13 11:56:05 +01002926void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
2927{
2928 cid->mcc = (buf[0] & 0xf) * 100;
2929 cid->mcc += (buf[0] >> 4) * 10;
2930 cid->mcc += (buf[1] & 0xf) * 1;
2931
2932 if (buf[1] >> 4 == 0xf) {
2933 cid->mnc = (buf[2] & 0xf) * 10;
2934 cid->mnc += (buf[2] >> 4) * 1;
2935 } else {
2936 cid->mnc = (buf[2] & 0xf) * 100;
2937 cid->mnc += (buf[2] >> 4) * 10;
2938 cid->mnc += (buf[1] >> 4) * 1;
2939 }
2940
Harald Welte161b4be2009-11-13 14:41:52 +01002941 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
2942 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002943}
2944
Harald Weltebeeae412009-11-12 14:48:42 +01002945/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
2946int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
2947{
2948 u_int8_t *cur = buf;
2949 u_int16_t len;
2950
2951 memset(binf, 0, sizeof(binf));
2952
2953 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2954 return -EINVAL;
2955 cur++;
2956
2957 len = ntohs(*(u_int16_t *)cur);
2958 cur += 2;
2959
2960 binf->info_type = ntohs(*(u_int16_t *)cur);
2961 cur += 2;
2962
2963 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2964 binf->freq_qual = *cur >> 2;
2965
2966 binf->arfcn = *cur++ & 3 << 8;
2967 binf->arfcn |= *cur++;
2968
2969 if (binf->info_type & IPAC_BINF_RXLEV)
2970 binf->rx_lev = *cur & 0x3f;
2971 cur++;
2972
2973 if (binf->info_type & IPAC_BINF_RXQUAL)
2974 binf->rx_qual = *cur & 0x7;
2975 cur++;
2976
2977 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2978 binf->freq_err = ntohs(*(u_int16_t *)cur);
2979 cur += 2;
2980
2981 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
2982 binf->frame_offset = ntohs(*(u_int16_t *)cur);
2983 cur += 2;
2984
2985 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
2986 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
2987 cur += 4;
2988
2989 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte161b4be2009-11-13 14:41:52 +01002990 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002991 cur++;
2992
Harald Weltebfc21092009-11-13 11:56:05 +01002993 ipac_parse_cgi(&binf->cgi, cur);
2994 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002995
2996 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2997 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2998 cur += sizeof(binf->ba_list_si2);
2999 }
3000
3001 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3002 memcpy(binf->ba_list_si2bis, cur,
3003 sizeof(binf->ba_list_si2bis));
3004 cur += sizeof(binf->ba_list_si2bis);
3005 }
3006
3007 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3008 memcpy(binf->ba_list_si2ter, cur,
3009 sizeof(binf->ba_list_si2ter));
3010 cur += sizeof(binf->ba_list_si2ter);
3011 }
3012
3013 return 0;
3014}