blob: 0d122c697f513b7918a9ba29534fcc35a0651169 [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte59b04682009-06-10 05:40:52 +080011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
Harald Welte59b04682009-06-10 05:40:52 +080033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
41#include <osmocom/core/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080042#include <openbsc/abis_nm.h>
43#include <openbsc/misdn.h>
44#include <openbsc/signal.h>
45
46#define OM_ALLOC_SIZE 1024
47#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010048#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080049
50/* unidirectional messages from BTS to BSC */
51static const enum abis_nm_msgtype reports[] = {
52 NM_MT_SW_ACTIVATED_REP,
53 NM_MT_TEST_REP,
54 NM_MT_STATECHG_EVENT_REP,
55 NM_MT_FAILURE_EVENT_REP,
56};
57
58/* messages without ACK/NACK */
59static const enum abis_nm_msgtype no_ack_nack[] = {
60 NM_MT_MEAS_RES_REQ,
61 NM_MT_STOP_MEAS,
62 NM_MT_START_MEAS,
63};
64
65/* Messages related to software load */
66static const enum abis_nm_msgtype sw_load_msgs[] = {
67 NM_MT_LOAD_INIT_ACK,
68 NM_MT_LOAD_INIT_NACK,
69 NM_MT_LOAD_SEG_ACK,
70 NM_MT_LOAD_ABORT,
71 NM_MT_LOAD_END_ACK,
72 NM_MT_LOAD_END_NACK,
73 //NM_MT_SW_ACT_REQ,
74 NM_MT_ACTIVATE_SW_ACK,
75 NM_MT_ACTIVATE_SW_NACK,
76 NM_MT_SW_ACTIVATED_REP,
77};
78
79static const enum abis_nm_msgtype nacks[] = {
80 NM_MT_LOAD_INIT_NACK,
81 NM_MT_LOAD_END_NACK,
82 NM_MT_SW_ACT_REQ_NACK,
83 NM_MT_ACTIVATE_SW_NACK,
84 NM_MT_ESTABLISH_TEI_NACK,
85 NM_MT_CONN_TERR_SIGN_NACK,
86 NM_MT_DISC_TERR_SIGN_NACK,
87 NM_MT_CONN_TERR_TRAF_NACK,
88 NM_MT_DISC_TERR_TRAF_NACK,
89 NM_MT_CONN_MDROP_LINK_NACK,
90 NM_MT_DISC_MDROP_LINK_NACK,
91 NM_MT_SET_BTS_ATTR_NACK,
92 NM_MT_SET_RADIO_ATTR_NACK,
93 NM_MT_SET_CHAN_ATTR_NACK,
94 NM_MT_PERF_TEST_NACK,
95 NM_MT_SEND_TEST_REP_NACK,
96 NM_MT_STOP_TEST_NACK,
97 NM_MT_STOP_EVENT_REP_NACK,
98 NM_MT_REST_EVENT_REP_NACK,
99 NM_MT_CHG_ADM_STATE_NACK,
100 NM_MT_CHG_ADM_STATE_REQ_NACK,
101 NM_MT_REP_OUTST_ALARMS_NACK,
102 NM_MT_CHANGEOVER_NACK,
103 NM_MT_OPSTART_NACK,
104 NM_MT_REINIT_NACK,
105 NM_MT_SET_SITE_OUT_NACK,
106 NM_MT_CHG_HW_CONF_NACK,
107 NM_MT_GET_ATTR_NACK,
108 NM_MT_SET_ALARM_THRES_NACK,
109 NM_MT_BS11_BEGIN_DB_TX_NACK,
110 NM_MT_BS11_END_DB_TX_NACK,
111 NM_MT_BS11_CREATE_OBJ_NACK,
112 NM_MT_BS11_DELETE_OBJ_NACK,
113};
114
Harald Welte453141f2010-03-25 11:45:30 +0800115static const struct value_string nack_names[] = {
116 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
117 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
118 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
119 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
120 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
121 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
122 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
123 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
124 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
125 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
126 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
127 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
128 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
129 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
130 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
131 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
132 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
133 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
134 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
135 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
136 { NM_MT_CHG_ADM_STATE_REQ_NACK,
137 "CHANGE ADMINISTRATIVE STATE REQUEST" },
138 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
139 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
140 { NM_MT_OPSTART_NACK, "OPSTART" },
141 { NM_MT_REINIT_NACK, "REINIT" },
142 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
143 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
144 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
145 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
146 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
147 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
148 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
149 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
150 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800151};
152
153/* Chapter 9.4.36 */
Harald Welte453141f2010-03-25 11:45:30 +0800154static const struct value_string nack_cause_names[] = {
Harald Welte59b04682009-06-10 05:40:52 +0800155 /* General Nack Causes */
Harald Welte453141f2010-03-25 11:45:30 +0800156 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
157 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
158 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
159 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
160 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
161 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
162 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
163 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
164 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
165 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
166 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
167 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
168 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
Harald Welte59b04682009-06-10 05:40:52 +0800169 /* Specific Nack Causes */
Harald Welte453141f2010-03-25 11:45:30 +0800170 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
171 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
172 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
173 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
174 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
175 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
176 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
177 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
178 { NM_NACK_TEST_NOSUCH, "No such test" },
179 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
180 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
181 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
182 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
183 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
184 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
185 { NM_NACK_WAIT, "Wait" },
186 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
187 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
188 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
189 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800190};
191
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200192static const char *nack_cause_name(uint8_t cause)
Harald Welte59b04682009-06-10 05:40:52 +0800193{
Harald Welte453141f2010-03-25 11:45:30 +0800194 return get_value_string(nack_cause_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800195}
196
197/* Chapter 9.4.16: Event Type */
Harald Welte453141f2010-03-25 11:45:30 +0800198static const struct value_string event_type_names[] = {
199 { NM_EVT_COMM_FAIL, "communication failure" },
200 { NM_EVT_QOS_FAIL, "quality of service failure" },
201 { NM_EVT_PROC_FAIL, "processing failure" },
202 { NM_EVT_EQUIP_FAIL, "equipment failure" },
203 { NM_EVT_ENV_FAIL, "environment failure" },
204 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800205};
206
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200207static const char *event_type_name(uint8_t cause)
Harald Welte59b04682009-06-10 05:40:52 +0800208{
Harald Welte453141f2010-03-25 11:45:30 +0800209 return get_value_string(event_type_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800210}
211
212/* Chapter 9.4.63: Perceived Severity */
Harald Welte453141f2010-03-25 11:45:30 +0800213static const struct value_string severity_names[] = {
214 { NM_SEVER_CEASED, "failure ceased" },
215 { NM_SEVER_CRITICAL, "critical failure" },
216 { NM_SEVER_MAJOR, "major failure" },
217 { NM_SEVER_MINOR, "minor failure" },
218 { NM_SEVER_WARNING, "warning level failure" },
219 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
220 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800221};
222
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200223static const char *severity_name(uint8_t cause)
Harald Welte59b04682009-06-10 05:40:52 +0800224{
Harald Welte453141f2010-03-25 11:45:30 +0800225 return get_value_string(severity_names, cause);
Harald Welte59b04682009-06-10 05:40:52 +0800226}
227
228/* Attributes that the BSC can set, not only get, according to Section 9.4 */
229static const enum abis_nm_attr nm_att_settable[] = {
230 NM_ATT_ADD_INFO,
231 NM_ATT_ADD_TEXT,
232 NM_ATT_DEST,
233 NM_ATT_EVENT_TYPE,
234 NM_ATT_FILE_DATA,
235 NM_ATT_GET_ARI,
236 NM_ATT_HW_CONF_CHG,
237 NM_ATT_LIST_REQ_ATTR,
238 NM_ATT_MDROP_LINK,
239 NM_ATT_MDROP_NEXT,
240 NM_ATT_NACK_CAUSES,
241 NM_ATT_OUTST_ALARM,
242 NM_ATT_PHYS_CONF,
243 NM_ATT_PROB_CAUSE,
244 NM_ATT_RAD_SUBC,
245 NM_ATT_SOURCE,
246 NM_ATT_SPEC_PROB,
247 NM_ATT_START_TIME,
248 NM_ATT_TEST_DUR,
249 NM_ATT_TEST_NO,
250 NM_ATT_TEST_REPORT,
251 NM_ATT_WINDOW_SIZE,
252 NM_ATT_SEVERITY,
253 NM_ATT_MEAS_RES,
254 NM_ATT_MEAS_TYPE,
255};
256
Harald Welte59698fb2010-01-10 18:01:52 +0100257const struct tlv_definition nm_att_tlvdef = {
Harald Welte59b04682009-06-10 05:40:52 +0800258 .def = {
259 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
260 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
261 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
262 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
263 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
264 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
265 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
266 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
267 [NM_ATT_BSIC] = { TLV_TYPE_TV },
268 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
269 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
270 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
271 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
272 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
273 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
274 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
275 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
276 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
277 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
278 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
279 [NM_ATT_HSN] = { TLV_TYPE_TV },
280 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
281 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
282 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
283 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
284 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
285 [NM_ATT_MAIO] = { TLV_TYPE_TV },
286 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
287 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
288 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
289 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
290 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
291 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
292 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
293 [NM_ATT_NY1] = { TLV_TYPE_TV },
294 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
295 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
296 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
297 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
298 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
299 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
300 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
301 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
302 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
303 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
304 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
305 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
306 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
307 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
308 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
309 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
310 [NM_ATT_TEI] = { TLV_TYPE_TV },
311 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
312 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
313 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
314 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
315 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
316 [NM_ATT_TSC] = { TLV_TYPE_TV },
317 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
318 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
319 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
320 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
321 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
Harald Welte59b04682009-06-10 05:40:52 +0800322 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
Harald Welte59b04682009-06-10 05:40:52 +0800323 },
324};
325
Harald Welte35cd5e92009-08-10 12:21:22 +0200326static const enum abis_nm_chan_comb chcomb4pchan[] = {
327 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
328 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
329 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
330 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
331 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
Harald Welte37884ed2009-10-24 10:25:50 +0200332 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
333 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
Harald Welte35cd5e92009-08-10 12:21:22 +0200334 /* FIXME: bounds check */
335};
336
337int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
338{
339 if (pchan < ARRAY_SIZE(chcomb4pchan))
340 return chcomb4pchan[pchan];
341
342 return -EINVAL;
343}
344
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200345int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte59b04682009-06-10 05:40:52 +0800346{
Harald Welte59698fb2010-01-10 18:01:52 +0100347 if (!bts->model)
348 return -EIO;
349 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +0800350}
351
352static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
353{
354 int i;
355
356 for (i = 0; i < size; i++) {
357 if (arr[i] == mt)
358 return 1;
359 }
360
361 return 0;
362}
363
364#if 0
365/* is this msgtype the usual ACK/NACK type ? */
366static int is_ack_nack(enum abis_nm_msgtype mt)
367{
368 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
369}
370#endif
371
372/* is this msgtype a report ? */
373static int is_report(enum abis_nm_msgtype mt)
374{
375 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
376}
377
378#define MT_ACK(x) (x+1)
379#define MT_NACK(x) (x+2)
380
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200381static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +0800382{
383 oh->mdisc = ABIS_OM_MDISC_FOM;
384 oh->placement = ABIS_OM_PLACEMENT_ONLY;
385 oh->sequence = 0;
386 oh->length = len;
387}
388
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200389static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
390 uint8_t msg_type, uint8_t obj_class,
391 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte59b04682009-06-10 05:40:52 +0800392{
393 struct abis_om_fom_hdr *foh =
394 (struct abis_om_fom_hdr *) oh->data;
395
396 fill_om_hdr(oh, len+sizeof(*foh));
397 foh->msg_type = msg_type;
398 foh->obj_class = obj_class;
399 foh->obj_inst.bts_nr = bts_nr;
400 foh->obj_inst.trx_nr = trx_nr;
401 foh->obj_inst.ts_nr = ts_nr;
402}
403
404static struct msgb *nm_msgb_alloc(void)
405{
Harald Welte9cfc9352009-06-26 19:39:35 +0200406 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
407 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800408}
409
410/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100411static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800412{
413 msg->trx = bts->c0;
414
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100415 /* queue OML messages */
416 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
417 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Weltec5845042011-02-14 15:26:13 +0100418 return _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100419 } else {
420 msgb_enqueue(&bts->abis_queue, msg);
421 return 0;
422 }
423
424}
425
426int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
427{
428 OBSC_NM_W_ACK_CB(msg) = 1;
429 return abis_nm_queue_msg(bts, msg);
430}
431
432static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
433{
434 OBSC_NM_W_ACK_CB(msg) = 0;
435 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800436}
437
438static int abis_nm_rcvmsg_sw(struct msgb *mb);
439
Harald Welte63b964e2010-05-31 16:40:40 +0200440const struct value_string abis_nm_obj_class_names[] = {
441 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
Harald Welte453141f2010-03-25 11:45:30 +0800442 { NM_OC_BTS, "BTS" },
Harald Welte63b964e2010-05-31 16:40:40 +0200443 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
444 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
Harald Welte453141f2010-03-25 11:45:30 +0800445 { NM_OC_CHANNEL, "CHANNEL" },
446 { NM_OC_BS11_ADJC, "ADJC" },
447 { NM_OC_BS11_HANDOVER, "HANDOVER" },
Harald Welte63b964e2010-05-31 16:40:40 +0200448 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
Harald Welte453141f2010-03-25 11:45:30 +0800449 { NM_OC_BS11_BTSE, "BTSE" },
450 { NM_OC_BS11_RACK, "RACK" },
451 { NM_OC_BS11_TEST, "TEST" },
452 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
453 { NM_OC_BS11_BPORT, "BPORT" },
Harald Welte63b964e2010-05-31 16:40:40 +0200454 { NM_OC_GPRS_NSE, "GPRS-NSE" },
455 { NM_OC_GPRS_CELL, "GPRS-CELL" },
456 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
Harald Welte453141f2010-03-25 11:45:30 +0800457 { NM_OC_BS11, "SIEMENSHW" },
458 { 0, NULL }
459};
460
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200461static const char *obj_class_name(uint8_t oc)
Harald Welte59b04682009-06-10 05:40:52 +0800462{
Harald Welte63b964e2010-05-31 16:40:40 +0200463 return get_value_string(abis_nm_obj_class_names, oc);
Harald Welte59b04682009-06-10 05:40:52 +0800464}
465
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200466const char *nm_opstate_name(uint8_t os)
Harald Welte59b04682009-06-10 05:40:52 +0800467{
468 switch (os) {
Harald Welte2c87ec12009-12-24 10:06:33 +0100469 case NM_OPSTATE_DISABLED:
Harald Welte59b04682009-06-10 05:40:52 +0800470 return "Disabled";
Harald Welte2c87ec12009-12-24 10:06:33 +0100471 case NM_OPSTATE_ENABLED:
Harald Welte59b04682009-06-10 05:40:52 +0800472 return "Enabled";
Harald Welte2c87ec12009-12-24 10:06:33 +0100473 case NM_OPSTATE_NULL:
Harald Welte59b04682009-06-10 05:40:52 +0800474 return "NULL";
475 default:
476 return "RFU";
477 }
478}
479
480/* Chapter 9.4.7 */
Harald Welte453141f2010-03-25 11:45:30 +0800481static const struct value_string avail_names[] = {
482 { 0, "In test" },
483 { 1, "Failed" },
484 { 2, "Power off" },
485 { 3, "Off line" },
486 /* Not used */
487 { 5, "Dependency" },
488 { 6, "Degraded" },
489 { 7, "Not installed" },
490 { 0xff, "OK" },
491 { 0, NULL }
Harald Welte59b04682009-06-10 05:40:52 +0800492};
493
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200494const char *nm_avail_name(uint8_t avail)
Harald Welte59b04682009-06-10 05:40:52 +0800495{
Harald Welte453141f2010-03-25 11:45:30 +0800496 return get_value_string(avail_names, avail);
Harald Welte59b04682009-06-10 05:40:52 +0800497}
498
Harald Weltebeeae412009-11-12 14:48:42 +0100499static struct value_string test_names[] = {
500 /* FIXME: standard test names */
501 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
502 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
503 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
504 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
505 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
506 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
507 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
508 { 0, NULL }
509};
510
Harald Welte63b964e2010-05-31 16:40:40 +0200511const struct value_string abis_nm_adm_state_names[] = {
512 { NM_STATE_LOCKED, "Locked" },
513 { NM_STATE_UNLOCKED, "Unlocked" },
514 { NM_STATE_SHUTDOWN, "Shutdown" },
515 { NM_STATE_NULL, "NULL" },
516 { 0, NULL }
517};
518
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200519const char *nm_adm_name(uint8_t adm)
Harald Welte59b04682009-06-10 05:40:52 +0800520{
Harald Welte63b964e2010-05-31 16:40:40 +0200521 return get_value_string(abis_nm_adm_state_names, adm);
Harald Welte59b04682009-06-10 05:40:52 +0800522}
523
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100524int nm_is_running(struct gsm_nm_state *s) {
525 return (s->operational == NM_OPSTATE_ENABLED) && (
526 (s->availability == NM_AVSTATE_OK) ||
527 (s->availability == 0xff)
528 );
529}
530
Harald Welteb7284a92009-10-20 09:56:18 +0200531static void debugp_foh(struct abis_om_fom_hdr *foh)
532{
533 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200534 obj_class_name(foh->obj_class), foh->obj_class,
Harald Welteb7284a92009-10-20 09:56:18 +0200535 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
536 foh->obj_inst.ts_nr);
537}
538
Harald Welte59b04682009-06-10 05:40:52 +0800539/* obtain the gsm_nm_state data structure for a given object instance */
540static struct gsm_nm_state *
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200541objclass2nmstate(struct gsm_bts *bts, uint8_t obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800542 struct abis_om_obj_inst *obj_inst)
543{
544 struct gsm_bts_trx *trx;
545 struct gsm_nm_state *nm_state = NULL;
546
547 switch (obj_class) {
548 case NM_OC_BTS:
549 nm_state = &bts->nm_state;
550 break;
551 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100552 if (obj_inst->trx_nr >= bts->num_trx) {
553 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800554 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100555 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200556 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800557 nm_state = &trx->nm_state;
558 break;
559 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100560 if (obj_inst->trx_nr >= bts->num_trx) {
561 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800562 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100563 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200564 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800565 nm_state = &trx->bb_transc.nm_state;
566 break;
567 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100568 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100569 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800570 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100571 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200572 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800573 if (obj_inst->ts_nr >= TRX_NR_TS)
574 return NULL;
575 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
576 break;
577 case NM_OC_SITE_MANAGER:
578 nm_state = &bts->site_mgr.nm_state;
579 break;
580 case NM_OC_BS11:
581 switch (obj_inst->bts_nr) {
582 case BS11_OBJ_CCLK:
583 nm_state = &bts->bs11.cclk.nm_state;
584 break;
585 case BS11_OBJ_BBSIG:
586 if (obj_inst->ts_nr > bts->num_trx)
587 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200588 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800589 nm_state = &trx->bs11.bbsig.nm_state;
590 break;
591 case BS11_OBJ_PA:
592 if (obj_inst->ts_nr > bts->num_trx)
593 return NULL;
Harald Weltee712a5f2009-06-21 16:17:15 +0200594 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800595 nm_state = &trx->bs11.pa.nm_state;
596 break;
597 default:
598 return NULL;
599 }
600 case NM_OC_BS11_RACK:
601 nm_state = &bts->bs11.rack.nm_state;
602 break;
603 case NM_OC_BS11_ENVABTSE:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100604 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
Harald Welte59b04682009-06-10 05:40:52 +0800605 return NULL;
606 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
607 break;
Harald Welte439e1282009-10-24 10:19:14 +0200608 case NM_OC_GPRS_NSE:
609 nm_state = &bts->gprs.nse.nm_state;
610 break;
611 case NM_OC_GPRS_CELL:
612 nm_state = &bts->gprs.cell.nm_state;
613 break;
614 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100615 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200616 return NULL;
617 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
618 break;
Harald Welte59b04682009-06-10 05:40:52 +0800619 }
620 return nm_state;
621}
622
623/* obtain the in-memory data structure of a given object instance */
624static void *
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200625objclass2obj(struct gsm_bts *bts, uint8_t obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800626 struct abis_om_obj_inst *obj_inst)
627{
628 struct gsm_bts_trx *trx;
629 void *obj = NULL;
630
631 switch (obj_class) {
632 case NM_OC_BTS:
633 obj = bts;
634 break;
635 case NM_OC_RADIO_CARRIER:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100636 if (obj_inst->trx_nr >= bts->num_trx) {
637 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800638 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100639 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200640 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800641 obj = trx;
642 break;
643 case NM_OC_BASEB_TRANSC:
Harald Welte3d9ecf72009-11-13 12:10:18 +0100644 if (obj_inst->trx_nr >= bts->num_trx) {
645 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800646 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100647 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200648 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800649 obj = &trx->bb_transc;
650 break;
651 case NM_OC_CHANNEL:
Holger Hans Peter Freyther9fe0d072009-12-21 16:56:28 +0100652 if (obj_inst->trx_nr >= bts->num_trx) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100653 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800654 return NULL;
Harald Welte3d9ecf72009-11-13 12:10:18 +0100655 }
Harald Weltee712a5f2009-06-21 16:17:15 +0200656 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
Harald Welte59b04682009-06-10 05:40:52 +0800657 if (obj_inst->ts_nr >= TRX_NR_TS)
658 return NULL;
659 obj = &trx->ts[obj_inst->ts_nr];
660 break;
661 case NM_OC_SITE_MANAGER:
662 obj = &bts->site_mgr;
663 break;
Harald Welte439e1282009-10-24 10:19:14 +0200664 case NM_OC_GPRS_NSE:
665 obj = &bts->gprs.nse;
666 break;
667 case NM_OC_GPRS_CELL:
668 obj = &bts->gprs.cell;
669 break;
670 case NM_OC_GPRS_NSVC:
Holger Hans Peter Freyther5bd48ca2009-12-21 17:06:07 +0100671 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
Harald Welte439e1282009-10-24 10:19:14 +0200672 return NULL;
673 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
674 break;
Harald Welte59b04682009-06-10 05:40:52 +0800675 }
676 return obj;
677}
678
679/* Update the administrative state of a given object in our in-memory data
680 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200681static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
682 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800683{
684 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100685 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800686
Harald Weltea348c082011-03-06 21:20:38 +0100687 memset(&nsd, 0, sizeof(nsd));
688
Harald Welte4c826f72011-01-14 15:55:42 +0100689 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
690 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100691 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800692 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
693 if (!nm_state)
694 return -1;
695
696 new_state = *nm_state;
697 new_state.administrative = adm_state;
698
Harald Welteb03c4482011-03-06 22:11:32 +0100699 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100700 nsd.obj_class = obj_class;
701 nsd.old_state = nm_state;
702 nsd.new_state = &new_state;
703 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200704 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800705
706 nm_state->administrative = adm_state;
707
Harald Welte4c826f72011-01-14 15:55:42 +0100708 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800709}
710
711static int abis_nm_rx_statechg_rep(struct msgb *mb)
712{
713 struct abis_om_hdr *oh = msgb_l2(mb);
714 struct abis_om_fom_hdr *foh = msgb_l3(mb);
715 struct gsm_bts *bts = mb->trx->bts;
716 struct tlv_parsed tp;
717 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800718
719 DEBUGPC(DNM, "STATE CHG: ");
720
721 memset(&new_state, 0, sizeof(new_state));
722
723 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
724 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100725 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800726 return -EINVAL;
727 }
728
729 new_state = *nm_state;
730
Harald Welte59698fb2010-01-10 18:01:52 +0100731 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800732 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
733 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
734 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
735 }
736 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
737 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
738 new_state.availability = 0xff;
739 else
740 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
741 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
742 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100743 } else
744 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800745 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
746 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Holger Hans Peter Freyther460fb3b2009-10-22 15:44:30 +0200747 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800748 }
749 DEBUGPC(DNM, "\n");
750
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100751 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
752 new_state.operational != nm_state->operational ||
753 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800754 /* Update the operational state of a given object in our in-memory data
755 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100756 struct nm_statechg_signal_data nsd;
757 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
758 nsd.obj_class = foh->obj_class;
759 nsd.old_state = nm_state;
760 nsd.new_state = &new_state;
761 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100762 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200763 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100764 nm_state->operational = new_state.operational;
765 nm_state->availability = new_state.availability;
766 if (nm_state->administrative == 0)
767 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800768 }
769#if 0
770 if (op_state == 1) {
771 /* try to enable objects that are disabled */
772 abis_nm_opstart(bts, foh->obj_class,
773 foh->obj_inst.bts_nr,
774 foh->obj_inst.trx_nr,
775 foh->obj_inst.ts_nr);
776 }
777#endif
778 return 0;
779}
780
781static int rx_fail_evt_rep(struct msgb *mb)
782{
783 struct abis_om_hdr *oh = msgb_l2(mb);
784 struct abis_om_fom_hdr *foh = msgb_l3(mb);
785 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100786 const uint8_t *p_val;
787 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800788
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200789 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800790
Harald Welte59698fb2010-01-10 18:01:52 +0100791 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800792
793 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200794 LOGPC(DNM, LOGL_ERROR, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800795 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200796 LOGPC(DNM, LOGL_ERROR, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100797 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
798 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200799 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100800 }
801 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
802 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
803 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
804 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200805 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100806 talloc_free(p_text);
807 }
808 }
Harald Welte59b04682009-06-10 05:40:52 +0800809
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200810 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800811
812 return 0;
813}
814
815static int abis_nm_rcvmsg_report(struct msgb *mb)
816{
817 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200818 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800819
Harald Welteb7284a92009-10-20 09:56:18 +0200820 debugp_foh(foh);
Harald Welte59b04682009-06-10 05:40:52 +0800821
822 //nmh->cfg->report_cb(mb, foh);
823
824 switch (mt) {
825 case NM_MT_STATECHG_EVENT_REP:
826 return abis_nm_rx_statechg_rep(mb);
827 break;
828 case NM_MT_SW_ACTIVATED_REP:
829 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200830 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800831 break;
832 case NM_MT_FAILURE_EVENT_REP:
833 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200834 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800835 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200836 case NM_MT_TEST_REP:
837 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200838 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200839 break;
Harald Welte59b04682009-06-10 05:40:52 +0800840 default:
841 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
842 break;
843
844 };
845
846 return 0;
847}
848
849/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200850static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
851 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800852{
853 struct abis_om_hdr *oh;
854 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200855 uint8_t len = swdesc_len;
856 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800857
858 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
859 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
860
861 trailer = msgb_put(msg, swdesc_len);
862 memcpy(trailer, sw_desc, swdesc_len);
863
864 return abis_nm_sendmsg(bts, msg);
865}
866
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200867static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100868{
869 static const struct tlv_definition sw_descr_def = {
870 .def = {
871 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
872 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
873 },
874 };
875
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200876 uint8_t tag;
877 uint16_t tag_len;
878 const uint8_t *val;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100879 int ofs = 0, len;
880
881 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
882 * nested nature and the fact you have to assume it contains only two sub
883 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
884
885 if (sw_descr[0] != NM_ATT_SW_DESCR) {
886 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
887 return -1;
888 }
889 ofs += 1;
890
891 len = tlv_parse_one(&tag, &tag_len, &val,
892 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
893 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
894 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
895 return -2;
896 }
897 ofs += len;
898
899 len = tlv_parse_one(&tag, &tag_len, &val,
900 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
901 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
902 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
903 return -3;
904 }
905 ofs += len;
906
907 return ofs;
908}
909
Harald Welte59b04682009-06-10 05:40:52 +0800910static int abis_nm_rx_sw_act_req(struct msgb *mb)
911{
912 struct abis_om_hdr *oh = msgb_l2(mb);
913 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Mike Haben322fc582009-10-01 14:56:13 +0200914 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200915 const uint8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100916 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800917
Harald Welteb7284a92009-10-20 09:56:18 +0200918 debugp_foh(foh);
919
920 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800921
Harald Welte3055e332010-03-14 15:37:43 +0800922 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800923
924 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
925 foh->obj_inst.bts_nr,
926 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800927 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800928 foh->data, oh->length-sizeof(*foh));
929
Harald Welte59698fb2010-01-10 18:01:52 +0100930 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200931 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
932 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
933 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
934 DEBUGP(DNM, "SW config not found! Can't continue.\n");
935 return -EINVAL;
936 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200937 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200938 }
939
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100940 /* Use the first SW_DESCR present in SW config */
941 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
942 if (sw_descr_len < 0)
943 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200944
Harald Welte59b04682009-06-10 05:40:52 +0800945 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
946 foh->obj_inst.bts_nr,
947 foh->obj_inst.trx_nr,
948 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100949 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800950}
951
952/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
953static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
954{
955 struct abis_om_hdr *oh = msgb_l2(mb);
956 struct abis_om_fom_hdr *foh = msgb_l3(mb);
957 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200958 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800959
Harald Welte59698fb2010-01-10 18:01:52 +0100960 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800961 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
962 return -EINVAL;
963
964 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
965
966 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
967}
968
969static int abis_nm_rx_lmt_event(struct msgb *mb)
970{
971 struct abis_om_hdr *oh = msgb_l2(mb);
972 struct abis_om_fom_hdr *foh = msgb_l3(mb);
973 struct tlv_parsed tp;
974
975 DEBUGP(DNM, "LMT Event ");
Harald Welte59698fb2010-01-10 18:01:52 +0100976 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800977 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
978 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200979 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800980 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
981 }
982 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
983 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200984 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800985 DEBUGPC(DNM, "Level=%u ", level);
986 }
987 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
988 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
989 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
990 DEBUGPC(DNM, "Username=%s ", name);
991 }
992 DEBUGPC(DNM, "\n");
993 /* FIXME: parse LMT LOGON TIME */
994 return 0;
995}
996
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100997static void abis_nm_queue_send_next(struct gsm_bts *bts)
998{
999 int wait = 0;
1000 struct msgb *msg;
1001 /* the queue is empty */
1002 while (!llist_empty(&bts->abis_queue)) {
1003 msg = msgb_dequeue(&bts->abis_queue);
1004 wait = OBSC_NM_W_ACK_CB(msg);
Harald Weltec5845042011-02-14 15:26:13 +01001005 _abis_nm_sendmsg(msg, 0);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001006
1007 if (wait)
1008 break;
1009 }
1010
1011 bts->abis_nm_pend = wait;
1012}
1013
Harald Welte59b04682009-06-10 05:40:52 +08001014/* Receive a OML NM Message from BTS */
1015static int abis_nm_rcvmsg_fom(struct msgb *mb)
1016{
1017 struct abis_om_hdr *oh = msgb_l2(mb);
1018 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001019 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001020 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +08001021
1022 /* check for unsolicited message */
1023 if (is_report(mt))
1024 return abis_nm_rcvmsg_report(mb);
1025
1026 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1027 return abis_nm_rcvmsg_sw(mb);
1028
1029 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001030 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +08001031 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +02001032
Harald Welteb7284a92009-10-20 09:56:18 +02001033 debugp_foh(foh);
Harald Welte935d10b2009-10-08 20:18:59 +02001034
Harald Welte453141f2010-03-25 11:45:30 +08001035 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
Harald Welte59b04682009-06-10 05:40:52 +08001036
Harald Welte59698fb2010-01-10 18:01:52 +01001037 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08001038 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001039 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08001040 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1041 else
1042 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001043
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +08001044 nack_data.msg = mb;
1045 nack_data.mt = mt;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02001046 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001047 abis_nm_queue_send_next(mb->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +02001048 return 0;
Harald Welte59b04682009-06-10 05:40:52 +08001049 }
1050#if 0
1051 /* check if last message is to be acked */
1052 if (is_ack_nack(nmh->last_msgtype)) {
1053 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +01001054 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001055 /* we got our ACK, continue sending the next msg */
1056 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1057 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +01001058 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08001059 /* FIXME: somehow signal this to the caller */
1060 } else {
1061 /* really strange things happen */
1062 return -EINVAL;
1063 }
1064 }
1065#endif
1066
1067 switch (mt) {
1068 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001069 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001070 break;
1071 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001072 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001073 break;
1074 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001075 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +08001076 break;
Harald Welte204317e2009-08-06 17:58:31 +02001077 case NM_MT_CONN_MDROP_LINK_ACK:
1078 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1079 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001080 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02001081 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001082 break;
1083 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02001084 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +01001085 break;
Harald Welte08011e22011-03-04 13:41:31 +01001086 case NM_MT_SET_BTS_ATTR_ACK:
1087 /* The HSL wants an OPSTART _after_ the SI has been set */
1088 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
1089 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
1090 }
1091 break;
Harald Welte59b04682009-06-10 05:40:52 +08001092 }
1093
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001094 abis_nm_queue_send_next(mb->trx->bts);
1095 return ret;
Harald Welte59b04682009-06-10 05:40:52 +08001096}
1097
1098static int abis_nm_rx_ipacc(struct msgb *mb);
1099
1100static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1101{
1102 int rc;
1103 int bts_type = mb->trx->bts->type;
1104
1105 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +01001106 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +08001107 rc = abis_nm_rx_ipacc(mb);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001108 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001109 break;
1110 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001111 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1112 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +08001113 rc = 0;
1114 break;
1115 }
1116
1117 return rc;
1118}
1119
1120/* High-Level API */
1121/* Entry-point where L2 OML from BTS enters the NM code */
1122int abis_nm_rcvmsg(struct msgb *msg)
1123{
1124 struct abis_om_hdr *oh = msgb_l2(msg);
1125 int rc = 0;
1126
1127 /* Various consistency checks */
1128 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001129 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +08001130 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +02001131 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1132 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +08001133 }
1134 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001135 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +08001136 oh->sequence);
1137 return -EINVAL;
1138 }
1139#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001140 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +08001141 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1142 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001143 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +08001144 oh->length + sizeof(*oh), l2_len);
1145 return -EINVAL;
1146 }
1147 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001148 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 +08001149#endif
1150 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1151
1152 switch (oh->mdisc) {
1153 case ABIS_OM_MDISC_FOM:
1154 rc = abis_nm_rcvmsg_fom(msg);
1155 break;
1156 case ABIS_OM_MDISC_MANUF:
1157 rc = abis_nm_rcvmsg_manuf(msg);
1158 break;
1159 case ABIS_OM_MDISC_MMI:
1160 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001161 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001162 oh->mdisc);
1163 break;
1164 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +01001165 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +08001166 oh->mdisc);
1167 return -EINVAL;
1168 }
1169
1170 msgb_free(msg);
1171 return rc;
1172}
1173
1174#if 0
1175/* initialized all resources */
1176struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1177{
1178 struct abis_nm_h *nmh;
1179
1180 nmh = malloc(sizeof(*nmh));
1181 if (!nmh)
1182 return NULL;
1183
1184 nmh->cfg = cfg;
1185
1186 return nmh;
1187}
1188
1189/* free all resources */
1190void abis_nm_fini(struct abis_nm_h *nmh)
1191{
1192 free(nmh);
1193}
1194#endif
1195
1196/* Here we are trying to define a high-level API that can be used by
1197 * the actual BSC implementation. However, the architecture is currently
1198 * still under design. Ideally the calls to this API would be synchronous,
1199 * while the underlying stack behind the APi runs in a traditional select
1200 * based state machine.
1201 */
1202
1203/* 6.2 Software Load: */
1204enum sw_state {
1205 SW_STATE_NONE,
1206 SW_STATE_WAIT_INITACK,
1207 SW_STATE_WAIT_SEGACK,
1208 SW_STATE_WAIT_ENDACK,
1209 SW_STATE_WAIT_ACTACK,
1210 SW_STATE_ERROR,
1211};
1212
1213struct abis_nm_sw {
1214 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001215 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +08001216 gsm_cbfn *cbfn;
1217 void *cb_data;
1218 int forced;
1219
1220 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001221 uint8_t obj_class;
1222 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +08001223
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001224 uint8_t file_id[255];
1225 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +08001226
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001227 uint8_t file_version[255];
1228 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +08001229
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001230 uint8_t window_size;
1231 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +08001232
1233 int fd;
1234 FILE *stream;
1235 enum sw_state state;
1236 int last_seg;
1237};
1238
1239static struct abis_nm_sw g_sw;
1240
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001241static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1242{
1243 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1244 msgb_v_put(msg, NM_ATT_SW_DESCR);
1245 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1246 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1247 sw->file_version);
1248 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1249 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1250 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1251 sw->file_version);
1252 } else {
1253 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1254 }
1255}
1256
Harald Welte59b04682009-06-10 05:40:52 +08001257/* 6.2.1 / 8.3.1: Load Data Initiate */
1258static int sw_load_init(struct abis_nm_sw *sw)
1259{
1260 struct abis_om_hdr *oh;
1261 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001262 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +08001263
1264 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1265 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1266 sw->obj_instance[0], sw->obj_instance[1],
1267 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001268
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001269 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001270 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1271
1272 return abis_nm_sendmsg(sw->bts, msg);
1273}
1274
1275static int is_last_line(FILE *stream)
1276{
1277 char next_seg_buf[256];
1278 long pos;
1279
1280 /* check if we're sending the last line */
1281 pos = ftell(stream);
1282 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1283 fseek(stream, pos, SEEK_SET);
1284 return 1;
1285 }
1286
1287 fseek(stream, pos, SEEK_SET);
1288 return 0;
1289}
1290
1291/* 6.2.2 / 8.3.2 Load Data Segment */
1292static int sw_load_segment(struct abis_nm_sw *sw)
1293{
1294 struct abis_om_hdr *oh;
1295 struct msgb *msg = nm_msgb_alloc();
1296 char seg_buf[256];
1297 char *line_buf = seg_buf+2;
1298 unsigned char *tlv;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001299 uint8_t len;
Harald Welte59b04682009-06-10 05:40:52 +08001300
1301 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1302
1303 switch (sw->bts->type) {
1304 case GSM_BTS_TYPE_BS11:
1305 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1306 perror("fgets reading segment");
1307 return -EINVAL;
1308 }
1309 seg_buf[0] = 0x00;
1310
1311 /* check if we're sending the last line */
1312 sw->last_seg = is_last_line(sw->stream);
1313 if (sw->last_seg)
1314 seg_buf[1] = 0;
1315 else
1316 seg_buf[1] = 1 + sw->seg_in_window++;
1317
1318 len = strlen(line_buf) + 2;
1319 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001320 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +08001321 /* BS11 wants CR + LF in excess of the TLV length !?! */
1322 tlv[1] -= 2;
1323
1324 /* we only now know the exact length for the OM hdr */
1325 len = strlen(line_buf)+2;
1326 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001327 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +02001328 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001329 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1330 if (len < 0) {
1331 perror("read failed");
1332 return -EINVAL;
1333 }
1334
1335 if (len != IPACC_SEGMENT_SIZE)
1336 sw->last_seg = 1;
1337
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +01001338 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001339 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +01001340 len += 3;
1341 break;
1342 }
Harald Welte59b04682009-06-10 05:40:52 +08001343 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +01001344 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +08001345 /* FIXME: Other BTS types */
1346 return -1;
1347 }
1348
1349 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1350 sw->obj_instance[0], sw->obj_instance[1],
1351 sw->obj_instance[2]);
1352
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001353 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001354}
1355
1356/* 6.2.4 / 8.3.4 Load Data End */
1357static int sw_load_end(struct abis_nm_sw *sw)
1358{
1359 struct abis_om_hdr *oh;
1360 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001361 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +08001362
1363 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1364 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1365 sw->obj_instance[0], sw->obj_instance[1],
1366 sw->obj_instance[2]);
1367
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +01001368 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001369 return abis_nm_sendmsg(sw->bts, msg);
1370}
1371
1372/* Activate the specified software into the BTS */
1373static int sw_activate(struct abis_nm_sw *sw)
1374{
1375 struct abis_om_hdr *oh;
1376 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001377 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +08001378
1379 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1380 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1381 sw->obj_instance[0], sw->obj_instance[1],
1382 sw->obj_instance[2]);
1383
1384 /* FIXME: this is BS11 specific format */
1385 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1386 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1387 sw->file_version);
1388
1389 return abis_nm_sendmsg(sw->bts, msg);
1390}
1391
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001392struct sdp_firmware {
1393 char magic[4];
1394 char more_magic[4];
1395 unsigned int header_length;
1396 unsigned int file_length;
1397} __attribute__ ((packed));
1398
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001399static int parse_sdp_header(struct abis_nm_sw *sw)
1400{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +01001401 struct sdp_firmware firmware_header;
1402 int rc;
1403 struct stat stat;
1404
1405 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1406 if (rc != sizeof(firmware_header)) {
1407 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1408 return -1;
1409 }
1410
1411 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1412 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1413 return -1;
1414 }
1415
1416 if (firmware_header.more_magic[0] != 0x10 ||
1417 firmware_header.more_magic[1] != 0x02 ||
1418 firmware_header.more_magic[2] != 0x00 ||
1419 firmware_header.more_magic[3] != 0x00) {
1420 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1421 return -1;
1422 }
1423
1424
1425 if (fstat(sw->fd, &stat) == -1) {
1426 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1427 return -1;
1428 }
1429
1430 if (ntohl(firmware_header.file_length) != stat.st_size) {
1431 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1432 return -1;
1433 }
1434
1435 /* go back to the start as we checked the whole filesize.. */
1436 lseek(sw->fd, 0l, SEEK_SET);
1437 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1438 "There might be checksums in the file that are not\n"
1439 "verified and incomplete firmware might be flashed.\n"
1440 "There is absolutely no WARRANTY that flashing will\n"
1441 "work.\n");
1442 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001443}
1444
Harald Welte59b04682009-06-10 05:40:52 +08001445static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1446{
1447 char file_id[12+1];
1448 char file_version[80+1];
1449 int rc;
1450
1451 sw->fd = open(fname, O_RDONLY);
1452 if (sw->fd < 0)
1453 return sw->fd;
1454
1455 switch (sw->bts->type) {
1456 case GSM_BTS_TYPE_BS11:
1457 sw->stream = fdopen(sw->fd, "r");
1458 if (!sw->stream) {
1459 perror("fdopen");
1460 return -1;
1461 }
1462 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001463 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001464 file_id, file_version);
1465 if (rc != 2) {
1466 perror("parsing header line of software file");
1467 return -1;
1468 }
1469 strcpy((char *)sw->file_id, file_id);
1470 sw->file_id_len = strlen(file_id);
1471 strcpy((char *)sw->file_version, file_version);
1472 sw->file_version_len = strlen(file_version);
1473 /* rewind to start of file */
1474 rewind(sw->stream);
1475 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001476 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001477 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001478 rc = parse_sdp_header(sw);
1479 if (rc < 0) {
1480 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1481 return -1;
1482 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001483
1484 strcpy((char *)sw->file_id, "id");
1485 sw->file_id_len = 3;
1486 strcpy((char *)sw->file_version, "version");
1487 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001488 break;
Harald Welte59b04682009-06-10 05:40:52 +08001489 default:
1490 /* We don't know how to treat them yet */
1491 close(sw->fd);
1492 return -EINVAL;
1493 }
1494
1495 return 0;
1496}
1497
1498static void sw_close_file(struct abis_nm_sw *sw)
1499{
1500 switch (sw->bts->type) {
1501 case GSM_BTS_TYPE_BS11:
1502 fclose(sw->stream);
1503 break;
1504 default:
1505 close(sw->fd);
1506 break;
1507 }
1508}
1509
1510/* Fill the window */
1511static int sw_fill_window(struct abis_nm_sw *sw)
1512{
1513 int rc;
1514
1515 while (sw->seg_in_window < sw->window_size) {
1516 rc = sw_load_segment(sw);
1517 if (rc < 0)
1518 return rc;
1519 if (sw->last_seg)
1520 break;
1521 }
1522 return 0;
1523}
1524
1525/* callback function from abis_nm_rcvmsg() handler */
1526static int abis_nm_rcvmsg_sw(struct msgb *mb)
1527{
1528 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1529 int rc = -1;
1530 struct abis_nm_sw *sw = &g_sw;
1531 enum sw_state old_state = sw->state;
1532
1533 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1534
1535 switch (sw->state) {
1536 case SW_STATE_WAIT_INITACK:
1537 switch (foh->msg_type) {
1538 case NM_MT_LOAD_INIT_ACK:
1539 /* fill window with segments */
1540 if (sw->cbfn)
1541 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1542 NM_MT_LOAD_INIT_ACK, mb,
1543 sw->cb_data, NULL);
1544 rc = sw_fill_window(sw);
1545 sw->state = SW_STATE_WAIT_SEGACK;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001546 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001547 break;
1548 case NM_MT_LOAD_INIT_NACK:
1549 if (sw->forced) {
1550 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1551 "Init NACK\n");
1552 if (sw->cbfn)
1553 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1554 NM_MT_LOAD_INIT_ACK, mb,
1555 sw->cb_data, NULL);
1556 rc = sw_fill_window(sw);
1557 sw->state = SW_STATE_WAIT_SEGACK;
1558 } else {
1559 DEBUGP(DNM, "Software Load Init NACK\n");
1560 /* FIXME: cause */
1561 if (sw->cbfn)
1562 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1563 NM_MT_LOAD_INIT_NACK, mb,
1564 sw->cb_data, NULL);
1565 sw->state = SW_STATE_ERROR;
1566 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001567 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001568 break;
1569 }
1570 break;
1571 case SW_STATE_WAIT_SEGACK:
1572 switch (foh->msg_type) {
1573 case NM_MT_LOAD_SEG_ACK:
1574 if (sw->cbfn)
1575 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1576 NM_MT_LOAD_SEG_ACK, mb,
1577 sw->cb_data, NULL);
1578 sw->seg_in_window = 0;
1579 if (!sw->last_seg) {
1580 /* fill window with more segments */
1581 rc = sw_fill_window(sw);
1582 sw->state = SW_STATE_WAIT_SEGACK;
1583 } else {
1584 /* end the transfer */
1585 sw->state = SW_STATE_WAIT_ENDACK;
1586 rc = sw_load_end(sw);
1587 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001588 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001589 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001590 case NM_MT_LOAD_ABORT:
1591 if (sw->cbfn)
1592 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1593 NM_MT_LOAD_ABORT, mb,
1594 sw->cb_data, NULL);
1595 break;
Harald Welte59b04682009-06-10 05:40:52 +08001596 }
1597 break;
1598 case SW_STATE_WAIT_ENDACK:
1599 switch (foh->msg_type) {
1600 case NM_MT_LOAD_END_ACK:
1601 sw_close_file(sw);
1602 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1603 sw->bts->nr);
1604 sw->state = SW_STATE_NONE;
1605 if (sw->cbfn)
1606 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1607 NM_MT_LOAD_END_ACK, mb,
1608 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001609 rc = 0;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001610 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001611 break;
1612 case NM_MT_LOAD_END_NACK:
1613 if (sw->forced) {
1614 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1615 "End NACK\n");
1616 sw->state = SW_STATE_NONE;
1617 if (sw->cbfn)
1618 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1619 NM_MT_LOAD_END_ACK, mb,
1620 sw->cb_data, NULL);
1621 } else {
1622 DEBUGP(DNM, "Software Load End NACK\n");
1623 /* FIXME: cause */
1624 sw->state = SW_STATE_ERROR;
1625 if (sw->cbfn)
1626 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1627 NM_MT_LOAD_END_NACK, mb,
1628 sw->cb_data, NULL);
1629 }
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001630 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001631 break;
1632 }
1633 case SW_STATE_WAIT_ACTACK:
1634 switch (foh->msg_type) {
1635 case NM_MT_ACTIVATE_SW_ACK:
1636 /* we're done */
1637 DEBUGP(DNM, "Activate Software DONE!\n");
1638 sw->state = SW_STATE_NONE;
1639 rc = 0;
1640 if (sw->cbfn)
1641 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1642 NM_MT_ACTIVATE_SW_ACK, mb,
1643 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001644 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001645 break;
1646 case NM_MT_ACTIVATE_SW_NACK:
1647 DEBUGP(DNM, "Activate Software NACK\n");
1648 /* FIXME: cause */
1649 sw->state = SW_STATE_ERROR;
1650 if (sw->cbfn)
1651 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1652 NM_MT_ACTIVATE_SW_NACK, mb,
1653 sw->cb_data, NULL);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001654 abis_nm_queue_send_next(mb->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001655 break;
1656 }
1657 case SW_STATE_NONE:
1658 switch (foh->msg_type) {
1659 case NM_MT_ACTIVATE_SW_ACK:
1660 rc = 0;
1661 break;
1662 }
1663 break;
1664 case SW_STATE_ERROR:
1665 break;
1666 }
1667
1668 if (rc)
1669 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1670 foh->msg_type, old_state, sw->state);
1671
1672 return rc;
1673}
1674
1675/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001676int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001677 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001678 gsm_cbfn *cbfn, void *cb_data)
1679{
1680 struct abis_nm_sw *sw = &g_sw;
1681 int rc;
1682
1683 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1684 bts->nr, fname);
1685
1686 if (sw->state != SW_STATE_NONE)
1687 return -EBUSY;
1688
1689 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001690 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001691
1692 switch (bts->type) {
1693 case GSM_BTS_TYPE_BS11:
1694 sw->obj_class = NM_OC_SITE_MANAGER;
1695 sw->obj_instance[0] = 0xff;
1696 sw->obj_instance[1] = 0xff;
1697 sw->obj_instance[2] = 0xff;
1698 break;
1699 case GSM_BTS_TYPE_NANOBTS:
1700 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001701 sw->obj_instance[0] = sw->bts->nr;
1702 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001703 sw->obj_instance[2] = 0xff;
1704 break;
1705 case GSM_BTS_TYPE_UNKNOWN:
1706 default:
1707 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1708 return -1;
1709 break;
1710 }
Harald Welte59b04682009-06-10 05:40:52 +08001711 sw->window_size = win_size;
1712 sw->state = SW_STATE_WAIT_INITACK;
1713 sw->cbfn = cbfn;
1714 sw->cb_data = cb_data;
1715 sw->forced = forced;
1716
1717 rc = sw_open_file(sw, fname);
1718 if (rc < 0) {
1719 sw->state = SW_STATE_NONE;
1720 return rc;
1721 }
1722
1723 return sw_load_init(sw);
1724}
1725
1726int abis_nm_software_load_status(struct gsm_bts *bts)
1727{
1728 struct abis_nm_sw *sw = &g_sw;
1729 struct stat st;
1730 int rc, percent;
1731
1732 rc = fstat(sw->fd, &st);
1733 if (rc < 0) {
1734 perror("ERROR during stat");
1735 return rc;
1736 }
1737
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001738 if (sw->stream)
1739 percent = (ftell(sw->stream) * 100) / st.st_size;
1740 else
1741 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001742 return percent;
1743}
1744
1745/* Activate the specified software into the BTS */
1746int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1747 gsm_cbfn *cbfn, void *cb_data)
1748{
1749 struct abis_nm_sw *sw = &g_sw;
1750 int rc;
1751
1752 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1753 bts->nr, fname);
1754
1755 if (sw->state != SW_STATE_NONE)
1756 return -EBUSY;
1757
1758 sw->bts = bts;
1759 sw->obj_class = NM_OC_SITE_MANAGER;
1760 sw->obj_instance[0] = 0xff;
1761 sw->obj_instance[1] = 0xff;
1762 sw->obj_instance[2] = 0xff;
1763 sw->state = SW_STATE_WAIT_ACTACK;
1764 sw->cbfn = cbfn;
1765 sw->cb_data = cb_data;
1766
1767 /* Open the file in order to fill some sw struct members */
1768 rc = sw_open_file(sw, fname);
1769 if (rc < 0) {
1770 sw->state = SW_STATE_NONE;
1771 return rc;
1772 }
1773 sw_close_file(sw);
1774
1775 return sw_activate(sw);
1776}
1777
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001778static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1779 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001780{
1781 ch->attrib = NM_ATT_ABIS_CHANNEL;
1782 ch->bts_port = bts_port;
1783 ch->timeslot = ts_nr;
1784 ch->subslot = subslot_nr;
1785}
1786
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001787int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1788 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1789 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001790{
1791 struct abis_om_hdr *oh;
1792 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001793 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001794 struct msgb *msg = nm_msgb_alloc();
1795
1796 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1797 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1798 bts->bts_nr, trx_nr, 0xff);
1799
1800 msgb_tv_put(msg, NM_ATT_TEI, tei);
1801
1802 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1803 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1804
1805 return abis_nm_sendmsg(bts, msg);
1806}
1807
1808/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1809int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001810 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001811{
1812 struct gsm_bts *bts = trx->bts;
1813 struct abis_om_hdr *oh;
1814 struct abis_nm_channel *ch;
1815 struct msgb *msg = nm_msgb_alloc();
1816
1817 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1818 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1819 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1820
1821 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1822 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1823
1824 return abis_nm_sendmsg(bts, msg);
1825}
1826
1827#if 0
1828int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1829 struct abis_nm_abis_channel *chan)
1830{
1831}
1832#endif
1833
1834int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001835 uint8_t e1_port, uint8_t e1_timeslot,
1836 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001837{
1838 struct gsm_bts *bts = ts->trx->bts;
1839 struct abis_om_hdr *oh;
1840 struct abis_nm_channel *ch;
1841 struct msgb *msg = nm_msgb_alloc();
1842
1843 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1844 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1845 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1846
1847 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1848 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1849
1850 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1851 gsm_ts_name(ts),
1852 e1_port, e1_timeslot, e1_subslot);
1853
1854 return abis_nm_sendmsg(bts, msg);
1855}
1856
1857#if 0
1858int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1859 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001860 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001861{
1862}
1863#endif
1864
1865/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001866int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001867{
1868 struct abis_om_hdr *oh;
1869 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001870 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001871
1872 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1873
1874 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1875 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1876 cur = msgb_put(msg, attr_len);
1877 memcpy(cur, attr, attr_len);
1878
1879 return abis_nm_sendmsg(bts, msg);
1880}
1881
1882/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001883int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001884{
1885 struct abis_om_hdr *oh;
1886 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001887 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001888
1889 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1890
1891 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1892 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1893 trx->bts->bts_nr, trx->nr, 0xff);
1894 cur = msgb_put(msg, attr_len);
1895 memcpy(cur, attr, attr_len);
1896
1897 return abis_nm_sendmsg(trx->bts, msg);
1898}
1899
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001900static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Weltef2eb2782009-08-09 21:49:48 +02001901{
1902 int i;
1903
1904 /* As it turns out, the BS-11 has some very peculiar restrictions
1905 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301906 switch (ts->trx->bts->type) {
1907 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001908 switch (chan_comb) {
1909 case NM_CHANC_TCHHalf:
1910 case NM_CHANC_TCHHalf2:
1911 /* not supported */
1912 return -EINVAL;
1913 case NM_CHANC_SDCCH:
1914 /* only one SDCCH/8 per TRX */
1915 for (i = 0; i < TRX_NR_TS; i++) {
1916 if (i == ts->nr)
1917 continue;
1918 if (ts->trx->ts[i].nm_chan_comb ==
1919 NM_CHANC_SDCCH)
1920 return -EINVAL;
1921 }
1922 /* not allowed for TS0 of BCCH-TRX */
1923 if (ts->trx == ts->trx->bts->c0 &&
1924 ts->nr == 0)
1925 return -EINVAL;
1926 /* not on the same TRX that has a BCCH+SDCCH4
1927 * combination */
1928 if (ts->trx == ts->trx->bts->c0 &&
1929 (ts->trx->ts[0].nm_chan_comb == 5 ||
1930 ts->trx->ts[0].nm_chan_comb == 8))
1931 return -EINVAL;
1932 break;
1933 case NM_CHANC_mainBCCH:
1934 case NM_CHANC_BCCHComb:
1935 /* allowed only for TS0 of C0 */
1936 if (ts->trx != ts->trx->bts->c0 ||
1937 ts->nr != 0)
1938 return -EINVAL;
1939 break;
1940 case NM_CHANC_BCCH:
1941 /* allowed only for TS 2/4/6 of C0 */
1942 if (ts->trx != ts->trx->bts->c0)
1943 return -EINVAL;
1944 if (ts->nr != 2 && ts->nr != 4 &&
1945 ts->nr != 6)
1946 return -EINVAL;
1947 break;
1948 case 8: /* this is not like 08.58, but in fact
1949 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1950 /* FIXME: only one CBCH allowed per cell */
1951 break;
1952 }
Harald Welte76ba8812009-12-02 02:45:23 +05301953 break;
1954 case GSM_BTS_TYPE_NANOBTS:
1955 switch (ts->nr) {
1956 case 0:
1957 if (ts->trx->nr == 0) {
1958 /* only on TRX0 */
1959 switch (chan_comb) {
1960 case NM_CHANC_BCCH:
1961 case NM_CHANC_mainBCCH:
1962 case NM_CHANC_BCCHComb:
1963 return 0;
1964 break;
1965 default:
1966 return -EINVAL;
1967 }
1968 } else {
1969 switch (chan_comb) {
1970 case NM_CHANC_TCHFull:
1971 case NM_CHANC_TCHHalf:
1972 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1973 return 0;
1974 default:
1975 return -EINVAL;
1976 }
1977 }
1978 break;
1979 case 1:
1980 if (ts->trx->nr == 0) {
1981 switch (chan_comb) {
1982 case NM_CHANC_SDCCH_CBCH:
1983 if (ts->trx->ts[0].nm_chan_comb ==
1984 NM_CHANC_mainBCCH)
1985 return 0;
1986 return -EINVAL;
1987 case NM_CHANC_SDCCH:
1988 case NM_CHANC_TCHFull:
1989 case NM_CHANC_TCHHalf:
1990 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1991 case NM_CHANC_IPAC_TCHFull_PDCH:
1992 return 0;
1993 }
1994 } else {
1995 switch (chan_comb) {
1996 case NM_CHANC_SDCCH:
1997 case NM_CHANC_TCHFull:
1998 case NM_CHANC_TCHHalf:
1999 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2000 return 0;
2001 default:
2002 return -EINVAL;
2003 }
2004 }
2005 break;
2006 case 2:
2007 case 3:
2008 case 4:
2009 case 5:
2010 case 6:
2011 case 7:
2012 switch (chan_comb) {
2013 case NM_CHANC_TCHFull:
2014 case NM_CHANC_TCHHalf:
2015 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2016 return 0;
2017 case NM_CHANC_IPAC_PDCH:
2018 case NM_CHANC_IPAC_TCHFull_PDCH:
2019 if (ts->trx->nr == 0)
2020 return 0;
2021 else
2022 return -EINVAL;
2023 }
2024 break;
2025 }
2026 return -EINVAL;
2027 default:
2028 /* unknown BTS type */
2029 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02002030 }
2031 return 0;
2032}
2033
Harald Welte59b04682009-06-10 05:40:52 +08002034/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002035int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08002036{
2037 struct gsm_bts *bts = ts->trx->bts;
2038 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002039 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08002040 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002041 uint8_t len = 2 + 2;
Harald Welte59b04682009-06-10 05:40:52 +08002042
2043 if (bts->type == GSM_BTS_TYPE_BS11)
2044 len += 4 + 2 + 2 + 3;
2045
2046 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02002047 if (verify_chan_comb(ts, chan_comb) < 0) {
2048 msgb_free(msg);
2049 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2050 return -EINVAL;
2051 }
2052 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08002053
2054 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2055 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
2056 NM_OC_CHANNEL, bts->bts_nr,
2057 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08002058 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02002059 if (ts->hopping.enabled) {
2060 unsigned int i;
2061 uint8_t *len;
2062
Harald Welte67104d12009-09-12 13:05:33 +02002063 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2064 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02002065
2066 /* build the ARFCN list */
2067 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2068 len = msgb_put(msg, 1);
2069 *len = 0;
2070 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2071 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2072 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02002073 /* At least BS-11 wants a TLV16 here */
2074 if (bts->type == GSM_BTS_TYPE_BS11)
2075 *len += 1;
2076 else
2077 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02002078 }
2079 }
Harald Welte59b04682009-06-10 05:40:52 +08002080 }
Harald Weltebeeb28f2009-07-21 20:40:05 +02002081 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08002082 if (bts->type == GSM_BTS_TYPE_BS11)
2083 msgb_tlv_put(msg, 0x59, 1, &zero);
2084
2085 return abis_nm_sendmsg(bts, msg);
2086}
2087
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002088int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
2089 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08002090{
2091 struct abis_om_hdr *oh;
2092 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002093 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2094 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08002095
2096 if (nack) {
2097 len += 2;
2098 msgtype = NM_MT_SW_ACT_REQ_NACK;
2099 }
2100
2101 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2102 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2103
2104 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002105 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08002106 memcpy(ptr, attr, att_len);
2107 }
2108 if (nack)
2109 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2110
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002111 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002112}
2113
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002114int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08002115{
2116 struct msgb *msg = nm_msgb_alloc();
2117 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002118 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002119
2120 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2121 fill_om_hdr(oh, len);
2122 data = msgb_put(msg, len);
2123 memcpy(data, rawmsg, len);
2124
2125 return abis_nm_sendmsg(bts, msg);
2126}
2127
2128/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002129static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08002130{
2131 struct abis_om_hdr *oh;
2132 struct msgb *msg = nm_msgb_alloc();
2133
2134 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2135 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2136 0xff, 0xff, 0xff);
2137
2138 return abis_nm_sendmsg(bts, msg);
2139}
2140
2141/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002142int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Harald Welte59b04682009-06-10 05:40:52 +08002143{
2144 struct abis_om_hdr *oh;
2145 struct msgb *msg = nm_msgb_alloc();
2146
Harald Welte59b04682009-06-10 05:40:52 +08002147 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2148 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2149
Harald Welteb7284a92009-10-20 09:56:18 +02002150 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2151 DEBUGPC(DNM, "Sending OPSTART\n");
2152
Harald Welte59b04682009-06-10 05:40:52 +08002153 return abis_nm_sendmsg(bts, msg);
2154}
2155
2156/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002157int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
2158 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08002159{
2160 struct abis_om_hdr *oh;
2161 struct msgb *msg = nm_msgb_alloc();
2162
2163 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2164 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2165 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2166
2167 return abis_nm_sendmsg(bts, msg);
2168}
2169
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002170int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
2171 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02002172{
2173 struct abis_om_hdr *oh;
2174 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002175 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02002176
2177 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2178 e1_port0, ts0, e1_port1, ts1);
2179
2180 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2181 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2182 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2183
2184 attr = msgb_put(msg, 3);
2185 attr[0] = NM_ATT_MDROP_LINK;
2186 attr[1] = e1_port0;
2187 attr[2] = ts0;
2188
2189 attr = msgb_put(msg, 3);
2190 attr[0] = NM_ATT_MDROP_NEXT;
2191 attr[1] = e1_port1;
2192 attr[2] = ts1;
2193
2194 return abis_nm_sendmsg(bts, msg);
2195}
Harald Welte59b04682009-06-10 05:40:52 +08002196
Harald Welte0bf8e302009-08-08 00:02:36 +02002197/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002198int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2199 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2200 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02002201{
2202 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02002203
Harald Welte30f93fb2011-02-19 16:48:17 +01002204 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01002205
2206 if (!msg)
2207 msg = nm_msgb_alloc();
2208
2209 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2210 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2211 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2212 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02002213 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02002214
2215 return abis_nm_sendmsg(bts, msg);
2216}
2217
Harald Welte59b04682009-06-10 05:40:52 +08002218int abis_nm_event_reports(struct gsm_bts *bts, int on)
2219{
2220 if (on == 0)
2221 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2222 else
2223 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2224}
2225
2226/* Siemens (or BS-11) specific commands */
2227
2228int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2229{
2230 if (reconnect == 0)
2231 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2232 else
2233 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2234}
2235
2236int abis_nm_bs11_restart(struct gsm_bts *bts)
2237{
2238 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2239}
2240
2241
2242struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002243 uint16_t year;
2244 uint8_t month;
2245 uint8_t day;
2246 uint8_t hour;
2247 uint8_t min;
2248 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08002249} __attribute__((packed));
2250
2251
2252void get_bs11_date_time(struct bs11_date_time *aet)
2253{
2254 time_t t;
2255 struct tm *tm;
2256
2257 t = time(NULL);
2258 tm = localtime(&t);
2259 aet->sec = tm->tm_sec;
2260 aet->min = tm->tm_min;
2261 aet->hour = tm->tm_hour;
2262 aet->day = tm->tm_mday;
2263 aet->month = tm->tm_mon;
2264 aet->year = htons(1900 + tm->tm_year);
2265}
2266
2267int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2268{
2269 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2270}
2271
2272int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2273{
2274 if (begin)
2275 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2276 else
2277 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2278}
2279
2280int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002281 enum abis_bs11_objtype type, uint8_t idx,
2282 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08002283{
2284 struct abis_om_hdr *oh;
2285 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002286 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08002287
2288 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2289 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2290 NM_OC_BS11, type, 0, idx);
2291 cur = msgb_put(msg, attr_len);
2292 memcpy(cur, attr, attr_len);
2293
2294 return abis_nm_sendmsg(bts, msg);
2295}
2296
2297int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002298 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08002299{
2300 struct abis_om_hdr *oh;
2301 struct msgb *msg = nm_msgb_alloc();
2302
2303 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2304 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2305 NM_OC_BS11, type, 0, idx);
2306
2307 return abis_nm_sendmsg(bts, msg);
2308}
2309
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002310int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08002311{
2312 struct abis_om_hdr *oh;
2313 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002314 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08002315
2316 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2317 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2318 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2319 msgb_tlv_put(msg, 0x99, 1, &zero);
2320
2321 return abis_nm_sendmsg(bts, msg);
2322}
2323
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002324int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08002325{
2326 struct abis_om_hdr *oh;
2327 struct msgb *msg = nm_msgb_alloc();
2328
2329 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2330 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02002331 idx, 0xff, 0xff);
2332
2333 return abis_nm_sendmsg(bts, msg);
2334}
2335
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002336int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02002337{
2338 struct abis_om_hdr *oh;
2339 struct msgb *msg = nm_msgb_alloc();
2340
2341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2342 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2343 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08002344
2345 return abis_nm_sendmsg(bts, msg);
2346}
2347
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002348static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08002349int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2350{
2351 struct abis_om_hdr *oh;
2352 struct msgb *msg = nm_msgb_alloc();
2353
2354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2355 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2356 0xff, 0xff, 0xff);
2357 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2358
2359 return abis_nm_sendmsg(bts, msg);
2360}
2361
2362/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002363int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2364 uint8_t e1_timeslot, uint8_t e1_subslot,
2365 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08002366{
2367 struct abis_om_hdr *oh;
2368 struct abis_nm_channel *ch;
2369 struct msgb *msg = nm_msgb_alloc();
2370
2371 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2372 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2373 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2374
2375 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2376 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2377 msgb_tv_put(msg, NM_ATT_TEI, tei);
2378
2379 return abis_nm_sendmsg(bts, msg);
2380}
2381
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002382int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08002383{
2384 struct abis_om_hdr *oh;
2385 struct msgb *msg = nm_msgb_alloc();
2386
2387 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2388 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2389 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2390 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2391
2392 return abis_nm_sendmsg(trx->bts, msg);
2393}
2394
2395int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2396{
2397 struct abis_om_hdr *oh;
2398 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002399 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08002400
2401 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2402 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2403 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2404 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2405
2406 return abis_nm_sendmsg(trx->bts, msg);
2407}
2408
2409int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2410{
2411 struct abis_om_hdr *oh;
2412 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002413 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08002414
2415 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2416 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2417 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2418 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2419
2420 return abis_nm_sendmsg(bts, msg);
2421}
2422
2423int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2424{
2425 struct abis_om_hdr *oh;
2426 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002427 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002428 NM_ATT_BS11_CCLK_TYPE };
2429
2430 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2431 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2432 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2433 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2434
2435 return abis_nm_sendmsg(bts, msg);
2436
2437}
2438
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002439//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002440
2441int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2442{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002443 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2444}
2445
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002446int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2447{
2448 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2449}
2450
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002451int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002452{
Harald Welte59b04682009-06-10 05:40:52 +08002453 struct abis_om_hdr *oh;
2454 struct msgb *msg = nm_msgb_alloc();
2455 struct bs11_date_time bdt;
2456
2457 get_bs11_date_time(&bdt);
2458
2459 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2460 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002461 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002462 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002463 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2464 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2465 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002466 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002467 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002468 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002469 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002470 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002471 } else {
2472 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2473 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2474 }
2475
2476 return abis_nm_sendmsg(bts, msg);
2477}
2478
2479int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2480{
2481 struct abis_om_hdr *oh;
2482 struct msgb *msg;
2483
2484 if (strlen(password) != 10)
2485 return -EINVAL;
2486
2487 msg = nm_msgb_alloc();
2488 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2489 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2490 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002491 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002492
2493 return abis_nm_sendmsg(bts, msg);
2494}
2495
2496/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2497int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2498{
2499 struct abis_om_hdr *oh;
2500 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002501 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002502
2503 msg = nm_msgb_alloc();
2504 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2505 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2506 BS11_OBJ_LI, 0x00, 0x00);
2507
2508 if (locked)
2509 tlv_value = BS11_LI_PLL_LOCKED;
2510 else
2511 tlv_value = BS11_LI_PLL_STANDALONE;
2512
2513 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2514
2515 return abis_nm_sendmsg(bts, msg);
2516}
2517
Daniel Willmann10b07db2010-01-07 00:54:01 +01002518/* Set the calibration value of the PLL (work value/set value)
2519 * It depends on the login which one is changed */
2520int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2521{
2522 struct abis_om_hdr *oh;
2523 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002524 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002525
2526 msg = nm_msgb_alloc();
2527 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2528 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2529 BS11_OBJ_TRX1, 0x00, 0x00);
2530
2531 tlv_value[0] = value>>8;
2532 tlv_value[1] = value&0xff;
2533
2534 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2535
2536 return abis_nm_sendmsg(bts, msg);
2537}
2538
Harald Welte59b04682009-06-10 05:40:52 +08002539int abis_nm_bs11_get_state(struct gsm_bts *bts)
2540{
2541 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2542}
2543
2544/* BS11 SWL */
2545
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002546void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002547
Harald Welte59b04682009-06-10 05:40:52 +08002548struct abis_nm_bs11_sw {
2549 struct gsm_bts *bts;
2550 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002551 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002552 int forced;
2553 struct llist_head file_list;
2554 gsm_cbfn *user_cb; /* specified by the user */
2555};
2556static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2557
2558struct file_list_entry {
2559 struct llist_head list;
2560 char fname[PATH_MAX];
2561};
2562
2563struct file_list_entry *fl_dequeue(struct llist_head *queue)
2564{
2565 struct llist_head *lh;
2566
2567 if (llist_empty(queue))
2568 return NULL;
2569
2570 lh = queue->next;
2571 llist_del(lh);
2572
2573 return llist_entry(lh, struct file_list_entry, list);
2574}
2575
2576static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2577{
2578 char linebuf[255];
2579 struct llist_head *lh, *lh2;
2580 FILE *swl;
2581 int rc = 0;
2582
2583 swl = fopen(bs11_sw->swl_fname, "r");
2584 if (!swl)
2585 return -ENODEV;
2586
2587 /* zero the stale file list, if any */
2588 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2589 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002590 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002591 }
2592
2593 while (fgets(linebuf, sizeof(linebuf), swl)) {
2594 char file_id[12+1];
2595 char file_version[80+1];
2596 struct file_list_entry *fle;
2597 static char dir[PATH_MAX];
2598
2599 if (strlen(linebuf) < 4)
2600 continue;
2601
2602 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2603 if (rc < 0) {
2604 perror("ERR parsing SWL file");
2605 rc = -EINVAL;
2606 goto out;
2607 }
2608 if (rc < 2)
2609 continue;
2610
Harald Welte857e00d2009-06-26 20:25:23 +02002611 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002612 if (!fle) {
2613 rc = -ENOMEM;
2614 goto out;
2615 }
Harald Welte59b04682009-06-10 05:40:52 +08002616
2617 /* construct new filename */
2618 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2619 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2620 strcat(fle->fname, "/");
2621 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2622
2623 llist_add_tail(&fle->list, &bs11_sw->file_list);
2624 }
2625
2626out:
2627 fclose(swl);
2628 return rc;
2629}
2630
2631/* bs11 swload specific callback, passed to abis_nm core swload */
2632static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2633 struct msgb *msg, void *data, void *param)
2634{
2635 struct abis_nm_bs11_sw *bs11_sw = data;
2636 struct file_list_entry *fle;
2637 int rc = 0;
2638
2639 switch (event) {
2640 case NM_MT_LOAD_END_ACK:
2641 fle = fl_dequeue(&bs11_sw->file_list);
2642 if (fle) {
2643 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002644 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002645 bs11_sw->win_size,
2646 bs11_sw->forced,
2647 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002648 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002649 } else {
2650 /* activate the SWL */
2651 rc = abis_nm_software_activate(bs11_sw->bts,
2652 bs11_sw->swl_fname,
2653 bs11_swload_cbfn,
2654 bs11_sw);
2655 }
2656 break;
2657 case NM_MT_LOAD_SEG_ACK:
2658 case NM_MT_LOAD_END_NACK:
2659 case NM_MT_LOAD_INIT_ACK:
2660 case NM_MT_LOAD_INIT_NACK:
2661 case NM_MT_ACTIVATE_SW_NACK:
2662 case NM_MT_ACTIVATE_SW_ACK:
2663 default:
2664 /* fallthrough to the user callback */
2665 if (bs11_sw->user_cb)
2666 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2667 break;
2668 }
2669
2670 return rc;
2671}
2672
2673/* Siemens provides a SWL file that is a mere listing of all the other
2674 * files that are part of a software release. We need to upload first
2675 * the list file, and then each file that is listed in the list file */
2676int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002677 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002678{
2679 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2680 struct file_list_entry *fle;
2681 int rc = 0;
2682
2683 INIT_LLIST_HEAD(&bs11_sw->file_list);
2684 bs11_sw->bts = bts;
2685 bs11_sw->win_size = win_size;
2686 bs11_sw->user_cb = cbfn;
2687 bs11_sw->forced = forced;
2688
2689 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2690 rc = bs11_read_swl_file(bs11_sw);
2691 if (rc < 0)
2692 return rc;
2693
2694 /* dequeue next item in file list */
2695 fle = fl_dequeue(&bs11_sw->file_list);
2696 if (!fle)
2697 return -EINVAL;
2698
2699 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002700 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002701 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002702 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002703 return rc;
2704}
2705
2706#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002707static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002708 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2709 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2710 NM_ATT_BS11_LMT_USER_NAME,
2711
2712 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2713
2714 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2715
2716 NM_ATT_BS11_SW_LOAD_STORED };
2717
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002718static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002719 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2720 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2721 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2722 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2723#endif
2724
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002725static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002726 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2727 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2728 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2729
2730int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2731{
2732 struct abis_om_hdr *oh;
2733 struct msgb *msg = nm_msgb_alloc();
2734
2735 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2736 /* SiemensHW CCTRL object */
2737 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2738 0x03, 0x00, 0x00);
2739 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2740
2741 return abis_nm_sendmsg(bts, msg);
2742}
2743
2744int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2745{
2746 struct abis_om_hdr *oh;
2747 struct msgb *msg = nm_msgb_alloc();
2748 struct bs11_date_time aet;
2749
2750 get_bs11_date_time(&aet);
2751 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2752 /* SiemensHW CCTRL object */
2753 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2754 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002755 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002756
2757 return abis_nm_sendmsg(bts, msg);
2758}
2759
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002760int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002761{
2762 struct abis_om_hdr *oh;
2763 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002764 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002765
2766 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2767 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2768 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2769 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2770
2771 return abis_nm_sendmsg(bts, msg);
2772}
2773
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002774int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Daniel Willmann5655afe2009-08-10 11:49:36 +02002775{
2776 struct abis_om_hdr *oh;
2777 struct msgb *msg = nm_msgb_alloc();
2778 struct bs11_date_time aet;
2779
2780 get_bs11_date_time(&aet);
2781 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2782 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2783 bport, 0xff, 0x02);
2784 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2785
2786 return abis_nm_sendmsg(bts, msg);
2787}
2788
Harald Welte59b04682009-06-10 05:40:52 +08002789/* ip.access nanoBTS specific commands */
2790static const char ipaccess_magic[] = "com.ipaccess";
2791
2792
2793static int abis_nm_rx_ipacc(struct msgb *msg)
2794{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002795 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002796 struct abis_om_hdr *oh = msgb_l2(msg);
2797 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002798 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002799 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002800 struct ipacc_ack_signal_data signal;
Harald Welte59b04682009-06-10 05:40:52 +08002801
2802 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002803 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002804 return -EINVAL;
2805 }
2806
2807 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Harald Welte59698fb2010-01-10 18:01:52 +01002808 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002809
Harald Welteb7284a92009-10-20 09:56:18 +02002810 debugp_foh(foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002811
Harald Welte5aeedd42009-10-19 22:11:11 +02002812 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002813
2814 switch (foh->msg_type) {
2815 case NM_MT_IPACC_RSL_CONNECT_ACK:
2816 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002817 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2818 memcpy(&addr,
2819 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2820
2821 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2822 }
Harald Welte4206d982009-07-12 09:33:54 +02002823 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002824 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002825 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002826 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002827 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2828 DEBUGPC(DNM, "STREAM=0x%02x ",
2829 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002830 DEBUGPC(DNM, "\n");
2831 break;
2832 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002833 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002834 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002835 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002836 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2837 else
2838 DEBUGPC(DNM, "\n");
2839 break;
2840 case NM_MT_IPACC_SET_NVATTR_ACK:
2841 DEBUGPC(DNM, "SET NVATTR ACK\n");
2842 /* FIXME: decode and show the actual attributes */
2843 break;
2844 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002845 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002846 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002847 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte59b04682009-06-10 05:40:52 +08002848 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2849 else
Harald Weltede4477a2009-12-24 12:20:20 +01002850 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002851 break;
Harald Welte21460f02009-07-03 11:26:45 +02002852 case NM_MT_IPACC_GET_NVATTR_ACK:
2853 DEBUGPC(DNM, "GET NVATTR ACK\n");
2854 /* FIXME: decode and show the actual attributes */
2855 break;
2856 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002857 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002858 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002859 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte21460f02009-07-03 11:26:45 +02002860 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2861 else
Harald Weltede4477a2009-12-24 12:20:20 +01002862 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002863 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002864 case NM_MT_IPACC_SET_ATTR_ACK:
2865 DEBUGPC(DNM, "SET ATTR ACK\n");
2866 break;
2867 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002868 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002869 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002870 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec76a2172009-10-08 20:15:24 +02002871 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2872 else
Harald Weltede4477a2009-12-24 12:20:20 +01002873 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002874 break;
Harald Welte59b04682009-06-10 05:40:52 +08002875 default:
2876 DEBUGPC(DNM, "unknown\n");
2877 break;
2878 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002879
2880 /* signal handling */
2881 switch (foh->msg_type) {
2882 case NM_MT_IPACC_RSL_CONNECT_NACK:
2883 case NM_MT_IPACC_SET_NVATTR_NACK:
2884 case NM_MT_IPACC_GET_NVATTR_NACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002885 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002886 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002887 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002888 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002889 case NM_MT_IPACC_SET_NVATTR_ACK:
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002890 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002891 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002892 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002893 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002894 default:
2895 break;
2896 }
2897
Harald Welte59b04682009-06-10 05:40:52 +08002898 return 0;
2899}
2900
2901/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002902int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2903 uint8_t obj_class, uint8_t bts_nr,
2904 uint8_t trx_nr, uint8_t ts_nr,
2905 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002906{
2907 struct msgb *msg = nm_msgb_alloc();
2908 struct abis_om_hdr *oh;
2909 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002910 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002911
2912 /* construct the 12.21 OM header, observe the erroneous length */
2913 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2914 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2915 oh->mdisc = ABIS_OM_MDISC_MANUF;
2916
2917 /* add the ip.access magic */
2918 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2919 *data++ = sizeof(ipaccess_magic);
2920 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2921
2922 /* fill the 12.21 FOM header */
2923 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2924 foh->msg_type = msg_type;
2925 foh->obj_class = obj_class;
2926 foh->obj_inst.bts_nr = bts_nr;
2927 foh->obj_inst.trx_nr = trx_nr;
2928 foh->obj_inst.ts_nr = ts_nr;
2929
2930 if (attr && attr_len) {
2931 data = msgb_put(msg, attr_len);
2932 memcpy(data, attr, attr_len);
2933 }
2934
2935 return abis_nm_sendmsg(bts, msg);
2936}
2937
2938/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002939int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002940 int attr_len)
2941{
Harald Weltef12c1052010-01-07 20:39:42 +01002942 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2943 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002944 attr_len);
2945}
2946
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002947int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002948 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002949{
2950 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002951 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002952 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2953 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2954
2955 int attr_len = sizeof(attr);
2956
2957 ia.s_addr = htonl(ip);
2958 attr[1] = stream;
2959 attr[3] = port >> 8;
2960 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002961 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002962
2963 /* if ip == 0, we use the default IP */
2964 if (ip == 0)
2965 attr_len -= 5;
2966
2967 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002968 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002969
2970 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2971 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2972 trx->nr, 0xff, attr, attr_len);
2973}
2974
Harald Welte59b04682009-06-10 05:40:52 +08002975/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002976int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002977{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002978 struct abis_om_hdr *oh;
2979 struct msgb *msg = nm_msgb_alloc();
2980
2981 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2982 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2983 trx->bts->nr, trx->nr, 0xff);
2984
2985 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002986}
Harald Welte0dfc6232009-10-24 10:20:41 +02002987
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002988int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2989 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2990 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002991{
2992 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2993 obj_class, bts_nr, trx_nr, ts_nr,
2994 attr, attr_len);
2995}
Harald Weltebeeae412009-11-12 14:48:42 +01002996
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002997void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002998{
2999 /* we simply reuse the GSM48 function and overwrite the RAC
3000 * with the Cell ID */
3001 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003002 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08003003}
3004
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01003005void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
3006{
3007 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
3008
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +01003009 trx->nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01003010 if (!trx->bts || !trx->bts->oml_link)
3011 return;
3012
3013 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3014 trx->bts->bts_nr, trx->nr, 0xff,
3015 new_state);
3016}
3017
Harald Welte453141f2010-03-25 11:45:30 +08003018static const struct value_string ipacc_testres_names[] = {
3019 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3020 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3021 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3022 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3023 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3024 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01003025};
3026
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003027const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01003028{
Harald Welte453141f2010-03-25 11:45:30 +08003029 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01003030}
3031
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003032void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01003033{
3034 cid->mcc = (buf[0] & 0xf) * 100;
3035 cid->mcc += (buf[0] >> 4) * 10;
3036 cid->mcc += (buf[1] & 0xf) * 1;
3037
3038 if (buf[1] >> 4 == 0xf) {
3039 cid->mnc = (buf[2] & 0xf) * 10;
3040 cid->mnc += (buf[2] >> 4) * 1;
3041 } else {
3042 cid->mnc = (buf[2] & 0xf) * 100;
3043 cid->mnc += (buf[2] >> 4) * 10;
3044 cid->mnc += (buf[1] >> 4) * 1;
3045 }
3046
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003047 cid->lac = ntohs(*((uint16_t *)&buf[3]));
3048 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01003049}
3050
Harald Weltebeeae412009-11-12 14:48:42 +01003051/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003052int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01003053{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003054 uint8_t *cur = buf;
3055 uint16_t len;
Harald Weltebeeae412009-11-12 14:48:42 +01003056
Harald Welteb784df82010-07-22 18:14:36 +02003057 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01003058
3059 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3060 return -EINVAL;
3061 cur++;
3062
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003063 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01003064 cur += 2;
3065
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003066 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01003067 cur += 2;
3068
3069 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3070 binf->freq_qual = *cur >> 2;
3071
Harald Welteb784df82010-07-22 18:14:36 +02003072 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01003073 binf->arfcn |= *cur++;
3074
3075 if (binf->info_type & IPAC_BINF_RXLEV)
3076 binf->rx_lev = *cur & 0x3f;
3077 cur++;
3078
3079 if (binf->info_type & IPAC_BINF_RXQUAL)
3080 binf->rx_qual = *cur & 0x7;
3081 cur++;
3082
3083 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003084 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01003085 cur += 2;
3086
3087 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003088 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01003089 cur += 2;
3090
3091 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02003092 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01003093 cur += 4;
3094
Harald Welte22cb81f2010-07-30 22:34:42 +02003095#if 0
3096 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01003097 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02003098#endif
Harald Welte161b4be2009-11-13 14:41:52 +01003099 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01003100 cur++;
3101
Harald Weltebfc21092009-11-13 11:56:05 +01003102 ipac_parse_cgi(&binf->cgi, cur);
3103 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01003104
3105 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3106 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3107 cur += sizeof(binf->ba_list_si2);
3108 }
3109
3110 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3111 memcpy(binf->ba_list_si2bis, cur,
3112 sizeof(binf->ba_list_si2bis));
3113 cur += sizeof(binf->ba_list_si2bis);
3114 }
3115
3116 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3117 memcpy(binf->ba_list_si2ter, cur,
3118 sizeof(binf->ba_list_si2ter));
3119 cur += sizeof(binf->ba_list_si2ter);
3120 }
3121
3122 return 0;
3123}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01003124
3125void abis_nm_clear_queue(struct gsm_bts *bts)
3126{
3127 struct msgb *msg;
3128
3129 while (!llist_empty(&bts->abis_queue)) {
3130 msg = msgb_dequeue(&bts->abis_queue);
3131 msgb_free(msg);
3132 }
3133
3134 bts->abis_nm_pend = 0;
3135}