blob: f491a0c20a8f31d2b80d6e8835dfc5ebb464328a [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 Freyther23e80002012-11-22 14:59:46 +0100362int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
363 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100364{
365 static const struct tlv_definition sw_descr_def = {
366 .def = {
367 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
368 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
369 },
370 };
371
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100372 size_t pos = 0;
373 int desc_pos = 0;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100374
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100375 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
376 uint8_t tag;
377 uint16_t tag_len;
378 const uint8_t *val;
379 int len;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100380
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100381 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
382 desc[desc_pos].start = &sw_descr[pos];
383
384 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
385 * nested nature and the fact you have to assume it contains only two sub
386 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
387 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
388 LOGP(DNM, LOGL_ERROR,
389 "SW_DESCR attribute identifier not found!\n");
390 return -1;
391 }
392
393 pos += 1;
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
396 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
397 LOGP(DNM, LOGL_ERROR,
398 "FILE_ID attribute identifier not found!\n");
399 return -2;
400 }
401 desc[desc_pos].file_id = val;
402 desc[desc_pos].file_id_len = tag_len;
403 pos += len;
404
405
406 len = tlv_parse_one(&tag, &tag_len, &val,
407 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
408 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
409 LOGP(DNM, LOGL_ERROR,
410 "FILE_VERSION attribute identifier not found!\n");
411 return -3;
412 }
413 desc[desc_pos].file_ver = val;
414 desc[desc_pos].file_ver_len = tag_len;
415 pos += len;
416
417 /* final size */
418 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100419 }
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100420
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100421 return desc_pos;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100422}
423
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100424int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
425 const size_t size)
426{
427 int res = 0;
428 int i;
429
430 for (i = 1; i < size; ++i) {
431 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
432 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
433 res = i;
434 }
435 }
436
437 return res;
438}
439
Harald Welte59b04682009-06-10 05:40:52 +0800440static int abis_nm_rx_sw_act_req(struct msgb *mb)
441{
442 struct abis_om_hdr *oh = msgb_l2(mb);
443 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200444 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200445 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200446 const uint8_t *sw_config;
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100447 int ret, sw_config_len, len;
448 struct abis_nm_sw_descr sw_descr[5];
Harald Welte59b04682009-06-10 05:40:52 +0800449
Harald Weltec61a90e2011-05-22 22:45:37 +0200450 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200451
452 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800453
Harald Welte3055e332010-03-14 15:37:43 +0800454 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800455
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200456 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800457 foh->obj_inst.bts_nr,
458 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800459 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800460 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100461 if (ret != 0) {
462 LOGP(DNM, LOGL_ERROR,
463 "Sending SW ActReq ACK failed: %d\n", ret);
464 return ret;
465 }
Harald Welte59b04682009-06-10 05:40:52 +0800466
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200467 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200468 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
469 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
470 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100471 LOGP(DNM, LOGL_ERROR,
472 "SW config not found! Can't continue.\n");
Mike Haben322fc582009-10-01 14:56:13 +0200473 return -EINVAL;
474 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200475 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200476 }
477
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100478 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100479 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100480 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100481 if (len <= 0) {
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100482 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100483 return -EINVAL;
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100484 }
Mike Haben322fc582009-10-01 14:56:13 +0200485
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100486 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
487 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
488
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200489 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800490 foh->obj_inst.bts_nr,
491 foh->obj_inst.trx_nr,
492 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100493 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte59b04682009-06-10 05:40:52 +0800494}
495
496/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
497static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
498{
499 struct abis_om_hdr *oh = msgb_l2(mb);
500 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200501 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800502 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200503 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800504
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200505 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800506 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
507 return -EINVAL;
508
509 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
510
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200511 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800512}
513
514static int abis_nm_rx_lmt_event(struct msgb *mb)
515{
516 struct abis_om_hdr *oh = msgb_l2(mb);
517 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200518 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800519 struct tlv_parsed tp;
520
521 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200522 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800523 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
524 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200525 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800526 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
527 }
528 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
529 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200530 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800531 DEBUGPC(DNM, "Level=%u ", level);
532 }
533 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
534 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
535 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
536 DEBUGPC(DNM, "Username=%s ", name);
537 }
538 DEBUGPC(DNM, "\n");
539 /* FIXME: parse LMT LOGON TIME */
540 return 0;
541}
542
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200543void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100544{
545 int wait = 0;
546 struct msgb *msg;
547 /* the queue is empty */
548 while (!llist_empty(&bts->abis_queue)) {
549 msg = msgb_dequeue(&bts->abis_queue);
550 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200551 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100552
553 if (wait)
554 break;
555 }
556
557 bts->abis_nm_pend = wait;
558}
559
Harald Welte59b04682009-06-10 05:40:52 +0800560/* Receive a OML NM Message from BTS */
561static int abis_nm_rcvmsg_fom(struct msgb *mb)
562{
563 struct abis_om_hdr *oh = msgb_l2(mb);
564 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200565 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200566 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100567 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800568
569 /* check for unsolicited message */
570 if (is_report(mt))
571 return abis_nm_rcvmsg_report(mb);
572
Harald Weltec61a90e2011-05-22 22:45:37 +0200573 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800574 return abis_nm_rcvmsg_sw(mb);
575
Harald Weltec61a90e2011-05-22 22:45:37 +0200576 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800577 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800578 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200579
Harald Weltec61a90e2011-05-22 22:45:37 +0200580 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200581
Harald Weltec61a90e2011-05-22 22:45:37 +0200582 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800583
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200584 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800585 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200586 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200587 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800588 else
589 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200590
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800591 nack_data.msg = mb;
592 nack_data.mt = mt;
Holger Hans Peter Freyther70f1e472012-11-11 18:26:23 +0100593 nack_data.bts = sign_link->trx->bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200594 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200595 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200596 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800597 }
598#if 0
599 /* check if last message is to be acked */
600 if (is_ack_nack(nmh->last_msgtype)) {
601 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100602 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800603 /* we got our ACK, continue sending the next msg */
604 } else if (mt == MT_NACK(nmh->last_msgtype)) {
605 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100606 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800607 /* FIXME: somehow signal this to the caller */
608 } else {
609 /* really strange things happen */
610 return -EINVAL;
611 }
612 }
613#endif
614
615 switch (mt) {
616 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100617 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800618 break;
619 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100620 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800621 break;
622 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100623 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800624 break;
Harald Welte204317e2009-08-06 17:58:31 +0200625 case NM_MT_CONN_MDROP_LINK_ACK:
626 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
627 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100628 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200629 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100630 break;
631 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200632 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100633 break;
Harald Welte08011e22011-03-04 13:41:31 +0100634 case NM_MT_SET_BTS_ATTR_ACK:
Harald Welte08011e22011-03-04 13:41:31 +0100635 break;
Harald Welte59b04682009-06-10 05:40:52 +0800636 }
637
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200638 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100639 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800640}
641
642static int abis_nm_rx_ipacc(struct msgb *mb);
643
644static int abis_nm_rcvmsg_manuf(struct msgb *mb)
645{
646 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200647 struct e1inp_sign_link *sign_link = mb->dst;
648 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800649
650 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100651 case GSM_BTS_TYPE_NANOBTS:
Harald Welte35ac0e42012-07-02 19:51:55 +0200652 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte59b04682009-06-10 05:40:52 +0800653 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200654 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800655 break;
656 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100657 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
658 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800659 rc = 0;
660 break;
661 }
662
663 return rc;
664}
665
666/* High-Level API */
667/* Entry-point where L2 OML from BTS enters the NM code */
668int abis_nm_rcvmsg(struct msgb *msg)
669{
670 struct abis_om_hdr *oh = msgb_l2(msg);
671 int rc = 0;
672
673 /* Various consistency checks */
674 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100675 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800676 oh->placement);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200677 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
678 rc = -EINVAL;
679 goto err;
680 }
Harald Welte59b04682009-06-10 05:40:52 +0800681 }
682 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100683 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800684 oh->sequence);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200685 rc = -EINVAL;
686 goto err;
Harald Welte59b04682009-06-10 05:40:52 +0800687 }
688#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200689 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800690 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
691 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100692 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800693 oh->length + sizeof(*oh), l2_len);
694 return -EINVAL;
695 }
696 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100697 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 +0800698#endif
699 msg->l3h = (unsigned char *)oh + sizeof(*oh);
700
701 switch (oh->mdisc) {
702 case ABIS_OM_MDISC_FOM:
703 rc = abis_nm_rcvmsg_fom(msg);
704 break;
705 case ABIS_OM_MDISC_MANUF:
706 rc = abis_nm_rcvmsg_manuf(msg);
707 break;
708 case ABIS_OM_MDISC_MMI:
709 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100710 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800711 oh->mdisc);
712 break;
713 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100714 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800715 oh->mdisc);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200716 rc = -EINVAL;
717 break;
Harald Welte59b04682009-06-10 05:40:52 +0800718 }
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200719err:
Harald Welte59b04682009-06-10 05:40:52 +0800720 msgb_free(msg);
721 return rc;
722}
723
724#if 0
725/* initialized all resources */
726struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
727{
728 struct abis_nm_h *nmh;
729
730 nmh = malloc(sizeof(*nmh));
731 if (!nmh)
732 return NULL;
733
734 nmh->cfg = cfg;
735
736 return nmh;
737}
738
739/* free all resources */
740void abis_nm_fini(struct abis_nm_h *nmh)
741{
742 free(nmh);
743}
744#endif
745
746/* Here we are trying to define a high-level API that can be used by
747 * the actual BSC implementation. However, the architecture is currently
748 * still under design. Ideally the calls to this API would be synchronous,
749 * while the underlying stack behind the APi runs in a traditional select
750 * based state machine.
751 */
752
753/* 6.2 Software Load: */
754enum sw_state {
755 SW_STATE_NONE,
756 SW_STATE_WAIT_INITACK,
757 SW_STATE_WAIT_SEGACK,
758 SW_STATE_WAIT_ENDACK,
759 SW_STATE_WAIT_ACTACK,
760 SW_STATE_ERROR,
761};
762
763struct abis_nm_sw {
764 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800765 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800766 gsm_cbfn *cbfn;
767 void *cb_data;
768 int forced;
769
770 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200771 uint8_t obj_class;
772 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800773
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200774 uint8_t file_id[255];
775 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800776
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200777 uint8_t file_version[255];
778 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800779
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200780 uint8_t window_size;
781 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800782
783 int fd;
784 FILE *stream;
785 enum sw_state state;
786 int last_seg;
787};
788
789static struct abis_nm_sw g_sw;
790
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100791static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
792{
793 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
794 msgb_v_put(msg, NM_ATT_SW_DESCR);
795 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
796 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
797 sw->file_version);
798 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
799 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
800 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
801 sw->file_version);
802 } else {
803 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
804 }
805}
806
Harald Welte59b04682009-06-10 05:40:52 +0800807/* 6.2.1 / 8.3.1: Load Data Initiate */
808static int sw_load_init(struct abis_nm_sw *sw)
809{
810 struct abis_om_hdr *oh;
811 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200812 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800813
814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
815 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
816 sw->obj_instance[0], sw->obj_instance[1],
817 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100818
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100819 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800820 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
821
822 return abis_nm_sendmsg(sw->bts, msg);
823}
824
825static int is_last_line(FILE *stream)
826{
827 char next_seg_buf[256];
828 long pos;
829
830 /* check if we're sending the last line */
831 pos = ftell(stream);
832 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
833 fseek(stream, pos, SEEK_SET);
834 return 1;
835 }
836
837 fseek(stream, pos, SEEK_SET);
838 return 0;
839}
840
841/* 6.2.2 / 8.3.2 Load Data Segment */
842static int sw_load_segment(struct abis_nm_sw *sw)
843{
844 struct abis_om_hdr *oh;
845 struct msgb *msg = nm_msgb_alloc();
846 char seg_buf[256];
847 char *line_buf = seg_buf+2;
848 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200849 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800850
851 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
852
853 switch (sw->bts->type) {
854 case GSM_BTS_TYPE_BS11:
855 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
856 perror("fgets reading segment");
857 return -EINVAL;
858 }
859 seg_buf[0] = 0x00;
860
861 /* check if we're sending the last line */
862 sw->last_seg = is_last_line(sw->stream);
863 if (sw->last_seg)
864 seg_buf[1] = 0;
865 else
866 seg_buf[1] = 1 + sw->seg_in_window++;
867
868 len = strlen(line_buf) + 2;
869 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200870 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800871 /* BS11 wants CR + LF in excess of the TLV length !?! */
872 tlv[1] -= 2;
873
874 /* we only now know the exact length for the OM hdr */
875 len = strlen(line_buf)+2;
876 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100877 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200878 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100879 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
880 if (len < 0) {
881 perror("read failed");
882 return -EINVAL;
883 }
884
885 if (len != IPACC_SEGMENT_SIZE)
886 sw->last_seg = 1;
887
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100888 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200889 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100890 len += 3;
891 break;
892 }
Harald Welte59b04682009-06-10 05:40:52 +0800893 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100894 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800895 /* FIXME: Other BTS types */
896 return -1;
897 }
898
899 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
900 sw->obj_instance[0], sw->obj_instance[1],
901 sw->obj_instance[2]);
902
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100903 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800904}
905
906/* 6.2.4 / 8.3.4 Load Data End */
907static int sw_load_end(struct abis_nm_sw *sw)
908{
909 struct abis_om_hdr *oh;
910 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200911 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800912
913 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
914 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
915 sw->obj_instance[0], sw->obj_instance[1],
916 sw->obj_instance[2]);
917
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100918 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800919 return abis_nm_sendmsg(sw->bts, msg);
920}
921
922/* Activate the specified software into the BTS */
923static int sw_activate(struct abis_nm_sw *sw)
924{
925 struct abis_om_hdr *oh;
926 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200927 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800928
929 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
930 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
931 sw->obj_instance[0], sw->obj_instance[1],
932 sw->obj_instance[2]);
933
934 /* FIXME: this is BS11 specific format */
935 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
936 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
937 sw->file_version);
938
939 return abis_nm_sendmsg(sw->bts, msg);
940}
941
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100942struct sdp_firmware {
943 char magic[4];
944 char more_magic[4];
945 unsigned int header_length;
946 unsigned int file_length;
947} __attribute__ ((packed));
948
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100949static int parse_sdp_header(struct abis_nm_sw *sw)
950{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100951 struct sdp_firmware firmware_header;
952 int rc;
953 struct stat stat;
954
955 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
956 if (rc != sizeof(firmware_header)) {
957 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
958 return -1;
959 }
960
961 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
962 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
963 return -1;
964 }
965
966 if (firmware_header.more_magic[0] != 0x10 ||
967 firmware_header.more_magic[1] != 0x02 ||
968 firmware_header.more_magic[2] != 0x00 ||
969 firmware_header.more_magic[3] != 0x00) {
970 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
971 return -1;
972 }
973
974
975 if (fstat(sw->fd, &stat) == -1) {
976 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
977 return -1;
978 }
979
980 if (ntohl(firmware_header.file_length) != stat.st_size) {
981 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
982 return -1;
983 }
984
985 /* go back to the start as we checked the whole filesize.. */
986 lseek(sw->fd, 0l, SEEK_SET);
987 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
988 "There might be checksums in the file that are not\n"
989 "verified and incomplete firmware might be flashed.\n"
990 "There is absolutely no WARRANTY that flashing will\n"
991 "work.\n");
992 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100993}
994
Harald Welte59b04682009-06-10 05:40:52 +0800995static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
996{
997 char file_id[12+1];
998 char file_version[80+1];
999 int rc;
1000
1001 sw->fd = open(fname, O_RDONLY);
1002 if (sw->fd < 0)
1003 return sw->fd;
1004
1005 switch (sw->bts->type) {
1006 case GSM_BTS_TYPE_BS11:
1007 sw->stream = fdopen(sw->fd, "r");
1008 if (!sw->stream) {
1009 perror("fdopen");
1010 return -1;
1011 }
1012 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001013 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001014 file_id, file_version);
1015 if (rc != 2) {
1016 perror("parsing header line of software file");
1017 return -1;
1018 }
1019 strcpy((char *)sw->file_id, file_id);
1020 sw->file_id_len = strlen(file_id);
1021 strcpy((char *)sw->file_version, file_version);
1022 sw->file_version_len = strlen(file_version);
1023 /* rewind to start of file */
1024 rewind(sw->stream);
1025 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001026 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001027 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001028 rc = parse_sdp_header(sw);
1029 if (rc < 0) {
1030 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1031 return -1;
1032 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001033
1034 strcpy((char *)sw->file_id, "id");
1035 sw->file_id_len = 3;
1036 strcpy((char *)sw->file_version, "version");
1037 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001038 break;
Harald Welte59b04682009-06-10 05:40:52 +08001039 default:
1040 /* We don't know how to treat them yet */
1041 close(sw->fd);
1042 return -EINVAL;
1043 }
1044
1045 return 0;
1046}
1047
1048static void sw_close_file(struct abis_nm_sw *sw)
1049{
1050 switch (sw->bts->type) {
1051 case GSM_BTS_TYPE_BS11:
1052 fclose(sw->stream);
1053 break;
1054 default:
1055 close(sw->fd);
1056 break;
1057 }
1058}
1059
1060/* Fill the window */
1061static int sw_fill_window(struct abis_nm_sw *sw)
1062{
1063 int rc;
1064
1065 while (sw->seg_in_window < sw->window_size) {
1066 rc = sw_load_segment(sw);
1067 if (rc < 0)
1068 return rc;
1069 if (sw->last_seg)
1070 break;
1071 }
1072 return 0;
1073}
1074
1075/* callback function from abis_nm_rcvmsg() handler */
1076static int abis_nm_rcvmsg_sw(struct msgb *mb)
1077{
1078 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001079 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001080 int rc = -1;
1081 struct abis_nm_sw *sw = &g_sw;
1082 enum sw_state old_state = sw->state;
1083
1084 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1085
1086 switch (sw->state) {
1087 case SW_STATE_WAIT_INITACK:
1088 switch (foh->msg_type) {
1089 case NM_MT_LOAD_INIT_ACK:
1090 /* fill window with segments */
1091 if (sw->cbfn)
1092 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1093 NM_MT_LOAD_INIT_ACK, mb,
1094 sw->cb_data, NULL);
1095 rc = sw_fill_window(sw);
1096 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001097 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001098 break;
1099 case NM_MT_LOAD_INIT_NACK:
1100 if (sw->forced) {
1101 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1102 "Init NACK\n");
1103 if (sw->cbfn)
1104 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1105 NM_MT_LOAD_INIT_ACK, mb,
1106 sw->cb_data, NULL);
1107 rc = sw_fill_window(sw);
1108 sw->state = SW_STATE_WAIT_SEGACK;
1109 } else {
1110 DEBUGP(DNM, "Software Load Init NACK\n");
1111 /* FIXME: cause */
1112 if (sw->cbfn)
1113 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1114 NM_MT_LOAD_INIT_NACK, mb,
1115 sw->cb_data, NULL);
1116 sw->state = SW_STATE_ERROR;
1117 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001118 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001119 break;
1120 }
1121 break;
1122 case SW_STATE_WAIT_SEGACK:
1123 switch (foh->msg_type) {
1124 case NM_MT_LOAD_SEG_ACK:
1125 if (sw->cbfn)
1126 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1127 NM_MT_LOAD_SEG_ACK, mb,
1128 sw->cb_data, NULL);
1129 sw->seg_in_window = 0;
1130 if (!sw->last_seg) {
1131 /* fill window with more segments */
1132 rc = sw_fill_window(sw);
1133 sw->state = SW_STATE_WAIT_SEGACK;
1134 } else {
1135 /* end the transfer */
1136 sw->state = SW_STATE_WAIT_ENDACK;
1137 rc = sw_load_end(sw);
1138 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001139 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001140 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001141 case NM_MT_LOAD_ABORT:
1142 if (sw->cbfn)
1143 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1144 NM_MT_LOAD_ABORT, mb,
1145 sw->cb_data, NULL);
1146 break;
Harald Welte59b04682009-06-10 05:40:52 +08001147 }
1148 break;
1149 case SW_STATE_WAIT_ENDACK:
1150 switch (foh->msg_type) {
1151 case NM_MT_LOAD_END_ACK:
1152 sw_close_file(sw);
1153 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1154 sw->bts->nr);
1155 sw->state = SW_STATE_NONE;
1156 if (sw->cbfn)
1157 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1158 NM_MT_LOAD_END_ACK, mb,
1159 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001160 rc = 0;
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 case NM_MT_LOAD_END_NACK:
1164 if (sw->forced) {
1165 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1166 "End NACK\n");
1167 sw->state = SW_STATE_NONE;
1168 if (sw->cbfn)
1169 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1170 NM_MT_LOAD_END_ACK, mb,
1171 sw->cb_data, NULL);
1172 } else {
1173 DEBUGP(DNM, "Software Load End NACK\n");
1174 /* FIXME: cause */
1175 sw->state = SW_STATE_ERROR;
1176 if (sw->cbfn)
1177 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1178 NM_MT_LOAD_END_NACK, mb,
1179 sw->cb_data, NULL);
1180 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001181 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001182 break;
1183 }
1184 case SW_STATE_WAIT_ACTACK:
1185 switch (foh->msg_type) {
1186 case NM_MT_ACTIVATE_SW_ACK:
1187 /* we're done */
1188 DEBUGP(DNM, "Activate Software DONE!\n");
1189 sw->state = SW_STATE_NONE;
1190 rc = 0;
1191 if (sw->cbfn)
1192 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1193 NM_MT_ACTIVATE_SW_ACK, mb,
1194 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001195 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001196 break;
1197 case NM_MT_ACTIVATE_SW_NACK:
1198 DEBUGP(DNM, "Activate Software NACK\n");
1199 /* FIXME: cause */
1200 sw->state = SW_STATE_ERROR;
1201 if (sw->cbfn)
1202 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1203 NM_MT_ACTIVATE_SW_NACK, mb,
1204 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001205 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001206 break;
1207 }
1208 case SW_STATE_NONE:
1209 switch (foh->msg_type) {
1210 case NM_MT_ACTIVATE_SW_ACK:
1211 rc = 0;
1212 break;
1213 }
1214 break;
1215 case SW_STATE_ERROR:
1216 break;
1217 }
1218
1219 if (rc)
1220 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1221 foh->msg_type, old_state, sw->state);
1222
1223 return rc;
1224}
1225
1226/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001227int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001228 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001229 gsm_cbfn *cbfn, void *cb_data)
1230{
1231 struct abis_nm_sw *sw = &g_sw;
1232 int rc;
1233
1234 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1235 bts->nr, fname);
1236
1237 if (sw->state != SW_STATE_NONE)
1238 return -EBUSY;
1239
1240 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001241 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001242
1243 switch (bts->type) {
1244 case GSM_BTS_TYPE_BS11:
1245 sw->obj_class = NM_OC_SITE_MANAGER;
1246 sw->obj_instance[0] = 0xff;
1247 sw->obj_instance[1] = 0xff;
1248 sw->obj_instance[2] = 0xff;
1249 break;
1250 case GSM_BTS_TYPE_NANOBTS:
1251 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001252 sw->obj_instance[0] = sw->bts->nr;
1253 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001254 sw->obj_instance[2] = 0xff;
1255 break;
1256 case GSM_BTS_TYPE_UNKNOWN:
1257 default:
1258 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1259 return -1;
1260 break;
1261 }
Harald Welte59b04682009-06-10 05:40:52 +08001262 sw->window_size = win_size;
1263 sw->state = SW_STATE_WAIT_INITACK;
1264 sw->cbfn = cbfn;
1265 sw->cb_data = cb_data;
1266 sw->forced = forced;
1267
1268 rc = sw_open_file(sw, fname);
1269 if (rc < 0) {
1270 sw->state = SW_STATE_NONE;
1271 return rc;
1272 }
1273
1274 return sw_load_init(sw);
1275}
1276
1277int abis_nm_software_load_status(struct gsm_bts *bts)
1278{
1279 struct abis_nm_sw *sw = &g_sw;
1280 struct stat st;
1281 int rc, percent;
1282
1283 rc = fstat(sw->fd, &st);
1284 if (rc < 0) {
1285 perror("ERROR during stat");
1286 return rc;
1287 }
1288
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001289 if (sw->stream)
1290 percent = (ftell(sw->stream) * 100) / st.st_size;
1291 else
1292 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001293 return percent;
1294}
1295
1296/* Activate the specified software into the BTS */
1297int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1298 gsm_cbfn *cbfn, void *cb_data)
1299{
1300 struct abis_nm_sw *sw = &g_sw;
1301 int rc;
1302
1303 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1304 bts->nr, fname);
1305
1306 if (sw->state != SW_STATE_NONE)
1307 return -EBUSY;
1308
1309 sw->bts = bts;
1310 sw->obj_class = NM_OC_SITE_MANAGER;
1311 sw->obj_instance[0] = 0xff;
1312 sw->obj_instance[1] = 0xff;
1313 sw->obj_instance[2] = 0xff;
1314 sw->state = SW_STATE_WAIT_ACTACK;
1315 sw->cbfn = cbfn;
1316 sw->cb_data = cb_data;
1317
1318 /* Open the file in order to fill some sw struct members */
1319 rc = sw_open_file(sw, fname);
1320 if (rc < 0) {
1321 sw->state = SW_STATE_NONE;
1322 return rc;
1323 }
1324 sw_close_file(sw);
1325
1326 return sw_activate(sw);
1327}
1328
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001329static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1330 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001331{
1332 ch->attrib = NM_ATT_ABIS_CHANNEL;
1333 ch->bts_port = bts_port;
1334 ch->timeslot = ts_nr;
1335 ch->subslot = subslot_nr;
1336}
1337
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001338int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1339 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1340 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001341{
1342 struct abis_om_hdr *oh;
1343 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001344 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001345 struct msgb *msg = nm_msgb_alloc();
1346
1347 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1348 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1349 bts->bts_nr, trx_nr, 0xff);
1350
1351 msgb_tv_put(msg, NM_ATT_TEI, tei);
1352
1353 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1354 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1355
1356 return abis_nm_sendmsg(bts, msg);
1357}
1358
1359/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1360int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001361 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001362{
1363 struct gsm_bts *bts = trx->bts;
1364 struct abis_om_hdr *oh;
1365 struct abis_nm_channel *ch;
1366 struct msgb *msg = nm_msgb_alloc();
1367
1368 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1369 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1370 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1371
1372 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1373 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1374
1375 return abis_nm_sendmsg(bts, msg);
1376}
1377
1378#if 0
1379int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1380 struct abis_nm_abis_channel *chan)
1381{
1382}
1383#endif
1384
1385int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001386 uint8_t e1_port, uint8_t e1_timeslot,
1387 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001388{
1389 struct gsm_bts *bts = ts->trx->bts;
1390 struct abis_om_hdr *oh;
1391 struct abis_nm_channel *ch;
1392 struct msgb *msg = nm_msgb_alloc();
1393
1394 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1395 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1396 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1397
1398 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1399 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1400
1401 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1402 gsm_ts_name(ts),
1403 e1_port, e1_timeslot, e1_subslot);
1404
1405 return abis_nm_sendmsg(bts, msg);
1406}
1407
1408#if 0
1409int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1410 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001411 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001412{
1413}
1414#endif
1415
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001416/* Chapter 8.11.1 */
1417int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1418 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1419 uint8_t *attr, uint8_t attr_len)
1420{
1421 struct abis_om_hdr *oh;
1422 struct msgb *msg = nm_msgb_alloc();
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001423
1424 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1425
1426 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1427 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1428 bts_nr, trx_nr, ts_nr);
1429 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1430
1431 return abis_nm_sendmsg(bts, msg);
1432}
1433
Harald Welte59b04682009-06-10 05:40:52 +08001434/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001435int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001436{
1437 struct abis_om_hdr *oh;
1438 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001439 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001440
1441 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1442
1443 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1444 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1445 cur = msgb_put(msg, attr_len);
1446 memcpy(cur, attr, attr_len);
1447
1448 return abis_nm_sendmsg(bts, msg);
1449}
1450
1451/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001452int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001453{
1454 struct abis_om_hdr *oh;
1455 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001456 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001457
1458 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1459
1460 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1461 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1462 trx->bts->bts_nr, trx->nr, 0xff);
1463 cur = msgb_put(msg, attr_len);
1464 memcpy(cur, attr, attr_len);
1465
1466 return abis_nm_sendmsg(trx->bts, msg);
1467}
1468
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001469static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1470 const char **reason)
Harald Weltef2eb2782009-08-09 21:49:48 +02001471{
1472 int i;
1473
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001474 *reason = "Reason unknown";
1475
Harald Weltef2eb2782009-08-09 21:49:48 +02001476 /* As it turns out, the BS-11 has some very peculiar restrictions
1477 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301478 switch (ts->trx->bts->type) {
1479 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001480 switch (chan_comb) {
1481 case NM_CHANC_TCHHalf:
1482 case NM_CHANC_TCHHalf2:
1483 /* not supported */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001484 *reason = "TCH/H is not supported.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001485 return -EINVAL;
1486 case NM_CHANC_SDCCH:
1487 /* only one SDCCH/8 per TRX */
1488 for (i = 0; i < TRX_NR_TS; i++) {
1489 if (i == ts->nr)
1490 continue;
1491 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001492 NM_CHANC_SDCCH) {
1493 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001494 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001495 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001496 }
1497 /* not allowed for TS0 of BCCH-TRX */
1498 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001499 ts->nr == 0) {
1500 *reason = "SDCCH/8 must be on TS0.";
1501 return -EINVAL;
1502 }
1503
Harald Weltef2eb2782009-08-09 21:49:48 +02001504 /* not on the same TRX that has a BCCH+SDCCH4
1505 * combination */
Holger Hans Peter Freytherfca3eb92013-01-08 19:30:14 +01001506 if (ts->trx != ts->trx->bts->c0 &&
Harald Weltef2eb2782009-08-09 21:49:48 +02001507 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001508 ts->trx->ts[0].nm_chan_comb == 8)) {
1509 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1510 return -EINVAL;
1511 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001512 break;
1513 case NM_CHANC_mainBCCH:
1514 case NM_CHANC_BCCHComb:
1515 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001516 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1517 *reason = "Main BCCH must be on TS0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001518 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001519 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001520 break;
1521 case NM_CHANC_BCCH:
1522 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001523 if (ts->trx != ts->trx->bts->c0) {
1524 *reason = "BCCH must be on C0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001525 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001526 }
1527 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1528 *reason = "BCCH must be on TS 2/4/6.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001529 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001530 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001531 break;
1532 case 8: /* this is not like 08.58, but in fact
1533 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1534 /* FIXME: only one CBCH allowed per cell */
1535 break;
1536 }
Harald Welte76ba8812009-12-02 02:45:23 +05301537 break;
1538 case GSM_BTS_TYPE_NANOBTS:
1539 switch (ts->nr) {
1540 case 0:
1541 if (ts->trx->nr == 0) {
1542 /* only on TRX0 */
1543 switch (chan_comb) {
1544 case NM_CHANC_BCCH:
1545 case NM_CHANC_mainBCCH:
1546 case NM_CHANC_BCCHComb:
1547 return 0;
1548 break;
1549 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001550 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301551 return -EINVAL;
1552 }
1553 } else {
1554 switch (chan_comb) {
1555 case NM_CHANC_TCHFull:
1556 case NM_CHANC_TCHHalf:
1557 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1558 return 0;
1559 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001560 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welte76ba8812009-12-02 02:45:23 +05301561 return -EINVAL;
1562 }
1563 }
1564 break;
1565 case 1:
1566 if (ts->trx->nr == 0) {
1567 switch (chan_comb) {
1568 case NM_CHANC_SDCCH_CBCH:
1569 if (ts->trx->ts[0].nm_chan_comb ==
1570 NM_CHANC_mainBCCH)
1571 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001572 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301573 return -EINVAL;
1574 case NM_CHANC_SDCCH:
1575 case NM_CHANC_TCHFull:
1576 case NM_CHANC_TCHHalf:
1577 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1578 case NM_CHANC_IPAC_TCHFull_PDCH:
1579 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001580 default:
1581 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1582 return -EINVAL;
Harald Welte76ba8812009-12-02 02:45:23 +05301583 }
1584 } else {
1585 switch (chan_comb) {
1586 case NM_CHANC_SDCCH:
1587 case NM_CHANC_TCHFull:
1588 case NM_CHANC_TCHHalf:
1589 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1590 return 0;
1591 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001592 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301593 return -EINVAL;
1594 }
1595 }
1596 break;
1597 case 2:
1598 case 3:
1599 case 4:
1600 case 5:
1601 case 6:
1602 case 7:
1603 switch (chan_comb) {
1604 case NM_CHANC_TCHFull:
1605 case NM_CHANC_TCHHalf:
1606 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1607 return 0;
1608 case NM_CHANC_IPAC_PDCH:
1609 case NM_CHANC_IPAC_TCHFull_PDCH:
1610 if (ts->trx->nr == 0)
1611 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001612 else {
1613 *reason = "PDCH must be on TRX0.";
Harald Welte76ba8812009-12-02 02:45:23 +05301614 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001615 }
Harald Welte76ba8812009-12-02 02:45:23 +05301616 }
1617 break;
1618 }
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001619 *reason = "Unknown combination";
Harald Welte76ba8812009-12-02 02:45:23 +05301620 return -EINVAL;
Harald Welte35ac0e42012-07-02 19:51:55 +02001621 case GSM_BTS_TYPE_OSMO_SYSMO:
1622 /* no known restrictions */
1623 return 0;
Harald Welte76ba8812009-12-02 02:45:23 +05301624 default:
1625 /* unknown BTS type */
1626 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001627 }
1628 return 0;
1629}
1630
Harald Welte59b04682009-06-10 05:40:52 +08001631/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001632int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001633{
1634 struct gsm_bts *bts = ts->trx->bts;
1635 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001636 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001637 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001638 uint8_t len = 2 + 2;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001639 const char *reason = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001640
1641 if (bts->type == GSM_BTS_TYPE_BS11)
1642 len += 4 + 2 + 2 + 3;
1643
1644 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001645 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Weltef2eb2782009-08-09 21:49:48 +02001646 msgb_free(msg);
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001647 LOGP(DNM, LOGL_ERROR,
1648 "Invalid Channel Combination %d on %s. Reason: %s\n",
1649 chan_comb, gsm_ts_name(ts), reason);
Harald Weltef2eb2782009-08-09 21:49:48 +02001650 return -EINVAL;
1651 }
1652 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001653
1654 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1655 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1656 NM_OC_CHANNEL, bts->bts_nr,
1657 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001658 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001659 if (ts->hopping.enabled) {
1660 unsigned int i;
1661 uint8_t *len;
1662
Harald Welte67104d12009-09-12 13:05:33 +02001663 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1664 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001665
1666 /* build the ARFCN list */
1667 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1668 len = msgb_put(msg, 1);
1669 *len = 0;
1670 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1671 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1672 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001673 /* At least BS-11 wants a TLV16 here */
1674 if (bts->type == GSM_BTS_TYPE_BS11)
1675 *len += 1;
1676 else
1677 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001678 }
1679 }
Harald Welte59b04682009-06-10 05:40:52 +08001680 }
Harald Welte025e6c92014-01-19 17:18:21 +01001681 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001682 if (bts->type == GSM_BTS_TYPE_BS11)
1683 msgb_tlv_put(msg, 0x59, 1, &zero);
1684
1685 return abis_nm_sendmsg(bts, msg);
1686}
1687
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001688int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1689 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001690{
1691 struct abis_om_hdr *oh;
1692 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001693 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1694 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001695
1696 if (nack) {
1697 len += 2;
1698 msgtype = NM_MT_SW_ACT_REQ_NACK;
1699 }
1700
1701 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1702 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1703
1704 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001705 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001706 memcpy(ptr, attr, att_len);
1707 }
1708 if (nack)
1709 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1710
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001711 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001712}
1713
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001714int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001715{
1716 struct msgb *msg = nm_msgb_alloc();
1717 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001718 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001719
1720 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1721 fill_om_hdr(oh, len);
1722 data = msgb_put(msg, len);
1723 memcpy(data, rawmsg, len);
1724
1725 return abis_nm_sendmsg(bts, msg);
1726}
1727
1728/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001729static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001730{
1731 struct abis_om_hdr *oh;
1732 struct msgb *msg = nm_msgb_alloc();
1733
1734 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1735 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1736 0xff, 0xff, 0xff);
1737
1738 return abis_nm_sendmsg(bts, msg);
1739}
1740
1741/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001742int 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 +08001743{
1744 struct abis_om_hdr *oh;
1745 struct msgb *msg = nm_msgb_alloc();
1746
Harald Welte59b04682009-06-10 05:40:52 +08001747 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1748 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1749
Harald Weltec61a90e2011-05-22 22:45:37 +02001750 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001751 DEBUGPC(DNM, "Sending OPSTART\n");
1752
Harald Welte59b04682009-06-10 05:40:52 +08001753 return abis_nm_sendmsg(bts, msg);
1754}
1755
1756/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001757int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1758 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001759{
1760 struct abis_om_hdr *oh;
1761 struct msgb *msg = nm_msgb_alloc();
1762
1763 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1764 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1765 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1766
1767 return abis_nm_sendmsg(bts, msg);
1768}
1769
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001770int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1771 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001772{
1773 struct abis_om_hdr *oh;
1774 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001775 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001776
1777 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1778 e1_port0, ts0, e1_port1, ts1);
1779
1780 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1781 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1782 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1783
1784 attr = msgb_put(msg, 3);
1785 attr[0] = NM_ATT_MDROP_LINK;
1786 attr[1] = e1_port0;
1787 attr[2] = ts0;
1788
1789 attr = msgb_put(msg, 3);
1790 attr[0] = NM_ATT_MDROP_NEXT;
1791 attr[1] = e1_port1;
1792 attr[2] = ts1;
1793
1794 return abis_nm_sendmsg(bts, msg);
1795}
Harald Welte59b04682009-06-10 05:40:52 +08001796
Harald Welte0bf8e302009-08-08 00:02:36 +02001797/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001798int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1799 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1800 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001801{
1802 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001803
Harald Weltec61a90e2011-05-22 22:45:37 +02001804 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001805
1806 if (!msg)
1807 msg = nm_msgb_alloc();
1808
1809 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1810 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1811 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1812 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001813 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001814
1815 return abis_nm_sendmsg(bts, msg);
1816}
1817
Harald Welte59b04682009-06-10 05:40:52 +08001818int abis_nm_event_reports(struct gsm_bts *bts, int on)
1819{
1820 if (on == 0)
1821 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1822 else
1823 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1824}
1825
1826/* Siemens (or BS-11) specific commands */
1827
1828int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1829{
1830 if (reconnect == 0)
1831 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1832 else
1833 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1834}
1835
1836int abis_nm_bs11_restart(struct gsm_bts *bts)
1837{
1838 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1839}
1840
1841
1842struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001843 uint16_t year;
1844 uint8_t month;
1845 uint8_t day;
1846 uint8_t hour;
1847 uint8_t min;
1848 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001849} __attribute__((packed));
1850
1851
1852void get_bs11_date_time(struct bs11_date_time *aet)
1853{
1854 time_t t;
1855 struct tm *tm;
1856
1857 t = time(NULL);
1858 tm = localtime(&t);
1859 aet->sec = tm->tm_sec;
1860 aet->min = tm->tm_min;
1861 aet->hour = tm->tm_hour;
1862 aet->day = tm->tm_mday;
1863 aet->month = tm->tm_mon;
1864 aet->year = htons(1900 + tm->tm_year);
1865}
1866
1867int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1868{
1869 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1870}
1871
1872int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1873{
1874 if (begin)
1875 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1876 else
1877 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1878}
1879
1880int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001881 enum abis_bs11_objtype type, uint8_t idx,
1882 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001883{
1884 struct abis_om_hdr *oh;
1885 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001886 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001887
1888 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1889 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1890 NM_OC_BS11, type, 0, idx);
1891 cur = msgb_put(msg, attr_len);
1892 memcpy(cur, attr, attr_len);
1893
1894 return abis_nm_sendmsg(bts, msg);
1895}
1896
1897int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001898 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001899{
1900 struct abis_om_hdr *oh;
1901 struct msgb *msg = nm_msgb_alloc();
1902
1903 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1904 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1905 NM_OC_BS11, type, 0, idx);
1906
1907 return abis_nm_sendmsg(bts, msg);
1908}
1909
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001910int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001911{
1912 struct abis_om_hdr *oh;
1913 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001914 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001915
1916 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1917 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1918 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1919 msgb_tlv_put(msg, 0x99, 1, &zero);
1920
1921 return abis_nm_sendmsg(bts, msg);
1922}
1923
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001924int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001925{
1926 struct abis_om_hdr *oh;
1927 struct msgb *msg = nm_msgb_alloc();
1928
1929 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1930 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001931 idx, 0xff, 0xff);
1932
1933 return abis_nm_sendmsg(bts, msg);
1934}
1935
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001936int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001937{
1938 struct abis_om_hdr *oh;
1939 struct msgb *msg = nm_msgb_alloc();
1940
1941 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1942 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1943 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001944
1945 return abis_nm_sendmsg(bts, msg);
1946}
1947
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001948static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001949int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1950{
1951 struct abis_om_hdr *oh;
1952 struct msgb *msg = nm_msgb_alloc();
1953
1954 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1955 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1956 0xff, 0xff, 0xff);
1957 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1958
1959 return abis_nm_sendmsg(bts, msg);
1960}
1961
1962/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001963int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1964 uint8_t e1_timeslot, uint8_t e1_subslot,
1965 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001966{
1967 struct abis_om_hdr *oh;
1968 struct abis_nm_channel *ch;
1969 struct msgb *msg = nm_msgb_alloc();
1970
1971 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1972 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1973 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1974
1975 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1976 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1977 msgb_tv_put(msg, NM_ATT_TEI, tei);
1978
1979 return abis_nm_sendmsg(bts, msg);
1980}
1981
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001982int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08001983{
1984 struct abis_om_hdr *oh;
1985 struct msgb *msg = nm_msgb_alloc();
1986
1987 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1988 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
1989 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1990 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1991
1992 return abis_nm_sendmsg(trx->bts, msg);
1993}
1994
1995int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1996{
1997 struct abis_om_hdr *oh;
1998 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001999 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08002000
2001 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2002 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2003 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2004 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2005
2006 return abis_nm_sendmsg(trx->bts, msg);
2007}
2008
2009int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2010{
2011 struct abis_om_hdr *oh;
2012 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002013 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08002014
2015 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2016 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2017 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2018 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2019
2020 return abis_nm_sendmsg(bts, msg);
2021}
2022
2023int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2024{
2025 struct abis_om_hdr *oh;
2026 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002027 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002028 NM_ATT_BS11_CCLK_TYPE };
2029
2030 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2031 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2032 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2033 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2034
2035 return abis_nm_sendmsg(bts, msg);
2036
2037}
2038
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002039//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002040
2041int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2042{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002043 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2044}
2045
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002046int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2047{
2048 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2049}
2050
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002051int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002052{
Harald Welte59b04682009-06-10 05:40:52 +08002053 struct abis_om_hdr *oh;
2054 struct msgb *msg = nm_msgb_alloc();
2055 struct bs11_date_time bdt;
2056
2057 get_bs11_date_time(&bdt);
2058
2059 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2060 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002061 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002062 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002063 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2064 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2065 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002066 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002067 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002068 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002069 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002070 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002071 } else {
2072 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2073 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2074 }
2075
2076 return abis_nm_sendmsg(bts, msg);
2077}
2078
2079int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2080{
2081 struct abis_om_hdr *oh;
2082 struct msgb *msg;
2083
2084 if (strlen(password) != 10)
2085 return -EINVAL;
2086
2087 msg = nm_msgb_alloc();
2088 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2089 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2090 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002091 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002092
2093 return abis_nm_sendmsg(bts, msg);
2094}
2095
2096/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2097int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2098{
2099 struct abis_om_hdr *oh;
2100 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002101 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002102
2103 msg = nm_msgb_alloc();
2104 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2105 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2106 BS11_OBJ_LI, 0x00, 0x00);
2107
2108 if (locked)
2109 tlv_value = BS11_LI_PLL_LOCKED;
2110 else
2111 tlv_value = BS11_LI_PLL_STANDALONE;
2112
2113 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2114
2115 return abis_nm_sendmsg(bts, msg);
2116}
2117
Daniel Willmann10b07db2010-01-07 00:54:01 +01002118/* Set the calibration value of the PLL (work value/set value)
2119 * It depends on the login which one is changed */
2120int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2121{
2122 struct abis_om_hdr *oh;
2123 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002124 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002125
2126 msg = nm_msgb_alloc();
2127 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2128 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2129 BS11_OBJ_TRX1, 0x00, 0x00);
2130
2131 tlv_value[0] = value>>8;
2132 tlv_value[1] = value&0xff;
2133
2134 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2135
2136 return abis_nm_sendmsg(bts, msg);
2137}
2138
Harald Welte59b04682009-06-10 05:40:52 +08002139int abis_nm_bs11_get_state(struct gsm_bts *bts)
2140{
2141 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2142}
2143
2144/* BS11 SWL */
2145
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002146void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002147
Harald Welte59b04682009-06-10 05:40:52 +08002148struct abis_nm_bs11_sw {
2149 struct gsm_bts *bts;
2150 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002151 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002152 int forced;
2153 struct llist_head file_list;
2154 gsm_cbfn *user_cb; /* specified by the user */
2155};
2156static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2157
2158struct file_list_entry {
2159 struct llist_head list;
2160 char fname[PATH_MAX];
2161};
2162
2163struct file_list_entry *fl_dequeue(struct llist_head *queue)
2164{
2165 struct llist_head *lh;
2166
2167 if (llist_empty(queue))
2168 return NULL;
2169
2170 lh = queue->next;
2171 llist_del(lh);
2172
2173 return llist_entry(lh, struct file_list_entry, list);
2174}
2175
2176static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2177{
2178 char linebuf[255];
2179 struct llist_head *lh, *lh2;
2180 FILE *swl;
2181 int rc = 0;
2182
2183 swl = fopen(bs11_sw->swl_fname, "r");
2184 if (!swl)
2185 return -ENODEV;
2186
2187 /* zero the stale file list, if any */
2188 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2189 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002190 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002191 }
2192
2193 while (fgets(linebuf, sizeof(linebuf), swl)) {
2194 char file_id[12+1];
2195 char file_version[80+1];
2196 struct file_list_entry *fle;
2197 static char dir[PATH_MAX];
2198
2199 if (strlen(linebuf) < 4)
2200 continue;
2201
2202 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2203 if (rc < 0) {
2204 perror("ERR parsing SWL file");
2205 rc = -EINVAL;
2206 goto out;
2207 }
2208 if (rc < 2)
2209 continue;
2210
Harald Welte857e00d2009-06-26 20:25:23 +02002211 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002212 if (!fle) {
2213 rc = -ENOMEM;
2214 goto out;
2215 }
Harald Welte59b04682009-06-10 05:40:52 +08002216
2217 /* construct new filename */
2218 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2219 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2220 strcat(fle->fname, "/");
2221 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2222
2223 llist_add_tail(&fle->list, &bs11_sw->file_list);
2224 }
2225
2226out:
2227 fclose(swl);
2228 return rc;
2229}
2230
2231/* bs11 swload specific callback, passed to abis_nm core swload */
2232static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2233 struct msgb *msg, void *data, void *param)
2234{
2235 struct abis_nm_bs11_sw *bs11_sw = data;
2236 struct file_list_entry *fle;
2237 int rc = 0;
2238
2239 switch (event) {
2240 case NM_MT_LOAD_END_ACK:
2241 fle = fl_dequeue(&bs11_sw->file_list);
2242 if (fle) {
2243 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002244 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002245 bs11_sw->win_size,
2246 bs11_sw->forced,
2247 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002248 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002249 } else {
2250 /* activate the SWL */
2251 rc = abis_nm_software_activate(bs11_sw->bts,
2252 bs11_sw->swl_fname,
2253 bs11_swload_cbfn,
2254 bs11_sw);
2255 }
2256 break;
2257 case NM_MT_LOAD_SEG_ACK:
2258 case NM_MT_LOAD_END_NACK:
2259 case NM_MT_LOAD_INIT_ACK:
2260 case NM_MT_LOAD_INIT_NACK:
2261 case NM_MT_ACTIVATE_SW_NACK:
2262 case NM_MT_ACTIVATE_SW_ACK:
2263 default:
2264 /* fallthrough to the user callback */
2265 if (bs11_sw->user_cb)
2266 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2267 break;
2268 }
2269
2270 return rc;
2271}
2272
2273/* Siemens provides a SWL file that is a mere listing of all the other
2274 * files that are part of a software release. We need to upload first
2275 * the list file, and then each file that is listed in the list file */
2276int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002277 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002278{
2279 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2280 struct file_list_entry *fle;
2281 int rc = 0;
2282
2283 INIT_LLIST_HEAD(&bs11_sw->file_list);
2284 bs11_sw->bts = bts;
2285 bs11_sw->win_size = win_size;
2286 bs11_sw->user_cb = cbfn;
2287 bs11_sw->forced = forced;
2288
2289 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2290 rc = bs11_read_swl_file(bs11_sw);
2291 if (rc < 0)
2292 return rc;
2293
2294 /* dequeue next item in file list */
2295 fle = fl_dequeue(&bs11_sw->file_list);
2296 if (!fle)
2297 return -EINVAL;
2298
2299 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002300 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002301 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002302 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002303 return rc;
2304}
2305
2306#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002307static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002308 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2309 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2310 NM_ATT_BS11_LMT_USER_NAME,
2311
2312 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2313
2314 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2315
2316 NM_ATT_BS11_SW_LOAD_STORED };
2317
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002318static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002319 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2320 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2321 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2322 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2323#endif
2324
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002325static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002326 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2327 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2328 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2329
2330int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2331{
2332 struct abis_om_hdr *oh;
2333 struct msgb *msg = nm_msgb_alloc();
2334
2335 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2336 /* SiemensHW CCTRL object */
2337 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2338 0x03, 0x00, 0x00);
2339 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2340
2341 return abis_nm_sendmsg(bts, msg);
2342}
2343
2344int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2345{
2346 struct abis_om_hdr *oh;
2347 struct msgb *msg = nm_msgb_alloc();
2348 struct bs11_date_time aet;
2349
2350 get_bs11_date_time(&aet);
2351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2352 /* SiemensHW CCTRL object */
2353 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2354 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002355 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002356
2357 return abis_nm_sendmsg(bts, msg);
2358}
2359
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002360int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002361{
2362 struct abis_om_hdr *oh;
2363 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002364 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002365
2366 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2367 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2368 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2369 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2370
2371 return abis_nm_sendmsg(bts, msg);
2372}
2373
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002374int 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 +02002375{
2376 struct abis_om_hdr *oh;
2377 struct msgb *msg = nm_msgb_alloc();
2378 struct bs11_date_time aet;
2379
2380 get_bs11_date_time(&aet);
2381 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2382 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2383 bport, 0xff, 0x02);
2384 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2385
2386 return abis_nm_sendmsg(bts, msg);
2387}
2388
Harald Welte59b04682009-06-10 05:40:52 +08002389/* ip.access nanoBTS specific commands */
2390static const char ipaccess_magic[] = "com.ipaccess";
2391
2392
2393static int abis_nm_rx_ipacc(struct msgb *msg)
2394{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002395 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002396 struct abis_om_hdr *oh = msgb_l2(msg);
2397 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002398 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002399 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002400 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002401 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002402
2403 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002404 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002405 return -EINVAL;
2406 }
2407
2408 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002409 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002410
Harald Weltec61a90e2011-05-22 22:45:37 +02002411 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002412
Harald Welte5aeedd42009-10-19 22:11:11 +02002413 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002414
2415 switch (foh->msg_type) {
2416 case NM_MT_IPACC_RSL_CONNECT_ACK:
2417 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002418 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2419 memcpy(&addr,
2420 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2421
2422 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2423 }
Harald Welte4206d982009-07-12 09:33:54 +02002424 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002425 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002426 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002427 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002428 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2429 DEBUGPC(DNM, "STREAM=0x%02x ",
2430 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002431 DEBUGPC(DNM, "\n");
2432 break;
2433 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002434 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002435 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002436 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002437 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002438 else
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002439 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002440 break;
2441 case NM_MT_IPACC_SET_NVATTR_ACK:
2442 DEBUGPC(DNM, "SET NVATTR ACK\n");
2443 /* FIXME: decode and show the actual attributes */
2444 break;
2445 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002446 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002447 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002448 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002449 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002450 else
Harald Weltede4477a2009-12-24 12:20:20 +01002451 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002452 break;
Harald Welte21460f02009-07-03 11:26:45 +02002453 case NM_MT_IPACC_GET_NVATTR_ACK:
2454 DEBUGPC(DNM, "GET NVATTR ACK\n");
2455 /* FIXME: decode and show the actual attributes */
2456 break;
2457 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002458 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002459 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002460 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002461 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002462 else
Harald Weltede4477a2009-12-24 12:20:20 +01002463 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002464 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002465 case NM_MT_IPACC_SET_ATTR_ACK:
2466 DEBUGPC(DNM, "SET ATTR ACK\n");
2467 break;
2468 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002469 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002470 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002471 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002472 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002473 else
Harald Weltede4477a2009-12-24 12:20:20 +01002474 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002475 break;
Harald Welte59b04682009-06-10 05:40:52 +08002476 default:
2477 DEBUGPC(DNM, "unknown\n");
2478 break;
2479 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002480
2481 /* signal handling */
2482 switch (foh->msg_type) {
2483 case NM_MT_IPACC_RSL_CONNECT_NACK:
2484 case NM_MT_IPACC_SET_NVATTR_NACK:
2485 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002486 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 +01002487 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002488 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002489 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002490 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002491 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 +01002492 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002493 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002494 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002495 default:
2496 break;
2497 }
2498
Harald Welte59b04682009-06-10 05:40:52 +08002499 return 0;
2500}
2501
2502/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002503int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2504 uint8_t obj_class, uint8_t bts_nr,
2505 uint8_t trx_nr, uint8_t ts_nr,
2506 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002507{
2508 struct msgb *msg = nm_msgb_alloc();
2509 struct abis_om_hdr *oh;
2510 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002511 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002512
2513 /* construct the 12.21 OM header, observe the erroneous length */
2514 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2515 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2516 oh->mdisc = ABIS_OM_MDISC_MANUF;
2517
2518 /* add the ip.access magic */
2519 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2520 *data++ = sizeof(ipaccess_magic);
2521 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2522
2523 /* fill the 12.21 FOM header */
2524 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2525 foh->msg_type = msg_type;
2526 foh->obj_class = obj_class;
2527 foh->obj_inst.bts_nr = bts_nr;
2528 foh->obj_inst.trx_nr = trx_nr;
2529 foh->obj_inst.ts_nr = ts_nr;
2530
2531 if (attr && attr_len) {
2532 data = msgb_put(msg, attr_len);
2533 memcpy(data, attr, attr_len);
2534 }
2535
2536 return abis_nm_sendmsg(bts, msg);
2537}
2538
2539/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002540int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002541 int attr_len)
2542{
Harald Weltef12c1052010-01-07 20:39:42 +01002543 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2544 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002545 attr_len);
2546}
2547
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002548int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002549 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002550{
2551 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002552 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002553 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2554 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2555
2556 int attr_len = sizeof(attr);
2557
2558 ia.s_addr = htonl(ip);
2559 attr[1] = stream;
2560 attr[3] = port >> 8;
2561 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002562 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002563
2564 /* if ip == 0, we use the default IP */
2565 if (ip == 0)
2566 attr_len -= 5;
2567
2568 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002569 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002570
2571 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2572 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2573 trx->nr, 0xff, attr, attr_len);
2574}
2575
Harald Welte59b04682009-06-10 05:40:52 +08002576/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002577int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002578{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002579 struct abis_om_hdr *oh;
2580 struct msgb *msg = nm_msgb_alloc();
2581
2582 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2583 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2584 trx->bts->nr, trx->nr, 0xff);
2585
2586 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002587}
Harald Welte0dfc6232009-10-24 10:20:41 +02002588
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002589int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2590 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2591 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002592{
2593 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2594 obj_class, bts_nr, trx_nr, ts_nr,
2595 attr, attr_len);
2596}
Harald Weltebeeae412009-11-12 14:48:42 +01002597
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002598void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002599{
2600 /* we simply reuse the GSM48 function and overwrite the RAC
2601 * with the Cell ID */
2602 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002603 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002604}
2605
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002606void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2607{
2608 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2609
Harald Welte69f6f812011-05-30 12:07:53 +02002610 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002611 if (!trx->bts || !trx->bts->oml_link)
2612 return;
2613
2614 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2615 trx->bts->bts_nr, trx->nr, 0xff,
2616 new_state);
2617}
2618
Harald Welte453141f2010-03-25 11:45:30 +08002619static const struct value_string ipacc_testres_names[] = {
2620 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2621 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2622 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2623 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2624 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2625 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002626};
2627
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002628const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002629{
Harald Welte453141f2010-03-25 11:45:30 +08002630 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002631}
2632
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002633void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002634{
2635 cid->mcc = (buf[0] & 0xf) * 100;
2636 cid->mcc += (buf[0] >> 4) * 10;
2637 cid->mcc += (buf[1] & 0xf) * 1;
2638
2639 if (buf[1] >> 4 == 0xf) {
2640 cid->mnc = (buf[2] & 0xf) * 10;
2641 cid->mnc += (buf[2] >> 4) * 1;
2642 } else {
2643 cid->mnc = (buf[2] & 0xf) * 100;
2644 cid->mnc += (buf[2] >> 4) * 10;
2645 cid->mnc += (buf[1] >> 4) * 1;
2646 }
2647
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002648 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2649 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002650}
2651
Harald Weltebeeae412009-11-12 14:48:42 +01002652/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002653int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002654{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002655 uint8_t *cur = buf;
Holger Hans Peter Freyther1a9f3ee2012-09-11 11:55:03 +02002656 uint16_t len __attribute__((unused));
Harald Weltebeeae412009-11-12 14:48:42 +01002657
Harald Welteb784df82010-07-22 18:14:36 +02002658 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002659
2660 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2661 return -EINVAL;
2662 cur++;
2663
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002664 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002665 cur += 2;
2666
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002667 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002668 cur += 2;
2669
2670 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2671 binf->freq_qual = *cur >> 2;
2672
Harald Welteb784df82010-07-22 18:14:36 +02002673 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002674 binf->arfcn |= *cur++;
2675
2676 if (binf->info_type & IPAC_BINF_RXLEV)
2677 binf->rx_lev = *cur & 0x3f;
2678 cur++;
2679
2680 if (binf->info_type & IPAC_BINF_RXQUAL)
2681 binf->rx_qual = *cur & 0x7;
2682 cur++;
2683
2684 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002685 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002686 cur += 2;
2687
2688 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002689 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002690 cur += 2;
2691
2692 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002693 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002694 cur += 4;
2695
Harald Welte22cb81f2010-07-30 22:34:42 +02002696#if 0
2697 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002698 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002699#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002700 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002701 cur++;
2702
Harald Weltebfc21092009-11-13 11:56:05 +01002703 ipac_parse_cgi(&binf->cgi, cur);
2704 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002705
2706 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2707 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2708 cur += sizeof(binf->ba_list_si2);
2709 }
2710
2711 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2712 memcpy(binf->ba_list_si2bis, cur,
2713 sizeof(binf->ba_list_si2bis));
2714 cur += sizeof(binf->ba_list_si2bis);
2715 }
2716
2717 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2718 memcpy(binf->ba_list_si2ter, cur,
2719 sizeof(binf->ba_list_si2ter));
2720 cur += sizeof(binf->ba_list_si2ter);
2721 }
2722
2723 return 0;
2724}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002725
2726void abis_nm_clear_queue(struct gsm_bts *bts)
2727{
2728 struct msgb *msg;
2729
2730 while (!llist_empty(&bts->abis_queue)) {
2731 msg = msgb_dequeue(&bts->abis_queue);
2732 msgb_free(msg);
2733 }
2734
2735 bts->abis_nm_pend = 0;
2736}