blob: 494d4cabafeb1f0023f78af34d8bca8ea974c9ea [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
Jonathan Santos03fd8d02011-05-25 13:54:02 -040033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Jonathan Santos5a45b152011-08-17 15:33:57 -040039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
41#include <osmocom/gsm/abis_nm.h>
42#include <osmocom/core/talloc.h>
Jonathan Santos03fd8d02011-05-25 13:54:02 -040043#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
Jonathan Santos5a45b152011-08-17 15:33:57 -040051int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -040052{
53 if (!bts->model)
54 return -EIO;
55 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
56}
57
58static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
59{
60 int i;
61
62 for (i = 0; i < size; i++) {
63 if (arr[i] == mt)
64 return 1;
65 }
66
67 return 0;
68}
69
70#if 0
71/* is this msgtype the usual ACK/NACK type ? */
72static int is_ack_nack(enum abis_nm_msgtype mt)
73{
74 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
75}
76#endif
77
78/* is this msgtype a report ? */
79static int is_report(enum abis_nm_msgtype mt)
80{
Jonathan Santos5a45b152011-08-17 15:33:57 -040081 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Jonathan Santos03fd8d02011-05-25 13:54:02 -040082}
83
84#define MT_ACK(x) (x+1)
85#define MT_NACK(x) (x+2)
86
Jonathan Santos5a45b152011-08-17 15:33:57 -040087static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -040088{
89 oh->mdisc = ABIS_OM_MDISC_FOM;
90 oh->placement = ABIS_OM_PLACEMENT_ONLY;
91 oh->sequence = 0;
92 oh->length = len;
93}
94
Jonathan Santos5a45b152011-08-17 15:33:57 -040095static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
96 uint8_t msg_type, uint8_t obj_class,
97 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Jonathan Santos03fd8d02011-05-25 13:54:02 -040098{
99 struct abis_om_fom_hdr *foh =
100 (struct abis_om_fom_hdr *) oh->data;
101
102 fill_om_hdr(oh, len+sizeof(*foh));
103 foh->msg_type = msg_type;
104 foh->obj_class = obj_class;
105 foh->obj_inst.bts_nr = bts_nr;
106 foh->obj_inst.trx_nr = trx_nr;
107 foh->obj_inst.ts_nr = ts_nr;
108}
109
110static struct msgb *nm_msgb_alloc(void)
111{
112 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
113 "OML");
114}
115
116/* Send a OML NM Message from BSC to BTS */
117static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
118{
119 msg->trx = bts->c0;
120
121 /* queue OML messages */
122 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
123 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
124 return _abis_nm_sendmsg(msg, 0);
125 } else {
126 msgb_enqueue(&bts->abis_queue, msg);
127 return 0;
128 }
129
130}
131
132int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
133{
134 OBSC_NM_W_ACK_CB(msg) = 1;
135 return abis_nm_queue_msg(bts, msg);
136}
137
138static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
139{
140 OBSC_NM_W_ACK_CB(msg) = 0;
141 return abis_nm_queue_msg(bts, msg);
142}
143
144static int abis_nm_rcvmsg_sw(struct msgb *mb);
145
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400146int nm_is_running(struct gsm_nm_state *s) {
147 return (s->operational == NM_OPSTATE_ENABLED) && (
148 (s->availability == NM_AVSTATE_OK) ||
149 (s->availability == 0xff)
150 );
151}
152
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400153/* Update the administrative state of a given object in our in-memory data
154 * structures and send an event to the higher layer */
Jonathan Santos5a45b152011-08-17 15:33:57 -0400155static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
156 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400157{
158 struct gsm_nm_state *nm_state, new_state;
159 struct nm_statechg_signal_data nsd;
160
Jonathan Santos5a45b152011-08-17 15:33:57 -0400161 memset(&nsd, 0, sizeof(nsd));
162
163 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400164 if (!nsd.obj)
165 return -EINVAL;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400166 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400167 if (!nm_state)
168 return -1;
169
170 new_state = *nm_state;
171 new_state.administrative = adm_state;
172
Jonathan Santos5a45b152011-08-17 15:33:57 -0400173 nsd.bts = bts;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400174 nsd.obj_class = obj_class;
175 nsd.old_state = nm_state;
176 nsd.new_state = &new_state;
177 nsd.obj_inst = obj_inst;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400178 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400179
180 nm_state->administrative = adm_state;
181
182 return 0;
183}
184
185static int abis_nm_rx_statechg_rep(struct msgb *mb)
186{
187 struct abis_om_hdr *oh = msgb_l2(mb);
188 struct abis_om_fom_hdr *foh = msgb_l3(mb);
189 struct gsm_bts *bts = mb->trx->bts;
190 struct tlv_parsed tp;
191 struct gsm_nm_state *nm_state, new_state;
192
193 DEBUGPC(DNM, "STATE CHG: ");
194
195 memset(&new_state, 0, sizeof(new_state));
196
Jonathan Santos5a45b152011-08-17 15:33:57 -0400197 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400198 if (!nm_state) {
199 DEBUGPC(DNM, "unknown object class\n");
200 return -EINVAL;
201 }
202
203 new_state = *nm_state;
204
205 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
206 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
207 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400208 DEBUGPC(DNM, "OP_STATE=%s ",
209 abis_nm_opstate_name(new_state.operational));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400210 }
211 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
212 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
213 new_state.availability = 0xff;
214 else
215 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400216 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
217 abis_nm_avail_name(new_state.availability),
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400218 new_state.availability);
219 } else
220 new_state.availability = 0xff;
221 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
222 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400223 DEBUGPC(DNM, "ADM=%2s ",
224 get_value_string(abis_nm_adm_state_names,
225 new_state.administrative));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400226 }
227 DEBUGPC(DNM, "\n");
228
229 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
230 new_state.operational != nm_state->operational ||
231 new_state.availability != nm_state->availability) {
232 /* Update the operational state of a given object in our in-memory data
233 * structures and send an event to the higher layer */
234 struct nm_statechg_signal_data nsd;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400235 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400236 nsd.obj_class = foh->obj_class;
237 nsd.old_state = nm_state;
238 nsd.new_state = &new_state;
239 nsd.obj_inst = &foh->obj_inst;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400240 nsd.bts = bts;
241 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400242 nm_state->operational = new_state.operational;
243 nm_state->availability = new_state.availability;
244 if (nm_state->administrative == 0)
245 nm_state->administrative = new_state.administrative;
246 }
247#if 0
248 if (op_state == 1) {
249 /* try to enable objects that are disabled */
250 abis_nm_opstart(bts, foh->obj_class,
251 foh->obj_inst.bts_nr,
252 foh->obj_inst.trx_nr,
253 foh->obj_inst.ts_nr);
254 }
255#endif
256 return 0;
257}
258
259static int rx_fail_evt_rep(struct msgb *mb)
260{
261 struct abis_om_hdr *oh = msgb_l2(mb);
262 struct abis_om_fom_hdr *foh = msgb_l3(mb);
263 struct tlv_parsed tp;
264 const uint8_t *p_val;
265 char *p_text;
266
Jonathan Santos5a45b152011-08-17 15:33:57 -0400267 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400268
269 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
270
271 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Jonathan Santos5a45b152011-08-17 15:33:57 -0400272 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
273 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400274 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Jonathan Santos5a45b152011-08-17 15:33:57 -0400275 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
276 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400277 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
278 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400279 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400280 }
281 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
282 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
283 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
284 if (p_text) {
Jonathan Santos5a45b152011-08-17 15:33:57 -0400285 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400286 talloc_free(p_text);
287 }
288 }
289
Jonathan Santos5a45b152011-08-17 15:33:57 -0400290 LOGPC(DNM, LOGL_ERROR, "\n");
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400291
292 return 0;
293}
294
295static int abis_nm_rcvmsg_report(struct msgb *mb)
296{
297 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400298 uint8_t mt = foh->msg_type;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400299
Jonathan Santos5a45b152011-08-17 15:33:57 -0400300 abis_nm_debugp_foh(DNM, foh);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400301
302 //nmh->cfg->report_cb(mb, foh);
303
304 switch (mt) {
305 case NM_MT_STATECHG_EVENT_REP:
306 return abis_nm_rx_statechg_rep(mb);
307 break;
308 case NM_MT_SW_ACTIVATED_REP:
309 DEBUGPC(DNM, "Software Activated Report\n");
Jonathan Santos5a45b152011-08-17 15:33:57 -0400310 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400311 break;
312 case NM_MT_FAILURE_EVENT_REP:
313 rx_fail_evt_rep(mb);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400314 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400315 break;
316 case NM_MT_TEST_REP:
317 DEBUGPC(DNM, "Test Report\n");
Jonathan Santos5a45b152011-08-17 15:33:57 -0400318 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400319 break;
320 default:
321 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
322 break;
323
324 };
325
326 return 0;
327}
328
329/* Activate the specified software into the BTS */
Jonathan Santos5a45b152011-08-17 15:33:57 -0400330static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
331 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400332{
333 struct abis_om_hdr *oh;
334 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -0400335 uint8_t len = swdesc_len;
336 uint8_t *trailer;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400337
338 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
339 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
340
341 trailer = msgb_put(msg, swdesc_len);
342 memcpy(trailer, sw_desc, swdesc_len);
343
344 return abis_nm_sendmsg(bts, msg);
345}
346
Jonathan Santos5a45b152011-08-17 15:33:57 -0400347static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400348{
349 static const struct tlv_definition sw_descr_def = {
350 .def = {
351 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
352 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
353 },
354 };
355
Jonathan Santos5a45b152011-08-17 15:33:57 -0400356 uint8_t tag;
357 uint16_t tag_len;
358 const uint8_t *val;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400359 int ofs = 0, len;
360
361 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
362 * nested nature and the fact you have to assume it contains only two sub
363 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
364
365 if (sw_descr[0] != NM_ATT_SW_DESCR) {
366 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
367 return -1;
368 }
369 ofs += 1;
370
371 len = tlv_parse_one(&tag, &tag_len, &val,
372 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
373 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
374 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
375 return -2;
376 }
377 ofs += len;
378
379 len = tlv_parse_one(&tag, &tag_len, &val,
380 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
381 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
382 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
383 return -3;
384 }
385 ofs += len;
386
387 return ofs;
388}
389
390static int abis_nm_rx_sw_act_req(struct msgb *mb)
391{
392 struct abis_om_hdr *oh = msgb_l2(mb);
393 struct abis_om_fom_hdr *foh = msgb_l3(mb);
394 struct tlv_parsed tp;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400395 const uint8_t *sw_config;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400396 int ret, sw_config_len, sw_descr_len;
397
Jonathan Santos5a45b152011-08-17 15:33:57 -0400398 abis_nm_debugp_foh(DNM, foh);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400399
400 DEBUGPC(DNM, "SW Activate Request: ");
401
402 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
403
404 ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
405 foh->obj_inst.bts_nr,
406 foh->obj_inst.trx_nr,
407 foh->obj_inst.ts_nr, 0,
408 foh->data, oh->length-sizeof(*foh));
409
410 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
411 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
412 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
413 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
414 DEBUGP(DNM, "SW config not found! Can't continue.\n");
415 return -EINVAL;
416 } else {
Jonathan Santos5a45b152011-08-17 15:33:57 -0400417 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400418 }
419
420 /* Use the first SW_DESCR present in SW config */
421 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
422 if (sw_descr_len < 0)
423 return -EINVAL;
424
425 return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
426 foh->obj_inst.bts_nr,
427 foh->obj_inst.trx_nr,
428 foh->obj_inst.ts_nr,
429 sw_config, sw_descr_len);
430}
431
432/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
433static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
434{
435 struct abis_om_hdr *oh = msgb_l2(mb);
436 struct abis_om_fom_hdr *foh = msgb_l3(mb);
437 struct tlv_parsed tp;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400438 uint8_t adm_state;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400439
440 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
441 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
442 return -EINVAL;
443
444 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
445
446 return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
447}
448
449static int abis_nm_rx_lmt_event(struct msgb *mb)
450{
451 struct abis_om_hdr *oh = msgb_l2(mb);
452 struct abis_om_fom_hdr *foh = msgb_l3(mb);
453 struct tlv_parsed tp;
454
455 DEBUGP(DNM, "LMT Event ");
456 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
457 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
458 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Jonathan Santos5a45b152011-08-17 15:33:57 -0400459 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400460 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
461 }
462 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
463 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Jonathan Santos5a45b152011-08-17 15:33:57 -0400464 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400465 DEBUGPC(DNM, "Level=%u ", level);
466 }
467 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
468 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
469 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
470 DEBUGPC(DNM, "Username=%s ", name);
471 }
472 DEBUGPC(DNM, "\n");
473 /* FIXME: parse LMT LOGON TIME */
474 return 0;
475}
476
477static void abis_nm_queue_send_next(struct gsm_bts *bts)
478{
479 int wait = 0;
480 struct msgb *msg;
481 /* the queue is empty */
482 while (!llist_empty(&bts->abis_queue)) {
483 msg = msgb_dequeue(&bts->abis_queue);
484 wait = OBSC_NM_W_ACK_CB(msg);
485 _abis_nm_sendmsg(msg, 0);
486
487 if (wait)
488 break;
489 }
490
491 bts->abis_nm_pend = wait;
492}
493
494/* Receive a OML NM Message from BTS */
495static int abis_nm_rcvmsg_fom(struct msgb *mb)
496{
497 struct abis_om_hdr *oh = msgb_l2(mb);
498 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Jonathan Santos5a45b152011-08-17 15:33:57 -0400499 uint8_t mt = foh->msg_type;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400500 int ret = 0;
501
502 /* check for unsolicited message */
503 if (is_report(mt))
504 return abis_nm_rcvmsg_report(mb);
505
Jonathan Santos5a45b152011-08-17 15:33:57 -0400506 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400507 return abis_nm_rcvmsg_sw(mb);
508
Jonathan Santos5a45b152011-08-17 15:33:57 -0400509 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400510 struct nm_nack_signal_data nack_data;
511 struct tlv_parsed tp;
512
Jonathan Santos5a45b152011-08-17 15:33:57 -0400513 abis_nm_debugp_foh(DNM, foh);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400514
Jonathan Santos5a45b152011-08-17 15:33:57 -0400515 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400516
517 abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
518 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
519 DEBUGPC(DNM, "CAUSE=%s\n",
Jonathan Santos5a45b152011-08-17 15:33:57 -0400520 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400521 else
522 DEBUGPC(DNM, "\n");
523
524 nack_data.msg = mb;
525 nack_data.mt = mt;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400526 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400527 abis_nm_queue_send_next(mb->trx->bts);
528 return 0;
529 }
530#if 0
531 /* check if last message is to be acked */
532 if (is_ack_nack(nmh->last_msgtype)) {
533 if (mt == MT_ACK(nmh->last_msgtype)) {
534 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
535 /* we got our ACK, continue sending the next msg */
536 } else if (mt == MT_NACK(nmh->last_msgtype)) {
537 /* we got a NACK, signal this to the caller */
538 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
539 /* FIXME: somehow signal this to the caller */
540 } else {
541 /* really strange things happen */
542 return -EINVAL;
543 }
544 }
545#endif
546
547 switch (mt) {
548 case NM_MT_CHG_ADM_STATE_ACK:
549 ret = abis_nm_rx_chg_adm_state_ack(mb);
550 break;
551 case NM_MT_SW_ACT_REQ:
552 ret = abis_nm_rx_sw_act_req(mb);
553 break;
554 case NM_MT_BS11_LMT_SESSION:
555 ret = abis_nm_rx_lmt_event(mb);
556 break;
557 case NM_MT_CONN_MDROP_LINK_ACK:
558 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
559 break;
560 case NM_MT_IPACC_RESTART_ACK:
Jonathan Santos5a45b152011-08-17 15:33:57 -0400561 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400562 break;
563 case NM_MT_IPACC_RESTART_NACK:
Jonathan Santos5a45b152011-08-17 15:33:57 -0400564 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400565 break;
566 case NM_MT_SET_BTS_ATTR_ACK:
567 /* The HSL wants an OPSTART _after_ the SI has been set */
568 if (mb->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
569 abis_nm_opstart(mb->trx->bts, NM_OC_BTS, 255, 255, 255);
570 }
571 break;
572 }
573
574 abis_nm_queue_send_next(mb->trx->bts);
575 return ret;
576}
577
578static int abis_nm_rx_ipacc(struct msgb *mb);
579
580static int abis_nm_rcvmsg_manuf(struct msgb *mb)
581{
582 int rc;
583 int bts_type = mb->trx->bts->type;
584
585 switch (bts_type) {
586 case GSM_BTS_TYPE_NANOBTS:
587 rc = abis_nm_rx_ipacc(mb);
588 abis_nm_queue_send_next(mb->trx->bts);
589 break;
590 default:
591 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
592 "BTS type (%u)\n", bts_type);
593 rc = 0;
594 break;
595 }
596
597 return rc;
598}
599
600/* High-Level API */
601/* Entry-point where L2 OML from BTS enters the NM code */
602int abis_nm_rcvmsg(struct msgb *msg)
603{
604 struct abis_om_hdr *oh = msgb_l2(msg);
605 int rc = 0;
606
607 /* Various consistency checks */
608 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
609 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
610 oh->placement);
611 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
612 return -EINVAL;
613 }
614 if (oh->sequence != 0) {
615 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
616 oh->sequence);
617 return -EINVAL;
618 }
619#if 0
Jonathan Santos5a45b152011-08-17 15:33:57 -0400620 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400621 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
622 if (oh->length + hlen > l2_len) {
623 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
624 oh->length + sizeof(*oh), l2_len);
625 return -EINVAL;
626 }
627 if (oh->length + hlen < l2_len)
628 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);
629#endif
630 msg->l3h = (unsigned char *)oh + sizeof(*oh);
631
632 switch (oh->mdisc) {
633 case ABIS_OM_MDISC_FOM:
634 rc = abis_nm_rcvmsg_fom(msg);
635 break;
636 case ABIS_OM_MDISC_MANUF:
637 rc = abis_nm_rcvmsg_manuf(msg);
638 break;
639 case ABIS_OM_MDISC_MMI:
640 case ABIS_OM_MDISC_TRAU:
641 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
642 oh->mdisc);
643 break;
644 default:
645 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
646 oh->mdisc);
647 return -EINVAL;
648 }
649
650 msgb_free(msg);
651 return rc;
652}
653
654#if 0
655/* initialized all resources */
656struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
657{
658 struct abis_nm_h *nmh;
659
660 nmh = malloc(sizeof(*nmh));
661 if (!nmh)
662 return NULL;
663
664 nmh->cfg = cfg;
665
666 return nmh;
667}
668
669/* free all resources */
670void abis_nm_fini(struct abis_nm_h *nmh)
671{
672 free(nmh);
673}
674#endif
675
676/* Here we are trying to define a high-level API that can be used by
677 * the actual BSC implementation. However, the architecture is currently
678 * still under design. Ideally the calls to this API would be synchronous,
679 * while the underlying stack behind the APi runs in a traditional select
680 * based state machine.
681 */
682
683/* 6.2 Software Load: */
684enum sw_state {
685 SW_STATE_NONE,
686 SW_STATE_WAIT_INITACK,
687 SW_STATE_WAIT_SEGACK,
688 SW_STATE_WAIT_ENDACK,
689 SW_STATE_WAIT_ACTACK,
690 SW_STATE_ERROR,
691};
692
693struct abis_nm_sw {
694 struct gsm_bts *bts;
695 int trx_nr;
696 gsm_cbfn *cbfn;
697 void *cb_data;
698 int forced;
699
700 /* this will become part of the SW LOAD INITIATE */
Jonathan Santos5a45b152011-08-17 15:33:57 -0400701 uint8_t obj_class;
702 uint8_t obj_instance[3];
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400703
Jonathan Santos5a45b152011-08-17 15:33:57 -0400704 uint8_t file_id[255];
705 uint8_t file_id_len;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400706
Jonathan Santos5a45b152011-08-17 15:33:57 -0400707 uint8_t file_version[255];
708 uint8_t file_version_len;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400709
Jonathan Santos5a45b152011-08-17 15:33:57 -0400710 uint8_t window_size;
711 uint8_t seg_in_window;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400712
713 int fd;
714 FILE *stream;
715 enum sw_state state;
716 int last_seg;
717};
718
719static struct abis_nm_sw g_sw;
720
721static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
722{
723 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
724 msgb_v_put(msg, NM_ATT_SW_DESCR);
725 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
726 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
727 sw->file_version);
728 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
729 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
730 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
731 sw->file_version);
732 } else {
733 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
734 }
735}
736
737/* 6.2.1 / 8.3.1: Load Data Initiate */
738static int sw_load_init(struct abis_nm_sw *sw)
739{
740 struct abis_om_hdr *oh;
741 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -0400742 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400743
744 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
745 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
746 sw->obj_instance[0], sw->obj_instance[1],
747 sw->obj_instance[2]);
748
749 sw_add_file_id_and_ver(sw, msg);
750 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
751
752 return abis_nm_sendmsg(sw->bts, msg);
753}
754
755static int is_last_line(FILE *stream)
756{
757 char next_seg_buf[256];
758 long pos;
759
760 /* check if we're sending the last line */
761 pos = ftell(stream);
762 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
763 fseek(stream, pos, SEEK_SET);
764 return 1;
765 }
766
767 fseek(stream, pos, SEEK_SET);
768 return 0;
769}
770
771/* 6.2.2 / 8.3.2 Load Data Segment */
772static int sw_load_segment(struct abis_nm_sw *sw)
773{
774 struct abis_om_hdr *oh;
775 struct msgb *msg = nm_msgb_alloc();
776 char seg_buf[256];
777 char *line_buf = seg_buf+2;
778 unsigned char *tlv;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400779 uint8_t len;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400780
781 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
782
783 switch (sw->bts->type) {
784 case GSM_BTS_TYPE_BS11:
785 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
786 perror("fgets reading segment");
787 return -EINVAL;
788 }
789 seg_buf[0] = 0x00;
790
791 /* check if we're sending the last line */
792 sw->last_seg = is_last_line(sw->stream);
793 if (sw->last_seg)
794 seg_buf[1] = 0;
795 else
796 seg_buf[1] = 1 + sw->seg_in_window++;
797
798 len = strlen(line_buf) + 2;
799 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Jonathan Santos5a45b152011-08-17 15:33:57 -0400800 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400801 /* BS11 wants CR + LF in excess of the TLV length !?! */
802 tlv[1] -= 2;
803
804 /* we only now know the exact length for the OM hdr */
805 len = strlen(line_buf)+2;
806 break;
807 case GSM_BTS_TYPE_NANOBTS: {
Jonathan Santos5a45b152011-08-17 15:33:57 -0400808 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400809 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
810 if (len < 0) {
811 perror("read failed");
812 return -EINVAL;
813 }
814
815 if (len != IPACC_SEGMENT_SIZE)
816 sw->last_seg = 1;
817
818 ++sw->seg_in_window;
Jonathan Santos5a45b152011-08-17 15:33:57 -0400819 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400820 len += 3;
821 break;
822 }
823 default:
824 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
825 /* FIXME: Other BTS types */
826 return -1;
827 }
828
829 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
830 sw->obj_instance[0], sw->obj_instance[1],
831 sw->obj_instance[2]);
832
833 return abis_nm_sendmsg_direct(sw->bts, msg);
834}
835
836/* 6.2.4 / 8.3.4 Load Data End */
837static int sw_load_end(struct abis_nm_sw *sw)
838{
839 struct abis_om_hdr *oh;
840 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -0400841 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400842
843 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
844 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
845 sw->obj_instance[0], sw->obj_instance[1],
846 sw->obj_instance[2]);
847
848 sw_add_file_id_and_ver(sw, msg);
849 return abis_nm_sendmsg(sw->bts, msg);
850}
851
852/* Activate the specified software into the BTS */
853static int sw_activate(struct abis_nm_sw *sw)
854{
855 struct abis_om_hdr *oh;
856 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -0400857 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Jonathan Santos03fd8d02011-05-25 13:54:02 -0400858
859 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
860 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
861 sw->obj_instance[0], sw->obj_instance[1],
862 sw->obj_instance[2]);
863
864 /* FIXME: this is BS11 specific format */
865 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
866 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
867 sw->file_version);
868
869 return abis_nm_sendmsg(sw->bts, msg);
870}
871
872struct sdp_firmware {
873 char magic[4];
874 char more_magic[4];
875 unsigned int header_length;
876 unsigned int file_length;
877} __attribute__ ((packed));
878
879static int parse_sdp_header(struct abis_nm_sw *sw)
880{
881 struct sdp_firmware firmware_header;
882 int rc;
883 struct stat stat;
884
885 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
886 if (rc != sizeof(firmware_header)) {
887 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
888 return -1;
889 }
890
891 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
892 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
893 return -1;
894 }
895
896 if (firmware_header.more_magic[0] != 0x10 ||
897 firmware_header.more_magic[1] != 0x02 ||
898 firmware_header.more_magic[2] != 0x00 ||
899 firmware_header.more_magic[3] != 0x00) {
900 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
901 return -1;
902 }
903
904
905 if (fstat(sw->fd, &stat) == -1) {
906 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
907 return -1;
908 }
909
910 if (ntohl(firmware_header.file_length) != stat.st_size) {
911 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
912 return -1;
913 }
914
915 /* go back to the start as we checked the whole filesize.. */
916 lseek(sw->fd, 0l, SEEK_SET);
917 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
918 "There might be checksums in the file that are not\n"
919 "verified and incomplete firmware might be flashed.\n"
920 "There is absolutely no WARRANTY that flashing will\n"
921 "work.\n");
922 return 0;
923}
924
925static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
926{
927 char file_id[12+1];
928 char file_version[80+1];
929 int rc;
930
931 sw->fd = open(fname, O_RDONLY);
932 if (sw->fd < 0)
933 return sw->fd;
934
935 switch (sw->bts->type) {
936 case GSM_BTS_TYPE_BS11:
937 sw->stream = fdopen(sw->fd, "r");
938 if (!sw->stream) {
939 perror("fdopen");
940 return -1;
941 }
942 /* read first line and parse file ID and VERSION */
943 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
944 file_id, file_version);
945 if (rc != 2) {
946 perror("parsing header line of software file");
947 return -1;
948 }
949 strcpy((char *)sw->file_id, file_id);
950 sw->file_id_len = strlen(file_id);
951 strcpy((char *)sw->file_version, file_version);
952 sw->file_version_len = strlen(file_version);
953 /* rewind to start of file */
954 rewind(sw->stream);
955 break;
956 case GSM_BTS_TYPE_NANOBTS:
957 /* TODO: extract that from the filename or content */
958 rc = parse_sdp_header(sw);
959 if (rc < 0) {
960 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
961 return -1;
962 }
963
964 strcpy((char *)sw->file_id, "id");
965 sw->file_id_len = 3;
966 strcpy((char *)sw->file_version, "version");
967 sw->file_version_len = 8;
968 break;
969 default:
970 /* We don't know how to treat them yet */
971 close(sw->fd);
972 return -EINVAL;
973 }
974
975 return 0;
976}
977
978static void sw_close_file(struct abis_nm_sw *sw)
979{
980 switch (sw->bts->type) {
981 case GSM_BTS_TYPE_BS11:
982 fclose(sw->stream);
983 break;
984 default:
985 close(sw->fd);
986 break;
987 }
988}
989
990/* Fill the window */
991static int sw_fill_window(struct abis_nm_sw *sw)
992{
993 int rc;
994
995 while (sw->seg_in_window < sw->window_size) {
996 rc = sw_load_segment(sw);
997 if (rc < 0)
998 return rc;
999 if (sw->last_seg)
1000 break;
1001 }
1002 return 0;
1003}
1004
1005/* callback function from abis_nm_rcvmsg() handler */
1006static int abis_nm_rcvmsg_sw(struct msgb *mb)
1007{
1008 struct abis_om_fom_hdr *foh = msgb_l3(mb);
1009 int rc = -1;
1010 struct abis_nm_sw *sw = &g_sw;
1011 enum sw_state old_state = sw->state;
1012
1013 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1014
1015 switch (sw->state) {
1016 case SW_STATE_WAIT_INITACK:
1017 switch (foh->msg_type) {
1018 case NM_MT_LOAD_INIT_ACK:
1019 /* fill window with segments */
1020 if (sw->cbfn)
1021 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1022 NM_MT_LOAD_INIT_ACK, mb,
1023 sw->cb_data, NULL);
1024 rc = sw_fill_window(sw);
1025 sw->state = SW_STATE_WAIT_SEGACK;
1026 abis_nm_queue_send_next(mb->trx->bts);
1027 break;
1028 case NM_MT_LOAD_INIT_NACK:
1029 if (sw->forced) {
1030 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1031 "Init NACK\n");
1032 if (sw->cbfn)
1033 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1034 NM_MT_LOAD_INIT_ACK, mb,
1035 sw->cb_data, NULL);
1036 rc = sw_fill_window(sw);
1037 sw->state = SW_STATE_WAIT_SEGACK;
1038 } else {
1039 DEBUGP(DNM, "Software Load Init NACK\n");
1040 /* FIXME: cause */
1041 if (sw->cbfn)
1042 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1043 NM_MT_LOAD_INIT_NACK, mb,
1044 sw->cb_data, NULL);
1045 sw->state = SW_STATE_ERROR;
1046 }
1047 abis_nm_queue_send_next(mb->trx->bts);
1048 break;
1049 }
1050 break;
1051 case SW_STATE_WAIT_SEGACK:
1052 switch (foh->msg_type) {
1053 case NM_MT_LOAD_SEG_ACK:
1054 if (sw->cbfn)
1055 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1056 NM_MT_LOAD_SEG_ACK, mb,
1057 sw->cb_data, NULL);
1058 sw->seg_in_window = 0;
1059 if (!sw->last_seg) {
1060 /* fill window with more segments */
1061 rc = sw_fill_window(sw);
1062 sw->state = SW_STATE_WAIT_SEGACK;
1063 } else {
1064 /* end the transfer */
1065 sw->state = SW_STATE_WAIT_ENDACK;
1066 rc = sw_load_end(sw);
1067 }
1068 abis_nm_queue_send_next(mb->trx->bts);
1069 break;
1070 case NM_MT_LOAD_ABORT:
1071 if (sw->cbfn)
1072 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1073 NM_MT_LOAD_ABORT, mb,
1074 sw->cb_data, NULL);
1075 break;
1076 }
1077 break;
1078 case SW_STATE_WAIT_ENDACK:
1079 switch (foh->msg_type) {
1080 case NM_MT_LOAD_END_ACK:
1081 sw_close_file(sw);
1082 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1083 sw->bts->nr);
1084 sw->state = SW_STATE_NONE;
1085 if (sw->cbfn)
1086 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1087 NM_MT_LOAD_END_ACK, mb,
1088 sw->cb_data, NULL);
1089 rc = 0;
1090 abis_nm_queue_send_next(mb->trx->bts);
1091 break;
1092 case NM_MT_LOAD_END_NACK:
1093 if (sw->forced) {
1094 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1095 "End NACK\n");
1096 sw->state = SW_STATE_NONE;
1097 if (sw->cbfn)
1098 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1099 NM_MT_LOAD_END_ACK, mb,
1100 sw->cb_data, NULL);
1101 } else {
1102 DEBUGP(DNM, "Software Load End NACK\n");
1103 /* FIXME: cause */
1104 sw->state = SW_STATE_ERROR;
1105 if (sw->cbfn)
1106 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1107 NM_MT_LOAD_END_NACK, mb,
1108 sw->cb_data, NULL);
1109 }
1110 abis_nm_queue_send_next(mb->trx->bts);
1111 break;
1112 }
1113 case SW_STATE_WAIT_ACTACK:
1114 switch (foh->msg_type) {
1115 case NM_MT_ACTIVATE_SW_ACK:
1116 /* we're done */
1117 DEBUGP(DNM, "Activate Software DONE!\n");
1118 sw->state = SW_STATE_NONE;
1119 rc = 0;
1120 if (sw->cbfn)
1121 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1122 NM_MT_ACTIVATE_SW_ACK, mb,
1123 sw->cb_data, NULL);
1124 abis_nm_queue_send_next(mb->trx->bts);
1125 break;
1126 case NM_MT_ACTIVATE_SW_NACK:
1127 DEBUGP(DNM, "Activate Software NACK\n");
1128 /* FIXME: cause */
1129 sw->state = SW_STATE_ERROR;
1130 if (sw->cbfn)
1131 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1132 NM_MT_ACTIVATE_SW_NACK, mb,
1133 sw->cb_data, NULL);
1134 abis_nm_queue_send_next(mb->trx->bts);
1135 break;
1136 }
1137 case SW_STATE_NONE:
1138 switch (foh->msg_type) {
1139 case NM_MT_ACTIVATE_SW_ACK:
1140 rc = 0;
1141 break;
1142 }
1143 break;
1144 case SW_STATE_ERROR:
1145 break;
1146 }
1147
1148 if (rc)
1149 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1150 foh->msg_type, old_state, sw->state);
1151
1152 return rc;
1153}
1154
1155/* Load the specified software into the BTS */
1156int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Jonathan Santos5a45b152011-08-17 15:33:57 -04001157 uint8_t win_size, int forced,
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001158 gsm_cbfn *cbfn, void *cb_data)
1159{
1160 struct abis_nm_sw *sw = &g_sw;
1161 int rc;
1162
1163 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1164 bts->nr, fname);
1165
1166 if (sw->state != SW_STATE_NONE)
1167 return -EBUSY;
1168
1169 sw->bts = bts;
1170 sw->trx_nr = trx_nr;
1171
1172 switch (bts->type) {
1173 case GSM_BTS_TYPE_BS11:
1174 sw->obj_class = NM_OC_SITE_MANAGER;
1175 sw->obj_instance[0] = 0xff;
1176 sw->obj_instance[1] = 0xff;
1177 sw->obj_instance[2] = 0xff;
1178 break;
1179 case GSM_BTS_TYPE_NANOBTS:
1180 sw->obj_class = NM_OC_BASEB_TRANSC;
1181 sw->obj_instance[0] = sw->bts->nr;
1182 sw->obj_instance[1] = sw->trx_nr;
1183 sw->obj_instance[2] = 0xff;
1184 break;
1185 case GSM_BTS_TYPE_UNKNOWN:
1186 default:
1187 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1188 return -1;
1189 break;
1190 }
1191 sw->window_size = win_size;
1192 sw->state = SW_STATE_WAIT_INITACK;
1193 sw->cbfn = cbfn;
1194 sw->cb_data = cb_data;
1195 sw->forced = forced;
1196
1197 rc = sw_open_file(sw, fname);
1198 if (rc < 0) {
1199 sw->state = SW_STATE_NONE;
1200 return rc;
1201 }
1202
1203 return sw_load_init(sw);
1204}
1205
1206int abis_nm_software_load_status(struct gsm_bts *bts)
1207{
1208 struct abis_nm_sw *sw = &g_sw;
1209 struct stat st;
1210 int rc, percent;
1211
1212 rc = fstat(sw->fd, &st);
1213 if (rc < 0) {
1214 perror("ERROR during stat");
1215 return rc;
1216 }
1217
1218 if (sw->stream)
1219 percent = (ftell(sw->stream) * 100) / st.st_size;
1220 else
1221 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
1222 return percent;
1223}
1224
1225/* Activate the specified software into the BTS */
1226int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1227 gsm_cbfn *cbfn, void *cb_data)
1228{
1229 struct abis_nm_sw *sw = &g_sw;
1230 int rc;
1231
1232 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1233 bts->nr, fname);
1234
1235 if (sw->state != SW_STATE_NONE)
1236 return -EBUSY;
1237
1238 sw->bts = bts;
1239 sw->obj_class = NM_OC_SITE_MANAGER;
1240 sw->obj_instance[0] = 0xff;
1241 sw->obj_instance[1] = 0xff;
1242 sw->obj_instance[2] = 0xff;
1243 sw->state = SW_STATE_WAIT_ACTACK;
1244 sw->cbfn = cbfn;
1245 sw->cb_data = cb_data;
1246
1247 /* Open the file in order to fill some sw struct members */
1248 rc = sw_open_file(sw, fname);
1249 if (rc < 0) {
1250 sw->state = SW_STATE_NONE;
1251 return rc;
1252 }
1253 sw_close_file(sw);
1254
1255 return sw_activate(sw);
1256}
1257
Jonathan Santos5a45b152011-08-17 15:33:57 -04001258static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1259 uint8_t ts_nr, uint8_t subslot_nr)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001260{
1261 ch->attrib = NM_ATT_ABIS_CHANNEL;
1262 ch->bts_port = bts_port;
1263 ch->timeslot = ts_nr;
1264 ch->subslot = subslot_nr;
1265}
1266
Jonathan Santos5a45b152011-08-17 15:33:57 -04001267int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1268 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1269 uint8_t tei)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001270{
1271 struct abis_om_hdr *oh;
1272 struct abis_nm_channel *ch;
Jonathan Santos5a45b152011-08-17 15:33:57 -04001273 uint8_t len = sizeof(*ch) + 2;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001274 struct msgb *msg = nm_msgb_alloc();
1275
1276 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1277 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1278 bts->bts_nr, trx_nr, 0xff);
1279
1280 msgb_tv_put(msg, NM_ATT_TEI, tei);
1281
1282 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1283 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1284
1285 return abis_nm_sendmsg(bts, msg);
1286}
1287
1288/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1289int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Jonathan Santos5a45b152011-08-17 15:33:57 -04001290 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001291{
1292 struct gsm_bts *bts = trx->bts;
1293 struct abis_om_hdr *oh;
1294 struct abis_nm_channel *ch;
1295 struct msgb *msg = nm_msgb_alloc();
1296
1297 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1298 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1299 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1300
1301 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1302 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1303
1304 return abis_nm_sendmsg(bts, msg);
1305}
1306
1307#if 0
1308int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1309 struct abis_nm_abis_channel *chan)
1310{
1311}
1312#endif
1313
1314int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Jonathan Santos5a45b152011-08-17 15:33:57 -04001315 uint8_t e1_port, uint8_t e1_timeslot,
1316 uint8_t e1_subslot)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001317{
1318 struct gsm_bts *bts = ts->trx->bts;
1319 struct abis_om_hdr *oh;
1320 struct abis_nm_channel *ch;
1321 struct msgb *msg = nm_msgb_alloc();
1322
1323 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1324 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1325 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1326
1327 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1328 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1329
1330 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1331 gsm_ts_name(ts),
1332 e1_port, e1_timeslot, e1_subslot);
1333
1334 return abis_nm_sendmsg(bts, msg);
1335}
1336
1337#if 0
1338int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1339 struct abis_nm_abis_channel *chan,
Jonathan Santos5a45b152011-08-17 15:33:57 -04001340 uint8_t subchan)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001341{
1342}
1343#endif
1344
1345/* Chapter 8.6.1 */
Jonathan Santos5a45b152011-08-17 15:33:57 -04001346int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001347{
1348 struct abis_om_hdr *oh;
1349 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001350 uint8_t *cur;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001351
1352 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1353
1354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1355 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1356 cur = msgb_put(msg, attr_len);
1357 memcpy(cur, attr, attr_len);
1358
1359 return abis_nm_sendmsg(bts, msg);
1360}
1361
1362/* Chapter 8.6.2 */
Jonathan Santos5a45b152011-08-17 15:33:57 -04001363int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001364{
1365 struct abis_om_hdr *oh;
1366 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001367 uint8_t *cur;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001368
1369 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1370
1371 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1372 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1373 trx->bts->bts_nr, trx->nr, 0xff);
1374 cur = msgb_put(msg, attr_len);
1375 memcpy(cur, attr, attr_len);
1376
1377 return abis_nm_sendmsg(trx->bts, msg);
1378}
1379
Jonathan Santos5a45b152011-08-17 15:33:57 -04001380static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001381{
1382 int i;
1383
1384 /* As it turns out, the BS-11 has some very peculiar restrictions
1385 * on the channel combinations it allows */
1386 switch (ts->trx->bts->type) {
1387 case GSM_BTS_TYPE_BS11:
1388 switch (chan_comb) {
1389 case NM_CHANC_TCHHalf:
1390 case NM_CHANC_TCHHalf2:
1391 /* not supported */
1392 return -EINVAL;
1393 case NM_CHANC_SDCCH:
1394 /* only one SDCCH/8 per TRX */
1395 for (i = 0; i < TRX_NR_TS; i++) {
1396 if (i == ts->nr)
1397 continue;
1398 if (ts->trx->ts[i].nm_chan_comb ==
1399 NM_CHANC_SDCCH)
1400 return -EINVAL;
1401 }
1402 /* not allowed for TS0 of BCCH-TRX */
1403 if (ts->trx == ts->trx->bts->c0 &&
1404 ts->nr == 0)
1405 return -EINVAL;
1406 /* not on the same TRX that has a BCCH+SDCCH4
1407 * combination */
1408 if (ts->trx == ts->trx->bts->c0 &&
1409 (ts->trx->ts[0].nm_chan_comb == 5 ||
1410 ts->trx->ts[0].nm_chan_comb == 8))
1411 return -EINVAL;
1412 break;
1413 case NM_CHANC_mainBCCH:
1414 case NM_CHANC_BCCHComb:
1415 /* allowed only for TS0 of C0 */
1416 if (ts->trx != ts->trx->bts->c0 ||
1417 ts->nr != 0)
1418 return -EINVAL;
1419 break;
1420 case NM_CHANC_BCCH:
1421 /* allowed only for TS 2/4/6 of C0 */
1422 if (ts->trx != ts->trx->bts->c0)
1423 return -EINVAL;
1424 if (ts->nr != 2 && ts->nr != 4 &&
1425 ts->nr != 6)
1426 return -EINVAL;
1427 break;
1428 case 8: /* this is not like 08.58, but in fact
1429 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1430 /* FIXME: only one CBCH allowed per cell */
1431 break;
1432 }
1433 break;
1434 case GSM_BTS_TYPE_NANOBTS:
1435 switch (ts->nr) {
1436 case 0:
1437 if (ts->trx->nr == 0) {
1438 /* only on TRX0 */
1439 switch (chan_comb) {
1440 case NM_CHANC_BCCH:
1441 case NM_CHANC_mainBCCH:
1442 case NM_CHANC_BCCHComb:
1443 return 0;
1444 break;
1445 default:
1446 return -EINVAL;
1447 }
1448 } else {
1449 switch (chan_comb) {
1450 case NM_CHANC_TCHFull:
1451 case NM_CHANC_TCHHalf:
1452 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1453 return 0;
1454 default:
1455 return -EINVAL;
1456 }
1457 }
1458 break;
1459 case 1:
1460 if (ts->trx->nr == 0) {
1461 switch (chan_comb) {
1462 case NM_CHANC_SDCCH_CBCH:
1463 if (ts->trx->ts[0].nm_chan_comb ==
1464 NM_CHANC_mainBCCH)
1465 return 0;
1466 return -EINVAL;
1467 case NM_CHANC_SDCCH:
1468 case NM_CHANC_TCHFull:
1469 case NM_CHANC_TCHHalf:
1470 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1471 case NM_CHANC_IPAC_TCHFull_PDCH:
1472 return 0;
1473 }
1474 } else {
1475 switch (chan_comb) {
1476 case NM_CHANC_SDCCH:
1477 case NM_CHANC_TCHFull:
1478 case NM_CHANC_TCHHalf:
1479 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1480 return 0;
1481 default:
1482 return -EINVAL;
1483 }
1484 }
1485 break;
1486 case 2:
1487 case 3:
1488 case 4:
1489 case 5:
1490 case 6:
1491 case 7:
1492 switch (chan_comb) {
1493 case NM_CHANC_TCHFull:
1494 case NM_CHANC_TCHHalf:
1495 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1496 return 0;
1497 case NM_CHANC_IPAC_PDCH:
1498 case NM_CHANC_IPAC_TCHFull_PDCH:
1499 if (ts->trx->nr == 0)
1500 return 0;
1501 else
1502 return -EINVAL;
1503 }
1504 break;
1505 }
1506 return -EINVAL;
1507 default:
1508 /* unknown BTS type */
1509 return 0;
1510 }
1511 return 0;
1512}
1513
1514/* Chapter 8.6.3 */
Jonathan Santos5a45b152011-08-17 15:33:57 -04001515int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001516{
1517 struct gsm_bts *bts = ts->trx->bts;
1518 struct abis_om_hdr *oh;
Jonathan Santos5a45b152011-08-17 15:33:57 -04001519 uint8_t zero = 0x00;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001520 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001521 uint8_t len = 2 + 2;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001522
1523 if (bts->type == GSM_BTS_TYPE_BS11)
1524 len += 4 + 2 + 2 + 3;
1525
1526 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
1527 if (verify_chan_comb(ts, chan_comb) < 0) {
1528 msgb_free(msg);
1529 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1530 return -EINVAL;
1531 }
1532 ts->nm_chan_comb = chan_comb;
1533
1534 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1535 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1536 NM_OC_CHANNEL, bts->bts_nr,
1537 ts->trx->nr, ts->nr);
1538 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
1539 if (ts->hopping.enabled) {
1540 unsigned int i;
1541 uint8_t *len;
1542
1543 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1544 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
1545
1546 /* build the ARFCN list */
1547 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1548 len = msgb_put(msg, 1);
1549 *len = 0;
1550 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1551 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1552 msgb_put_u16(msg, i);
1553 /* At least BS-11 wants a TLV16 here */
1554 if (bts->type == GSM_BTS_TYPE_BS11)
1555 *len += 1;
1556 else
1557 *len += sizeof(uint16_t);
1558 }
1559 }
1560 }
Jonathan Santos5a45b152011-08-17 15:33:57 -04001561 if (ts->tsc == -1)
1562 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1563 else
1564 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001565 if (bts->type == GSM_BTS_TYPE_BS11)
1566 msgb_tlv_put(msg, 0x59, 1, &zero);
1567
1568 return abis_nm_sendmsg(bts, msg);
1569}
1570
Jonathan Santos5a45b152011-08-17 15:33:57 -04001571int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1572 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001573{
1574 struct abis_om_hdr *oh;
1575 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001576 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1577 uint8_t len = att_len;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001578
1579 if (nack) {
1580 len += 2;
1581 msgtype = NM_MT_SW_ACT_REQ_NACK;
1582 }
1583
1584 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1585 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1586
1587 if (attr) {
Jonathan Santos5a45b152011-08-17 15:33:57 -04001588 uint8_t *ptr = msgb_put(msg, att_len);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001589 memcpy(ptr, attr, att_len);
1590 }
1591 if (nack)
1592 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1593
1594 return abis_nm_sendmsg_direct(bts, msg);
1595}
1596
Jonathan Santos5a45b152011-08-17 15:33:57 -04001597int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001598{
1599 struct msgb *msg = nm_msgb_alloc();
1600 struct abis_om_hdr *oh;
Jonathan Santos5a45b152011-08-17 15:33:57 -04001601 uint8_t *data;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001602
1603 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1604 fill_om_hdr(oh, len);
1605 data = msgb_put(msg, len);
1606 memcpy(data, rawmsg, len);
1607
1608 return abis_nm_sendmsg(bts, msg);
1609}
1610
1611/* Siemens specific commands */
Jonathan Santos5a45b152011-08-17 15:33:57 -04001612static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001613{
1614 struct abis_om_hdr *oh;
1615 struct msgb *msg = nm_msgb_alloc();
1616
1617 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1618 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1619 0xff, 0xff, 0xff);
1620
1621 return abis_nm_sendmsg(bts, msg);
1622}
1623
1624/* Chapter 8.9.2 */
Jonathan Santos5a45b152011-08-17 15:33:57 -04001625int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001626{
1627 struct abis_om_hdr *oh;
1628 struct msgb *msg = nm_msgb_alloc();
1629
1630 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1631 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1632
Jonathan Santos5a45b152011-08-17 15:33:57 -04001633 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001634 DEBUGPC(DNM, "Sending OPSTART\n");
1635
1636 return abis_nm_sendmsg(bts, msg);
1637}
1638
1639/* Chapter 8.8.5 */
Jonathan Santos5a45b152011-08-17 15:33:57 -04001640int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1641 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001642{
1643 struct abis_om_hdr *oh;
1644 struct msgb *msg = nm_msgb_alloc();
1645
1646 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1647 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1648 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1649
1650 return abis_nm_sendmsg(bts, msg);
1651}
1652
Jonathan Santos5a45b152011-08-17 15:33:57 -04001653int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1654 uint8_t e1_port1, uint8_t ts1)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001655{
1656 struct abis_om_hdr *oh;
1657 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001658 uint8_t *attr;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001659
1660 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1661 e1_port0, ts0, e1_port1, ts1);
1662
1663 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1664 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1665 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1666
1667 attr = msgb_put(msg, 3);
1668 attr[0] = NM_ATT_MDROP_LINK;
1669 attr[1] = e1_port0;
1670 attr[2] = ts0;
1671
1672 attr = msgb_put(msg, 3);
1673 attr[0] = NM_ATT_MDROP_NEXT;
1674 attr[1] = e1_port1;
1675 attr[2] = ts1;
1676
1677 return abis_nm_sendmsg(bts, msg);
1678}
1679
1680/* Chapter 8.7.1 */
Jonathan Santos5a45b152011-08-17 15:33:57 -04001681int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1682 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1683 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001684{
1685 struct abis_om_hdr *oh;
1686
Jonathan Santos5a45b152011-08-17 15:33:57 -04001687 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001688
1689 if (!msg)
1690 msg = nm_msgb_alloc();
1691
1692 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1693 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1694 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1695 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
1696 obj_class, bts_nr, trx_nr, ts_nr);
1697
1698 return abis_nm_sendmsg(bts, msg);
1699}
1700
1701int abis_nm_event_reports(struct gsm_bts *bts, int on)
1702{
1703 if (on == 0)
1704 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1705 else
1706 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1707}
1708
1709/* Siemens (or BS-11) specific commands */
1710
1711int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1712{
1713 if (reconnect == 0)
1714 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1715 else
1716 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1717}
1718
1719int abis_nm_bs11_restart(struct gsm_bts *bts)
1720{
1721 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1722}
1723
1724
1725struct bs11_date_time {
Jonathan Santos5a45b152011-08-17 15:33:57 -04001726 uint16_t year;
1727 uint8_t month;
1728 uint8_t day;
1729 uint8_t hour;
1730 uint8_t min;
1731 uint8_t sec;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001732} __attribute__((packed));
1733
1734
1735void get_bs11_date_time(struct bs11_date_time *aet)
1736{
1737 time_t t;
1738 struct tm *tm;
1739
1740 t = time(NULL);
1741 tm = localtime(&t);
1742 aet->sec = tm->tm_sec;
1743 aet->min = tm->tm_min;
1744 aet->hour = tm->tm_hour;
1745 aet->day = tm->tm_mday;
1746 aet->month = tm->tm_mon;
1747 aet->year = htons(1900 + tm->tm_year);
1748}
1749
1750int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1751{
1752 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1753}
1754
1755int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1756{
1757 if (begin)
1758 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1759 else
1760 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1761}
1762
1763int abis_nm_bs11_create_object(struct gsm_bts *bts,
Jonathan Santos5a45b152011-08-17 15:33:57 -04001764 enum abis_bs11_objtype type, uint8_t idx,
1765 uint8_t attr_len, const uint8_t *attr)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001766{
1767 struct abis_om_hdr *oh;
1768 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001769 uint8_t *cur;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001770
1771 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1772 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1773 NM_OC_BS11, type, 0, idx);
1774 cur = msgb_put(msg, attr_len);
1775 memcpy(cur, attr, attr_len);
1776
1777 return abis_nm_sendmsg(bts, msg);
1778}
1779
1780int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Jonathan Santos5a45b152011-08-17 15:33:57 -04001781 enum abis_bs11_objtype type, uint8_t idx)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001782{
1783 struct abis_om_hdr *oh;
1784 struct msgb *msg = nm_msgb_alloc();
1785
1786 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1787 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1788 NM_OC_BS11, type, 0, idx);
1789
1790 return abis_nm_sendmsg(bts, msg);
1791}
1792
Jonathan Santos5a45b152011-08-17 15:33:57 -04001793int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001794{
1795 struct abis_om_hdr *oh;
1796 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001797 uint8_t zero = 0x00;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001798
1799 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1800 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1801 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1802 msgb_tlv_put(msg, 0x99, 1, &zero);
1803
1804 return abis_nm_sendmsg(bts, msg);
1805}
1806
Jonathan Santos5a45b152011-08-17 15:33:57 -04001807int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001808{
1809 struct abis_om_hdr *oh;
1810 struct msgb *msg = nm_msgb_alloc();
1811
1812 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1813 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
1814 idx, 0xff, 0xff);
1815
1816 return abis_nm_sendmsg(bts, msg);
1817}
1818
Jonathan Santos5a45b152011-08-17 15:33:57 -04001819int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001820{
1821 struct abis_om_hdr *oh;
1822 struct msgb *msg = nm_msgb_alloc();
1823
1824 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1825 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1826 idx, 0xff, 0xff);
1827
1828 return abis_nm_sendmsg(bts, msg);
1829}
1830
Jonathan Santos5a45b152011-08-17 15:33:57 -04001831static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001832int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1833{
1834 struct abis_om_hdr *oh;
1835 struct msgb *msg = nm_msgb_alloc();
1836
1837 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1838 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1839 0xff, 0xff, 0xff);
1840 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1841
1842 return abis_nm_sendmsg(bts, msg);
1843}
1844
1845/* like abis_nm_conn_terr_traf + set_tei */
Jonathan Santos5a45b152011-08-17 15:33:57 -04001846int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1847 uint8_t e1_timeslot, uint8_t e1_subslot,
1848 uint8_t tei)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001849{
1850 struct abis_om_hdr *oh;
1851 struct abis_nm_channel *ch;
1852 struct msgb *msg = nm_msgb_alloc();
1853
1854 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1855 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1856 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1857
1858 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1859 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1860 msgb_tv_put(msg, NM_ATT_TEI, tei);
1861
1862 return abis_nm_sendmsg(bts, msg);
1863}
1864
Jonathan Santos5a45b152011-08-17 15:33:57 -04001865int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001866{
1867 struct abis_om_hdr *oh;
1868 struct msgb *msg = nm_msgb_alloc();
1869
1870 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1871 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
1872 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1873 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1874
1875 return abis_nm_sendmsg(trx->bts, msg);
1876}
1877
1878int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1879{
1880 struct abis_om_hdr *oh;
1881 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001882 uint8_t attr = NM_ATT_BS11_TXPWR;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001883
1884 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1885 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1886 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1887 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1888
1889 return abis_nm_sendmsg(trx->bts, msg);
1890}
1891
1892int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1893{
1894 struct abis_om_hdr *oh;
1895 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001896 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001897
1898 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1899 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1900 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
1901 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1902
1903 return abis_nm_sendmsg(bts, msg);
1904}
1905
1906int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1907{
1908 struct abis_om_hdr *oh;
1909 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04001910 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001911 NM_ATT_BS11_CCLK_TYPE };
1912
1913 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1914 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1915 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1916 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1917
1918 return abis_nm_sendmsg(bts, msg);
1919
1920}
1921
Jonathan Santos5a45b152011-08-17 15:33:57 -04001922//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001923
1924int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
1925{
1926 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1927}
1928
1929int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1930{
1931 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1932}
1933
Jonathan Santos5a45b152011-08-17 15:33:57 -04001934int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001935{
1936 struct abis_om_hdr *oh;
1937 struct msgb *msg = nm_msgb_alloc();
1938 struct bs11_date_time bdt;
1939
1940 get_bs11_date_time(&bdt);
1941
1942 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1943 if (on) {
Jonathan Santos5a45b152011-08-17 15:33:57 -04001944 uint8_t len = 3*2 + sizeof(bdt)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001945 + 1 + strlen(name);
1946 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
1947 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1948 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Jonathan Santos5a45b152011-08-17 15:33:57 -04001949 sizeof(bdt), (uint8_t *) &bdt);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001950 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
1951 1, &level);
1952 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Jonathan Santos5a45b152011-08-17 15:33:57 -04001953 strlen(name), (uint8_t *)name);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001954 } else {
1955 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
1956 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1957 }
1958
1959 return abis_nm_sendmsg(bts, msg);
1960}
1961
1962int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1963{
1964 struct abis_om_hdr *oh;
1965 struct msgb *msg;
1966
1967 if (strlen(password) != 10)
1968 return -EINVAL;
1969
1970 msg = nm_msgb_alloc();
1971 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1972 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
1973 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Jonathan Santos5a45b152011-08-17 15:33:57 -04001974 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001975
1976 return abis_nm_sendmsg(bts, msg);
1977}
1978
1979/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
1980int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
1981{
1982 struct abis_om_hdr *oh;
1983 struct msgb *msg;
Jonathan Santos5a45b152011-08-17 15:33:57 -04001984 uint8_t tlv_value;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001985
1986 msg = nm_msgb_alloc();
1987 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1988 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
1989 BS11_OBJ_LI, 0x00, 0x00);
1990
1991 if (locked)
1992 tlv_value = BS11_LI_PLL_LOCKED;
1993 else
1994 tlv_value = BS11_LI_PLL_STANDALONE;
1995
1996 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
1997
1998 return abis_nm_sendmsg(bts, msg);
1999}
2000
2001/* Set the calibration value of the PLL (work value/set value)
2002 * It depends on the login which one is changed */
2003int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2004{
2005 struct abis_om_hdr *oh;
2006 struct msgb *msg;
Jonathan Santos5a45b152011-08-17 15:33:57 -04002007 uint8_t tlv_value[2];
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002008
2009 msg = nm_msgb_alloc();
2010 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2011 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2012 BS11_OBJ_TRX1, 0x00, 0x00);
2013
2014 tlv_value[0] = value>>8;
2015 tlv_value[1] = value&0xff;
2016
2017 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2018
2019 return abis_nm_sendmsg(bts, msg);
2020}
2021
2022int abis_nm_bs11_get_state(struct gsm_bts *bts)
2023{
2024 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2025}
2026
2027/* BS11 SWL */
2028
2029void *tall_fle_ctx;
2030
2031struct abis_nm_bs11_sw {
2032 struct gsm_bts *bts;
2033 char swl_fname[PATH_MAX];
Jonathan Santos5a45b152011-08-17 15:33:57 -04002034 uint8_t win_size;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002035 int forced;
2036 struct llist_head file_list;
2037 gsm_cbfn *user_cb; /* specified by the user */
2038};
2039static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2040
2041struct file_list_entry {
2042 struct llist_head list;
2043 char fname[PATH_MAX];
2044};
2045
2046struct file_list_entry *fl_dequeue(struct llist_head *queue)
2047{
2048 struct llist_head *lh;
2049
2050 if (llist_empty(queue))
2051 return NULL;
2052
2053 lh = queue->next;
2054 llist_del(lh);
2055
2056 return llist_entry(lh, struct file_list_entry, list);
2057}
2058
2059static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2060{
2061 char linebuf[255];
2062 struct llist_head *lh, *lh2;
2063 FILE *swl;
2064 int rc = 0;
2065
2066 swl = fopen(bs11_sw->swl_fname, "r");
2067 if (!swl)
2068 return -ENODEV;
2069
2070 /* zero the stale file list, if any */
2071 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2072 llist_del(lh);
2073 talloc_free(lh);
2074 }
2075
2076 while (fgets(linebuf, sizeof(linebuf), swl)) {
2077 char file_id[12+1];
2078 char file_version[80+1];
2079 struct file_list_entry *fle;
2080 static char dir[PATH_MAX];
2081
2082 if (strlen(linebuf) < 4)
2083 continue;
2084
2085 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2086 if (rc < 0) {
2087 perror("ERR parsing SWL file");
2088 rc = -EINVAL;
2089 goto out;
2090 }
2091 if (rc < 2)
2092 continue;
2093
2094 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
2095 if (!fle) {
2096 rc = -ENOMEM;
2097 goto out;
2098 }
2099
2100 /* construct new filename */
2101 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2102 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2103 strcat(fle->fname, "/");
2104 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2105
2106 llist_add_tail(&fle->list, &bs11_sw->file_list);
2107 }
2108
2109out:
2110 fclose(swl);
2111 return rc;
2112}
2113
2114/* bs11 swload specific callback, passed to abis_nm core swload */
2115static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2116 struct msgb *msg, void *data, void *param)
2117{
2118 struct abis_nm_bs11_sw *bs11_sw = data;
2119 struct file_list_entry *fle;
2120 int rc = 0;
2121
2122 switch (event) {
2123 case NM_MT_LOAD_END_ACK:
2124 fle = fl_dequeue(&bs11_sw->file_list);
2125 if (fle) {
2126 /* start download the next file of our file list */
2127 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
2128 bs11_sw->win_size,
2129 bs11_sw->forced,
2130 &bs11_swload_cbfn, bs11_sw);
2131 talloc_free(fle);
2132 } else {
2133 /* activate the SWL */
2134 rc = abis_nm_software_activate(bs11_sw->bts,
2135 bs11_sw->swl_fname,
2136 bs11_swload_cbfn,
2137 bs11_sw);
2138 }
2139 break;
2140 case NM_MT_LOAD_SEG_ACK:
2141 case NM_MT_LOAD_END_NACK:
2142 case NM_MT_LOAD_INIT_ACK:
2143 case NM_MT_LOAD_INIT_NACK:
2144 case NM_MT_ACTIVATE_SW_NACK:
2145 case NM_MT_ACTIVATE_SW_ACK:
2146 default:
2147 /* fallthrough to the user callback */
2148 if (bs11_sw->user_cb)
2149 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2150 break;
2151 }
2152
2153 return rc;
2154}
2155
2156/* Siemens provides a SWL file that is a mere listing of all the other
2157 * files that are part of a software release. We need to upload first
2158 * the list file, and then each file that is listed in the list file */
2159int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Jonathan Santos5a45b152011-08-17 15:33:57 -04002160 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002161{
2162 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2163 struct file_list_entry *fle;
2164 int rc = 0;
2165
2166 INIT_LLIST_HEAD(&bs11_sw->file_list);
2167 bs11_sw->bts = bts;
2168 bs11_sw->win_size = win_size;
2169 bs11_sw->user_cb = cbfn;
2170 bs11_sw->forced = forced;
2171
2172 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2173 rc = bs11_read_swl_file(bs11_sw);
2174 if (rc < 0)
2175 return rc;
2176
2177 /* dequeue next item in file list */
2178 fle = fl_dequeue(&bs11_sw->file_list);
2179 if (!fle)
2180 return -EINVAL;
2181
2182 /* start download the next file of our file list */
2183 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
2184 bs11_swload_cbfn, bs11_sw);
2185 talloc_free(fle);
2186 return rc;
2187}
2188
2189#if 0
Jonathan Santos5a45b152011-08-17 15:33:57 -04002190static uint8_t req_attr_btse[] = {
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002191 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2192 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2193 NM_ATT_BS11_LMT_USER_NAME,
2194
2195 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2196
2197 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2198
2199 NM_ATT_BS11_SW_LOAD_STORED };
2200
Jonathan Santos5a45b152011-08-17 15:33:57 -04002201static uint8_t req_attr_btsm[] = {
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002202 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2203 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2204 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2205 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2206#endif
2207
Jonathan Santos5a45b152011-08-17 15:33:57 -04002208static uint8_t req_attr[] = {
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002209 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2210 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2211 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2212
2213int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2214{
2215 struct abis_om_hdr *oh;
2216 struct msgb *msg = nm_msgb_alloc();
2217
2218 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2219 /* SiemensHW CCTRL object */
2220 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2221 0x03, 0x00, 0x00);
2222 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2223
2224 return abis_nm_sendmsg(bts, msg);
2225}
2226
2227int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2228{
2229 struct abis_om_hdr *oh;
2230 struct msgb *msg = nm_msgb_alloc();
2231 struct bs11_date_time aet;
2232
2233 get_bs11_date_time(&aet);
2234 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2235 /* SiemensHW CCTRL object */
2236 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2237 0xff, 0xff, 0xff);
Jonathan Santos5a45b152011-08-17 15:33:57 -04002238 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002239
2240 return abis_nm_sendmsg(bts, msg);
2241}
2242
Jonathan Santos5a45b152011-08-17 15:33:57 -04002243int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002244{
2245 struct abis_om_hdr *oh;
2246 struct msgb *msg = nm_msgb_alloc();
Jonathan Santos5a45b152011-08-17 15:33:57 -04002247 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002248
2249 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2250 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2251 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2252 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2253
2254 return abis_nm_sendmsg(bts, msg);
2255}
2256
Jonathan Santos5a45b152011-08-17 15:33:57 -04002257int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002258{
2259 struct abis_om_hdr *oh;
2260 struct msgb *msg = nm_msgb_alloc();
2261 struct bs11_date_time aet;
2262
2263 get_bs11_date_time(&aet);
2264 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2265 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2266 bport, 0xff, 0x02);
2267 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2268
2269 return abis_nm_sendmsg(bts, msg);
2270}
2271
2272/* ip.access nanoBTS specific commands */
2273static const char ipaccess_magic[] = "com.ipaccess";
2274
2275
2276static int abis_nm_rx_ipacc(struct msgb *msg)
2277{
2278 struct in_addr addr;
2279 struct abis_om_hdr *oh = msgb_l2(msg);
2280 struct abis_om_fom_hdr *foh;
Jonathan Santos5a45b152011-08-17 15:33:57 -04002281 uint8_t idstrlen = oh->data[0];
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002282 struct tlv_parsed tp;
2283 struct ipacc_ack_signal_data signal;
2284
2285 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
2286 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
2287 return -EINVAL;
2288 }
2289
2290 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
2291 abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
2292
Jonathan Santos5a45b152011-08-17 15:33:57 -04002293 abis_nm_debugp_foh(DNM, foh);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002294
2295 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
2296
2297 switch (foh->msg_type) {
2298 case NM_MT_IPACC_RSL_CONNECT_ACK:
2299 DEBUGPC(DNM, "RSL CONNECT ACK ");
2300 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2301 memcpy(&addr,
2302 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2303
2304 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2305 }
2306 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
2307 DEBUGPC(DNM, "PORT=%u ",
Jonathan Santos5a45b152011-08-17 15:33:57 -04002308 ntohs(*((uint16_t *)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002309 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
2310 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2311 DEBUGPC(DNM, "STREAM=0x%02x ",
2312 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
2313 DEBUGPC(DNM, "\n");
2314 break;
2315 case NM_MT_IPACC_RSL_CONNECT_NACK:
2316 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
2317 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2318 DEBUGPC(DNM, " CAUSE=%s\n",
Jonathan Santos5a45b152011-08-17 15:33:57 -04002319 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002320 else
2321 DEBUGPC(DNM, "\n");
2322 break;
2323 case NM_MT_IPACC_SET_NVATTR_ACK:
2324 DEBUGPC(DNM, "SET NVATTR ACK\n");
2325 /* FIXME: decode and show the actual attributes */
2326 break;
2327 case NM_MT_IPACC_SET_NVATTR_NACK:
2328 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
2329 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2330 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Jonathan Santos5a45b152011-08-17 15:33:57 -04002331 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002332 else
2333 LOGPC(DNM, LOGL_ERROR, "\n");
2334 break;
2335 case NM_MT_IPACC_GET_NVATTR_ACK:
2336 DEBUGPC(DNM, "GET NVATTR ACK\n");
2337 /* FIXME: decode and show the actual attributes */
2338 break;
2339 case NM_MT_IPACC_GET_NVATTR_NACK:
2340 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
2341 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2342 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Jonathan Santos5a45b152011-08-17 15:33:57 -04002343 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002344 else
2345 LOGPC(DNM, LOGL_ERROR, "\n");
2346 break;
2347 case NM_MT_IPACC_SET_ATTR_ACK:
2348 DEBUGPC(DNM, "SET ATTR ACK\n");
2349 break;
2350 case NM_MT_IPACC_SET_ATTR_NACK:
2351 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
2352 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
2353 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Jonathan Santos5a45b152011-08-17 15:33:57 -04002354 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002355 else
2356 LOGPC(DNM, LOGL_ERROR, "\n");
2357 break;
2358 default:
2359 DEBUGPC(DNM, "unknown\n");
2360 break;
2361 }
2362
2363 /* signal handling */
2364 switch (foh->msg_type) {
2365 case NM_MT_IPACC_RSL_CONNECT_NACK:
2366 case NM_MT_IPACC_SET_NVATTR_NACK:
2367 case NM_MT_IPACC_GET_NVATTR_NACK:
2368 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
2369 signal.msg_type = foh->msg_type;
Jonathan Santos5a45b152011-08-17 15:33:57 -04002370 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002371 break;
2372 case NM_MT_IPACC_SET_NVATTR_ACK:
2373 signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
2374 signal.msg_type = foh->msg_type;
Jonathan Santos5a45b152011-08-17 15:33:57 -04002375 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002376 break;
2377 default:
2378 break;
2379 }
2380
2381 return 0;
2382}
2383
2384/* send an ip-access manufacturer specific message */
Jonathan Santos5a45b152011-08-17 15:33:57 -04002385int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2386 uint8_t obj_class, uint8_t bts_nr,
2387 uint8_t trx_nr, uint8_t ts_nr,
2388 uint8_t *attr, int attr_len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002389{
2390 struct msgb *msg = nm_msgb_alloc();
2391 struct abis_om_hdr *oh;
2392 struct abis_om_fom_hdr *foh;
Jonathan Santos5a45b152011-08-17 15:33:57 -04002393 uint8_t *data;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002394
2395 /* construct the 12.21 OM header, observe the erroneous length */
2396 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2397 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2398 oh->mdisc = ABIS_OM_MDISC_MANUF;
2399
2400 /* add the ip.access magic */
2401 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2402 *data++ = sizeof(ipaccess_magic);
2403 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2404
2405 /* fill the 12.21 FOM header */
2406 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2407 foh->msg_type = msg_type;
2408 foh->obj_class = obj_class;
2409 foh->obj_inst.bts_nr = bts_nr;
2410 foh->obj_inst.trx_nr = trx_nr;
2411 foh->obj_inst.ts_nr = ts_nr;
2412
2413 if (attr && attr_len) {
2414 data = msgb_put(msg, attr_len);
2415 memcpy(data, attr, attr_len);
2416 }
2417
2418 return abis_nm_sendmsg(bts, msg);
2419}
2420
2421/* set some attributes in NVRAM */
Jonathan Santos5a45b152011-08-17 15:33:57 -04002422int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002423 int attr_len)
2424{
2425 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2426 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
2427 attr_len);
2428}
2429
2430int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Jonathan Santos5a45b152011-08-17 15:33:57 -04002431 uint32_t ip, uint16_t port, uint8_t stream)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002432{
2433 struct in_addr ia;
Jonathan Santos5a45b152011-08-17 15:33:57 -04002434 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002435 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2436 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2437
2438 int attr_len = sizeof(attr);
2439
2440 ia.s_addr = htonl(ip);
2441 attr[1] = stream;
2442 attr[3] = port >> 8;
2443 attr[4] = port & 0xff;
Jonathan Santos5a45b152011-08-17 15:33:57 -04002444 *(uint32_t *)(attr+6) = ia.s_addr;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002445
2446 /* if ip == 0, we use the default IP */
2447 if (ip == 0)
2448 attr_len -= 5;
2449
2450 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
2451 inet_ntoa(ia), port, stream);
2452
2453 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2454 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2455 trx->nr, 0xff, attr, attr_len);
2456}
2457
2458/* restart / reboot an ip.access nanoBTS */
2459int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
2460{
2461 struct abis_om_hdr *oh;
2462 struct msgb *msg = nm_msgb_alloc();
2463
2464 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2465 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2466 trx->bts->nr, trx->nr, 0xff);
2467
2468 return abis_nm_sendmsg(trx->bts, msg);
2469}
2470
Jonathan Santos5a45b152011-08-17 15:33:57 -04002471int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2472 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2473 uint8_t *attr, uint8_t attr_len)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002474{
2475 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2476 obj_class, bts_nr, trx_nr, ts_nr,
2477 attr, attr_len);
2478}
2479
Jonathan Santos5a45b152011-08-17 15:33:57 -04002480void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002481{
2482 /* we simply reuse the GSM48 function and overwrite the RAC
2483 * with the Cell ID */
2484 gsm48_ra_id_by_bts(buf, bts);
Jonathan Santos5a45b152011-08-17 15:33:57 -04002485 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002486}
2487
2488void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2489{
2490 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2491
Jonathan Santos5a45b152011-08-17 15:33:57 -04002492 trx->mo.nm_state.administrative = new_state;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002493 if (!trx->bts || !trx->bts->oml_link)
2494 return;
2495
2496 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2497 trx->bts->bts_nr, trx->nr, 0xff,
2498 new_state);
2499}
2500
2501static const struct value_string ipacc_testres_names[] = {
2502 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2503 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2504 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2505 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2506 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2507 { 0, NULL }
2508};
2509
Jonathan Santos5a45b152011-08-17 15:33:57 -04002510const char *ipacc_testres_name(uint8_t res)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002511{
2512 return get_value_string(ipacc_testres_names, res);
2513}
2514
Jonathan Santos5a45b152011-08-17 15:33:57 -04002515void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002516{
2517 cid->mcc = (buf[0] & 0xf) * 100;
2518 cid->mcc += (buf[0] >> 4) * 10;
2519 cid->mcc += (buf[1] & 0xf) * 1;
2520
2521 if (buf[1] >> 4 == 0xf) {
2522 cid->mnc = (buf[2] & 0xf) * 10;
2523 cid->mnc += (buf[2] >> 4) * 1;
2524 } else {
2525 cid->mnc = (buf[2] & 0xf) * 100;
2526 cid->mnc += (buf[2] >> 4) * 10;
2527 cid->mnc += (buf[1] >> 4) * 1;
2528 }
2529
Jonathan Santos5a45b152011-08-17 15:33:57 -04002530 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2531 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002532}
2533
2534/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Jonathan Santos5a45b152011-08-17 15:33:57 -04002535int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002536{
Jonathan Santos5a45b152011-08-17 15:33:57 -04002537 uint8_t *cur = buf;
2538 uint16_t len;
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002539
2540 memset(binf, 0, sizeof(*binf));
2541
2542 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2543 return -EINVAL;
2544 cur++;
2545
Jonathan Santos5a45b152011-08-17 15:33:57 -04002546 len = ntohs(*(uint16_t *)cur);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002547 cur += 2;
2548
Jonathan Santos5a45b152011-08-17 15:33:57 -04002549 binf->info_type = ntohs(*(uint16_t *)cur);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002550 cur += 2;
2551
2552 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2553 binf->freq_qual = *cur >> 2;
2554
2555 binf->arfcn = (*cur++ & 3) << 8;
2556 binf->arfcn |= *cur++;
2557
2558 if (binf->info_type & IPAC_BINF_RXLEV)
2559 binf->rx_lev = *cur & 0x3f;
2560 cur++;
2561
2562 if (binf->info_type & IPAC_BINF_RXQUAL)
2563 binf->rx_qual = *cur & 0x7;
2564 cur++;
2565
2566 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Jonathan Santos5a45b152011-08-17 15:33:57 -04002567 binf->freq_err = ntohs(*(uint16_t *)cur);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002568 cur += 2;
2569
2570 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Jonathan Santos5a45b152011-08-17 15:33:57 -04002571 binf->frame_offset = ntohs(*(uint16_t *)cur);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002572 cur += 2;
2573
2574 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Jonathan Santos5a45b152011-08-17 15:33:57 -04002575 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Jonathan Santos03fd8d02011-05-25 13:54:02 -04002576 cur += 4;
2577
2578#if 0
2579 /* Somehow this is not set correctly */
2580 if (binf->info_type & IPAC_BINF_BSIC)
2581#endif
2582 binf->bsic = *cur & 0x3f;
2583 cur++;
2584
2585 ipac_parse_cgi(&binf->cgi, cur);
2586 cur += 7;
2587
2588 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2589 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2590 cur += sizeof(binf->ba_list_si2);
2591 }
2592
2593 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2594 memcpy(binf->ba_list_si2bis, cur,
2595 sizeof(binf->ba_list_si2bis));
2596 cur += sizeof(binf->ba_list_si2bis);
2597 }
2598
2599 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2600 memcpy(binf->ba_list_si2ter, cur,
2601 sizeof(binf->ba_list_si2ter));
2602 cur += sizeof(binf->ba_list_si2ter);
2603 }
2604
2605 return 0;
2606}
2607
2608void abis_nm_clear_queue(struct gsm_bts *bts)
2609{
2610 struct msgb *msg;
2611
2612 while (!llist_empty(&bts->abis_queue)) {
2613 msg = msgb_dequeue(&bts->abis_queue);
2614 msgb_free(msg);
2615 }
2616
2617 bts->abis_nm_pend = 0;
2618}