blob: 6568b53422924e3db45920f3cf40808a92958331 [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte59b04682009-06-10 05:40:52 +080011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
Harald Welte59b04682009-06-10 05:40:52 +080033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Weltec61a90e2011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080043#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte59b04682009-06-10 05:40:52 +080047
48#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080051
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte59b04682009-06-10 05:40:52 +080053{
Harald Welte59698fb2010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +080057}
58
59static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
71#if 0
72/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
77#endif
78
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Weltec61a90e2011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte59b04682009-06-10 05:40:52 +080083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +080089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte59b04682009-06-10 05:40:52 +080099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
103 fill_om_hdr(oh, len+sizeof(*foh));
104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte9cfc9352009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800115}
116
Harald Welte607044f2011-09-26 23:43:23 +0200117int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200118{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200119 msg->l2h = msg->data;
120
121 if (!msg->dst) {
122 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
123 return -EINVAL;
124 }
125
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200126 return abis_sendmsg(msg);
127}
128
Harald Welte59b04682009-06-10 05:40:52 +0800129/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100130static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800131{
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200132 msg->dst = bts->oml_link;
Harald Welte59b04682009-06-10 05:40:52 +0800133
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100134 /* queue OML messages */
135 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
136 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200137 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100138 } else {
139 msgb_enqueue(&bts->abis_queue, msg);
140 return 0;
141 }
142
143}
144
145int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
146{
147 OBSC_NM_W_ACK_CB(msg) = 1;
148 return abis_nm_queue_msg(bts, msg);
149}
150
151static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 0;
154 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800155}
156
157static int abis_nm_rcvmsg_sw(struct msgb *mb);
158
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100159int nm_is_running(struct gsm_nm_state *s) {
160 return (s->operational == NM_OPSTATE_ENABLED) && (
161 (s->availability == NM_AVSTATE_OK) ||
162 (s->availability == 0xff)
163 );
164}
165
Harald Welte59b04682009-06-10 05:40:52 +0800166/* Update the administrative state of a given object in our in-memory data
167 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200168static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
169 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800170{
171 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100172 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800173
Harald Weltea348c082011-03-06 21:20:38 +0100174 memset(&nsd, 0, sizeof(nsd));
175
Harald Weltec6ed9282011-06-06 18:31:20 +0200176 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100177 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100178 return -EINVAL;
Harald Weltec6ed9282011-06-06 18:31:20 +0200179 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800180 if (!nm_state)
181 return -1;
182
183 new_state = *nm_state;
184 new_state.administrative = adm_state;
185
Harald Welteb03c4482011-03-06 22:11:32 +0100186 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100187 nsd.obj_class = obj_class;
188 nsd.old_state = nm_state;
189 nsd.new_state = &new_state;
190 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200191 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800192
193 nm_state->administrative = adm_state;
194
Harald Welte4c826f72011-01-14 15:55:42 +0100195 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800196}
197
198static int abis_nm_rx_statechg_rep(struct msgb *mb)
199{
200 struct abis_om_hdr *oh = msgb_l2(mb);
201 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200202 struct e1inp_sign_link *sign_link = mb->dst;
203 struct gsm_bts *bts = sign_link->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +0800204 struct tlv_parsed tp;
205 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800206
207 DEBUGPC(DNM, "STATE CHG: ");
208
209 memset(&new_state, 0, sizeof(new_state));
210
Harald Weltec6ed9282011-06-06 18:31:20 +0200211 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800212 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100213 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800214 return -EINVAL;
215 }
216
217 new_state = *nm_state;
218
Harald Welte59698fb2010-01-10 18:01:52 +0100219 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800220 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
221 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200222 DEBUGPC(DNM, "OP_STATE=%s ",
223 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800224 }
225 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
226 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
227 new_state.availability = 0xff;
228 else
229 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Weltec61a90e2011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
231 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800232 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100233 } else
234 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800235 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
236 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200238 get_value_string(abis_nm_adm_state_names,
239 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800240 }
241 DEBUGPC(DNM, "\n");
242
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100243 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
244 new_state.operational != nm_state->operational ||
245 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800246 /* Update the operational state of a given object in our in-memory data
247 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100248 struct nm_statechg_signal_data nsd;
Harald Weltec6ed9282011-06-06 18:31:20 +0200249 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100250 nsd.obj_class = foh->obj_class;
251 nsd.old_state = nm_state;
252 nsd.new_state = &new_state;
253 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100254 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200255 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100256 nm_state->operational = new_state.operational;
257 nm_state->availability = new_state.availability;
258 if (nm_state->administrative == 0)
259 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800260 }
261#if 0
262 if (op_state == 1) {
263 /* try to enable objects that are disabled */
264 abis_nm_opstart(bts, foh->obj_class,
265 foh->obj_inst.bts_nr,
266 foh->obj_inst.trx_nr,
267 foh->obj_inst.ts_nr);
268 }
269#endif
270 return 0;
271}
272
273static int rx_fail_evt_rep(struct msgb *mb)
274{
275 struct abis_om_hdr *oh = msgb_l2(mb);
276 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200277 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800278 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100279 const uint8_t *p_val;
280 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800281
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200282 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800283
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200284 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800285
286 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-05-22 22:45:37 +0200287 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
288 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800289 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200290 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
291 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100292 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
293 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200294 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100295 }
296 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
297 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
298 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
299 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100301 talloc_free(p_text);
302 }
303 }
Harald Welte59b04682009-06-10 05:40:52 +0800304
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200305 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800306
307 return 0;
308}
309
310static int abis_nm_rcvmsg_report(struct msgb *mb)
311{
312 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200313 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800314
Harald Weltec61a90e2011-05-22 22:45:37 +0200315 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800316
317 //nmh->cfg->report_cb(mb, foh);
318
319 switch (mt) {
320 case NM_MT_STATECHG_EVENT_REP:
321 return abis_nm_rx_statechg_rep(mb);
322 break;
323 case NM_MT_SW_ACTIVATED_REP:
324 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200325 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800326 break;
327 case NM_MT_FAILURE_EVENT_REP:
328 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200329 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800330 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200331 case NM_MT_TEST_REP:
332 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200334 break;
Harald Welte59b04682009-06-10 05:40:52 +0800335 default:
336 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
337 break;
338
339 };
340
341 return 0;
342}
343
344/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200345static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
346 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800347{
348 struct abis_om_hdr *oh;
349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200350 uint8_t len = swdesc_len;
351 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800352
353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
354 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
355
356 trailer = msgb_put(msg, swdesc_len);
357 memcpy(trailer, sw_desc, swdesc_len);
358
359 return abis_nm_sendmsg(bts, msg);
360}
361
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200362static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100363{
364 static const struct tlv_definition sw_descr_def = {
365 .def = {
366 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
367 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
368 },
369 };
370
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200371 uint8_t tag;
372 uint16_t tag_len;
373 const uint8_t *val;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100374 int ofs = 0, len;
375
376 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
377 * nested nature and the fact you have to assume it contains only two sub
378 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
379
380 if (sw_descr[0] != NM_ATT_SW_DESCR) {
381 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
382 return -1;
383 }
384 ofs += 1;
385
386 len = tlv_parse_one(&tag, &tag_len, &val,
387 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
388 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
389 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
390 return -2;
391 }
392 ofs += len;
393
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
396 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
397 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
398 return -3;
399 }
400 ofs += len;
401
402 return ofs;
403}
404
Harald Welte59b04682009-06-10 05:40:52 +0800405static int abis_nm_rx_sw_act_req(struct msgb *mb)
406{
407 struct abis_om_hdr *oh = msgb_l2(mb);
408 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200409 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200410 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200411 const uint8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100412 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800413
Harald Weltec61a90e2011-05-22 22:45:37 +0200414 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200415
416 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800417
Harald Welte3055e332010-03-14 15:37:43 +0800418 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800419
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200420 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800421 foh->obj_inst.bts_nr,
422 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800423 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800424 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100425 if (ret != 0) {
426 LOGP(DNM, LOGL_ERROR,
427 "Sending SW ActReq ACK failed: %d\n", ret);
428 return ret;
429 }
Harald Welte59b04682009-06-10 05:40:52 +0800430
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200431 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200432 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
433 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
434 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100435 LOGP(DNM, LOGL_ERROR,
436 "SW config not found! Can't continue.\n");
Mike Haben322fc582009-10-01 14:56:13 +0200437 return -EINVAL;
438 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200439 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200440 }
441
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100442 /* Use the first SW_DESCR present in SW config */
443 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
444 if (sw_descr_len < 0)
445 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200446
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200447 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800448 foh->obj_inst.bts_nr,
449 foh->obj_inst.trx_nr,
450 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100451 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800452}
453
454/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
455static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
456{
457 struct abis_om_hdr *oh = msgb_l2(mb);
458 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200459 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800460 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200461 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800462
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200463 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800464 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
465 return -EINVAL;
466
467 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
468
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200469 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800470}
471
472static int abis_nm_rx_lmt_event(struct msgb *mb)
473{
474 struct abis_om_hdr *oh = msgb_l2(mb);
475 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200476 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800477 struct tlv_parsed tp;
478
479 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200480 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800481 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
482 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200483 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800484 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
485 }
486 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
487 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200488 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800489 DEBUGPC(DNM, "Level=%u ", level);
490 }
491 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
492 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
493 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
494 DEBUGPC(DNM, "Username=%s ", name);
495 }
496 DEBUGPC(DNM, "\n");
497 /* FIXME: parse LMT LOGON TIME */
498 return 0;
499}
500
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200501void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100502{
503 int wait = 0;
504 struct msgb *msg;
505 /* the queue is empty */
506 while (!llist_empty(&bts->abis_queue)) {
507 msg = msgb_dequeue(&bts->abis_queue);
508 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200509 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100510
511 if (wait)
512 break;
513 }
514
515 bts->abis_nm_pend = wait;
516}
517
Harald Welte59b04682009-06-10 05:40:52 +0800518/* Receive a OML NM Message from BTS */
519static int abis_nm_rcvmsg_fom(struct msgb *mb)
520{
521 struct abis_om_hdr *oh = msgb_l2(mb);
522 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200523 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200524 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100525 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800526
527 /* check for unsolicited message */
528 if (is_report(mt))
529 return abis_nm_rcvmsg_report(mb);
530
Harald Weltec61a90e2011-05-22 22:45:37 +0200531 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800532 return abis_nm_rcvmsg_sw(mb);
533
Harald Weltec61a90e2011-05-22 22:45:37 +0200534 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800535 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800536 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200537
Harald Weltec61a90e2011-05-22 22:45:37 +0200538 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200539
Harald Weltec61a90e2011-05-22 22:45:37 +0200540 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800541
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200542 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800543 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200544 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200545 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800546 else
547 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200548
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800549 nack_data.msg = mb;
550 nack_data.mt = mt;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200551 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200552 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200553 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800554 }
555#if 0
556 /* check if last message is to be acked */
557 if (is_ack_nack(nmh->last_msgtype)) {
558 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100559 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800560 /* we got our ACK, continue sending the next msg */
561 } else if (mt == MT_NACK(nmh->last_msgtype)) {
562 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100563 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800564 /* FIXME: somehow signal this to the caller */
565 } else {
566 /* really strange things happen */
567 return -EINVAL;
568 }
569 }
570#endif
571
572 switch (mt) {
573 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100574 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800575 break;
576 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100577 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800578 break;
579 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100580 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800581 break;
Harald Welte204317e2009-08-06 17:58:31 +0200582 case NM_MT_CONN_MDROP_LINK_ACK:
583 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
584 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100585 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200586 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100587 break;
588 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200589 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100590 break;
Harald Welte08011e22011-03-04 13:41:31 +0100591 case NM_MT_SET_BTS_ATTR_ACK:
592 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200593 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
594 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Welte08011e22011-03-04 13:41:31 +0100595 }
596 break;
Harald Welte59b04682009-06-10 05:40:52 +0800597 }
598
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200599 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100600 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800601}
602
603static int abis_nm_rx_ipacc(struct msgb *mb);
604
605static int abis_nm_rcvmsg_manuf(struct msgb *mb)
606{
607 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200608 struct e1inp_sign_link *sign_link = mb->dst;
609 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800610
611 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100612 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +0800613 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200614 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800615 break;
616 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100617 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
618 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800619 rc = 0;
620 break;
621 }
622
623 return rc;
624}
625
626/* High-Level API */
627/* Entry-point where L2 OML from BTS enters the NM code */
628int abis_nm_rcvmsg(struct msgb *msg)
629{
630 struct abis_om_hdr *oh = msgb_l2(msg);
631 int rc = 0;
632
633 /* Various consistency checks */
634 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100635 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800636 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +0200637 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
638 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800639 }
640 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100641 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800642 oh->sequence);
643 return -EINVAL;
644 }
645#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200646 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800647 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
648 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100649 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800650 oh->length + sizeof(*oh), l2_len);
651 return -EINVAL;
652 }
653 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100654 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte59b04682009-06-10 05:40:52 +0800655#endif
656 msg->l3h = (unsigned char *)oh + sizeof(*oh);
657
658 switch (oh->mdisc) {
659 case ABIS_OM_MDISC_FOM:
660 rc = abis_nm_rcvmsg_fom(msg);
661 break;
662 case ABIS_OM_MDISC_MANUF:
663 rc = abis_nm_rcvmsg_manuf(msg);
664 break;
665 case ABIS_OM_MDISC_MMI:
666 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100667 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800668 oh->mdisc);
669 break;
670 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100671 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800672 oh->mdisc);
673 return -EINVAL;
674 }
675
676 msgb_free(msg);
677 return rc;
678}
679
680#if 0
681/* initialized all resources */
682struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
683{
684 struct abis_nm_h *nmh;
685
686 nmh = malloc(sizeof(*nmh));
687 if (!nmh)
688 return NULL;
689
690 nmh->cfg = cfg;
691
692 return nmh;
693}
694
695/* free all resources */
696void abis_nm_fini(struct abis_nm_h *nmh)
697{
698 free(nmh);
699}
700#endif
701
702/* Here we are trying to define a high-level API that can be used by
703 * the actual BSC implementation. However, the architecture is currently
704 * still under design. Ideally the calls to this API would be synchronous,
705 * while the underlying stack behind the APi runs in a traditional select
706 * based state machine.
707 */
708
709/* 6.2 Software Load: */
710enum sw_state {
711 SW_STATE_NONE,
712 SW_STATE_WAIT_INITACK,
713 SW_STATE_WAIT_SEGACK,
714 SW_STATE_WAIT_ENDACK,
715 SW_STATE_WAIT_ACTACK,
716 SW_STATE_ERROR,
717};
718
719struct abis_nm_sw {
720 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800721 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800722 gsm_cbfn *cbfn;
723 void *cb_data;
724 int forced;
725
726 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200727 uint8_t obj_class;
728 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800729
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200730 uint8_t file_id[255];
731 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800732
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200733 uint8_t file_version[255];
734 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800735
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200736 uint8_t window_size;
737 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800738
739 int fd;
740 FILE *stream;
741 enum sw_state state;
742 int last_seg;
743};
744
745static struct abis_nm_sw g_sw;
746
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100747static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
748{
749 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
750 msgb_v_put(msg, NM_ATT_SW_DESCR);
751 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
752 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
753 sw->file_version);
754 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
755 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
756 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
757 sw->file_version);
758 } else {
759 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
760 }
761}
762
Harald Welte59b04682009-06-10 05:40:52 +0800763/* 6.2.1 / 8.3.1: Load Data Initiate */
764static int sw_load_init(struct abis_nm_sw *sw)
765{
766 struct abis_om_hdr *oh;
767 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200768 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800769
770 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
771 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
772 sw->obj_instance[0], sw->obj_instance[1],
773 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100774
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100775 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800776 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
777
778 return abis_nm_sendmsg(sw->bts, msg);
779}
780
781static int is_last_line(FILE *stream)
782{
783 char next_seg_buf[256];
784 long pos;
785
786 /* check if we're sending the last line */
787 pos = ftell(stream);
788 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
789 fseek(stream, pos, SEEK_SET);
790 return 1;
791 }
792
793 fseek(stream, pos, SEEK_SET);
794 return 0;
795}
796
797/* 6.2.2 / 8.3.2 Load Data Segment */
798static int sw_load_segment(struct abis_nm_sw *sw)
799{
800 struct abis_om_hdr *oh;
801 struct msgb *msg = nm_msgb_alloc();
802 char seg_buf[256];
803 char *line_buf = seg_buf+2;
804 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200805 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800806
807 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
808
809 switch (sw->bts->type) {
810 case GSM_BTS_TYPE_BS11:
811 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
812 perror("fgets reading segment");
813 return -EINVAL;
814 }
815 seg_buf[0] = 0x00;
816
817 /* check if we're sending the last line */
818 sw->last_seg = is_last_line(sw->stream);
819 if (sw->last_seg)
820 seg_buf[1] = 0;
821 else
822 seg_buf[1] = 1 + sw->seg_in_window++;
823
824 len = strlen(line_buf) + 2;
825 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200826 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800827 /* BS11 wants CR + LF in excess of the TLV length !?! */
828 tlv[1] -= 2;
829
830 /* we only now know the exact length for the OM hdr */
831 len = strlen(line_buf)+2;
832 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100833 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200834 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100835 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
836 if (len < 0) {
837 perror("read failed");
838 return -EINVAL;
839 }
840
841 if (len != IPACC_SEGMENT_SIZE)
842 sw->last_seg = 1;
843
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100844 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200845 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100846 len += 3;
847 break;
848 }
Harald Welte59b04682009-06-10 05:40:52 +0800849 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100850 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800851 /* FIXME: Other BTS types */
852 return -1;
853 }
854
855 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
856 sw->obj_instance[0], sw->obj_instance[1],
857 sw->obj_instance[2]);
858
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100859 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800860}
861
862/* 6.2.4 / 8.3.4 Load Data End */
863static int sw_load_end(struct abis_nm_sw *sw)
864{
865 struct abis_om_hdr *oh;
866 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200867 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800868
869 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
870 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
871 sw->obj_instance[0], sw->obj_instance[1],
872 sw->obj_instance[2]);
873
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100874 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800875 return abis_nm_sendmsg(sw->bts, msg);
876}
877
878/* Activate the specified software into the BTS */
879static int sw_activate(struct abis_nm_sw *sw)
880{
881 struct abis_om_hdr *oh;
882 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200883 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800884
885 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
886 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
887 sw->obj_instance[0], sw->obj_instance[1],
888 sw->obj_instance[2]);
889
890 /* FIXME: this is BS11 specific format */
891 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
892 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
893 sw->file_version);
894
895 return abis_nm_sendmsg(sw->bts, msg);
896}
897
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100898struct sdp_firmware {
899 char magic[4];
900 char more_magic[4];
901 unsigned int header_length;
902 unsigned int file_length;
903} __attribute__ ((packed));
904
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100905static int parse_sdp_header(struct abis_nm_sw *sw)
906{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100907 struct sdp_firmware firmware_header;
908 int rc;
909 struct stat stat;
910
911 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
912 if (rc != sizeof(firmware_header)) {
913 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
914 return -1;
915 }
916
917 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
918 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
919 return -1;
920 }
921
922 if (firmware_header.more_magic[0] != 0x10 ||
923 firmware_header.more_magic[1] != 0x02 ||
924 firmware_header.more_magic[2] != 0x00 ||
925 firmware_header.more_magic[3] != 0x00) {
926 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
927 return -1;
928 }
929
930
931 if (fstat(sw->fd, &stat) == -1) {
932 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
933 return -1;
934 }
935
936 if (ntohl(firmware_header.file_length) != stat.st_size) {
937 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
938 return -1;
939 }
940
941 /* go back to the start as we checked the whole filesize.. */
942 lseek(sw->fd, 0l, SEEK_SET);
943 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
944 "There might be checksums in the file that are not\n"
945 "verified and incomplete firmware might be flashed.\n"
946 "There is absolutely no WARRANTY that flashing will\n"
947 "work.\n");
948 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100949}
950
Harald Welte59b04682009-06-10 05:40:52 +0800951static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
952{
953 char file_id[12+1];
954 char file_version[80+1];
955 int rc;
956
957 sw->fd = open(fname, O_RDONLY);
958 if (sw->fd < 0)
959 return sw->fd;
960
961 switch (sw->bts->type) {
962 case GSM_BTS_TYPE_BS11:
963 sw->stream = fdopen(sw->fd, "r");
964 if (!sw->stream) {
965 perror("fdopen");
966 return -1;
967 }
968 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200969 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +0800970 file_id, file_version);
971 if (rc != 2) {
972 perror("parsing header line of software file");
973 return -1;
974 }
975 strcpy((char *)sw->file_id, file_id);
976 sw->file_id_len = strlen(file_id);
977 strcpy((char *)sw->file_version, file_version);
978 sw->file_version_len = strlen(file_version);
979 /* rewind to start of file */
980 rewind(sw->stream);
981 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100982 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100983 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100984 rc = parse_sdp_header(sw);
985 if (rc < 0) {
986 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
987 return -1;
988 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100989
990 strcpy((char *)sw->file_id, "id");
991 sw->file_id_len = 3;
992 strcpy((char *)sw->file_version, "version");
993 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100994 break;
Harald Welte59b04682009-06-10 05:40:52 +0800995 default:
996 /* We don't know how to treat them yet */
997 close(sw->fd);
998 return -EINVAL;
999 }
1000
1001 return 0;
1002}
1003
1004static void sw_close_file(struct abis_nm_sw *sw)
1005{
1006 switch (sw->bts->type) {
1007 case GSM_BTS_TYPE_BS11:
1008 fclose(sw->stream);
1009 break;
1010 default:
1011 close(sw->fd);
1012 break;
1013 }
1014}
1015
1016/* Fill the window */
1017static int sw_fill_window(struct abis_nm_sw *sw)
1018{
1019 int rc;
1020
1021 while (sw->seg_in_window < sw->window_size) {
1022 rc = sw_load_segment(sw);
1023 if (rc < 0)
1024 return rc;
1025 if (sw->last_seg)
1026 break;
1027 }
1028 return 0;
1029}
1030
1031/* callback function from abis_nm_rcvmsg() handler */
1032static int abis_nm_rcvmsg_sw(struct msgb *mb)
1033{
1034 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001035 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001036 int rc = -1;
1037 struct abis_nm_sw *sw = &g_sw;
1038 enum sw_state old_state = sw->state;
1039
1040 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1041
1042 switch (sw->state) {
1043 case SW_STATE_WAIT_INITACK:
1044 switch (foh->msg_type) {
1045 case NM_MT_LOAD_INIT_ACK:
1046 /* fill window with segments */
1047 if (sw->cbfn)
1048 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1049 NM_MT_LOAD_INIT_ACK, mb,
1050 sw->cb_data, NULL);
1051 rc = sw_fill_window(sw);
1052 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001053 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001054 break;
1055 case NM_MT_LOAD_INIT_NACK:
1056 if (sw->forced) {
1057 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1058 "Init NACK\n");
1059 if (sw->cbfn)
1060 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1061 NM_MT_LOAD_INIT_ACK, mb,
1062 sw->cb_data, NULL);
1063 rc = sw_fill_window(sw);
1064 sw->state = SW_STATE_WAIT_SEGACK;
1065 } else {
1066 DEBUGP(DNM, "Software Load Init NACK\n");
1067 /* FIXME: cause */
1068 if (sw->cbfn)
1069 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1070 NM_MT_LOAD_INIT_NACK, mb,
1071 sw->cb_data, NULL);
1072 sw->state = SW_STATE_ERROR;
1073 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001074 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001075 break;
1076 }
1077 break;
1078 case SW_STATE_WAIT_SEGACK:
1079 switch (foh->msg_type) {
1080 case NM_MT_LOAD_SEG_ACK:
1081 if (sw->cbfn)
1082 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1083 NM_MT_LOAD_SEG_ACK, mb,
1084 sw->cb_data, NULL);
1085 sw->seg_in_window = 0;
1086 if (!sw->last_seg) {
1087 /* fill window with more segments */
1088 rc = sw_fill_window(sw);
1089 sw->state = SW_STATE_WAIT_SEGACK;
1090 } else {
1091 /* end the transfer */
1092 sw->state = SW_STATE_WAIT_ENDACK;
1093 rc = sw_load_end(sw);
1094 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001095 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001096 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001097 case NM_MT_LOAD_ABORT:
1098 if (sw->cbfn)
1099 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1100 NM_MT_LOAD_ABORT, mb,
1101 sw->cb_data, NULL);
1102 break;
Harald Welte59b04682009-06-10 05:40:52 +08001103 }
1104 break;
1105 case SW_STATE_WAIT_ENDACK:
1106 switch (foh->msg_type) {
1107 case NM_MT_LOAD_END_ACK:
1108 sw_close_file(sw);
1109 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1110 sw->bts->nr);
1111 sw->state = SW_STATE_NONE;
1112 if (sw->cbfn)
1113 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1114 NM_MT_LOAD_END_ACK, mb,
1115 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001116 rc = 0;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001117 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001118 break;
1119 case NM_MT_LOAD_END_NACK:
1120 if (sw->forced) {
1121 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1122 "End NACK\n");
1123 sw->state = SW_STATE_NONE;
1124 if (sw->cbfn)
1125 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1126 NM_MT_LOAD_END_ACK, mb,
1127 sw->cb_data, NULL);
1128 } else {
1129 DEBUGP(DNM, "Software Load End NACK\n");
1130 /* FIXME: cause */
1131 sw->state = SW_STATE_ERROR;
1132 if (sw->cbfn)
1133 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1134 NM_MT_LOAD_END_NACK, mb,
1135 sw->cb_data, NULL);
1136 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001137 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001138 break;
1139 }
1140 case SW_STATE_WAIT_ACTACK:
1141 switch (foh->msg_type) {
1142 case NM_MT_ACTIVATE_SW_ACK:
1143 /* we're done */
1144 DEBUGP(DNM, "Activate Software DONE!\n");
1145 sw->state = SW_STATE_NONE;
1146 rc = 0;
1147 if (sw->cbfn)
1148 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1149 NM_MT_ACTIVATE_SW_ACK, mb,
1150 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001151 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001152 break;
1153 case NM_MT_ACTIVATE_SW_NACK:
1154 DEBUGP(DNM, "Activate Software NACK\n");
1155 /* FIXME: cause */
1156 sw->state = SW_STATE_ERROR;
1157 if (sw->cbfn)
1158 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1159 NM_MT_ACTIVATE_SW_NACK, mb,
1160 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001161 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001162 break;
1163 }
1164 case SW_STATE_NONE:
1165 switch (foh->msg_type) {
1166 case NM_MT_ACTIVATE_SW_ACK:
1167 rc = 0;
1168 break;
1169 }
1170 break;
1171 case SW_STATE_ERROR:
1172 break;
1173 }
1174
1175 if (rc)
1176 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1177 foh->msg_type, old_state, sw->state);
1178
1179 return rc;
1180}
1181
1182/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001183int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001184 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001185 gsm_cbfn *cbfn, void *cb_data)
1186{
1187 struct abis_nm_sw *sw = &g_sw;
1188 int rc;
1189
1190 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1191 bts->nr, fname);
1192
1193 if (sw->state != SW_STATE_NONE)
1194 return -EBUSY;
1195
1196 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001197 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001198
1199 switch (bts->type) {
1200 case GSM_BTS_TYPE_BS11:
1201 sw->obj_class = NM_OC_SITE_MANAGER;
1202 sw->obj_instance[0] = 0xff;
1203 sw->obj_instance[1] = 0xff;
1204 sw->obj_instance[2] = 0xff;
1205 break;
1206 case GSM_BTS_TYPE_NANOBTS:
1207 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001208 sw->obj_instance[0] = sw->bts->nr;
1209 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001210 sw->obj_instance[2] = 0xff;
1211 break;
1212 case GSM_BTS_TYPE_UNKNOWN:
1213 default:
1214 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1215 return -1;
1216 break;
1217 }
Harald Welte59b04682009-06-10 05:40:52 +08001218 sw->window_size = win_size;
1219 sw->state = SW_STATE_WAIT_INITACK;
1220 sw->cbfn = cbfn;
1221 sw->cb_data = cb_data;
1222 sw->forced = forced;
1223
1224 rc = sw_open_file(sw, fname);
1225 if (rc < 0) {
1226 sw->state = SW_STATE_NONE;
1227 return rc;
1228 }
1229
1230 return sw_load_init(sw);
1231}
1232
1233int abis_nm_software_load_status(struct gsm_bts *bts)
1234{
1235 struct abis_nm_sw *sw = &g_sw;
1236 struct stat st;
1237 int rc, percent;
1238
1239 rc = fstat(sw->fd, &st);
1240 if (rc < 0) {
1241 perror("ERROR during stat");
1242 return rc;
1243 }
1244
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001245 if (sw->stream)
1246 percent = (ftell(sw->stream) * 100) / st.st_size;
1247 else
1248 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001249 return percent;
1250}
1251
1252/* Activate the specified software into the BTS */
1253int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1254 gsm_cbfn *cbfn, void *cb_data)
1255{
1256 struct abis_nm_sw *sw = &g_sw;
1257 int rc;
1258
1259 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1260 bts->nr, fname);
1261
1262 if (sw->state != SW_STATE_NONE)
1263 return -EBUSY;
1264
1265 sw->bts = bts;
1266 sw->obj_class = NM_OC_SITE_MANAGER;
1267 sw->obj_instance[0] = 0xff;
1268 sw->obj_instance[1] = 0xff;
1269 sw->obj_instance[2] = 0xff;
1270 sw->state = SW_STATE_WAIT_ACTACK;
1271 sw->cbfn = cbfn;
1272 sw->cb_data = cb_data;
1273
1274 /* Open the file in order to fill some sw struct members */
1275 rc = sw_open_file(sw, fname);
1276 if (rc < 0) {
1277 sw->state = SW_STATE_NONE;
1278 return rc;
1279 }
1280 sw_close_file(sw);
1281
1282 return sw_activate(sw);
1283}
1284
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001285static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1286 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001287{
1288 ch->attrib = NM_ATT_ABIS_CHANNEL;
1289 ch->bts_port = bts_port;
1290 ch->timeslot = ts_nr;
1291 ch->subslot = subslot_nr;
1292}
1293
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001294int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1295 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1296 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001297{
1298 struct abis_om_hdr *oh;
1299 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001300 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001301 struct msgb *msg = nm_msgb_alloc();
1302
1303 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1304 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1305 bts->bts_nr, trx_nr, 0xff);
1306
1307 msgb_tv_put(msg, NM_ATT_TEI, tei);
1308
1309 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1310 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1311
1312 return abis_nm_sendmsg(bts, msg);
1313}
1314
1315/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1316int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001317 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001318{
1319 struct gsm_bts *bts = trx->bts;
1320 struct abis_om_hdr *oh;
1321 struct abis_nm_channel *ch;
1322 struct msgb *msg = nm_msgb_alloc();
1323
1324 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1325 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1326 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1327
1328 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1329 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1330
1331 return abis_nm_sendmsg(bts, msg);
1332}
1333
1334#if 0
1335int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1336 struct abis_nm_abis_channel *chan)
1337{
1338}
1339#endif
1340
1341int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001342 uint8_t e1_port, uint8_t e1_timeslot,
1343 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001344{
1345 struct gsm_bts *bts = ts->trx->bts;
1346 struct abis_om_hdr *oh;
1347 struct abis_nm_channel *ch;
1348 struct msgb *msg = nm_msgb_alloc();
1349
1350 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1351 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1352 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1353
1354 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1355 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1356
1357 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1358 gsm_ts_name(ts),
1359 e1_port, e1_timeslot, e1_subslot);
1360
1361 return abis_nm_sendmsg(bts, msg);
1362}
1363
1364#if 0
1365int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1366 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001367 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001368{
1369}
1370#endif
1371
1372/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001373int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001374{
1375 struct abis_om_hdr *oh;
1376 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001377 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001378
1379 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1380
1381 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1382 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1383 cur = msgb_put(msg, attr_len);
1384 memcpy(cur, attr, attr_len);
1385
1386 return abis_nm_sendmsg(bts, msg);
1387}
1388
1389/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001390int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001391{
1392 struct abis_om_hdr *oh;
1393 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001394 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001395
1396 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1397
1398 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1399 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1400 trx->bts->bts_nr, trx->nr, 0xff);
1401 cur = msgb_put(msg, attr_len);
1402 memcpy(cur, attr, attr_len);
1403
1404 return abis_nm_sendmsg(trx->bts, msg);
1405}
1406
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001407static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Weltef2eb2782009-08-09 21:49:48 +02001408{
1409 int i;
1410
1411 /* As it turns out, the BS-11 has some very peculiar restrictions
1412 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301413 switch (ts->trx->bts->type) {
1414 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001415 switch (chan_comb) {
1416 case NM_CHANC_TCHHalf:
1417 case NM_CHANC_TCHHalf2:
1418 /* not supported */
1419 return -EINVAL;
1420 case NM_CHANC_SDCCH:
1421 /* only one SDCCH/8 per TRX */
1422 for (i = 0; i < TRX_NR_TS; i++) {
1423 if (i == ts->nr)
1424 continue;
1425 if (ts->trx->ts[i].nm_chan_comb ==
1426 NM_CHANC_SDCCH)
1427 return -EINVAL;
1428 }
1429 /* not allowed for TS0 of BCCH-TRX */
1430 if (ts->trx == ts->trx->bts->c0 &&
1431 ts->nr == 0)
1432 return -EINVAL;
1433 /* not on the same TRX that has a BCCH+SDCCH4
1434 * combination */
1435 if (ts->trx == ts->trx->bts->c0 &&
1436 (ts->trx->ts[0].nm_chan_comb == 5 ||
1437 ts->trx->ts[0].nm_chan_comb == 8))
1438 return -EINVAL;
1439 break;
1440 case NM_CHANC_mainBCCH:
1441 case NM_CHANC_BCCHComb:
1442 /* allowed only for TS0 of C0 */
1443 if (ts->trx != ts->trx->bts->c0 ||
1444 ts->nr != 0)
1445 return -EINVAL;
1446 break;
1447 case NM_CHANC_BCCH:
1448 /* allowed only for TS 2/4/6 of C0 */
1449 if (ts->trx != ts->trx->bts->c0)
1450 return -EINVAL;
1451 if (ts->nr != 2 && ts->nr != 4 &&
1452 ts->nr != 6)
1453 return -EINVAL;
1454 break;
1455 case 8: /* this is not like 08.58, but in fact
1456 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1457 /* FIXME: only one CBCH allowed per cell */
1458 break;
1459 }
Harald Welte76ba8812009-12-02 02:45:23 +05301460 break;
1461 case GSM_BTS_TYPE_NANOBTS:
1462 switch (ts->nr) {
1463 case 0:
1464 if (ts->trx->nr == 0) {
1465 /* only on TRX0 */
1466 switch (chan_comb) {
1467 case NM_CHANC_BCCH:
1468 case NM_CHANC_mainBCCH:
1469 case NM_CHANC_BCCHComb:
1470 return 0;
1471 break;
1472 default:
1473 return -EINVAL;
1474 }
1475 } else {
1476 switch (chan_comb) {
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 1:
1487 if (ts->trx->nr == 0) {
1488 switch (chan_comb) {
1489 case NM_CHANC_SDCCH_CBCH:
1490 if (ts->trx->ts[0].nm_chan_comb ==
1491 NM_CHANC_mainBCCH)
1492 return 0;
1493 return -EINVAL;
1494 case NM_CHANC_SDCCH:
1495 case NM_CHANC_TCHFull:
1496 case NM_CHANC_TCHHalf:
1497 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1498 case NM_CHANC_IPAC_TCHFull_PDCH:
1499 return 0;
1500 }
1501 } else {
1502 switch (chan_comb) {
1503 case NM_CHANC_SDCCH:
1504 case NM_CHANC_TCHFull:
1505 case NM_CHANC_TCHHalf:
1506 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1507 return 0;
1508 default:
1509 return -EINVAL;
1510 }
1511 }
1512 break;
1513 case 2:
1514 case 3:
1515 case 4:
1516 case 5:
1517 case 6:
1518 case 7:
1519 switch (chan_comb) {
1520 case NM_CHANC_TCHFull:
1521 case NM_CHANC_TCHHalf:
1522 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1523 return 0;
1524 case NM_CHANC_IPAC_PDCH:
1525 case NM_CHANC_IPAC_TCHFull_PDCH:
1526 if (ts->trx->nr == 0)
1527 return 0;
1528 else
1529 return -EINVAL;
1530 }
1531 break;
1532 }
1533 return -EINVAL;
1534 default:
1535 /* unknown BTS type */
1536 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001537 }
1538 return 0;
1539}
1540
Harald Welte59b04682009-06-10 05:40:52 +08001541/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001542int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001543{
1544 struct gsm_bts *bts = ts->trx->bts;
1545 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001546 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001547 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001548 uint8_t len = 2 + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001549
1550 if (bts->type == GSM_BTS_TYPE_BS11)
1551 len += 4 + 2 + 2 + 3;
1552
1553 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001554 if (verify_chan_comb(ts, chan_comb) < 0) {
1555 msgb_free(msg);
1556 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1557 return -EINVAL;
1558 }
1559 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001560
1561 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1562 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1563 NM_OC_CHANNEL, bts->bts_nr,
1564 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001565 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001566 if (ts->hopping.enabled) {
1567 unsigned int i;
1568 uint8_t *len;
1569
Harald Welte67104d12009-09-12 13:05:33 +02001570 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1571 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001572
1573 /* build the ARFCN list */
1574 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1575 len = msgb_put(msg, 1);
1576 *len = 0;
1577 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1578 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1579 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001580 /* At least BS-11 wants a TLV16 here */
1581 if (bts->type == GSM_BTS_TYPE_BS11)
1582 *len += 1;
1583 else
1584 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001585 }
1586 }
Harald Welte59b04682009-06-10 05:40:52 +08001587 }
Harald Welte85771a42011-05-30 12:09:13 +02001588 if (ts->tsc == -1)
1589 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1590 else
1591 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001592 if (bts->type == GSM_BTS_TYPE_BS11)
1593 msgb_tlv_put(msg, 0x59, 1, &zero);
1594
1595 return abis_nm_sendmsg(bts, msg);
1596}
1597
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001598int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1599 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001600{
1601 struct abis_om_hdr *oh;
1602 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001603 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1604 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001605
1606 if (nack) {
1607 len += 2;
1608 msgtype = NM_MT_SW_ACT_REQ_NACK;
1609 }
1610
1611 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1612 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1613
1614 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001615 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001616 memcpy(ptr, attr, att_len);
1617 }
1618 if (nack)
1619 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1620
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001621 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001622}
1623
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001624int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001625{
1626 struct msgb *msg = nm_msgb_alloc();
1627 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001628 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001629
1630 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1631 fill_om_hdr(oh, len);
1632 data = msgb_put(msg, len);
1633 memcpy(data, rawmsg, len);
1634
1635 return abis_nm_sendmsg(bts, msg);
1636}
1637
1638/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001639static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001640{
1641 struct abis_om_hdr *oh;
1642 struct msgb *msg = nm_msgb_alloc();
1643
1644 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1645 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1646 0xff, 0xff, 0xff);
1647
1648 return abis_nm_sendmsg(bts, msg);
1649}
1650
1651/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001652int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Harald Welte59b04682009-06-10 05:40:52 +08001653{
1654 struct abis_om_hdr *oh;
1655 struct msgb *msg = nm_msgb_alloc();
1656
Harald Welte59b04682009-06-10 05:40:52 +08001657 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1658 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1659
Harald Weltec61a90e2011-05-22 22:45:37 +02001660 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001661 DEBUGPC(DNM, "Sending OPSTART\n");
1662
Harald Welte59b04682009-06-10 05:40:52 +08001663 return abis_nm_sendmsg(bts, msg);
1664}
1665
1666/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001667int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1668 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001669{
1670 struct abis_om_hdr *oh;
1671 struct msgb *msg = nm_msgb_alloc();
1672
1673 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1674 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1675 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1676
1677 return abis_nm_sendmsg(bts, msg);
1678}
1679
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001680int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1681 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001682{
1683 struct abis_om_hdr *oh;
1684 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001685 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001686
1687 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1688 e1_port0, ts0, e1_port1, ts1);
1689
1690 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1691 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1692 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1693
1694 attr = msgb_put(msg, 3);
1695 attr[0] = NM_ATT_MDROP_LINK;
1696 attr[1] = e1_port0;
1697 attr[2] = ts0;
1698
1699 attr = msgb_put(msg, 3);
1700 attr[0] = NM_ATT_MDROP_NEXT;
1701 attr[1] = e1_port1;
1702 attr[2] = ts1;
1703
1704 return abis_nm_sendmsg(bts, msg);
1705}
Harald Welte59b04682009-06-10 05:40:52 +08001706
Harald Welte0bf8e302009-08-08 00:02:36 +02001707/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001708int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1709 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1710 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001711{
1712 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001713
Harald Weltec61a90e2011-05-22 22:45:37 +02001714 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001715
1716 if (!msg)
1717 msg = nm_msgb_alloc();
1718
1719 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1720 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1721 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1722 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001723 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001724
1725 return abis_nm_sendmsg(bts, msg);
1726}
1727
Harald Welte59b04682009-06-10 05:40:52 +08001728int abis_nm_event_reports(struct gsm_bts *bts, int on)
1729{
1730 if (on == 0)
1731 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1732 else
1733 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1734}
1735
1736/* Siemens (or BS-11) specific commands */
1737
1738int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1739{
1740 if (reconnect == 0)
1741 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1742 else
1743 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1744}
1745
1746int abis_nm_bs11_restart(struct gsm_bts *bts)
1747{
1748 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1749}
1750
1751
1752struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001753 uint16_t year;
1754 uint8_t month;
1755 uint8_t day;
1756 uint8_t hour;
1757 uint8_t min;
1758 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001759} __attribute__((packed));
1760
1761
1762void get_bs11_date_time(struct bs11_date_time *aet)
1763{
1764 time_t t;
1765 struct tm *tm;
1766
1767 t = time(NULL);
1768 tm = localtime(&t);
1769 aet->sec = tm->tm_sec;
1770 aet->min = tm->tm_min;
1771 aet->hour = tm->tm_hour;
1772 aet->day = tm->tm_mday;
1773 aet->month = tm->tm_mon;
1774 aet->year = htons(1900 + tm->tm_year);
1775}
1776
1777int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1778{
1779 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1780}
1781
1782int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1783{
1784 if (begin)
1785 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1786 else
1787 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1788}
1789
1790int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001791 enum abis_bs11_objtype type, uint8_t idx,
1792 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001793{
1794 struct abis_om_hdr *oh;
1795 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001796 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001797
1798 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1799 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1800 NM_OC_BS11, type, 0, idx);
1801 cur = msgb_put(msg, attr_len);
1802 memcpy(cur, attr, attr_len);
1803
1804 return abis_nm_sendmsg(bts, msg);
1805}
1806
1807int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001808 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001809{
1810 struct abis_om_hdr *oh;
1811 struct msgb *msg = nm_msgb_alloc();
1812
1813 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1814 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1815 NM_OC_BS11, type, 0, idx);
1816
1817 return abis_nm_sendmsg(bts, msg);
1818}
1819
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001820int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001821{
1822 struct abis_om_hdr *oh;
1823 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001824 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001825
1826 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1827 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1828 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1829 msgb_tlv_put(msg, 0x99, 1, &zero);
1830
1831 return abis_nm_sendmsg(bts, msg);
1832}
1833
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001834int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001835{
1836 struct abis_om_hdr *oh;
1837 struct msgb *msg = nm_msgb_alloc();
1838
1839 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1840 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001841 idx, 0xff, 0xff);
1842
1843 return abis_nm_sendmsg(bts, msg);
1844}
1845
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001846int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001847{
1848 struct abis_om_hdr *oh;
1849 struct msgb *msg = nm_msgb_alloc();
1850
1851 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1852 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1853 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001854
1855 return abis_nm_sendmsg(bts, msg);
1856}
1857
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001858static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001859int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1860{
1861 struct abis_om_hdr *oh;
1862 struct msgb *msg = nm_msgb_alloc();
1863
1864 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1865 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1866 0xff, 0xff, 0xff);
1867 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1868
1869 return abis_nm_sendmsg(bts, msg);
1870}
1871
1872/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001873int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1874 uint8_t e1_timeslot, uint8_t e1_subslot,
1875 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001876{
1877 struct abis_om_hdr *oh;
1878 struct abis_nm_channel *ch;
1879 struct msgb *msg = nm_msgb_alloc();
1880
1881 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1882 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1883 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1884
1885 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1886 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1887 msgb_tv_put(msg, NM_ATT_TEI, tei);
1888
1889 return abis_nm_sendmsg(bts, msg);
1890}
1891
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001892int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08001893{
1894 struct abis_om_hdr *oh;
1895 struct msgb *msg = nm_msgb_alloc();
1896
1897 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1898 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
1899 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1900 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1901
1902 return abis_nm_sendmsg(trx->bts, msg);
1903}
1904
1905int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1906{
1907 struct abis_om_hdr *oh;
1908 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001909 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08001910
1911 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1912 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1913 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1914 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1915
1916 return abis_nm_sendmsg(trx->bts, msg);
1917}
1918
1919int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1920{
1921 struct abis_om_hdr *oh;
1922 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001923 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08001924
1925 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1926 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1927 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
1928 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1929
1930 return abis_nm_sendmsg(bts, msg);
1931}
1932
1933int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1934{
1935 struct abis_om_hdr *oh;
1936 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001937 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08001938 NM_ATT_BS11_CCLK_TYPE };
1939
1940 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1941 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1942 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1943 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1944
1945 return abis_nm_sendmsg(bts, msg);
1946
1947}
1948
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001949//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08001950
1951int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
1952{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001953 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1954}
1955
Daniel Willmannbf2ca572010-01-07 00:46:26 +01001956int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1957{
1958 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1959}
1960
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001961int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001962{
Harald Welte59b04682009-06-10 05:40:52 +08001963 struct abis_om_hdr *oh;
1964 struct msgb *msg = nm_msgb_alloc();
1965 struct bs11_date_time bdt;
1966
1967 get_bs11_date_time(&bdt);
1968
1969 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1970 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001971 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001972 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08001973 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
1974 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1975 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001976 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08001977 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001978 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08001979 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001980 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08001981 } else {
1982 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
1983 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1984 }
1985
1986 return abis_nm_sendmsg(bts, msg);
1987}
1988
1989int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1990{
1991 struct abis_om_hdr *oh;
1992 struct msgb *msg;
1993
1994 if (strlen(password) != 10)
1995 return -EINVAL;
1996
1997 msg = nm_msgb_alloc();
1998 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1999 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2000 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002001 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002002
2003 return abis_nm_sendmsg(bts, msg);
2004}
2005
2006/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2007int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2008{
2009 struct abis_om_hdr *oh;
2010 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002011 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002012
2013 msg = nm_msgb_alloc();
2014 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2015 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2016 BS11_OBJ_LI, 0x00, 0x00);
2017
2018 if (locked)
2019 tlv_value = BS11_LI_PLL_LOCKED;
2020 else
2021 tlv_value = BS11_LI_PLL_STANDALONE;
2022
2023 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2024
2025 return abis_nm_sendmsg(bts, msg);
2026}
2027
Daniel Willmann10b07db2010-01-07 00:54:01 +01002028/* Set the calibration value of the PLL (work value/set value)
2029 * It depends on the login which one is changed */
2030int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2031{
2032 struct abis_om_hdr *oh;
2033 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002034 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002035
2036 msg = nm_msgb_alloc();
2037 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2038 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2039 BS11_OBJ_TRX1, 0x00, 0x00);
2040
2041 tlv_value[0] = value>>8;
2042 tlv_value[1] = value&0xff;
2043
2044 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2045
2046 return abis_nm_sendmsg(bts, msg);
2047}
2048
Harald Welte59b04682009-06-10 05:40:52 +08002049int abis_nm_bs11_get_state(struct gsm_bts *bts)
2050{
2051 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2052}
2053
2054/* BS11 SWL */
2055
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002056void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002057
Harald Welte59b04682009-06-10 05:40:52 +08002058struct abis_nm_bs11_sw {
2059 struct gsm_bts *bts;
2060 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002061 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002062 int forced;
2063 struct llist_head file_list;
2064 gsm_cbfn *user_cb; /* specified by the user */
2065};
2066static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2067
2068struct file_list_entry {
2069 struct llist_head list;
2070 char fname[PATH_MAX];
2071};
2072
2073struct file_list_entry *fl_dequeue(struct llist_head *queue)
2074{
2075 struct llist_head *lh;
2076
2077 if (llist_empty(queue))
2078 return NULL;
2079
2080 lh = queue->next;
2081 llist_del(lh);
2082
2083 return llist_entry(lh, struct file_list_entry, list);
2084}
2085
2086static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2087{
2088 char linebuf[255];
2089 struct llist_head *lh, *lh2;
2090 FILE *swl;
2091 int rc = 0;
2092
2093 swl = fopen(bs11_sw->swl_fname, "r");
2094 if (!swl)
2095 return -ENODEV;
2096
2097 /* zero the stale file list, if any */
2098 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2099 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002100 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002101 }
2102
2103 while (fgets(linebuf, sizeof(linebuf), swl)) {
2104 char file_id[12+1];
2105 char file_version[80+1];
2106 struct file_list_entry *fle;
2107 static char dir[PATH_MAX];
2108
2109 if (strlen(linebuf) < 4)
2110 continue;
2111
2112 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2113 if (rc < 0) {
2114 perror("ERR parsing SWL file");
2115 rc = -EINVAL;
2116 goto out;
2117 }
2118 if (rc < 2)
2119 continue;
2120
Harald Welte857e00d2009-06-26 20:25:23 +02002121 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002122 if (!fle) {
2123 rc = -ENOMEM;
2124 goto out;
2125 }
Harald Welte59b04682009-06-10 05:40:52 +08002126
2127 /* construct new filename */
2128 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2129 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2130 strcat(fle->fname, "/");
2131 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2132
2133 llist_add_tail(&fle->list, &bs11_sw->file_list);
2134 }
2135
2136out:
2137 fclose(swl);
2138 return rc;
2139}
2140
2141/* bs11 swload specific callback, passed to abis_nm core swload */
2142static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2143 struct msgb *msg, void *data, void *param)
2144{
2145 struct abis_nm_bs11_sw *bs11_sw = data;
2146 struct file_list_entry *fle;
2147 int rc = 0;
2148
2149 switch (event) {
2150 case NM_MT_LOAD_END_ACK:
2151 fle = fl_dequeue(&bs11_sw->file_list);
2152 if (fle) {
2153 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002154 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002155 bs11_sw->win_size,
2156 bs11_sw->forced,
2157 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002158 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002159 } else {
2160 /* activate the SWL */
2161 rc = abis_nm_software_activate(bs11_sw->bts,
2162 bs11_sw->swl_fname,
2163 bs11_swload_cbfn,
2164 bs11_sw);
2165 }
2166 break;
2167 case NM_MT_LOAD_SEG_ACK:
2168 case NM_MT_LOAD_END_NACK:
2169 case NM_MT_LOAD_INIT_ACK:
2170 case NM_MT_LOAD_INIT_NACK:
2171 case NM_MT_ACTIVATE_SW_NACK:
2172 case NM_MT_ACTIVATE_SW_ACK:
2173 default:
2174 /* fallthrough to the user callback */
2175 if (bs11_sw->user_cb)
2176 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2177 break;
2178 }
2179
2180 return rc;
2181}
2182
2183/* Siemens provides a SWL file that is a mere listing of all the other
2184 * files that are part of a software release. We need to upload first
2185 * the list file, and then each file that is listed in the list file */
2186int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002187 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002188{
2189 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2190 struct file_list_entry *fle;
2191 int rc = 0;
2192
2193 INIT_LLIST_HEAD(&bs11_sw->file_list);
2194 bs11_sw->bts = bts;
2195 bs11_sw->win_size = win_size;
2196 bs11_sw->user_cb = cbfn;
2197 bs11_sw->forced = forced;
2198
2199 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2200 rc = bs11_read_swl_file(bs11_sw);
2201 if (rc < 0)
2202 return rc;
2203
2204 /* dequeue next item in file list */
2205 fle = fl_dequeue(&bs11_sw->file_list);
2206 if (!fle)
2207 return -EINVAL;
2208
2209 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002210 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002211 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002212 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002213 return rc;
2214}
2215
2216#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002217static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002218 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2219 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2220 NM_ATT_BS11_LMT_USER_NAME,
2221
2222 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2223
2224 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2225
2226 NM_ATT_BS11_SW_LOAD_STORED };
2227
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002228static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002229 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2230 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2231 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2232 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2233#endif
2234
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002235static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002236 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2237 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2238 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2239
2240int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2241{
2242 struct abis_om_hdr *oh;
2243 struct msgb *msg = nm_msgb_alloc();
2244
2245 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2246 /* SiemensHW CCTRL object */
2247 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2248 0x03, 0x00, 0x00);
2249 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2250
2251 return abis_nm_sendmsg(bts, msg);
2252}
2253
2254int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2255{
2256 struct abis_om_hdr *oh;
2257 struct msgb *msg = nm_msgb_alloc();
2258 struct bs11_date_time aet;
2259
2260 get_bs11_date_time(&aet);
2261 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2262 /* SiemensHW CCTRL object */
2263 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2264 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002265 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002266
2267 return abis_nm_sendmsg(bts, msg);
2268}
2269
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002270int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002271{
2272 struct abis_om_hdr *oh;
2273 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002274 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002275
2276 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2277 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2278 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2279 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2280
2281 return abis_nm_sendmsg(bts, msg);
2282}
2283
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002284int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Daniel Willmann5655afe2009-08-10 11:49:36 +02002285{
2286 struct abis_om_hdr *oh;
2287 struct msgb *msg = nm_msgb_alloc();
2288 struct bs11_date_time aet;
2289
2290 get_bs11_date_time(&aet);
2291 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2292 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2293 bport, 0xff, 0x02);
2294 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2295
2296 return abis_nm_sendmsg(bts, msg);
2297}
2298
Harald Welte59b04682009-06-10 05:40:52 +08002299/* ip.access nanoBTS specific commands */
2300static const char ipaccess_magic[] = "com.ipaccess";
2301
2302
2303static int abis_nm_rx_ipacc(struct msgb *msg)
2304{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002305 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002306 struct abis_om_hdr *oh = msgb_l2(msg);
2307 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002308 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002309 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002310 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002311 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002312
2313 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002314 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002315 return -EINVAL;
2316 }
2317
2318 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002319 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002320
Harald Weltec61a90e2011-05-22 22:45:37 +02002321 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002322
Harald Welte5aeedd42009-10-19 22:11:11 +02002323 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002324
2325 switch (foh->msg_type) {
2326 case NM_MT_IPACC_RSL_CONNECT_ACK:
2327 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002328 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2329 memcpy(&addr,
2330 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2331
2332 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2333 }
Harald Welte4206d982009-07-12 09:33:54 +02002334 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002335 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002336 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002337 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002338 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2339 DEBUGPC(DNM, "STREAM=0x%02x ",
2340 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002341 DEBUGPC(DNM, "\n");
2342 break;
2343 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002344 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002345 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002346 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002347 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002348 else
2349 DEBUGPC(DNM, "\n");
2350 break;
2351 case NM_MT_IPACC_SET_NVATTR_ACK:
2352 DEBUGPC(DNM, "SET NVATTR ACK\n");
2353 /* FIXME: decode and show the actual attributes */
2354 break;
2355 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002356 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002357 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002358 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002359 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002360 else
Harald Weltede4477a2009-12-24 12:20:20 +01002361 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002362 break;
Harald Welte21460f02009-07-03 11:26:45 +02002363 case NM_MT_IPACC_GET_NVATTR_ACK:
2364 DEBUGPC(DNM, "GET NVATTR ACK\n");
2365 /* FIXME: decode and show the actual attributes */
2366 break;
2367 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002368 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002369 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002370 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002371 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002372 else
Harald Weltede4477a2009-12-24 12:20:20 +01002373 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002374 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002375 case NM_MT_IPACC_SET_ATTR_ACK:
2376 DEBUGPC(DNM, "SET ATTR ACK\n");
2377 break;
2378 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002379 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002380 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002381 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002382 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002383 else
Harald Weltede4477a2009-12-24 12:20:20 +01002384 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002385 break;
Harald Welte59b04682009-06-10 05:40:52 +08002386 default:
2387 DEBUGPC(DNM, "unknown\n");
2388 break;
2389 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002390
2391 /* signal handling */
2392 switch (foh->msg_type) {
2393 case NM_MT_IPACC_RSL_CONNECT_NACK:
2394 case NM_MT_IPACC_SET_NVATTR_NACK:
2395 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002396 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002397 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002398 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002399 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002400 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002401 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002402 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002403 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002404 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002405 default:
2406 break;
2407 }
2408
Harald Welte59b04682009-06-10 05:40:52 +08002409 return 0;
2410}
2411
2412/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002413int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2414 uint8_t obj_class, uint8_t bts_nr,
2415 uint8_t trx_nr, uint8_t ts_nr,
2416 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002417{
2418 struct msgb *msg = nm_msgb_alloc();
2419 struct abis_om_hdr *oh;
2420 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002421 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002422
2423 /* construct the 12.21 OM header, observe the erroneous length */
2424 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2425 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2426 oh->mdisc = ABIS_OM_MDISC_MANUF;
2427
2428 /* add the ip.access magic */
2429 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2430 *data++ = sizeof(ipaccess_magic);
2431 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2432
2433 /* fill the 12.21 FOM header */
2434 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2435 foh->msg_type = msg_type;
2436 foh->obj_class = obj_class;
2437 foh->obj_inst.bts_nr = bts_nr;
2438 foh->obj_inst.trx_nr = trx_nr;
2439 foh->obj_inst.ts_nr = ts_nr;
2440
2441 if (attr && attr_len) {
2442 data = msgb_put(msg, attr_len);
2443 memcpy(data, attr, attr_len);
2444 }
2445
2446 return abis_nm_sendmsg(bts, msg);
2447}
2448
2449/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002450int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002451 int attr_len)
2452{
Harald Weltef12c1052010-01-07 20:39:42 +01002453 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2454 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002455 attr_len);
2456}
2457
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002458int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002459 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002460{
2461 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002462 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002463 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2464 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2465
2466 int attr_len = sizeof(attr);
2467
2468 ia.s_addr = htonl(ip);
2469 attr[1] = stream;
2470 attr[3] = port >> 8;
2471 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002472 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002473
2474 /* if ip == 0, we use the default IP */
2475 if (ip == 0)
2476 attr_len -= 5;
2477
2478 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002479 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002480
2481 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2482 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2483 trx->nr, 0xff, attr, attr_len);
2484}
2485
Harald Welte59b04682009-06-10 05:40:52 +08002486/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002487int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002488{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002489 struct abis_om_hdr *oh;
2490 struct msgb *msg = nm_msgb_alloc();
2491
2492 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2493 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2494 trx->bts->nr, trx->nr, 0xff);
2495
2496 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002497}
Harald Welte0dfc6232009-10-24 10:20:41 +02002498
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002499int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2500 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2501 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002502{
2503 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2504 obj_class, bts_nr, trx_nr, ts_nr,
2505 attr, attr_len);
2506}
Harald Weltebeeae412009-11-12 14:48:42 +01002507
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002508void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002509{
2510 /* we simply reuse the GSM48 function and overwrite the RAC
2511 * with the Cell ID */
2512 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002513 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002514}
2515
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002516void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2517{
2518 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2519
Harald Welte69f6f812011-05-30 12:07:53 +02002520 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002521 if (!trx->bts || !trx->bts->oml_link)
2522 return;
2523
2524 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2525 trx->bts->bts_nr, trx->nr, 0xff,
2526 new_state);
2527}
2528
Harald Welte453141f2010-03-25 11:45:30 +08002529static const struct value_string ipacc_testres_names[] = {
2530 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2531 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2532 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2533 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2534 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2535 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002536};
2537
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002538const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002539{
Harald Welte453141f2010-03-25 11:45:30 +08002540 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002541}
2542
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002543void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002544{
2545 cid->mcc = (buf[0] & 0xf) * 100;
2546 cid->mcc += (buf[0] >> 4) * 10;
2547 cid->mcc += (buf[1] & 0xf) * 1;
2548
2549 if (buf[1] >> 4 == 0xf) {
2550 cid->mnc = (buf[2] & 0xf) * 10;
2551 cid->mnc += (buf[2] >> 4) * 1;
2552 } else {
2553 cid->mnc = (buf[2] & 0xf) * 100;
2554 cid->mnc += (buf[2] >> 4) * 10;
2555 cid->mnc += (buf[1] >> 4) * 1;
2556 }
2557
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002558 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2559 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002560}
2561
Harald Weltebeeae412009-11-12 14:48:42 +01002562/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002563int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002564{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002565 uint8_t *cur = buf;
2566 uint16_t len;
Harald Weltebeeae412009-11-12 14:48:42 +01002567
Harald Welteb784df82010-07-22 18:14:36 +02002568 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002569
2570 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2571 return -EINVAL;
2572 cur++;
2573
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002574 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002575 cur += 2;
2576
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002577 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002578 cur += 2;
2579
2580 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2581 binf->freq_qual = *cur >> 2;
2582
Harald Welteb784df82010-07-22 18:14:36 +02002583 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002584 binf->arfcn |= *cur++;
2585
2586 if (binf->info_type & IPAC_BINF_RXLEV)
2587 binf->rx_lev = *cur & 0x3f;
2588 cur++;
2589
2590 if (binf->info_type & IPAC_BINF_RXQUAL)
2591 binf->rx_qual = *cur & 0x7;
2592 cur++;
2593
2594 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002595 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002596 cur += 2;
2597
2598 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002599 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002600 cur += 2;
2601
2602 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002603 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002604 cur += 4;
2605
Harald Welte22cb81f2010-07-30 22:34:42 +02002606#if 0
2607 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002608 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002609#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002610 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002611 cur++;
2612
Harald Weltebfc21092009-11-13 11:56:05 +01002613 ipac_parse_cgi(&binf->cgi, cur);
2614 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002615
2616 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2617 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2618 cur += sizeof(binf->ba_list_si2);
2619 }
2620
2621 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2622 memcpy(binf->ba_list_si2bis, cur,
2623 sizeof(binf->ba_list_si2bis));
2624 cur += sizeof(binf->ba_list_si2bis);
2625 }
2626
2627 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2628 memcpy(binf->ba_list_si2ter, cur,
2629 sizeof(binf->ba_list_si2ter));
2630 cur += sizeof(binf->ba_list_si2ter);
2631 }
2632
2633 return 0;
2634}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002635
2636void abis_nm_clear_queue(struct gsm_bts *bts)
2637{
2638 struct msgb *msg;
2639
2640 while (!llist_empty(&bts->abis_queue)) {
2641 msg = msgb_dequeue(&bts->abis_queue);
2642 msgb_free(msg);
2643 }
2644
2645 bts->abis_nm_pend = 0;
2646}