blob: 0e7fc8d8c3dd8e3260ee4a0f973e25616389419d [file] [log] [blame]
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001/* GSM Network Management (OML) messages on the A-bis interface
2 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * 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/>.
20 *
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
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37
38#include <openbsc/gsm_data.h>
39#include <openbsc/debug.h>
40#include <osmocore/msgb.h>
41#include <osmocore/tlv.h>
42#include <osmocore/talloc.h>
43#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
46
47#define OM_ALLOC_SIZE 1024
48#define OM_HEADROOM_SIZE 128
49#define IPACC_SEGMENT_SIZE 245
50
51/* unidirectional messages from BTS to BSC */
52static const enum abis_nm_msgtype reports[] = {
53 NM_MT_SW_ACTIVATED_REP,
54 NM_MT_TEST_REP,
55 NM_MT_STATECHG_EVENT_REP,
56 NM_MT_FAILURE_EVENT_REP,
57};
58
59/* messages without ACK/NACK */
60static const enum abis_nm_msgtype no_ack_nack[] = {
61 NM_MT_MEAS_RES_REQ,
62 NM_MT_STOP_MEAS,
63 NM_MT_START_MEAS,
64};
65
66/* Messages related to software load */
67static const enum abis_nm_msgtype sw_load_msgs[] = {
68 NM_MT_LOAD_INIT_ACK,
69 NM_MT_LOAD_INIT_NACK,
70 NM_MT_LOAD_SEG_ACK,
71 NM_MT_LOAD_ABORT,
72 NM_MT_LOAD_END_ACK,
73 NM_MT_LOAD_END_NACK,
74 //NM_MT_SW_ACT_REQ,
75 NM_MT_ACTIVATE_SW_ACK,
76 NM_MT_ACTIVATE_SW_NACK,
77 NM_MT_SW_ACTIVATED_REP,
78};
79
80static const enum abis_nm_msgtype nacks[] = {
81 NM_MT_LOAD_INIT_NACK,
82 NM_MT_LOAD_END_NACK,
83 NM_MT_SW_ACT_REQ_NACK,
84 NM_MT_ACTIVATE_SW_NACK,
85 NM_MT_ESTABLISH_TEI_NACK,
86 NM_MT_CONN_TERR_SIGN_NACK,
87 NM_MT_DISC_TERR_SIGN_NACK,
88 NM_MT_CONN_TERR_TRAF_NACK,
89 NM_MT_DISC_TERR_TRAF_NACK,
90 NM_MT_CONN_MDROP_LINK_NACK,
91 NM_MT_DISC_MDROP_LINK_NACK,
92 NM_MT_SET_BTS_ATTR_NACK,
93 NM_MT_SET_RADIO_ATTR_NACK,
94 NM_MT_SET_CHAN_ATTR_NACK,
95 NM_MT_PERF_TEST_NACK,
96 NM_MT_SEND_TEST_REP_NACK,
97 NM_MT_STOP_TEST_NACK,
98 NM_MT_STOP_EVENT_REP_NACK,
99 NM_MT_REST_EVENT_REP_NACK,
100 NM_MT_CHG_ADM_STATE_NACK,
101 NM_MT_CHG_ADM_STATE_REQ_NACK,
102 NM_MT_REP_OUTST_ALARMS_NACK,
103 NM_MT_CHANGEOVER_NACK,
104 NM_MT_OPSTART_NACK,
105 NM_MT_REINIT_NACK,
106 NM_MT_SET_SITE_OUT_NACK,
107 NM_MT_CHG_HW_CONF_NACK,
108 NM_MT_GET_ATTR_NACK,
109 NM_MT_SET_ALARM_THRES_NACK,
110 NM_MT_BS11_BEGIN_DB_TX_NACK,
111 NM_MT_BS11_END_DB_TX_NACK,
112 NM_MT_BS11_CREATE_OBJ_NACK,
113 NM_MT_BS11_DELETE_OBJ_NACK,
114};
115
116static const struct value_string nack_names[] = {
117 { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" },
118 { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" },
119 { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" },
120 { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" },
121 { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" },
122 { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" },
123 { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" },
124 { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" },
125 { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" },
126 { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" },
127 { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" },
128 { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" },
129 { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" },
130 { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" },
131 { NM_MT_PERF_TEST_NACK, "PERFORM TEST" },
132 { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" },
133 { NM_MT_STOP_TEST_NACK, "STOP TEST" },
134 { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" },
135 { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" },
136 { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" },
137 { NM_MT_CHG_ADM_STATE_REQ_NACK,
138 "CHANGE ADMINISTRATIVE STATE REQUEST" },
139 { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" },
140 { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" },
141 { NM_MT_OPSTART_NACK, "OPSTART" },
142 { NM_MT_REINIT_NACK, "REINIT" },
143 { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" },
144 { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" },
145 { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" },
146 { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" },
147 { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" },
148 { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" },
149 { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" },
150 { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" },
151 { 0, NULL }
152};
153
154/* Chapter 9.4.36 */
155static const struct value_string nack_cause_names[] = {
156 /* General Nack Causes */
157 { NM_NACK_INCORR_STRUCT, "Incorrect message structure" },
158 { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" },
159 { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" },
160 { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" },
161 { NM_NACK_BTSNR_UNKN, "BTS no. unknown" },
162 { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" },
163 { NM_NACK_OBJINST_UNKN, "Object Instance unknown" },
164 { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" },
165 { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" },
166 { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" },
167 { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" },
168 { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" },
169 { NM_NACK_CANT_PERFORM, "Message cannot be performed" },
170 /* Specific Nack Causes */
171 { NM_NACK_RES_NOTIMPL, "Resource not implemented" },
172 { NM_NACK_RES_NOTAVAIL, "Resource not available" },
173 { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" },
174 { NM_NACK_TEST_NOTSUPP, "Test not supported" },
175 { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" },
176 { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" },
177 { NM_NACK_TEST_NOTINIT, "Test not initiated" },
178 { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" },
179 { NM_NACK_TEST_NOSUCH, "No such test" },
180 { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" },
181 { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" },
182 { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" },
183 { NM_NACK_FILE_NOTAVAIL, "File not available at destination" },
184 { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" },
185 { NM_NACK_REQ_NOT_GRANT, "Request not granted" },
186 { NM_NACK_WAIT, "Wait" },
187 { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" },
188 { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" },
189 { NM_NACK_MEAS_NOTSTART, "Measurement not started" },
190 { 0, NULL }
191};
192
193static const char *nack_cause_name(u_int8_t cause)
194{
195 return get_value_string(nack_cause_names, cause);
196}
197
198/* Chapter 9.4.16: Event Type */
199static const struct value_string event_type_names[] = {
200 { NM_EVT_COMM_FAIL, "communication failure" },
201 { NM_EVT_QOS_FAIL, "quality of service failure" },
202 { NM_EVT_PROC_FAIL, "processing failure" },
203 { NM_EVT_EQUIP_FAIL, "equipment failure" },
204 { NM_EVT_ENV_FAIL, "environment failure" },
205 { 0, NULL }
206};
207
208static const char *event_type_name(u_int8_t cause)
209{
210 return get_value_string(event_type_names, cause);
211}
212
213/* Chapter 9.4.63: Perceived Severity */
214static const struct value_string severity_names[] = {
215 { NM_SEVER_CEASED, "failure ceased" },
216 { NM_SEVER_CRITICAL, "critical failure" },
217 { NM_SEVER_MAJOR, "major failure" },
218 { NM_SEVER_MINOR, "minor failure" },
219 { NM_SEVER_WARNING, "warning level failure" },
220 { NM_SEVER_INDETERMINATE, "indeterminate failure" },
221 { 0, NULL }
222};
223
224static const char *severity_name(u_int8_t cause)
225{
226 return get_value_string(severity_names, cause);
227}
228
229/* Attributes that the BSC can set, not only get, according to Section 9.4 */
230static const enum abis_nm_attr nm_att_settable[] = {
231 NM_ATT_ADD_INFO,
232 NM_ATT_ADD_TEXT,
233 NM_ATT_DEST,
234 NM_ATT_EVENT_TYPE,
235 NM_ATT_FILE_DATA,
236 NM_ATT_GET_ARI,
237 NM_ATT_HW_CONF_CHG,
238 NM_ATT_LIST_REQ_ATTR,
239 NM_ATT_MDROP_LINK,
240 NM_ATT_MDROP_NEXT,
241 NM_ATT_NACK_CAUSES,
242 NM_ATT_OUTST_ALARM,
243 NM_ATT_PHYS_CONF,
244 NM_ATT_PROB_CAUSE,
245 NM_ATT_RAD_SUBC,
246 NM_ATT_SOURCE,
247 NM_ATT_SPEC_PROB,
248 NM_ATT_START_TIME,
249 NM_ATT_TEST_DUR,
250 NM_ATT_TEST_NO,
251 NM_ATT_TEST_REPORT,
252 NM_ATT_WINDOW_SIZE,
253 NM_ATT_SEVERITY,
254 NM_ATT_MEAS_RES,
255 NM_ATT_MEAS_TYPE,
256};
257
258const struct tlv_definition nm_att_tlvdef = {
259 .def = {
260 [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
261 [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
262 [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
263 [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
264 [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
265 [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
266 [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
267 [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
268 [NM_ATT_BSIC] = { TLV_TYPE_TV },
269 [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
270 [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
271 [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
272 [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
273 [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
274 [NM_ATT_DEST] = { TLV_TYPE_TL16V },
275 [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
276 [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
277 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
278 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
279 [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
280 [NM_ATT_HSN] = { TLV_TYPE_TV },
281 [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
282 [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
283 [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
284 [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
285 [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
286 [NM_ATT_MAIO] = { TLV_TYPE_TV },
287 [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
288 [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
289 [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
290 [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
291 [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
292 [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
293 [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
294 [NM_ATT_NY1] = { TLV_TYPE_TV },
295 [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
296 [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
297 [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
298 [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
299 [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
300 [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
301 [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
302 [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
303 [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
304 [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
305 [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
306 [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
307 [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
308 [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
309 [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
310 [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
311 [NM_ATT_TEI] = { TLV_TYPE_TV },
312 [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
313 [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
314 [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
315 [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
316 [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
317 [NM_ATT_TSC] = { TLV_TYPE_TV },
318 [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
319 [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
320 [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
321 [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
322 [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
323 [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
324 },
325};
326
327static const enum abis_nm_chan_comb chcomb4pchan[] = {
328 [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
329 [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
330 [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
331 [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
332 [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
333 [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
334 [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
335 /* FIXME: bounds check */
336};
337
338int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
339{
340 if (pchan < ARRAY_SIZE(chcomb4pchan))
341 return chcomb4pchan[pchan];
342
343 return -EINVAL;
344}
345
346int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
347{
348 if (!bts->model)
349 return -EIO;
350 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
351}
352
353static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
354{
355 int i;
356
357 for (i = 0; i < size; i++) {
358 if (arr[i] == mt)
359 return 1;
360 }
361
362 return 0;
363}
364
365#if 0
366/* is this msgtype the usual ACK/NACK type ? */
367static int is_ack_nack(enum abis_nm_msgtype mt)
368{
369 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
370}
371#endif
372
373/* is this msgtype a report ? */
374static int is_report(enum abis_nm_msgtype mt)
375{
376 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
377}
378
379#define MT_ACK(x) (x+1)
380#define MT_NACK(x) (x+2)
381
382static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
383{
384 oh->mdisc = ABIS_OM_MDISC_FOM;
385 oh->placement = ABIS_OM_PLACEMENT_ONLY;
386 oh->sequence = 0;
387 oh->length = len;
388}
389
390static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
391 u_int8_t msg_type, u_int8_t obj_class,
392 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
393{
394 struct abis_om_fom_hdr *foh =
395 (struct abis_om_fom_hdr *) oh->data;
396
397 fill_om_hdr(oh, len+sizeof(*foh));
398 foh->msg_type = msg_type;
399 foh->obj_class = obj_class;
400 foh->obj_inst.bts_nr = bts_nr;
401 foh->obj_inst.trx_nr = trx_nr;
402 foh->obj_inst.ts_nr = ts_nr;
403}
404
405static struct msgb *nm_msgb_alloc(void)
406{
407 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
408 "OML");
409}
410
411/* Send a OML NM Message from BSC to BTS */
412static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
413{
414 msg->trx = bts->c0;
415
416 /* queue OML messages */
417 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
418 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
419 return _abis_nm_sendmsg(msg, 0);
420 } else {
421 msgb_enqueue(&bts->abis_queue, msg);
422 return 0;
423 }
424
425}
426
427int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
428{
429 OBSC_NM_W_ACK_CB(msg) = 1;
430 return abis_nm_queue_msg(bts, msg);
431}
432
433static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
434{
435 OBSC_NM_W_ACK_CB(msg) = 0;
436 return abis_nm_queue_msg(bts, msg);
437}
438
439static int abis_nm_rcvmsg_sw(struct msgb *mb);
440
441const struct value_string abis_nm_obj_class_names[] = {
442 { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
443 { NM_OC_BTS, "BTS" },
444 { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
445 { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
446 { NM_OC_CHANNEL, "CHANNEL" },
447 { NM_OC_BS11_ADJC, "ADJC" },
448 { NM_OC_BS11_HANDOVER, "HANDOVER" },
449 { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
450 { NM_OC_BS11_BTSE, "BTSE" },
451 { NM_OC_BS11_RACK, "RACK" },
452 { NM_OC_BS11_TEST, "TEST" },
453 { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
454 { NM_OC_BS11_BPORT, "BPORT" },
455 { NM_OC_GPRS_NSE, "GPRS-NSE" },
456 { NM_OC_GPRS_CELL, "GPRS-CELL" },
457 { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
458 { NM_OC_BS11, "SIEMENSHW" },
459 { 0, NULL }
460};
461
462static const char *obj_class_name(u_int8_t oc)
463{
464 return get_value_string(abis_nm_obj_class_names, oc);
465}
466
467const char *nm_opstate_name(u_int8_t os)
468{
469 switch (os) {
470 case NM_OPSTATE_DISABLED:
471 return "Disabled";
472 case NM_OPSTATE_ENABLED:
473 return "Enabled";
474 case NM_OPSTATE_NULL:
475 return "NULL";
476 default:
477 return "RFU";
478 }
479}
480
481/* Chapter 9.4.7 */
482static const struct value_string avail_names[] = {
483 { 0, "In test" },
484 { 1, "Failed" },
485 { 2, "Power off" },
486 { 3, "Off line" },
487 /* Not used */
488 { 5, "Dependency" },
489 { 6, "Degraded" },
490 { 7, "Not installed" },
491 { 0xff, "OK" },
492 { 0, NULL }
493};
494
495const char *nm_avail_name(u_int8_t avail)
496{
497 return get_value_string(avail_names, avail);
498}
499
500static struct value_string test_names[] = {
501 /* FIXME: standard test names */
502 { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
503 { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
504 { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
505 { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
506 { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
507 { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
508 { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
509 { 0, NULL }
510};
511
512const struct value_string abis_nm_adm_state_names[] = {
513 { NM_STATE_LOCKED, "Locked" },
514 { NM_STATE_UNLOCKED, "Unlocked" },
515 { NM_STATE_SHUTDOWN, "Shutdown" },
516 { NM_STATE_NULL, "NULL" },
517 { 0, NULL }
518};
519
520const char *nm_adm_name(u_int8_t adm)
521{
522 return get_value_string(abis_nm_adm_state_names, adm);
523}
524
525int nm_is_running(struct gsm_nm_state *s) {
526 return (s->operational == NM_OPSTATE_ENABLED) && (
527 (s->availability == NM_AVSTATE_OK) ||
528 (s->availability == 0xff)
529 );
530}
531
532static void debugp_foh(struct abis_om_fom_hdr *foh)
533{
534 DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
535 obj_class_name(foh->obj_class), foh->obj_class,
536 foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
537 foh->obj_inst.ts_nr);
538}
539
540/* obtain the gsm_nm_state data structure for a given object instance */
541static struct gsm_nm_state *
542objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
543 struct abis_om_obj_inst *obj_inst)
544{
545 struct gsm_bts_trx *trx;
546 struct gsm_nm_state *nm_state = NULL;
547
548 switch (obj_class) {
549 case NM_OC_BTS:
550 nm_state = &bts->nm_state;
551 break;
552 case NM_OC_RADIO_CARRIER:
553 if (obj_inst->trx_nr >= bts->num_trx) {
554 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
555 return NULL;
556 }
557 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
558 nm_state = &trx->nm_state;
559 break;
560 case NM_OC_BASEB_TRANSC:
561 if (obj_inst->trx_nr >= bts->num_trx) {
562 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
563 return NULL;
564 }
565 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
566 nm_state = &trx->bb_transc.nm_state;
567 break;
568 case NM_OC_CHANNEL:
569 if (obj_inst->trx_nr >= bts->num_trx) {
570 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
571 return NULL;
572 }
573 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
574 if (obj_inst->ts_nr >= TRX_NR_TS)
575 return NULL;
576 nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
577 break;
578 case NM_OC_SITE_MANAGER:
579 nm_state = &bts->site_mgr.nm_state;
580 break;
581 case NM_OC_BS11:
582 switch (obj_inst->bts_nr) {
583 case BS11_OBJ_CCLK:
584 nm_state = &bts->bs11.cclk.nm_state;
585 break;
586 case BS11_OBJ_BBSIG:
587 if (obj_inst->ts_nr > bts->num_trx)
588 return NULL;
589 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
590 nm_state = &trx->bs11.bbsig.nm_state;
591 break;
592 case BS11_OBJ_PA:
593 if (obj_inst->ts_nr > bts->num_trx)
594 return NULL;
595 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
596 nm_state = &trx->bs11.pa.nm_state;
597 break;
598 default:
599 return NULL;
600 }
601 case NM_OC_BS11_RACK:
602 nm_state = &bts->bs11.rack.nm_state;
603 break;
604 case NM_OC_BS11_ENVABTSE:
605 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->bs11.envabtse))
606 return NULL;
607 nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
608 break;
609 case NM_OC_GPRS_NSE:
610 nm_state = &bts->gprs.nse.nm_state;
611 break;
612 case NM_OC_GPRS_CELL:
613 nm_state = &bts->gprs.cell.nm_state;
614 break;
615 case NM_OC_GPRS_NSVC:
616 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
617 return NULL;
618 nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state;
619 break;
620 }
621 return nm_state;
622}
623
624/* obtain the in-memory data structure of a given object instance */
625static void *
626objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
627 struct abis_om_obj_inst *obj_inst)
628{
629 struct gsm_bts_trx *trx;
630 void *obj = NULL;
631
632 switch (obj_class) {
633 case NM_OC_BTS:
634 obj = bts;
635 break;
636 case NM_OC_RADIO_CARRIER:
637 if (obj_inst->trx_nr >= bts->num_trx) {
638 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
639 return NULL;
640 }
641 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
642 obj = trx;
643 break;
644 case NM_OC_BASEB_TRANSC:
645 if (obj_inst->trx_nr >= bts->num_trx) {
646 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
647 return NULL;
648 }
649 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
650 obj = &trx->bb_transc;
651 break;
652 case NM_OC_CHANNEL:
653 if (obj_inst->trx_nr >= bts->num_trx) {
654 DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
655 return NULL;
656 }
657 trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
658 if (obj_inst->ts_nr >= TRX_NR_TS)
659 return NULL;
660 obj = &trx->ts[obj_inst->ts_nr];
661 break;
662 case NM_OC_SITE_MANAGER:
663 obj = &bts->site_mgr;
664 break;
665 case NM_OC_GPRS_NSE:
666 obj = &bts->gprs.nse;
667 break;
668 case NM_OC_GPRS_CELL:
669 obj = &bts->gprs.cell;
670 break;
671 case NM_OC_GPRS_NSVC:
672 if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
673 return NULL;
674 obj = &bts->gprs.nsvc[obj_inst->trx_nr];
675 break;
676 }
677 return obj;
678}
679
680/* Update the administrative state of a given object in our in-memory data
681 * structures and send an event to the higher layer */
682static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
683 struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
684{
685 struct gsm_nm_state *nm_state, new_state;
686 struct nm_statechg_signal_data nsd;
687
688 nsd.obj = objclass2obj(bts, obj_class, obj_inst);
689 if (!nsd.obj)
690 return -EINVAL;
691 nm_state = objclass2nmstate(bts, obj_class, obj_inst);
692 if (!nm_state)
693 return -1;
694
695 new_state = *nm_state;
696 new_state.administrative = adm_state;
697
698 nsd.obj_class = obj_class;
699 nsd.old_state = nm_state;
700 nsd.new_state = &new_state;
701 nsd.obj_inst = obj_inst;
702 dispatch_signal(SS_NM, S_NM_STATECHG_ADM, &nsd);
703
704 nm_state->administrative = adm_state;
705
706 return 0;
707}
708
709static int abis_nm_rx_statechg_rep(struct msgb *mb)
710{
711 struct abis_om_hdr *oh = msgb_l2(mb);
712 struct abis_om_fom_hdr *foh = msgb_l3(mb);
713 struct gsm_bts *bts = mb->trx->bts;
714 struct tlv_parsed tp;
715 struct gsm_nm_state *nm_state, new_state;
716
717 DEBUGPC(DNM, "STATE CHG: ");
718
719 memset(&new_state, 0, sizeof(new_state));
720
721 nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
722 if (!nm_state) {
723 DEBUGPC(DNM, "unknown object class\n");
724 return -EINVAL;
725 }
726
727 new_state = *nm_state;
728
729 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
730 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
731 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
732 DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
733 }
734 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
735 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
736 new_state.availability = 0xff;
737 else
738 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
739 DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
740 new_state.availability);
741 } else
742 new_state.availability = 0xff;
743 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
744 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
745 DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
746 }
747 DEBUGPC(DNM, "\n");
748
749 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
750 new_state.operational != nm_state->operational ||
751 new_state.availability != nm_state->availability) {
752 /* Update the operational state of a given object in our in-memory data
753 * structures and send an event to the higher layer */
754 struct nm_statechg_signal_data nsd;
755 nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
756 nsd.obj_class = foh->obj_class;
757 nsd.old_state = nm_state;
758 nsd.new_state = &new_state;
759 nsd.obj_inst = &foh->obj_inst;
760 dispatch_signal(SS_NM, S_NM_STATECHG_OPER, &nsd);
761 nm_state->operational = new_state.operational;
762 nm_state->availability = new_state.availability;
763 if (nm_state->administrative == 0)
764 nm_state->administrative = new_state.administrative;
765 }
766#if 0
767 if (op_state == 1) {
768 /* try to enable objects that are disabled */
769 abis_nm_opstart(bts, foh->obj_class,
770 foh->obj_inst.bts_nr,
771 foh->obj_inst.trx_nr,
772 foh->obj_inst.ts_nr);
773 }
774#endif
775 return 0;
776}
777
778static int rx_fail_evt_rep(struct msgb *mb)
779{
780 struct abis_om_hdr *oh = msgb_l2(mb);
781 struct abis_om_fom_hdr *foh = msgb_l3(mb);
782 struct tlv_parsed tp;
783 const uint8_t *p_val;
784 char *p_text;
785
786 DEBUGPC(DNM, "Failure Event Report ");
787
788 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
789
790 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
791 DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
792 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
793 DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
794 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
795 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
796 DEBUGPC(DNM, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
797 }
798 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
799 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
800 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
801 if (p_text) {
802 DEBUGPC(DNM, "Additional Text=%s ", p_text);
803 talloc_free(p_text);
804 }
805 }
806
807 DEBUGPC(DNM, "\n");
808
809 return 0;
810}
811
812static int abis_nm_rcvmsg_report(struct msgb *mb)
813{
814 struct abis_om_fom_hdr *foh = msgb_l3(mb);
815 u_int8_t mt = foh->msg_type;
816
817 debugp_foh(foh);
818
819 //nmh->cfg->report_cb(mb, foh);
820
821 switch (mt) {
822 case NM_MT_STATECHG_EVENT_REP:
823 return abis_nm_rx_statechg_rep(mb);
824 break;
825 case NM_MT_SW_ACTIVATED_REP:
826 DEBUGPC(DNM, "Software Activated Report\n");
827 dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
828 break;
829 case NM_MT_FAILURE_EVENT_REP:
830 rx_fail_evt_rep(mb);
831 dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
832 break;
833 case NM_MT_TEST_REP:
834 DEBUGPC(DNM, "Test Report\n");
835 dispatch_signal(SS_NM, S_NM_TEST_REP, mb);
836 break;
837 default:
838 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
839 break;
840
841 };
842
843 return 0;
844}
845
846/* Activate the specified software into the BTS */
847static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
848 u_int8_t i2, const u_int8_t *sw_desc, u_int8_t swdesc_len)
849{
850 struct abis_om_hdr *oh;
851 struct msgb *msg = nm_msgb_alloc();
852 u_int8_t len = swdesc_len;
853 u_int8_t *trailer;
854
855 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
856 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
857
858 trailer = msgb_put(msg, swdesc_len);
859 memcpy(trailer, sw_desc, swdesc_len);
860
861 return abis_nm_sendmsg(bts, msg);
862}
863
864static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
865{
866 static const struct tlv_definition sw_descr_def = {
867 .def = {
868 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
869 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
870 },
871 };
872
873 u_int8_t tag;
874 u_int16_t tag_len;
875 const u_int8_t *val;
876 int ofs = 0, len;
877
878 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
879 * nested nature and the fact you have to assume it contains only two sub
880 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
881
882 if (sw_descr[0] != NM_ATT_SW_DESCR) {
883 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
884 return -1;
885 }
886 ofs += 1;
887
888 len = tlv_parse_one(&tag, &tag_len, &val,
889 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
890 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
891 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
892 return -2;
893 }
894 ofs += len;
895
896 len = tlv_parse_one(&tag, &tag_len, &val,
897 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
898 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
899 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
900 return -3;
901 }
902 ofs += len;
903
904 return ofs;
905}
906
907static int abis_nm_rx_sw_act_req(struct msgb *mb)
908{
909 struct abis_om_hdr *oh = msgb_l2(mb);
910 struct abis_om_fom_hdr *foh = msgb_l3(mb);
911 struct tlv_parsed tp;
912 const u_int8_t *sw_config;
913 int ret, sw_config_len, sw_descr_len;
914
915 debugp_foh(foh);
916
917 DEBUGPC(DNM, "SW Activate Request: ");
918
919 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
920
921 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
922 foh->obj_inst.bts_nr,
923 foh->obj_inst.trx_nr,
924 foh->obj_inst.ts_nr, 0,
925 foh->data, oh->length-sizeof(*foh));
926
927 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
928 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
929 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
930 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
931 DEBUGP(DNM, "SW config not found! Can't continue.\n");
932 return -EINVAL;
933 } else {
934 DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
935 }
936
937 /* Use the first SW_DESCR present in SW config */
938 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
939 if (sw_descr_len < 0)
940 return -EINVAL;
941
942 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
943 foh->obj_inst.bts_nr,
944 foh->obj_inst.trx_nr,
945 foh->obj_inst.ts_nr,
946 sw_config, sw_descr_len);
947}
948
949/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
950static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
951{
952 struct abis_om_hdr *oh = msgb_l2(mb);
953 struct abis_om_fom_hdr *foh = msgb_l3(mb);
954 struct tlv_parsed tp;
955 u_int8_t adm_state;
956
957 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
958 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
959 return -EINVAL;
960
961 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
962
963 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
964}
965
966static int abis_nm_rx_lmt_event(struct msgb *mb)
967{
968 struct abis_om_hdr *oh = msgb_l2(mb);
969 struct abis_om_fom_hdr *foh = msgb_l3(mb);
970 struct tlv_parsed tp;
971
972 DEBUGP(DNM, "LMT Event ");
973 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
974 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
975 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
976 u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
977 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
978 }
979 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
980 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
981 u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
982 DEBUGPC(DNM, "Level=%u ", level);
983 }
984 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
985 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
986 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
987 DEBUGPC(DNM, "Username=%s ", name);
988 }
989 DEBUGPC(DNM, "\n");
990 /* FIXME: parse LMT LOGON TIME */
991 return 0;
992}
993
994static void abis_nm_queue_send_next(struct gsm_bts *bts)
995{
996 int wait = 0;
997 struct msgb *msg;
998 /* the queue is empty */
999 while (!llist_empty(&bts->abis_queue)) {
1000 msg = msgb_dequeue(&bts->abis_queue);
1001 wait = OBSC_NM_W_ACK_CB(msg);
1002 _abis_nm_sendmsg(msg, 0);
1003
1004 if (wait)
1005 break;
1006 }
1007
1008 bts->abis_nm_pend = wait;
1009}
1010
1011/* Receive a OML NM Message from BTS */
1012static int abis_nm_rcvmsg_fom(struct msgb *mb)
1013{
1014 struct abis_om_hdr *oh = msgb_l2(mb);
1015 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1016 u_int8_t mt = foh->msg_type;
1017 int ret = 0;
1018
1019 /* check for unsolicited message */
1020 if (is_report(mt))
1021 return abis_nm_rcvmsg_report(mb);
1022
1023 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
1024 return abis_nm_rcvmsg_sw(mb);
1025
1026 if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
1027 struct nm_nack_signal_data nack_data;
1028 struct tlv_parsed tp;
1029
1030 debugp_foh(foh);
1031
1032 DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
1033
1034 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
1035 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
1036 DEBUGPC(DNM, "CAUSE=%s\n",
1037 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
1038 else
1039 DEBUGPC(DNM, "\n");
1040
1041 nack_data.msg = mb;
1042 nack_data.mt = mt;
1043 dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
1044 abis_nm_queue_send_next(mb->trx->bts);
1045 return 0;
1046 }
1047#if 0
1048 /* check if last message is to be acked */
1049 if (is_ack_nack(nmh->last_msgtype)) {
1050 if (mt == MT_ACK(nmh->last_msgtype)) {
1051 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
1052 /* we got our ACK, continue sending the next msg */
1053 } else if (mt == MT_NACK(nmh->last_msgtype)) {
1054 /* we got a NACK, signal this to the caller */
1055 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
1056 /* FIXME: somehow signal this to the caller */
1057 } else {
1058 /* really strange things happen */
1059 return -EINVAL;
1060 }
1061 }
1062#endif
1063
1064 switch (mt) {
1065 case NM_MT_CHG_ADM_STATE_ACK:
1066 ret = abis_nm_rx_chg_adm_state_ack(mb);
1067 break;
1068 case NM_MT_SW_ACT_REQ:
1069 ret = abis_nm_rx_sw_act_req(mb);
1070 break;
1071 case NM_MT_BS11_LMT_SESSION:
1072 ret = abis_nm_rx_lmt_event(mb);
1073 break;
1074 case NM_MT_CONN_MDROP_LINK_ACK:
1075 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
1076 break;
1077 case NM_MT_IPACC_RESTART_ACK:
1078 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
1079 break;
1080 case NM_MT_IPACC_RESTART_NACK:
1081 dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
1082 break;
1083 case NM_MT_SET_BTS_ATTR_ACK:
1084 /* The HSL wants an OPSTART _after_ the SI has been set */
1085 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
1086 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
1087 }
1088 break;
1089 }
1090
1091 abis_nm_queue_send_next(mb->trx->bts);
1092 return ret;
1093}
1094
1095static int abis_nm_rx_ipacc(struct msgb *mb);
1096
1097static int abis_nm_rcvmsg_manuf(struct msgb *mb)
1098{
1099 int rc;
1100 int bts_type = mb->trx->bts->type;
1101
1102 switch (bts_type) {
1103 case GSM_BTS_TYPE_NANOBTS:
1104 rc = abis_nm_rx_ipacc(mb);
1105 abis_nm_queue_send_next(mb->trx->bts);
1106 break;
1107 default:
1108 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
1109 "BTS type (%u)\n", bts_type);
1110 rc = 0;
1111 break;
1112 }
1113
1114 return rc;
1115}
1116
1117/* High-Level API */
1118/* Entry-point where L2 OML from BTS enters the NM code */
1119int abis_nm_rcvmsg(struct msgb *msg)
1120{
1121 struct abis_om_hdr *oh = msgb_l2(msg);
1122 int rc = 0;
1123
1124 /* Various consistency checks */
1125 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
1126 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
1127 oh->placement);
1128 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
1129 return -EINVAL;
1130 }
1131 if (oh->sequence != 0) {
1132 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
1133 oh->sequence);
1134 return -EINVAL;
1135 }
1136#if 0
1137 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
1138 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
1139 if (oh->length + hlen > l2_len) {
1140 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
1141 oh->length + sizeof(*oh), l2_len);
1142 return -EINVAL;
1143 }
1144 if (oh->length + hlen < l2_len)
1145 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);
1146#endif
1147 msg->l3h = (unsigned char *)oh + sizeof(*oh);
1148
1149 switch (oh->mdisc) {
1150 case ABIS_OM_MDISC_FOM:
1151 rc = abis_nm_rcvmsg_fom(msg);
1152 break;
1153 case ABIS_OM_MDISC_MANUF:
1154 rc = abis_nm_rcvmsg_manuf(msg);
1155 break;
1156 case ABIS_OM_MDISC_MMI:
1157 case ABIS_OM_MDISC_TRAU:
1158 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
1159 oh->mdisc);
1160 break;
1161 default:
1162 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
1163 oh->mdisc);
1164 return -EINVAL;
1165 }
1166
1167 msgb_free(msg);
1168 return rc;
1169}
1170
1171#if 0
1172/* initialized all resources */
1173struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
1174{
1175 struct abis_nm_h *nmh;
1176
1177 nmh = malloc(sizeof(*nmh));
1178 if (!nmh)
1179 return NULL;
1180
1181 nmh->cfg = cfg;
1182
1183 return nmh;
1184}
1185
1186/* free all resources */
1187void abis_nm_fini(struct abis_nm_h *nmh)
1188{
1189 free(nmh);
1190}
1191#endif
1192
1193/* Here we are trying to define a high-level API that can be used by
1194 * the actual BSC implementation. However, the architecture is currently
1195 * still under design. Ideally the calls to this API would be synchronous,
1196 * while the underlying stack behind the APi runs in a traditional select
1197 * based state machine.
1198 */
1199
1200/* 6.2 Software Load: */
1201enum sw_state {
1202 SW_STATE_NONE,
1203 SW_STATE_WAIT_INITACK,
1204 SW_STATE_WAIT_SEGACK,
1205 SW_STATE_WAIT_ENDACK,
1206 SW_STATE_WAIT_ACTACK,
1207 SW_STATE_ERROR,
1208};
1209
1210struct abis_nm_sw {
1211 struct gsm_bts *bts;
1212 int trx_nr;
1213 gsm_cbfn *cbfn;
1214 void *cb_data;
1215 int forced;
1216
1217 /* this will become part of the SW LOAD INITIATE */
1218 u_int8_t obj_class;
1219 u_int8_t obj_instance[3];
1220
1221 u_int8_t file_id[255];
1222 u_int8_t file_id_len;
1223
1224 u_int8_t file_version[255];
1225 u_int8_t file_version_len;
1226
1227 u_int8_t window_size;
1228 u_int8_t seg_in_window;
1229
1230 int fd;
1231 FILE *stream;
1232 enum sw_state state;
1233 int last_seg;
1234};
1235
1236static struct abis_nm_sw g_sw;
1237
1238static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1239{
1240 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1241 msgb_v_put(msg, NM_ATT_SW_DESCR);
1242 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1243 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1244 sw->file_version);
1245 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1246 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1247 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1248 sw->file_version);
1249 } else {
1250 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1251 }
1252}
1253
1254/* 6.2.1 / 8.3.1: Load Data Initiate */
1255static int sw_load_init(struct abis_nm_sw *sw)
1256{
1257 struct abis_om_hdr *oh;
1258 struct msgb *msg = nm_msgb_alloc();
1259 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
1260
1261 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1262 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1263 sw->obj_instance[0], sw->obj_instance[1],
1264 sw->obj_instance[2]);
1265
1266 sw_add_file_id_and_ver(sw, msg);
1267 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1268
1269 return abis_nm_sendmsg(sw->bts, msg);
1270}
1271
1272static int is_last_line(FILE *stream)
1273{
1274 char next_seg_buf[256];
1275 long pos;
1276
1277 /* check if we're sending the last line */
1278 pos = ftell(stream);
1279 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
1280 fseek(stream, pos, SEEK_SET);
1281 return 1;
1282 }
1283
1284 fseek(stream, pos, SEEK_SET);
1285 return 0;
1286}
1287
1288/* 6.2.2 / 8.3.2 Load Data Segment */
1289static int sw_load_segment(struct abis_nm_sw *sw)
1290{
1291 struct abis_om_hdr *oh;
1292 struct msgb *msg = nm_msgb_alloc();
1293 char seg_buf[256];
1294 char *line_buf = seg_buf+2;
1295 unsigned char *tlv;
1296 u_int8_t len;
1297
1298 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1299
1300 switch (sw->bts->type) {
1301 case GSM_BTS_TYPE_BS11:
1302 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1303 perror("fgets reading segment");
1304 return -EINVAL;
1305 }
1306 seg_buf[0] = 0x00;
1307
1308 /* check if we're sending the last line */
1309 sw->last_seg = is_last_line(sw->stream);
1310 if (sw->last_seg)
1311 seg_buf[1] = 0;
1312 else
1313 seg_buf[1] = 1 + sw->seg_in_window++;
1314
1315 len = strlen(line_buf) + 2;
1316 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
1317 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
1318 /* BS11 wants CR + LF in excess of the TLV length !?! */
1319 tlv[1] -= 2;
1320
1321 /* we only now know the exact length for the OM hdr */
1322 len = strlen(line_buf)+2;
1323 break;
1324 case GSM_BTS_TYPE_NANOBTS: {
1325 static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
1326 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1327 if (len < 0) {
1328 perror("read failed");
1329 return -EINVAL;
1330 }
1331
1332 if (len != IPACC_SEGMENT_SIZE)
1333 sw->last_seg = 1;
1334
1335 ++sw->seg_in_window;
1336 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
1337 len += 3;
1338 break;
1339 }
1340 default:
1341 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
1342 /* FIXME: Other BTS types */
1343 return -1;
1344 }
1345
1346 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1347 sw->obj_instance[0], sw->obj_instance[1],
1348 sw->obj_instance[2]);
1349
1350 return abis_nm_sendmsg_direct(sw->bts, msg);
1351}
1352
1353/* 6.2.4 / 8.3.4 Load Data End */
1354static int sw_load_end(struct abis_nm_sw *sw)
1355{
1356 struct abis_om_hdr *oh;
1357 struct msgb *msg = nm_msgb_alloc();
1358 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1359
1360 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1361 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1362 sw->obj_instance[0], sw->obj_instance[1],
1363 sw->obj_instance[2]);
1364
1365 sw_add_file_id_and_ver(sw, msg);
1366 return abis_nm_sendmsg(sw->bts, msg);
1367}
1368
1369/* Activate the specified software into the BTS */
1370static int sw_activate(struct abis_nm_sw *sw)
1371{
1372 struct abis_om_hdr *oh;
1373 struct msgb *msg = nm_msgb_alloc();
1374 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
1375
1376 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1377 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1378 sw->obj_instance[0], sw->obj_instance[1],
1379 sw->obj_instance[2]);
1380
1381 /* FIXME: this is BS11 specific format */
1382 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1383 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1384 sw->file_version);
1385
1386 return abis_nm_sendmsg(sw->bts, msg);
1387}
1388
1389struct sdp_firmware {
1390 char magic[4];
1391 char more_magic[4];
1392 unsigned int header_length;
1393 unsigned int file_length;
1394} __attribute__ ((packed));
1395
1396static int parse_sdp_header(struct abis_nm_sw *sw)
1397{
1398 struct sdp_firmware firmware_header;
1399 int rc;
1400 struct stat stat;
1401
1402 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1403 if (rc != sizeof(firmware_header)) {
1404 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1405 return -1;
1406 }
1407
1408 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1409 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1410 return -1;
1411 }
1412
1413 if (firmware_header.more_magic[0] != 0x10 ||
1414 firmware_header.more_magic[1] != 0x02 ||
1415 firmware_header.more_magic[2] != 0x00 ||
1416 firmware_header.more_magic[3] != 0x00) {
1417 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1418 return -1;
1419 }
1420
1421
1422 if (fstat(sw->fd, &stat) == -1) {
1423 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1424 return -1;
1425 }
1426
1427 if (ntohl(firmware_header.file_length) != stat.st_size) {
1428 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1429 return -1;
1430 }
1431
1432 /* go back to the start as we checked the whole filesize.. */
1433 lseek(sw->fd, 0l, SEEK_SET);
1434 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1435 "There might be checksums in the file that are not\n"
1436 "verified and incomplete firmware might be flashed.\n"
1437 "There is absolutely no WARRANTY that flashing will\n"
1438 "work.\n");
1439 return 0;
1440}
1441
1442static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1443{
1444 char file_id[12+1];
1445 char file_version[80+1];
1446 int rc;
1447
1448 sw->fd = open(fname, O_RDONLY);
1449 if (sw->fd < 0)
1450 return sw->fd;
1451
1452 switch (sw->bts->type) {
1453 case GSM_BTS_TYPE_BS11:
1454 sw->stream = fdopen(sw->fd, "r");
1455 if (!sw->stream) {
1456 perror("fdopen");
1457 return -1;
1458 }
1459 /* read first line and parse file ID and VERSION */
1460 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
1461 file_id, file_version);
1462 if (rc != 2) {
1463 perror("parsing header line of software file");
1464 return -1;
1465 }
1466 strcpy((char *)sw->file_id, file_id);
1467 sw->file_id_len = strlen(file_id);
1468 strcpy((char *)sw->file_version, file_version);
1469 sw->file_version_len = strlen(file_version);
1470 /* rewind to start of file */
1471 rewind(sw->stream);
1472 break;
1473 case GSM_BTS_TYPE_NANOBTS:
1474 /* TODO: extract that from the filename or content */
1475 rc = parse_sdp_header(sw);
1476 if (rc < 0) {
1477 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1478 return -1;
1479 }
1480
1481 strcpy((char *)sw->file_id, "id");
1482 sw->file_id_len = 3;
1483 strcpy((char *)sw->file_version, "version");
1484 sw->file_version_len = 8;
1485 break;
1486 default:
1487 /* We don't know how to treat them yet */
1488 close(sw->fd);
1489 return -EINVAL;
1490 }
1491
1492 return 0;
1493}
1494
1495static void sw_close_file(struct abis_nm_sw *sw)
1496{
1497 switch (sw->bts->type) {
1498 case GSM_BTS_TYPE_BS11:
1499 fclose(sw->stream);
1500 break;
1501 default:
1502 close(sw->fd);
1503 break;
1504 }
1505}
1506
1507/* Fill the window */
1508static int sw_fill_window(struct abis_nm_sw *sw)
1509{
1510 int rc;
1511
1512 while (sw->seg_in_window < sw->window_size) {
1513 rc = sw_load_segment(sw);
1514 if (rc < 0)
1515 return rc;
1516 if (sw->last_seg)
1517 break;
1518 }
1519 return 0;
1520}
1521
1522/* callback function from abis_nm_rcvmsg() handler */
1523static int abis_nm_rcvmsg_sw(struct msgb *mb)
1524{
1525 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1526 int rc = -1;
1527 struct abis_nm_sw *sw = &g_sw;
1528 enum sw_state old_state = sw->state;
1529
1530 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1531
1532 switch (sw->state) {
1533 case SW_STATE_WAIT_INITACK:
1534 switch (foh->msg_type) {
1535 case NM_MT_LOAD_INIT_ACK:
1536 /* fill window with segments */
1537 if (sw->cbfn)
1538 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1539 NM_MT_LOAD_INIT_ACK, mb,
1540 sw->cb_data, NULL);
1541 rc = sw_fill_window(sw);
1542 sw->state = SW_STATE_WAIT_SEGACK;
1543 abis_nm_queue_send_next(mb->trx->bts);
1544 break;
1545 case NM_MT_LOAD_INIT_NACK:
1546 if (sw->forced) {
1547 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1548 "Init NACK\n");
1549 if (sw->cbfn)
1550 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1551 NM_MT_LOAD_INIT_ACK, mb,
1552 sw->cb_data, NULL);
1553 rc = sw_fill_window(sw);
1554 sw->state = SW_STATE_WAIT_SEGACK;
1555 } else {
1556 DEBUGP(DNM, "Software Load Init NACK\n");
1557 /* FIXME: cause */
1558 if (sw->cbfn)
1559 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1560 NM_MT_LOAD_INIT_NACK, mb,
1561 sw->cb_data, NULL);
1562 sw->state = SW_STATE_ERROR;
1563 }
1564 abis_nm_queue_send_next(mb->trx->bts);
1565 break;
1566 }
1567 break;
1568 case SW_STATE_WAIT_SEGACK:
1569 switch (foh->msg_type) {
1570 case NM_MT_LOAD_SEG_ACK:
1571 if (sw->cbfn)
1572 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1573 NM_MT_LOAD_SEG_ACK, mb,
1574 sw->cb_data, NULL);
1575 sw->seg_in_window = 0;
1576 if (!sw->last_seg) {
1577 /* fill window with more segments */
1578 rc = sw_fill_window(sw);
1579 sw->state = SW_STATE_WAIT_SEGACK;
1580 } else {
1581 /* end the transfer */
1582 sw->state = SW_STATE_WAIT_ENDACK;
1583 rc = sw_load_end(sw);
1584 }
1585 abis_nm_queue_send_next(mb->trx->bts);
1586 break;
1587 case NM_MT_LOAD_ABORT:
1588 if (sw->cbfn)
1589 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1590 NM_MT_LOAD_ABORT, mb,
1591 sw->cb_data, NULL);
1592 break;
1593 }
1594 break;
1595 case SW_STATE_WAIT_ENDACK:
1596 switch (foh->msg_type) {
1597 case NM_MT_LOAD_END_ACK:
1598 sw_close_file(sw);
1599 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1600 sw->bts->nr);
1601 sw->state = SW_STATE_NONE;
1602 if (sw->cbfn)
1603 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1604 NM_MT_LOAD_END_ACK, mb,
1605 sw->cb_data, NULL);
1606 rc = 0;
1607 abis_nm_queue_send_next(mb->trx->bts);
1608 break;
1609 case NM_MT_LOAD_END_NACK:
1610 if (sw->forced) {
1611 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1612 "End NACK\n");
1613 sw->state = SW_STATE_NONE;
1614 if (sw->cbfn)
1615 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1616 NM_MT_LOAD_END_ACK, mb,
1617 sw->cb_data, NULL);
1618 } else {
1619 DEBUGP(DNM, "Software Load End NACK\n");
1620 /* FIXME: cause */
1621 sw->state = SW_STATE_ERROR;
1622 if (sw->cbfn)
1623 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1624 NM_MT_LOAD_END_NACK, mb,
1625 sw->cb_data, NULL);
1626 }
1627 abis_nm_queue_send_next(mb->trx->bts);
1628 break;
1629 }
1630 case SW_STATE_WAIT_ACTACK:
1631 switch (foh->msg_type) {
1632 case NM_MT_ACTIVATE_SW_ACK:
1633 /* we're done */
1634 DEBUGP(DNM, "Activate Software DONE!\n");
1635 sw->state = SW_STATE_NONE;
1636 rc = 0;
1637 if (sw->cbfn)
1638 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1639 NM_MT_ACTIVATE_SW_ACK, mb,
1640 sw->cb_data, NULL);
1641 abis_nm_queue_send_next(mb->trx->bts);
1642 break;
1643 case NM_MT_ACTIVATE_SW_NACK:
1644 DEBUGP(DNM, "Activate Software NACK\n");
1645 /* FIXME: cause */
1646 sw->state = SW_STATE_ERROR;
1647 if (sw->cbfn)
1648 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1649 NM_MT_ACTIVATE_SW_NACK, mb,
1650 sw->cb_data, NULL);
1651 abis_nm_queue_send_next(mb->trx->bts);
1652 break;
1653 }
1654 case SW_STATE_NONE:
1655 switch (foh->msg_type) {
1656 case NM_MT_ACTIVATE_SW_ACK:
1657 rc = 0;
1658 break;
1659 }
1660 break;
1661 case SW_STATE_ERROR:
1662 break;
1663 }
1664
1665 if (rc)
1666 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1667 foh->msg_type, old_state, sw->state);
1668
1669 return rc;
1670}
1671
1672/* Load the specified software into the BTS */
1673int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
1674 u_int8_t win_size, int forced,
1675 gsm_cbfn *cbfn, void *cb_data)
1676{
1677 struct abis_nm_sw *sw = &g_sw;
1678 int rc;
1679
1680 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1681 bts->nr, fname);
1682
1683 if (sw->state != SW_STATE_NONE)
1684 return -EBUSY;
1685
1686 sw->bts = bts;
1687 sw->trx_nr = trx_nr;
1688
1689 switch (bts->type) {
1690 case GSM_BTS_TYPE_BS11:
1691 sw->obj_class = NM_OC_SITE_MANAGER;
1692 sw->obj_instance[0] = 0xff;
1693 sw->obj_instance[1] = 0xff;
1694 sw->obj_instance[2] = 0xff;
1695 break;
1696 case GSM_BTS_TYPE_NANOBTS:
1697 sw->obj_class = NM_OC_BASEB_TRANSC;
1698 sw->obj_instance[0] = sw->bts->nr;
1699 sw->obj_instance[1] = sw->trx_nr;
1700 sw->obj_instance[2] = 0xff;
1701 break;
1702 case GSM_BTS_TYPE_UNKNOWN:
1703 default:
1704 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1705 return -1;
1706 break;
1707 }
1708 sw->window_size = win_size;
1709 sw->state = SW_STATE_WAIT_INITACK;
1710 sw->cbfn = cbfn;
1711 sw->cb_data = cb_data;
1712 sw->forced = forced;
1713
1714 rc = sw_open_file(sw, fname);
1715 if (rc < 0) {
1716 sw->state = SW_STATE_NONE;
1717 return rc;
1718 }
1719
1720 return sw_load_init(sw);
1721}
1722
1723int abis_nm_software_load_status(struct gsm_bts *bts)
1724{
1725 struct abis_nm_sw *sw = &g_sw;
1726 struct stat st;
1727 int rc, percent;
1728
1729 rc = fstat(sw->fd, &st);
1730 if (rc < 0) {
1731 perror("ERROR during stat");
1732 return rc;
1733 }
1734
1735 if (sw->stream)
1736 percent = (ftell(sw->stream) * 100) / st.st_size;
1737 else
1738 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
1739 return percent;
1740}
1741
1742/* Activate the specified software into the BTS */
1743int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1744 gsm_cbfn *cbfn, void *cb_data)
1745{
1746 struct abis_nm_sw *sw = &g_sw;
1747 int rc;
1748
1749 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1750 bts->nr, fname);
1751
1752 if (sw->state != SW_STATE_NONE)
1753 return -EBUSY;
1754
1755 sw->bts = bts;
1756 sw->obj_class = NM_OC_SITE_MANAGER;
1757 sw->obj_instance[0] = 0xff;
1758 sw->obj_instance[1] = 0xff;
1759 sw->obj_instance[2] = 0xff;
1760 sw->state = SW_STATE_WAIT_ACTACK;
1761 sw->cbfn = cbfn;
1762 sw->cb_data = cb_data;
1763
1764 /* Open the file in order to fill some sw struct members */
1765 rc = sw_open_file(sw, fname);
1766 if (rc < 0) {
1767 sw->state = SW_STATE_NONE;
1768 return rc;
1769 }
1770 sw_close_file(sw);
1771
1772 return sw_activate(sw);
1773}
1774
1775static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
1776 u_int8_t ts_nr, u_int8_t subslot_nr)
1777{
1778 ch->attrib = NM_ATT_ABIS_CHANNEL;
1779 ch->bts_port = bts_port;
1780 ch->timeslot = ts_nr;
1781 ch->subslot = subslot_nr;
1782}
1783
1784int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
1785 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
1786 u_int8_t tei)
1787{
1788 struct abis_om_hdr *oh;
1789 struct abis_nm_channel *ch;
1790 u_int8_t len = sizeof(*ch) + 2;
1791 struct msgb *msg = nm_msgb_alloc();
1792
1793 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1794 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1795 bts->bts_nr, trx_nr, 0xff);
1796
1797 msgb_tv_put(msg, NM_ATT_TEI, tei);
1798
1799 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1800 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1801
1802 return abis_nm_sendmsg(bts, msg);
1803}
1804
1805/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1806int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
1807 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
1808{
1809 struct gsm_bts *bts = trx->bts;
1810 struct abis_om_hdr *oh;
1811 struct abis_nm_channel *ch;
1812 struct msgb *msg = nm_msgb_alloc();
1813
1814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1815 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1816 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1817
1818 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1819 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1820
1821 return abis_nm_sendmsg(bts, msg);
1822}
1823
1824#if 0
1825int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1826 struct abis_nm_abis_channel *chan)
1827{
1828}
1829#endif
1830
1831int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
1832 u_int8_t e1_port, u_int8_t e1_timeslot,
1833 u_int8_t e1_subslot)
1834{
1835 struct gsm_bts *bts = ts->trx->bts;
1836 struct abis_om_hdr *oh;
1837 struct abis_nm_channel *ch;
1838 struct msgb *msg = nm_msgb_alloc();
1839
1840 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1841 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1842 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1843
1844 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1845 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1846
1847 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1848 gsm_ts_name(ts),
1849 e1_port, e1_timeslot, e1_subslot);
1850
1851 return abis_nm_sendmsg(bts, msg);
1852}
1853
1854#if 0
1855int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1856 struct abis_nm_abis_channel *chan,
1857 u_int8_t subchan)
1858{
1859}
1860#endif
1861
1862/* Chapter 8.6.1 */
1863int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
1864{
1865 struct abis_om_hdr *oh;
1866 struct msgb *msg = nm_msgb_alloc();
1867 u_int8_t *cur;
1868
1869 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1870
1871 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1872 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1873 cur = msgb_put(msg, attr_len);
1874 memcpy(cur, attr, attr_len);
1875
1876 return abis_nm_sendmsg(bts, msg);
1877}
1878
1879/* Chapter 8.6.2 */
1880int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
1881{
1882 struct abis_om_hdr *oh;
1883 struct msgb *msg = nm_msgb_alloc();
1884 u_int8_t *cur;
1885
1886 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1887
1888 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1889 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1890 trx->bts->bts_nr, trx->nr, 0xff);
1891 cur = msgb_put(msg, attr_len);
1892 memcpy(cur, attr, attr_len);
1893
1894 return abis_nm_sendmsg(trx->bts, msg);
1895}
1896
1897static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
1898{
1899 int i;
1900
1901 /* As it turns out, the BS-11 has some very peculiar restrictions
1902 * on the channel combinations it allows */
1903 switch (ts->trx->bts->type) {
1904 case GSM_BTS_TYPE_BS11:
1905 switch (chan_comb) {
1906 case NM_CHANC_TCHHalf:
1907 case NM_CHANC_TCHHalf2:
1908 /* not supported */
1909 return -EINVAL;
1910 case NM_CHANC_SDCCH:
1911 /* only one SDCCH/8 per TRX */
1912 for (i = 0; i < TRX_NR_TS; i++) {
1913 if (i == ts->nr)
1914 continue;
1915 if (ts->trx->ts[i].nm_chan_comb ==
1916 NM_CHANC_SDCCH)
1917 return -EINVAL;
1918 }
1919 /* not allowed for TS0 of BCCH-TRX */
1920 if (ts->trx == ts->trx->bts->c0 &&
1921 ts->nr == 0)
1922 return -EINVAL;
1923 /* not on the same TRX that has a BCCH+SDCCH4
1924 * combination */
1925 if (ts->trx == ts->trx->bts->c0 &&
1926 (ts->trx->ts[0].nm_chan_comb == 5 ||
1927 ts->trx->ts[0].nm_chan_comb == 8))
1928 return -EINVAL;
1929 break;
1930 case NM_CHANC_mainBCCH:
1931 case NM_CHANC_BCCHComb:
1932 /* allowed only for TS0 of C0 */
1933 if (ts->trx != ts->trx->bts->c0 ||
1934 ts->nr != 0)
1935 return -EINVAL;
1936 break;
1937 case NM_CHANC_BCCH:
1938 /* allowed only for TS 2/4/6 of C0 */
1939 if (ts->trx != ts->trx->bts->c0)
1940 return -EINVAL;
1941 if (ts->nr != 2 && ts->nr != 4 &&
1942 ts->nr != 6)
1943 return -EINVAL;
1944 break;
1945 case 8: /* this is not like 08.58, but in fact
1946 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1947 /* FIXME: only one CBCH allowed per cell */
1948 break;
1949 }
1950 break;
1951 case GSM_BTS_TYPE_NANOBTS:
1952 switch (ts->nr) {
1953 case 0:
1954 if (ts->trx->nr == 0) {
1955 /* only on TRX0 */
1956 switch (chan_comb) {
1957 case NM_CHANC_BCCH:
1958 case NM_CHANC_mainBCCH:
1959 case NM_CHANC_BCCHComb:
1960 return 0;
1961 break;
1962 default:
1963 return -EINVAL;
1964 }
1965 } else {
1966 switch (chan_comb) {
1967 case NM_CHANC_TCHFull:
1968 case NM_CHANC_TCHHalf:
1969 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1970 return 0;
1971 default:
1972 return -EINVAL;
1973 }
1974 }
1975 break;
1976 case 1:
1977 if (ts->trx->nr == 0) {
1978 switch (chan_comb) {
1979 case NM_CHANC_SDCCH_CBCH:
1980 if (ts->trx->ts[0].nm_chan_comb ==
1981 NM_CHANC_mainBCCH)
1982 return 0;
1983 return -EINVAL;
1984 case NM_CHANC_SDCCH:
1985 case NM_CHANC_TCHFull:
1986 case NM_CHANC_TCHHalf:
1987 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1988 case NM_CHANC_IPAC_TCHFull_PDCH:
1989 return 0;
1990 }
1991 } else {
1992 switch (chan_comb) {
1993 case NM_CHANC_SDCCH:
1994 case NM_CHANC_TCHFull:
1995 case NM_CHANC_TCHHalf:
1996 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1997 return 0;
1998 default:
1999 return -EINVAL;
2000 }
2001 }
2002 break;
2003 case 2:
2004 case 3:
2005 case 4:
2006 case 5:
2007 case 6:
2008 case 7:
2009 switch (chan_comb) {
2010 case NM_CHANC_TCHFull:
2011 case NM_CHANC_TCHHalf:
2012 case NM_CHANC_IPAC_TCHFull_TCHHalf:
2013 return 0;
2014 case NM_CHANC_IPAC_PDCH:
2015 case NM_CHANC_IPAC_TCHFull_PDCH:
2016 if (ts->trx->nr == 0)
2017 return 0;
2018 else
2019 return -EINVAL;
2020 }
2021 break;
2022 }
2023 return -EINVAL;
2024 default:
2025 /* unknown BTS type */
2026 return 0;
2027 }
2028 return 0;
2029}
2030
2031/* Chapter 8.6.3 */
2032int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
2033{
2034 struct gsm_bts *bts = ts->trx->bts;
2035 struct abis_om_hdr *oh;
2036 u_int8_t zero = 0x00;
2037 struct msgb *msg = nm_msgb_alloc();
2038 u_int8_t len = 2 + 2;
2039
2040 if (bts->type == GSM_BTS_TYPE_BS11)
2041 len += 4 + 2 + 2 + 3;
2042
2043 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
2044 if (verify_chan_comb(ts, chan_comb) < 0) {
2045 msgb_free(msg);
2046 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
2047 return -EINVAL;
2048 }
2049 ts->nm_chan_comb = chan_comb;
2050
2051 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2052 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
2053 NM_OC_CHANNEL, bts->bts_nr,
2054 ts->trx->nr, ts->nr);
2055 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
2056 if (ts->hopping.enabled) {
2057 unsigned int i;
2058 uint8_t *len;
2059
2060 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
2061 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
2062
2063 /* build the ARFCN list */
2064 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
2065 len = msgb_put(msg, 1);
2066 *len = 0;
2067 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
2068 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
2069 msgb_put_u16(msg, i);
2070 /* At least BS-11 wants a TLV16 here */
2071 if (bts->type == GSM_BTS_TYPE_BS11)
2072 *len += 1;
2073 else
2074 *len += sizeof(uint16_t);
2075 }
2076 }
2077 }
2078 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
2079 if (bts->type == GSM_BTS_TYPE_BS11)
2080 msgb_tlv_put(msg, 0x59, 1, &zero);
2081
2082 return abis_nm_sendmsg(bts, msg);
2083}
2084
2085int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
2086 u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
2087{
2088 struct abis_om_hdr *oh;
2089 struct msgb *msg = nm_msgb_alloc();
2090 u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
2091 u_int8_t len = att_len;
2092
2093 if (nack) {
2094 len += 2;
2095 msgtype = NM_MT_SW_ACT_REQ_NACK;
2096 }
2097
2098 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2099 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
2100
2101 if (attr) {
2102 u_int8_t *ptr = msgb_put(msg, att_len);
2103 memcpy(ptr, attr, att_len);
2104 }
2105 if (nack)
2106 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
2107
2108 return abis_nm_sendmsg_direct(bts, msg);
2109}
2110
2111int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
2112{
2113 struct msgb *msg = nm_msgb_alloc();
2114 struct abis_om_hdr *oh;
2115 u_int8_t *data;
2116
2117 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2118 fill_om_hdr(oh, len);
2119 data = msgb_put(msg, len);
2120 memcpy(data, rawmsg, len);
2121
2122 return abis_nm_sendmsg(bts, msg);
2123}
2124
2125/* Siemens specific commands */
2126static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
2127{
2128 struct abis_om_hdr *oh;
2129 struct msgb *msg = nm_msgb_alloc();
2130
2131 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2132 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
2133 0xff, 0xff, 0xff);
2134
2135 return abis_nm_sendmsg(bts, msg);
2136}
2137
2138/* Chapter 8.9.2 */
2139int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
2140{
2141 struct abis_om_hdr *oh;
2142 struct msgb *msg = nm_msgb_alloc();
2143
2144 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2145 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
2146
2147 debugp_foh((struct abis_om_fom_hdr *) oh->data);
2148 DEBUGPC(DNM, "Sending OPSTART\n");
2149
2150 return abis_nm_sendmsg(bts, msg);
2151}
2152
2153/* Chapter 8.8.5 */
2154int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
2155 u_int8_t i1, u_int8_t i2, enum abis_nm_adm_state adm_state)
2156{
2157 struct abis_om_hdr *oh;
2158 struct msgb *msg = nm_msgb_alloc();
2159
2160 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2161 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
2162 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
2163
2164 return abis_nm_sendmsg(bts, msg);
2165}
2166
2167int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
2168 u_int8_t e1_port1, u_int8_t ts1)
2169{
2170 struct abis_om_hdr *oh;
2171 struct msgb *msg = nm_msgb_alloc();
2172 u_int8_t *attr;
2173
2174 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2175 e1_port0, ts0, e1_port1, ts1);
2176
2177 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2178 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2179 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2180
2181 attr = msgb_put(msg, 3);
2182 attr[0] = NM_ATT_MDROP_LINK;
2183 attr[1] = e1_port0;
2184 attr[2] = ts0;
2185
2186 attr = msgb_put(msg, 3);
2187 attr[0] = NM_ATT_MDROP_NEXT;
2188 attr[1] = e1_port1;
2189 attr[2] = ts1;
2190
2191 return abis_nm_sendmsg(bts, msg);
2192}
2193
2194/* Chapter 8.7.1 */
2195int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
2196 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2197 u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
2198{
2199 struct abis_om_hdr *oh;
2200
2201 DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
2202
2203 if (!msg)
2204 msg = nm_msgb_alloc();
2205
2206 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2207 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2208 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2209 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
2210 obj_class, bts_nr, trx_nr, ts_nr);
2211
2212 return abis_nm_sendmsg(bts, msg);
2213}
2214
2215int abis_nm_event_reports(struct gsm_bts *bts, int on)
2216{
2217 if (on == 0)
2218 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
2219 else
2220 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
2221}
2222
2223/* Siemens (or BS-11) specific commands */
2224
2225int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2226{
2227 if (reconnect == 0)
2228 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2229 else
2230 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2231}
2232
2233int abis_nm_bs11_restart(struct gsm_bts *bts)
2234{
2235 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2236}
2237
2238
2239struct bs11_date_time {
2240 u_int16_t year;
2241 u_int8_t month;
2242 u_int8_t day;
2243 u_int8_t hour;
2244 u_int8_t min;
2245 u_int8_t sec;
2246} __attribute__((packed));
2247
2248
2249void get_bs11_date_time(struct bs11_date_time *aet)
2250{
2251 time_t t;
2252 struct tm *tm;
2253
2254 t = time(NULL);
2255 tm = localtime(&t);
2256 aet->sec = tm->tm_sec;
2257 aet->min = tm->tm_min;
2258 aet->hour = tm->tm_hour;
2259 aet->day = tm->tm_mday;
2260 aet->month = tm->tm_mon;
2261 aet->year = htons(1900 + tm->tm_year);
2262}
2263
2264int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
2265{
2266 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
2267}
2268
2269int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
2270{
2271 if (begin)
2272 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
2273 else
2274 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
2275}
2276
2277int abis_nm_bs11_create_object(struct gsm_bts *bts,
2278 enum abis_bs11_objtype type, u_int8_t idx,
2279 u_int8_t attr_len, const u_int8_t *attr)
2280{
2281 struct abis_om_hdr *oh;
2282 struct msgb *msg = nm_msgb_alloc();
2283 u_int8_t *cur;
2284
2285 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2286 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
2287 NM_OC_BS11, type, 0, idx);
2288 cur = msgb_put(msg, attr_len);
2289 memcpy(cur, attr, attr_len);
2290
2291 return abis_nm_sendmsg(bts, msg);
2292}
2293
2294int abis_nm_bs11_delete_object(struct gsm_bts *bts,
2295 enum abis_bs11_objtype type, u_int8_t idx)
2296{
2297 struct abis_om_hdr *oh;
2298 struct msgb *msg = nm_msgb_alloc();
2299
2300 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2301 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2302 NM_OC_BS11, type, 0, idx);
2303
2304 return abis_nm_sendmsg(bts, msg);
2305}
2306
2307int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
2308{
2309 struct abis_om_hdr *oh;
2310 struct msgb *msg = nm_msgb_alloc();
2311 u_int8_t zero = 0x00;
2312
2313 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2314 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
2315 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2316 msgb_tlv_put(msg, 0x99, 1, &zero);
2317
2318 return abis_nm_sendmsg(bts, msg);
2319}
2320
2321int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
2322{
2323 struct abis_om_hdr *oh;
2324 struct msgb *msg = nm_msgb_alloc();
2325
2326 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2327 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
2328 idx, 0xff, 0xff);
2329
2330 return abis_nm_sendmsg(bts, msg);
2331}
2332
2333int abis_nm_bs11_delete_bport(struct gsm_bts *bts, u_int8_t idx)
2334{
2335 struct abis_om_hdr *oh;
2336 struct msgb *msg = nm_msgb_alloc();
2337
2338 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2339 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2340 idx, 0xff, 0xff);
2341
2342 return abis_nm_sendmsg(bts, msg);
2343}
2344
2345static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
2346int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2347{
2348 struct abis_om_hdr *oh;
2349 struct msgb *msg = nm_msgb_alloc();
2350
2351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2352 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2353 0xff, 0xff, 0xff);
2354 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2355
2356 return abis_nm_sendmsg(bts, msg);
2357}
2358
2359/* like abis_nm_conn_terr_traf + set_tei */
2360int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
2361 u_int8_t e1_timeslot, u_int8_t e1_subslot,
2362 u_int8_t tei)
2363{
2364 struct abis_om_hdr *oh;
2365 struct abis_nm_channel *ch;
2366 struct msgb *msg = nm_msgb_alloc();
2367
2368 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2369 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
2370 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2371
2372 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2373 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
2374 msgb_tv_put(msg, NM_ATT_TEI, tei);
2375
2376 return abis_nm_sendmsg(bts, msg);
2377}
2378
2379int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
2380{
2381 struct abis_om_hdr *oh;
2382 struct msgb *msg = nm_msgb_alloc();
2383
2384 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2385 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2386 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2387 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2388
2389 return abis_nm_sendmsg(trx->bts, msg);
2390}
2391
2392int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2393{
2394 struct abis_om_hdr *oh;
2395 struct msgb *msg = nm_msgb_alloc();
2396 u_int8_t attr = NM_ATT_BS11_TXPWR;
2397
2398 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2399 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2400 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2401 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2402
2403 return abis_nm_sendmsg(trx->bts, msg);
2404}
2405
2406int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2407{
2408 struct abis_om_hdr *oh;
2409 struct msgb *msg = nm_msgb_alloc();
2410 u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
2411
2412 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2413 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2414 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2415 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2416
2417 return abis_nm_sendmsg(bts, msg);
2418}
2419
2420int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2421{
2422 struct abis_om_hdr *oh;
2423 struct msgb *msg = nm_msgb_alloc();
2424 u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
2425 NM_ATT_BS11_CCLK_TYPE };
2426
2427 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2428 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2429 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2430 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2431
2432 return abis_nm_sendmsg(bts, msg);
2433
2434}
2435
2436//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
2437
2438int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2439{
2440 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2441}
2442
2443int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2444{
2445 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2446}
2447
2448int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, int on)
2449{
2450 struct abis_om_hdr *oh;
2451 struct msgb *msg = nm_msgb_alloc();
2452 struct bs11_date_time bdt;
2453
2454 get_bs11_date_time(&bdt);
2455
2456 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2457 if (on) {
2458 u_int8_t len = 3*2 + sizeof(bdt)
2459 + 1 + strlen(name);
2460 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2461 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2462 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
2463 sizeof(bdt), (u_int8_t *) &bdt);
2464 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
2465 1, &level);
2466 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
2467 strlen(name), (u_int8_t *)name);
2468 } else {
2469 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2470 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2471 }
2472
2473 return abis_nm_sendmsg(bts, msg);
2474}
2475
2476int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2477{
2478 struct abis_om_hdr *oh;
2479 struct msgb *msg;
2480
2481 if (strlen(password) != 10)
2482 return -EINVAL;
2483
2484 msg = nm_msgb_alloc();
2485 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2486 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2487 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
2488 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
2489
2490 return abis_nm_sendmsg(bts, msg);
2491}
2492
2493/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2494int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2495{
2496 struct abis_om_hdr *oh;
2497 struct msgb *msg;
2498 u_int8_t tlv_value;
2499
2500 msg = nm_msgb_alloc();
2501 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2502 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2503 BS11_OBJ_LI, 0x00, 0x00);
2504
2505 if (locked)
2506 tlv_value = BS11_LI_PLL_LOCKED;
2507 else
2508 tlv_value = BS11_LI_PLL_STANDALONE;
2509
2510 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2511
2512 return abis_nm_sendmsg(bts, msg);
2513}
2514
2515/* Set the calibration value of the PLL (work value/set value)
2516 * It depends on the login which one is changed */
2517int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2518{
2519 struct abis_om_hdr *oh;
2520 struct msgb *msg;
2521 u_int8_t tlv_value[2];
2522
2523 msg = nm_msgb_alloc();
2524 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2525 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2526 BS11_OBJ_TRX1, 0x00, 0x00);
2527
2528 tlv_value[0] = value>>8;
2529 tlv_value[1] = value&0xff;
2530
2531 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2532
2533 return abis_nm_sendmsg(bts, msg);
2534}
2535
2536int abis_nm_bs11_get_state(struct gsm_bts *bts)
2537{
2538 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2539}
2540
2541/* BS11 SWL */
2542
2543void *tall_fle_ctx;
2544
2545struct abis_nm_bs11_sw {
2546 struct gsm_bts *bts;
2547 char swl_fname[PATH_MAX];
2548 u_int8_t win_size;
2549 int forced;
2550 struct llist_head file_list;
2551 gsm_cbfn *user_cb; /* specified by the user */
2552};
2553static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2554
2555struct file_list_entry {
2556 struct llist_head list;
2557 char fname[PATH_MAX];
2558};
2559
2560struct file_list_entry *fl_dequeue(struct llist_head *queue)
2561{
2562 struct llist_head *lh;
2563
2564 if (llist_empty(queue))
2565 return NULL;
2566
2567 lh = queue->next;
2568 llist_del(lh);
2569
2570 return llist_entry(lh, struct file_list_entry, list);
2571}
2572
2573static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2574{
2575 char linebuf[255];
2576 struct llist_head *lh, *lh2;
2577 FILE *swl;
2578 int rc = 0;
2579
2580 swl = fopen(bs11_sw->swl_fname, "r");
2581 if (!swl)
2582 return -ENODEV;
2583
2584 /* zero the stale file list, if any */
2585 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2586 llist_del(lh);
2587 talloc_free(lh);
2588 }
2589
2590 while (fgets(linebuf, sizeof(linebuf), swl)) {
2591 char file_id[12+1];
2592 char file_version[80+1];
2593 struct file_list_entry *fle;
2594 static char dir[PATH_MAX];
2595
2596 if (strlen(linebuf) < 4)
2597 continue;
2598
2599 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2600 if (rc < 0) {
2601 perror("ERR parsing SWL file");
2602 rc = -EINVAL;
2603 goto out;
2604 }
2605 if (rc < 2)
2606 continue;
2607
2608 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
2609 if (!fle) {
2610 rc = -ENOMEM;
2611 goto out;
2612 }
2613
2614 /* construct new filename */
2615 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2616 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2617 strcat(fle->fname, "/");
2618 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2619
2620 llist_add_tail(&fle->list, &bs11_sw->file_list);
2621 }
2622
2623out:
2624 fclose(swl);
2625 return rc;
2626}
2627
2628/* bs11 swload specific callback, passed to abis_nm core swload */
2629static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2630 struct msgb *msg, void *data, void *param)
2631{
2632 struct abis_nm_bs11_sw *bs11_sw = data;
2633 struct file_list_entry *fle;
2634 int rc = 0;
2635
2636 switch (event) {
2637 case NM_MT_LOAD_END_ACK:
2638 fle = fl_dequeue(&bs11_sw->file_list);
2639 if (fle) {
2640 /* start download the next file of our file list */
2641 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
2642 bs11_sw->win_size,
2643 bs11_sw->forced,
2644 &bs11_swload_cbfn, bs11_sw);
2645 talloc_free(fle);
2646 } else {
2647 /* activate the SWL */
2648 rc = abis_nm_software_activate(bs11_sw->bts,
2649 bs11_sw->swl_fname,
2650 bs11_swload_cbfn,
2651 bs11_sw);
2652 }
2653 break;
2654 case NM_MT_LOAD_SEG_ACK:
2655 case NM_MT_LOAD_END_NACK:
2656 case NM_MT_LOAD_INIT_ACK:
2657 case NM_MT_LOAD_INIT_NACK:
2658 case NM_MT_ACTIVATE_SW_NACK:
2659 case NM_MT_ACTIVATE_SW_ACK:
2660 default:
2661 /* fallthrough to the user callback */
2662 if (bs11_sw->user_cb)
2663 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2664 break;
2665 }
2666
2667 return rc;
2668}
2669
2670/* Siemens provides a SWL file that is a mere listing of all the other
2671 * files that are part of a software release. We need to upload first
2672 * the list file, and then each file that is listed in the list file */
2673int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
2674 u_int8_t win_size, int forced, gsm_cbfn *cbfn)
2675{
2676 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2677 struct file_list_entry *fle;
2678 int rc = 0;
2679
2680 INIT_LLIST_HEAD(&bs11_sw->file_list);
2681 bs11_sw->bts = bts;
2682 bs11_sw->win_size = win_size;
2683 bs11_sw->user_cb = cbfn;
2684 bs11_sw->forced = forced;
2685
2686 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2687 rc = bs11_read_swl_file(bs11_sw);
2688 if (rc < 0)
2689 return rc;
2690
2691 /* dequeue next item in file list */
2692 fle = fl_dequeue(&bs11_sw->file_list);
2693 if (!fle)
2694 return -EINVAL;
2695
2696 /* start download the next file of our file list */
2697 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
2698 bs11_swload_cbfn, bs11_sw);
2699 talloc_free(fle);
2700 return rc;
2701}
2702
2703#if 0
2704static u_int8_t req_attr_btse[] = {
2705 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2706 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2707 NM_ATT_BS11_LMT_USER_NAME,
2708
2709 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2710
2711 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2712
2713 NM_ATT_BS11_SW_LOAD_STORED };
2714
2715static u_int8_t req_attr_btsm[] = {
2716 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2717 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2718 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2719 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2720#endif
2721
2722static u_int8_t req_attr[] = {
2723 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2724 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2725 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2726
2727int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2728{
2729 struct abis_om_hdr *oh;
2730 struct msgb *msg = nm_msgb_alloc();
2731
2732 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2733 /* SiemensHW CCTRL object */
2734 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2735 0x03, 0x00, 0x00);
2736 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2737
2738 return abis_nm_sendmsg(bts, msg);
2739}
2740
2741int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2742{
2743 struct abis_om_hdr *oh;
2744 struct msgb *msg = nm_msgb_alloc();
2745 struct bs11_date_time aet;
2746
2747 get_bs11_date_time(&aet);
2748 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2749 /* SiemensHW CCTRL object */
2750 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2751 0xff, 0xff, 0xff);
2752 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
2753
2754 return abis_nm_sendmsg(bts, msg);
2755}
2756
2757int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
2758{
2759 struct abis_om_hdr *oh;
2760 struct msgb *msg = nm_msgb_alloc();
2761 u_int8_t attr = NM_ATT_BS11_LINE_CFG;
2762
2763 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2764 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2765 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2766 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2767
2768 return abis_nm_sendmsg(bts, msg);
2769}
2770
2771int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
2772{
2773 struct abis_om_hdr *oh;
2774 struct msgb *msg = nm_msgb_alloc();
2775 struct bs11_date_time aet;
2776
2777 get_bs11_date_time(&aet);
2778 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2779 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2780 bport, 0xff, 0x02);
2781 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2782
2783 return abis_nm_sendmsg(bts, msg);
2784}
2785
2786/* ip.access nanoBTS specific commands */
2787static const char ipaccess_magic[] = "com.ipaccess";
2788
2789
2790static int abis_nm_rx_ipacc(struct msgb *msg)
2791{
2792 struct in_addr addr;
2793 struct abis_om_hdr *oh = msgb_l2(msg);
2794 struct abis_om_fom_hdr *foh;
2795 u_int8_t idstrlen = oh->data[0];
2796 struct tlv_parsed tp;
2797 struct ipacc_ack_signal_data signal;
2798
2799 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
2800 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
2801 return -EINVAL;
2802 }
2803
2804 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
2805 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
2806
2807 debugp_foh(foh);
2808
2809 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
2810
2811 switch (foh->msg_type) {
2812 case NM_MT_IPACC_RSL_CONNECT_ACK:
2813 DEBUGPC(DNM, "RSL CONNECT ACK ");
2814 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2815 memcpy(&addr,
2816 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2817
2818 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2819 }
2820 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
2821 DEBUGPC(DNM, "PORT=%u ",
2822 ntohs(*((u_int16_t *)
2823 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
2824 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2825 DEBUGPC(DNM, "STREAM=0x%02x ",
2826 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
2827 DEBUGPC(DNM, "\n");
2828 break;
2829 case NM_MT_IPACC_RSL_CONNECT_NACK:
2830 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
2831 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2832 DEBUGPC(DNM, " CAUSE=%s\n",
2833 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2834 else
2835 DEBUGPC(DNM, "\n");
2836 break;
2837 case NM_MT_IPACC_SET_NVATTR_ACK:
2838 DEBUGPC(DNM, "SET NVATTR ACK\n");
2839 /* FIXME: decode and show the actual attributes */
2840 break;
2841 case NM_MT_IPACC_SET_NVATTR_NACK:
2842 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
2843 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2844 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
2845 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2846 else
2847 LOGPC(DNM, LOGL_ERROR, "\n");
2848 break;
2849 case NM_MT_IPACC_GET_NVATTR_ACK:
2850 DEBUGPC(DNM, "GET NVATTR ACK\n");
2851 /* FIXME: decode and show the actual attributes */
2852 break;
2853 case NM_MT_IPACC_GET_NVATTR_NACK:
2854 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
2855 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2856 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
2857 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2858 else
2859 LOGPC(DNM, LOGL_ERROR, "\n");
2860 break;
2861 case NM_MT_IPACC_SET_ATTR_ACK:
2862 DEBUGPC(DNM, "SET ATTR ACK\n");
2863 break;
2864 case NM_MT_IPACC_SET_ATTR_NACK:
2865 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
2866 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2867 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
2868 nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
2869 else
2870 LOGPC(DNM, LOGL_ERROR, "\n");
2871 break;
2872 default:
2873 DEBUGPC(DNM, "unknown\n");
2874 break;
2875 }
2876
2877 /* signal handling */
2878 switch (foh->msg_type) {
2879 case NM_MT_IPACC_RSL_CONNECT_NACK:
2880 case NM_MT_IPACC_SET_NVATTR_NACK:
2881 case NM_MT_IPACC_GET_NVATTR_NACK:
2882 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
2883 signal.msg_type = foh->msg_type;
2884 dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
2885 break;
2886 case NM_MT_IPACC_SET_NVATTR_ACK:
2887 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
2888 signal.msg_type = foh->msg_type;
2889 dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
2890 break;
2891 default:
2892 break;
2893 }
2894
2895 return 0;
2896}
2897
2898/* send an ip-access manufacturer specific message */
2899int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
2900 u_int8_t obj_class, u_int8_t bts_nr,
2901 u_int8_t trx_nr, u_int8_t ts_nr,
2902 u_int8_t *attr, int attr_len)
2903{
2904 struct msgb *msg = nm_msgb_alloc();
2905 struct abis_om_hdr *oh;
2906 struct abis_om_fom_hdr *foh;
2907 u_int8_t *data;
2908
2909 /* construct the 12.21 OM header, observe the erroneous length */
2910 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2911 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2912 oh->mdisc = ABIS_OM_MDISC_MANUF;
2913
2914 /* add the ip.access magic */
2915 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2916 *data++ = sizeof(ipaccess_magic);
2917 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2918
2919 /* fill the 12.21 FOM header */
2920 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2921 foh->msg_type = msg_type;
2922 foh->obj_class = obj_class;
2923 foh->obj_inst.bts_nr = bts_nr;
2924 foh->obj_inst.trx_nr = trx_nr;
2925 foh->obj_inst.ts_nr = ts_nr;
2926
2927 if (attr && attr_len) {
2928 data = msgb_put(msg, attr_len);
2929 memcpy(data, attr, attr_len);
2930 }
2931
2932 return abis_nm_sendmsg(bts, msg);
2933}
2934
2935/* set some attributes in NVRAM */
2936int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
2937 int attr_len)
2938{
2939 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2940 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
2941 attr_len);
2942}
2943
2944int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
2945 u_int32_t ip, u_int16_t port, u_int8_t stream)
2946{
2947 struct in_addr ia;
2948 u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
2949 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2950 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2951
2952 int attr_len = sizeof(attr);
2953
2954 ia.s_addr = htonl(ip);
2955 attr[1] = stream;
2956 attr[3] = port >> 8;
2957 attr[4] = port & 0xff;
2958 *(u_int32_t *)(attr+6) = ia.s_addr;
2959
2960 /* if ip == 0, we use the default IP */
2961 if (ip == 0)
2962 attr_len -= 5;
2963
2964 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
2965 inet_ntoa(ia), port, stream);
2966
2967 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2968 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2969 trx->nr, 0xff, attr, attr_len);
2970}
2971
2972/* restart / reboot an ip.access nanoBTS */
2973int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
2974{
2975 struct abis_om_hdr *oh;
2976 struct msgb *msg = nm_msgb_alloc();
2977
2978 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2979 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2980 trx->bts->nr, trx->nr, 0xff);
2981
2982 return abis_nm_sendmsg(trx->bts, msg);
2983}
2984
2985int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
2986 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
2987 u_int8_t *attr, u_int8_t attr_len)
2988{
2989 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2990 obj_class, bts_nr, trx_nr, ts_nr,
2991 attr, attr_len);
2992}
2993
2994void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
2995{
2996 /* we simply reuse the GSM48 function and overwrite the RAC
2997 * with the Cell ID */
2998 gsm48_ra_id_by_bts(buf, bts);
2999 *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
3000}
3001
3002void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
3003{
3004 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
3005
3006 trx->nm_state.administrative = new_state;
3007 if (!trx->bts || !trx->bts->oml_link)
3008 return;
3009
3010 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
3011 trx->bts->bts_nr, trx->nr, 0xff,
3012 new_state);
3013}
3014
3015static const struct value_string ipacc_testres_names[] = {
3016 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
3017 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
3018 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
3019 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
3020 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
3021 { 0, NULL }
3022};
3023
3024const char *ipacc_testres_name(u_int8_t res)
3025{
3026 return get_value_string(ipacc_testres_names, res);
3027}
3028
3029void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
3030{
3031 cid->mcc = (buf[0] & 0xf) * 100;
3032 cid->mcc += (buf[0] >> 4) * 10;
3033 cid->mcc += (buf[1] & 0xf) * 1;
3034
3035 if (buf[1] >> 4 == 0xf) {
3036 cid->mnc = (buf[2] & 0xf) * 10;
3037 cid->mnc += (buf[2] >> 4) * 1;
3038 } else {
3039 cid->mnc = (buf[2] & 0xf) * 100;
3040 cid->mnc += (buf[2] >> 4) * 10;
3041 cid->mnc += (buf[1] >> 4) * 1;
3042 }
3043
3044 cid->lac = ntohs(*((u_int16_t *)&buf[3]));
3045 cid->ci = ntohs(*((u_int16_t *)&buf[5]));
3046}
3047
3048/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
3049int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
3050{
3051 u_int8_t *cur = buf;
3052 u_int16_t len;
3053
3054 memset(binf, 0, sizeof(*binf));
3055
3056 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
3057 return -EINVAL;
3058 cur++;
3059
3060 len = ntohs(*(u_int16_t *)cur);
3061 cur += 2;
3062
3063 binf->info_type = ntohs(*(u_int16_t *)cur);
3064 cur += 2;
3065
3066 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3067 binf->freq_qual = *cur >> 2;
3068
3069 binf->arfcn = (*cur++ & 3) << 8;
3070 binf->arfcn |= *cur++;
3071
3072 if (binf->info_type & IPAC_BINF_RXLEV)
3073 binf->rx_lev = *cur & 0x3f;
3074 cur++;
3075
3076 if (binf->info_type & IPAC_BINF_RXQUAL)
3077 binf->rx_qual = *cur & 0x7;
3078 cur++;
3079
3080 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
3081 binf->freq_err = ntohs(*(u_int16_t *)cur);
3082 cur += 2;
3083
3084 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
3085 binf->frame_offset = ntohs(*(u_int16_t *)cur);
3086 cur += 2;
3087
3088 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
3089 binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
3090 cur += 4;
3091
3092#if 0
3093 /* Somehow this is not set correctly */
3094 if (binf->info_type & IPAC_BINF_BSIC)
3095#endif
3096 binf->bsic = *cur & 0x3f;
3097 cur++;
3098
3099 ipac_parse_cgi(&binf->cgi, cur);
3100 cur += 7;
3101
3102 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
3103 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
3104 cur += sizeof(binf->ba_list_si2);
3105 }
3106
3107 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
3108 memcpy(binf->ba_list_si2bis, cur,
3109 sizeof(binf->ba_list_si2bis));
3110 cur += sizeof(binf->ba_list_si2bis);
3111 }
3112
3113 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
3114 memcpy(binf->ba_list_si2ter, cur,
3115 sizeof(binf->ba_list_si2ter));
3116 cur += sizeof(binf->ba_list_si2ter);
3117 }
3118
3119 return 0;
3120}
3121
3122void abis_nm_clear_queue(struct gsm_bts *bts)
3123{
3124 struct msgb *msg;
3125
3126 while (!llist_empty(&bts->abis_queue)) {
3127 msg = msgb_dequeue(&bts->abis_queue);
3128 msgb_free(msg);
3129 }
3130
3131 bts->abis_nm_pend = 0;
3132}