blob: 259132029b6ef8699c3ca98b9d8173ca448954d3 [file] [log] [blame]
Harald Welte52b1f982008-12-23 20:25:15 +00001/* 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
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000026#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000027#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000028#include <fcntl.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <malloc.h>
30#include <libgen.h>
Harald Welte4724f992009-01-18 18:01:49 +000031
Harald Welte52b1f982008-12-23 20:25:15 +000032#include <sys/types.h>
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte52b1f982008-12-23 20:25:15 +000035
Harald Welte8470bf22008-12-25 23:28:35 +000036#include <openbsc/gsm_data.h>
37#include <openbsc/debug.h>
38#include <openbsc/msgb.h>
39#include <openbsc/tlv.h>
40#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000041#include <openbsc/misdn.h>
Harald Welte52b1f982008-12-23 20:25:15 +000042
Harald Welte8470bf22008-12-25 23:28:35 +000043#define OM_ALLOC_SIZE 1024
44#define OM_HEADROOM_SIZE 128
Harald Welte52b1f982008-12-23 20:25:15 +000045
46/* unidirectional messages from BTS to BSC */
47static const enum abis_nm_msgtype reports[] = {
48 NM_MT_SW_ACTIVATED_REP,
49 NM_MT_TEST_REP,
50 NM_MT_STATECHG_EVENT_REP,
51 NM_MT_FAILURE_EVENT_REP,
52};
53
54/* messages without ACK/NACK */
55static const enum abis_nm_msgtype no_ack_nack[] = {
56 NM_MT_MEAS_RES_REQ,
57 NM_MT_STOP_MEAS,
58 NM_MT_START_MEAS,
59};
60
Harald Welte4724f992009-01-18 18:01:49 +000061/* Messages related to software load */
62static const enum abis_nm_msgtype sw_load_msgs[] = {
63 NM_MT_LOAD_INIT_ACK,
64 NM_MT_LOAD_INIT_NACK,
65 NM_MT_LOAD_SEG_ACK,
66 NM_MT_LOAD_ABORT,
67 NM_MT_LOAD_END_ACK,
68 NM_MT_LOAD_END_NACK,
69 NM_MT_SW_ACT_REQ,
70 NM_MT_ACTIVATE_SW_ACK,
71 NM_MT_ACTIVATE_SW_NACK,
72 NM_MT_SW_ACTIVATED_REP,
73};
74
Harald Welte52b1f982008-12-23 20:25:15 +000075/* Attributes that the BSC can set, not only get, according to Section 9.4 */
76static const enum abis_nm_attr nm_att_settable[] = {
77 NM_ATT_ADD_INFO,
78 NM_ATT_ADD_TEXT,
79 NM_ATT_DEST,
80 NM_ATT_EVENT_TYPE,
81 NM_ATT_FILE_DATA,
82 NM_ATT_GET_ARI,
83 NM_ATT_HW_CONF_CHG,
84 NM_ATT_LIST_REQ_ATTR,
85 NM_ATT_MDROP_LINK,
86 NM_ATT_MDROP_NEXT,
87 NM_ATT_NACK_CAUSES,
88 NM_ATT_OUTST_ALARM,
89 NM_ATT_PHYS_CONF,
90 NM_ATT_PROB_CAUSE,
91 NM_ATT_RAD_SUBC,
92 NM_ATT_SOURCE,
93 NM_ATT_SPEC_PROB,
94 NM_ATT_START_TIME,
95 NM_ATT_TEST_DUR,
96 NM_ATT_TEST_NO,
97 NM_ATT_TEST_REPORT,
98 NM_ATT_WINDOW_SIZE,
99 NM_ATT_SEVERITY,
100 NM_ATT_MEAS_RES,
101 NM_ATT_MEAS_TYPE,
102};
103
104static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
105{
106 int i;
107
108 for (i = 0; i < size; i++) {
109 if (arr[i] == mt)
110 return 1;
111 }
112
113 return 0;
114}
115
Holger Freytherca362a62009-01-04 21:05:01 +0000116#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000117/* is this msgtype the usual ACK/NACK type ? */
118static int is_ack_nack(enum abis_nm_msgtype mt)
119{
120 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
121}
Holger Freytherca362a62009-01-04 21:05:01 +0000122#endif
Harald Welte52b1f982008-12-23 20:25:15 +0000123
124/* is this msgtype a report ? */
125static int is_report(enum abis_nm_msgtype mt)
126{
Harald Welte8470bf22008-12-25 23:28:35 +0000127 return is_in_arr(mt, reports, ARRAY_SIZE(reports));
Harald Welte52b1f982008-12-23 20:25:15 +0000128}
129
130#define MT_ACK(x) (x+1)
131#define MT_NACK(x) (x+2)
132
133static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
134{
135 oh->mdisc = ABIS_OM_MDISC_FOM;
136 oh->placement = ABIS_OM_PLACEMENT_ONLY;
137 oh->sequence = 0;
138 oh->length = len;
139}
140
141static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
142 u_int8_t msg_type, u_int8_t obj_class,
143 u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
144{
145 struct abis_om_fom_hdr *foh =
146 (struct abis_om_fom_hdr *) oh->data;
147
Harald Welte702d8702008-12-26 20:25:35 +0000148 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000149 foh->msg_type = msg_type;
150 foh->obj_class = obj_class;
151 foh->obj_inst.bts_nr = bts_nr;
152 foh->obj_inst.trx_nr = trx_nr;
153 foh->obj_inst.ts_nr = ts_nr;
154}
155
Harald Welte8470bf22008-12-25 23:28:35 +0000156static struct msgb *nm_msgb_alloc(void)
157{
158 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE);
159}
160
Harald Welte52b1f982008-12-23 20:25:15 +0000161/* Send a OML NM Message from BSC to BTS */
162int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
163{
Harald Weltead384642008-12-26 10:20:07 +0000164 return _abis_nm_sendmsg(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000165}
166
Harald Welte4724f992009-01-18 18:01:49 +0000167static int abis_nm_rcvmsg_sw(struct msgb *mb);
168
Harald Welte52b1f982008-12-23 20:25:15 +0000169/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000170static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000171{
172 struct abis_om_fom_hdr *foh = msgb_l3(mb);
173 u_int8_t mt = foh->msg_type;
174
175 /* check for unsolicited message */
176 if (is_report(mt)) {
Harald Weltead384642008-12-26 10:20:07 +0000177 DEBUGP(DNM, "reporting NM MT 0x%02x\n", mt);
178 //nmh->cfg->report_cb(mb, foh);
Harald Welte52b1f982008-12-23 20:25:15 +0000179 return 0;
180 }
181
Harald Welte4724f992009-01-18 18:01:49 +0000182 if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
183 return abis_nm_rcvmsg_sw(mb);
184
Harald Weltead384642008-12-26 10:20:07 +0000185#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000186 /* check if last message is to be acked */
187 if (is_ack_nack(nmh->last_msgtype)) {
188 if (mt == MT_ACK(nmh->last_msgtype)) {
189 fprintf(stderr, "received ACK (0x%x)\n",
190 foh->msg_type);
191 /* we got our ACK, continue sending the next msg */
192 } else if (mt == MT_NACK(nmh->last_msgtype)) {
193 /* we got a NACK, signal this to the caller */
194 fprintf(stderr, "received NACK (0x%x)\n",
195 foh->msg_type);
196 /* FIXME: somehow signal this to the caller */
197 } else {
198 /* really strange things happen */
199 return -EINVAL;
200 }
201 }
Harald Weltead384642008-12-26 10:20:07 +0000202#endif
203
204 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000205}
206
207/* High-Level API */
208/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000209int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000210{
211 int rc;
212 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000213
214 /* Various consistency checks */
215 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
216 fprintf(stderr, "ABIS OML placement 0x%x not supported\n",
217 oh->placement);
218 return -EINVAL;
219 }
220 if (oh->sequence != 0) {
221 fprintf(stderr, "ABIS OML sequence 0x%x != 0x00\n",
222 oh->sequence);
223 return -EINVAL;
224 }
Harald Welte702d8702008-12-26 20:25:35 +0000225#if 0
Holger Freytherca362a62009-01-04 21:05:01 +0000226 unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
227 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000228 if (oh->length + hlen > l2_len) {
Harald Welte52b1f982008-12-23 20:25:15 +0000229 fprintf(stderr, "ABIS OML truncated message (%u > %u)\n",
230 oh->length + sizeof(*oh), l2_len);
231 return -EINVAL;
232 }
Harald Welte702d8702008-12-26 20:25:35 +0000233 if (oh->length + hlen < l2_len)
234 fprintf(stderr, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
235#endif
Harald Weltead384642008-12-26 10:20:07 +0000236 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000237
238 switch (oh->mdisc) {
239 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000240 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000241 break;
242 case ABIS_OM_MDISC_MMI:
243 case ABIS_OM_MDISC_TRAU:
244 case ABIS_OM_MDISC_MANUF:
245 default:
246 fprintf(stderr, "unknown ABIS OML message discriminator 0x%x\n",
247 oh->mdisc);
248 return -EINVAL;
249 }
250
Harald Weltead384642008-12-26 10:20:07 +0000251 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000252 return rc;
253}
254
255#if 0
256/* initialized all resources */
257struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
258{
259 struct abis_nm_h *nmh;
260
261 nmh = malloc(sizeof(*nmh));
262 if (!nmh)
263 return NULL;
264
265 nmh->cfg = cfg;
266
267 return nmh;
268}
269
270/* free all resources */
271void abis_nm_fini(struct abis_nm_h *nmh)
272{
273 free(nmh);
274}
275#endif
276
277/* Here we are trying to define a high-level API that can be used by
278 * the actual BSC implementation. However, the architecture is currently
279 * still under design. Ideally the calls to this API would be synchronous,
280 * while the underlying stack behind the APi runs in a traditional select
281 * based state machine.
282 */
283
Harald Welte4724f992009-01-18 18:01:49 +0000284/* 6.2 Software Load: */
285enum sw_state {
286 SW_STATE_NONE,
287 SW_STATE_WAIT_INITACK,
288 SW_STATE_WAIT_SEGACK,
289 SW_STATE_WAIT_ENDACK,
290 SW_STATE_WAIT_ACTACK,
291 SW_STATE_ERROR,
292};
Harald Welte52b1f982008-12-23 20:25:15 +0000293
Harald Welte52b1f982008-12-23 20:25:15 +0000294struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000295 struct gsm_bts *bts;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000296 gsm_cbfn *cbfn;
297 void *cb_data;
298
Harald Welte52b1f982008-12-23 20:25:15 +0000299 /* this will become part of the SW LOAD INITIATE */
300 u_int8_t obj_class;
301 u_int8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000302
303 u_int8_t file_id[255];
304 u_int8_t file_id_len;
305
306 u_int8_t file_version[255];
307 u_int8_t file_version_len;
308
309 u_int8_t window_size;
310 u_int8_t seg_in_window;
311
312 int fd;
313 FILE *stream;
314 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000315 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000316};
317
Harald Welte4724f992009-01-18 18:01:49 +0000318static struct abis_nm_sw g_sw;
319
320/* 6.2.1 / 8.3.1: Load Data Initiate */
321static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000322{
Harald Welte4724f992009-01-18 18:01:49 +0000323 struct abis_om_hdr *oh;
324 struct msgb *msg = nm_msgb_alloc();
325 u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
326
327 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
328 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
329 sw->obj_instance[0], sw->obj_instance[1],
330 sw->obj_instance[2]);
331
332 /* FIXME: this is BS11 specific format */
333 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
334 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
335 sw->file_version);
336 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
337
338 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000339}
340
Harald Welte1602ade2009-01-29 21:12:39 +0000341static int is_last_line(FILE *stream)
342{
343 char next_seg_buf[256];
344 long pos;
345
346 /* check if we're sending the last line */
347 pos = ftell(stream);
348 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
349 fseek(stream, pos, SEEK_SET);
350 return 1;
351 }
352
353 fseek(stream, pos, SEEK_SET);
354 return 0;
355}
356
Harald Welte4724f992009-01-18 18:01:49 +0000357/* 6.2.2 / 8.3.2 Load Data Segment */
358static int sw_load_segment(struct abis_nm_sw *sw)
359{
360 struct abis_om_hdr *oh;
361 struct msgb *msg = nm_msgb_alloc();
362 char seg_buf[256];
363 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000364 unsigned char *tlv;
Harald Welte4724f992009-01-18 18:01:49 +0000365 u_int8_t len;
Harald Welte4724f992009-01-18 18:01:49 +0000366
367 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000368
369 switch (sw->bts->type) {
370 case GSM_BTS_TYPE_BS11:
371 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
372 perror("fgets reading segment");
373 return -EINVAL;
374 }
375 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000376
377 /* check if we're sending the last line */
378 sw->last_seg = is_last_line(sw->stream);
379 if (sw->last_seg)
380 seg_buf[1] = 0;
381 else
382 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000383
384 len = strlen(line_buf) + 2;
385 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
386 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
387 /* BS11 wants CR + LF in excess of the TLV length !?! */
388 tlv[1] -= 2;
389
390 /* we only now know the exact length for the OM hdr */
391 len = strlen(line_buf)+2;
392 break;
393 default:
394 /* FIXME: Other BTS types */
395 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000396 }
Harald Welte4724f992009-01-18 18:01:49 +0000397
Harald Welte4724f992009-01-18 18:01:49 +0000398 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
399 sw->obj_instance[0], sw->obj_instance[1],
400 sw->obj_instance[2]);
401
402 return abis_nm_sendmsg(sw->bts, msg);
403}
404
405/* 6.2.4 / 8.3.4 Load Data End */
406static int sw_load_end(struct abis_nm_sw *sw)
407{
408 struct abis_om_hdr *oh;
409 struct msgb *msg = nm_msgb_alloc();
410 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
411
412 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
413 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
414 sw->obj_instance[0], sw->obj_instance[1],
415 sw->obj_instance[2]);
416
417 /* FIXME: this is BS11 specific format */
418 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
419 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
420 sw->file_version);
421
422 return abis_nm_sendmsg(sw->bts, msg);
423}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000424
Harald Welte52b1f982008-12-23 20:25:15 +0000425/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000426static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000427{
Harald Welte4724f992009-01-18 18:01:49 +0000428 struct abis_om_hdr *oh;
429 struct msgb *msg = nm_msgb_alloc();
430 u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000431
Harald Welte4724f992009-01-18 18:01:49 +0000432 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
433 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
434 sw->obj_instance[0], sw->obj_instance[1],
435 sw->obj_instance[2]);
436
437 /* FIXME: this is BS11 specific format */
438 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
439 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
440 sw->file_version);
441
442 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000443}
Harald Welte4724f992009-01-18 18:01:49 +0000444
445static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
446{
447 char file_id[12+1];
448 char file_version[80+1];
449 int rc;
450
451 sw->fd = open(fname, O_RDONLY);
452 if (sw->fd < 0)
453 return sw->fd;
454
455 switch (sw->bts->type) {
456 case GSM_BTS_TYPE_BS11:
457 sw->stream = fdopen(sw->fd, "r");
458 if (!sw->stream) {
459 perror("fdopen");
460 return -1;
461 }
462 /* read first line and parse file ID and VERSION */
Harald Welte3b8ba212009-01-29 12:27:58 +0000463 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +0000464 file_id, file_version);
465 if (rc != 2) {
466 perror("parsing header line of software file");
467 return -1;
468 }
469 strcpy((char *)sw->file_id, file_id);
470 sw->file_id_len = strlen(file_id);
471 strcpy((char *)sw->file_version, file_version);
472 sw->file_version_len = strlen(file_version);
473 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +0000474 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +0000475 break;
476 default:
477 /* We don't know how to treat them yet */
478 close(sw->fd);
479 return -EINVAL;
480 }
481
482 return 0;
483}
484
485static void sw_close_file(struct abis_nm_sw *sw)
486{
487 switch (sw->bts->type) {
488 case GSM_BTS_TYPE_BS11:
489 fclose(sw->stream);
490 break;
491 default:
492 close(sw->fd);
493 break;
494 }
495}
496
497/* Fill the window */
498static int sw_fill_window(struct abis_nm_sw *sw)
499{
500 int rc;
501
502 while (sw->seg_in_window < sw->window_size) {
503 rc = sw_load_segment(sw);
504 if (rc < 0)
505 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000506 if (sw->last_seg)
507 break;
Harald Welte4724f992009-01-18 18:01:49 +0000508 }
509 return 0;
510}
511
512/* callback function from abis_nm_rcvmsg() handler */
513static int abis_nm_rcvmsg_sw(struct msgb *mb)
514{
515 struct abis_om_fom_hdr *foh = msgb_l3(mb);
516 int rc = -1;
517 struct abis_nm_sw *sw = &g_sw;
518 enum sw_state old_state = sw->state;
519
520 DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
521
522 switch (sw->state) {
523 case SW_STATE_WAIT_INITACK:
524 switch (foh->msg_type) {
525 case NM_MT_LOAD_INIT_ACK:
526 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +0000527 if (sw->cbfn)
528 sw->cbfn(GSM_HOOK_NM_SWLOAD,
529 NM_MT_LOAD_INIT_ACK, mb,
530 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +0000531 rc = sw_fill_window(sw);
532 sw->state = SW_STATE_WAIT_SEGACK;
533 break;
534 case NM_MT_LOAD_INIT_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +0000535 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte5e4d1b32009-02-01 13:36:56 +0000536 if (sw->cbfn)
537 sw->cbfn(GSM_HOOK_NM_SWLOAD,
538 NM_MT_LOAD_INIT_NACK, mb,
539 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +0000540 sw->state = SW_STATE_ERROR;
541 break;
542 }
543 break;
544 case SW_STATE_WAIT_SEGACK:
545 switch (foh->msg_type) {
546 case NM_MT_LOAD_SEG_ACK:
547 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +0000548 if (!sw->last_seg) {
549 /* fill window with more segments */
550 rc = sw_fill_window(sw);
551 sw->state = SW_STATE_WAIT_SEGACK;
552 } else {
553 /* end the transfer */
554 sw->state = SW_STATE_WAIT_ENDACK;
555 rc = sw_load_end(sw);
556 }
Harald Welte4724f992009-01-18 18:01:49 +0000557 break;
558 }
559 break;
560 case SW_STATE_WAIT_ENDACK:
561 switch (foh->msg_type) {
562 case NM_MT_LOAD_END_ACK:
563 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +0000564 DEBUGP(DNM, "Software Load End (BTS %u)\n",
565 sw->bts->nr);
566 sw->state = SW_STATE_NONE;
567 if (sw->cbfn)
568 sw->cbfn(GSM_HOOK_NM_SWLOAD,
569 NM_MT_LOAD_END_ACK, mb,
570 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +0000571 break;
572 case NM_MT_LOAD_END_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +0000573 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte4724f992009-01-18 18:01:49 +0000574 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000575 if (sw->cbfn)
576 sw->cbfn(GSM_HOOK_NM_SWLOAD,
577 NM_MT_LOAD_END_NACK, mb,
578 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +0000579 break;
580 }
581 case SW_STATE_WAIT_ACTACK:
582 switch (foh->msg_type) {
583 case NM_MT_ACTIVATE_SW_ACK:
584 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +0000585 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +0000586 sw->state = SW_STATE_NONE;
587 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000588 if (sw->cbfn)
589 sw->cbfn(GSM_HOOK_NM_SWLOAD,
590 NM_MT_ACTIVATE_SW_ACK, mb,
591 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +0000592 break;
593 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +0000594 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte4724f992009-01-18 18:01:49 +0000595 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000596 if (sw->cbfn)
597 sw->cbfn(GSM_HOOK_NM_SWLOAD,
598 NM_MT_ACTIVATE_SW_NACK, mb,
599 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +0000600 break;
601 }
602 case SW_STATE_NONE:
603 case SW_STATE_ERROR:
604 break;
605 }
606
607 if (rc)
608 fprintf(stderr, "unexpected NM MT 0x%02x in state %u -> %u\n",
609 foh->msg_type, old_state, sw->state);
610
611 return rc;
612}
613
614/* Load the specified software into the BTS */
615int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +0000616 u_int8_t win_size, gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +0000617{
618 struct abis_nm_sw *sw = &g_sw;
619 int rc;
620
Harald Welte5e4d1b32009-02-01 13:36:56 +0000621 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
622 bts->nr, fname);
623
Harald Welte4724f992009-01-18 18:01:49 +0000624 if (sw->state != SW_STATE_NONE)
625 return -EBUSY;
626
627 sw->bts = bts;
628 sw->obj_class = NM_OC_SITE_MANAGER;
629 sw->obj_instance[0] = 0xff;
630 sw->obj_instance[1] = 0xff;
631 sw->obj_instance[2] = 0xff;
632 sw->window_size = win_size;
633 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000634 sw->cbfn = cbfn;
635 sw->cb_data = cb_data;
Harald Welte4724f992009-01-18 18:01:49 +0000636
637 rc = sw_open_file(sw, fname);
638 if (rc < 0) {
639 sw->state = SW_STATE_NONE;
640 return rc;
641 }
642
643 return sw_load_init(sw);
644}
Harald Welte52b1f982008-12-23 20:25:15 +0000645
Harald Welte1602ade2009-01-29 21:12:39 +0000646int abis_nm_software_load_status(struct gsm_bts *bts)
647{
648 struct abis_nm_sw *sw = &g_sw;
649 struct stat st;
650 int rc, percent;
651
652 rc = fstat(sw->fd, &st);
653 if (rc < 0) {
654 perror("ERROR during stat");
655 return rc;
656 }
657
658 percent = (ftell(sw->stream) * 100) / st.st_size;
659 return percent;
660}
661
Harald Welte5e4d1b32009-02-01 13:36:56 +0000662/* Activate the specified software into the BTS */
663int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
664 gsm_cbfn *cbfn, void *cb_data)
665{
666 struct abis_nm_sw *sw = &g_sw;
667 int rc;
668
669 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
670 bts->nr, fname);
671
672 if (sw->state != SW_STATE_NONE)
673 return -EBUSY;
674
675 sw->bts = bts;
676 sw->obj_class = NM_OC_SITE_MANAGER;
677 sw->obj_instance[0] = 0xff;
678 sw->obj_instance[1] = 0xff;
679 sw->obj_instance[2] = 0xff;
680 sw->state = SW_STATE_WAIT_ACTACK;
681 sw->cbfn = cbfn;
682 sw->cb_data = cb_data;
683
684 /* Open the file in order to fill some sw struct members */
685 rc = sw_open_file(sw, fname);
686 if (rc < 0) {
687 sw->state = SW_STATE_NONE;
688 return rc;
689 }
690 sw_close_file(sw);
691
692 return sw_activate(sw);
693}
694
Harald Welte8470bf22008-12-25 23:28:35 +0000695static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
Harald Welte52b1f982008-12-23 20:25:15 +0000696 u_int8_t ts_nr, u_int8_t subslot_nr)
697{
Harald Welteadaf08b2009-01-18 11:08:10 +0000698 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +0000699 ch->bts_port = bts_port;
700 ch->timeslot = ts_nr;
701 ch->subslot = subslot_nr;
702}
703
704int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
705 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
706 u_int8_t tei)
707{
708 struct abis_om_hdr *oh;
709 struct abis_nm_channel *ch;
Harald Welte702d8702008-12-26 20:25:35 +0000710 u_int8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +0000711 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000712
713 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
714 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
715 bts->bts_nr, trx_nr, 0xff);
716
Harald Welte8470bf22008-12-25 23:28:35 +0000717 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +0000718
719 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
720 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
721
722 return abis_nm_sendmsg(bts, msg);
723}
724
725/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
726int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
727 u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
728{
Harald Welte8470bf22008-12-25 23:28:35 +0000729 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +0000730 struct abis_om_hdr *oh;
731 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +0000732 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000733
734 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +0000735 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +0000736 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
737
738 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
739 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
740
741 return abis_nm_sendmsg(bts, msg);
742}
743
744#if 0
745int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
746 struct abis_nm_abis_channel *chan)
747{
748}
749#endif
750
751int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
752 u_int8_t e1_port, u_int8_t e1_timeslot,
753 u_int8_t e1_subslot)
754{
755 struct gsm_bts *bts = ts->trx->bts;
756 struct abis_om_hdr *oh;
757 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +0000758 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000759
760 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
761 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
762 NM_OC_BASEB_TRANSC, bts->bts_nr, ts->trx->nr, ts->nr);
763
764 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
765 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
766
767 return abis_nm_sendmsg(bts, msg);
768}
769
770#if 0
771int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
772 struct abis_nm_abis_channel *chan,
773 u_int8_t subchan)
774{
775}
776#endif
777
778int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
779{
780 struct gsm_bts *bts = ts->trx->bts;
781 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +0000782 u_int16_t arfcn = htons(ts->trx->arfcn);
Harald Welte52b1f982008-12-23 20:25:15 +0000783 u_int8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +0000784 struct msgb *msg = nm_msgb_alloc();
Harald Welte702d8702008-12-26 20:25:35 +0000785 u_int8_t len = 4 + 2 + 2 + 2 + 2 +3;
Harald Welte52b1f982008-12-23 20:25:15 +0000786
787 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +0000788 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Harald Welte52b1f982008-12-23 20:25:15 +0000789 NM_OC_BASEB_TRANSC, bts->bts_nr,
790 ts->trx->nr, ts->nr);
791 /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
792 msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
793 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
794 msgb_tv_put(msg, NM_ATT_HSN, 0x00);
795 msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
796 msgb_tv_put(msg, NM_ATT_TSC, 0x07); /* training sequence */
797 msgb_tlv_put(msg, 0x59, 1, &zero);
798
799 return abis_nm_sendmsg(bts, msg);
800}
801
Harald Welte8470bf22008-12-25 23:28:35 +0000802int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +0000803{
Harald Welte8470bf22008-12-25 23:28:35 +0000804 struct msgb *msg = nm_msgb_alloc();
805 struct abis_om_hdr *oh;
Harald Welte52b1f982008-12-23 20:25:15 +0000806 u_int8_t *data;
807
808 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
809 fill_om_hdr(oh, len);
810 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +0000811 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +0000812
813 return abis_nm_sendmsg(bts, msg);
814}
815
816/* Siemens specific commands */
817static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
818{
819 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +0000820 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +0000821
822 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +0000823 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +0000824 0xff, 0xff, 0xff);
825
826 return abis_nm_sendmsg(bts, msg);
827}
828
829int abis_nm_event_reports(struct gsm_bts *bts, int on)
830{
831 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +0000832 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +0000833 else
Harald Welte227d4072009-01-03 08:16:25 +0000834 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +0000835}
836
Harald Welte47d88ae2009-01-04 12:02:08 +0000837/* Siemens (or BS-11) specific commands */
838
Harald Welte05188ee2009-01-18 11:39:08 +0000839int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +0000840{
Harald Welte4668fda2009-01-03 08:19:29 +0000841 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +0000842}
843
Harald Welte05188ee2009-01-18 11:39:08 +0000844int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +0000845{
846 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +0000847 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +0000848 else
Harald Welte4668fda2009-01-03 08:19:29 +0000849 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +0000850}
Harald Welte47d88ae2009-01-04 12:02:08 +0000851
Harald Welte05188ee2009-01-18 11:39:08 +0000852int abis_nm_bs11_create_object(struct gsm_bts *bts,
Harald Welte1bc09062009-01-18 14:17:52 +0000853 enum abis_bs11_objtype type, u_int8_t idx,
854 u_int8_t attr_len, const u_int8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +0000855{
856 struct abis_om_hdr *oh;
857 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +0000858 u_int8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +0000859
860 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +0000861 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +0000862 NM_OC_BS11, type, idx, 0);
863 cur = msgb_put(msg, attr_len);
864 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +0000865
866 return abis_nm_sendmsg(bts, msg);
867}
868
Harald Welte05188ee2009-01-18 11:39:08 +0000869int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +0000870{
871 struct abis_om_hdr *oh;
872 struct msgb *msg = nm_msgb_alloc();
Harald Welte1bc09062009-01-18 14:17:52 +0000873 u_int8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +0000874
875 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +0000876 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +0000877 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
878 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +0000879
880 return abis_nm_sendmsg(bts, msg);
881}
882
Harald Welte05188ee2009-01-18 11:39:08 +0000883int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +0000884{
885 struct abis_om_hdr *oh;
886 struct msgb *msg = nm_msgb_alloc();
887
888 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
889 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
890 idx, 0, 0);
891
892 return abis_nm_sendmsg(bts, msg);
893}
Harald Welte05188ee2009-01-18 11:39:08 +0000894
895int abis_nm_bs11_set_oml_tei(struct gsm_bts *bts, u_int8_t tei)
896{
897 struct abis_om_hdr *oh;
898 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +0000899
900 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +0000901 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
Harald Welte05188ee2009-01-18 11:39:08 +0000902 0xff, 0xff, 0xff);
903 msgb_tv_put(msg, NM_ATT_TEI, tei);
904
905 return abis_nm_sendmsg(bts, msg);
906}
907
908/* like abis_nm_conn_terr_traf */
909int abis_nm_bs11_conn_oml(struct gsm_bts *bts, u_int8_t e1_port,
910 u_int8_t e1_timeslot, u_int8_t e1_subslot)
911{
912 struct abis_om_hdr *oh;
913 struct abis_nm_channel *ch;
914 struct msgb *msg = nm_msgb_alloc();
915
916 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte05188ee2009-01-18 11:39:08 +0000917 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_BS11_SET_ATTR,
918 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
919
920 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
921 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
922
923 return abis_nm_sendmsg(bts, msg);
924}
925
926int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
927{
928 struct abis_om_hdr *oh;
929 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +0000930
931 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +0000932 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +0000933 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
934 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
935
936 return abis_nm_sendmsg(trx->bts, msg);
937}
938
939static const u_int8_t bs11_logon_c7[] =
940 { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Weltebb151312009-01-28 20:42:07 +0000941static const u_int8_t bs11_logon_c8[] = { 0x02 };
Harald Welte05188ee2009-01-18 11:39:08 +0000942static const u_int8_t bs11_logon_c9[] = "FACTORY";
943
Harald Welte1bc09062009-01-18 14:17:52 +0000944int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +0000945{
946 struct abis_om_hdr *oh;
947 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +0000948
949 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +0000950 if (on) {
Harald Welte6f676a32009-01-18 14:27:48 +0000951 u_int8_t len = 3*2 + sizeof(bs11_logon_c7)
952 + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
Harald Welte043d04a2009-01-29 23:15:30 +0000953 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte1bc09062009-01-18 14:17:52 +0000954 NM_OC_BS11_A3, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +0000955 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
956 sizeof(bs11_logon_c7), bs11_logon_c7);
957 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
958 sizeof(bs11_logon_c8), bs11_logon_c8);
959 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
960 sizeof(bs11_logon_c9), bs11_logon_c9);
Harald Welte1bc09062009-01-18 14:17:52 +0000961 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +0000962 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte1bc09062009-01-18 14:17:52 +0000963 NM_OC_BS11_A3, 0xff, 0xff, 0xff);
964 }
Harald Welte05188ee2009-01-18 11:39:08 +0000965
966 return abis_nm_sendmsg(bts, msg);
967}
Harald Welte1bc09062009-01-18 14:17:52 +0000968
969int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
970{
971 struct abis_om_hdr *oh;
972 struct msgb *msg;
973
974 if (strlen(password) != 10)
975 return -EINVAL;
976
977 msg = nm_msgb_alloc();
978 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +0000979 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +0000980 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
981 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
982
983 return abis_nm_sendmsg(bts, msg);
984}
985
986int abis_nm_bs11_get_state(struct gsm_bts *bts)
987{
988 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
989}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000990
991/* BS11 SWL */
992
993struct abis_nm_bs11_sw {
994 struct gsm_bts *bts;
995 char swl_fname[PATH_MAX];
996 u_int8_t win_size;
997 struct llist_head file_list;
998 gsm_cbfn *user_cb; /* specified by the user */
999};
1000static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
1001
1002struct file_list_entry {
1003 struct llist_head list;
1004 char fname[PATH_MAX];
1005};
1006
1007struct file_list_entry *fl_dequeue(struct llist_head *queue)
1008{
1009 struct llist_head *lh;
1010
1011 if (llist_empty(queue))
1012 return NULL;
1013
1014 lh = queue->next;
1015 llist_del(lh);
1016
1017 return llist_entry(lh, struct file_list_entry, list);
1018}
1019
1020static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
1021{
1022 char linebuf[255];
1023 struct llist_head *lh, *lh2;
1024 FILE *swl;
1025 int rc = 0;
1026
1027 swl = fopen(bs11_sw->swl_fname, "r");
1028 if (!swl)
1029 return -ENODEV;
1030
1031 /* zero the stale file list, if any */
1032 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
1033 llist_del(lh);
1034 free(lh);
1035 }
1036
1037 while (fgets(linebuf, sizeof(linebuf), swl)) {
1038 char file_id[12+1];
1039 char file_version[80+1];
1040 struct file_list_entry *fle;
1041 static char dir[PATH_MAX];
1042
1043 if (strlen(linebuf) < 4)
1044 continue;
1045 printf("linebuf='%s'\n", linebuf);
1046 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
1047 if (rc < 0) {
1048 perror("ERR parsing SWL file");
1049 rc = -EINVAL;
1050 goto out;
1051 }
1052 if (rc < 2)
1053 continue;
1054
1055 fle = malloc(sizeof(*fle));
1056 if (!fle) {
1057 rc = -ENOMEM;
1058 goto out;
1059 }
1060 memset(fle, 0, sizeof(*fle));
1061
1062 /* construct new filename */
1063 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
1064 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
1065 strcat(fle->fname, "/");
1066 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
1067 printf("fname='%s'\n", fle->fname);
1068
1069 llist_add_tail(&fle->list, &bs11_sw->file_list);
1070 }
1071
1072out:
1073 fclose(swl);
1074 return rc;
1075}
1076
1077/* bs11 swload specific callback, passed to abis_nm core swload */
1078static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
1079 struct msgb *msg, void *data, void *param)
1080{
1081 struct abis_nm_bs11_sw *bs11_sw = data;
1082 struct file_list_entry *fle;
1083 int rc = 0;
1084
1085 printf("bs11_swload_cbfn(%u, %u, %p, %p, %p)\n", hook, event, msg, data, param);
1086
1087 switch (event) {
1088 case NM_MT_LOAD_END_ACK:
1089 fle = fl_dequeue(&bs11_sw->file_list);
1090 if (fle) {
1091 /* start download the next file of our file list */
1092 rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
1093 bs11_sw->win_size,
1094 &bs11_swload_cbfn, bs11_sw);
1095 free(fle);
1096 } else {
1097 /* activate the SWL */
1098 rc = abis_nm_software_activate(bs11_sw->bts,
1099 bs11_sw->swl_fname,
1100 bs11_swload_cbfn,
1101 bs11_sw);
1102 }
1103 break;
1104 case NM_MT_LOAD_END_NACK:
1105 case NM_MT_LOAD_INIT_ACK:
1106 case NM_MT_LOAD_INIT_NACK:
1107 case NM_MT_ACTIVATE_SW_NACK:
1108 case NM_MT_ACTIVATE_SW_ACK:
1109 default:
1110 /* fallthrough to the user callback */
1111 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
1112 break;
1113 }
1114
1115 return rc;
1116}
1117
1118/* Siemens provides a SWL file that is a mere listing of all the other
1119 * files that are part of a software release. We need to upload first
1120 * the list file, and then each file that is listed in the list file */
1121int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
1122 u_int8_t win_size, gsm_cbfn *cbfn)
1123{
1124 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
1125 struct file_list_entry *fle;
1126 int rc = 0;
1127
1128 INIT_LLIST_HEAD(&bs11_sw->file_list);
1129 bs11_sw->bts = bts;
1130 bs11_sw->win_size = win_size;
1131 bs11_sw->user_cb = cbfn;
1132
1133 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
1134 rc = bs11_read_swl_file(bs11_sw);
1135 if (rc < 0)
1136 return rc;
1137
1138 /* dequeue next item in file list */
1139 fle = fl_dequeue(&bs11_sw->file_list);
1140 if (!fle)
1141 return -EINVAL;
1142
1143 /* start download the next file of our file list */
1144 rc = abis_nm_software_load(bts, fle->fname, win_size,
1145 bs11_swload_cbfn, bs11_sw);
1146 free(fle);
1147 return rc;
1148}
1149
1150static u_int8_t req_attr_btse[] = {
1151 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
1152 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
1153 NM_ATT_BS11_LMT_USER_NAME,
1154
1155 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
1156
1157 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
1158
1159 NM_ATT_BS11_SW_LOAD_STORED };
1160
1161static u_int8_t req_attr_btsm[] = {
1162 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
1163 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
1164 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
1165 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
1166
1167static u_int8_t req_attr[] = {
1168 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
1169 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
1170 0x42, NM_ATT_BS11_ESN_PCB_SERIAL };
1171
1172int abis_nm_bs11_get_serno(struct gsm_bts *bts)
1173{
1174 struct abis_om_hdr *oh;
1175 struct msgb *msg = nm_msgb_alloc();
1176
1177 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1178 /* SiemensHW CCTRL object */
1179 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
1180 0x03, 0x00, 0x00);
1181 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
1182
1183 return abis_nm_sendmsg(bts, msg);
1184}