blob: 23d5fa314207ca40a4f1d85e25ddb9a5be72df1e [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte59b04682009-06-10 05:40:52 +080011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
Harald Welte59b04682009-06-10 05:40:52 +080033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Weltec61a90e2011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080043#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte59b04682009-06-10 05:40:52 +080047
48#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080051
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte59b04682009-06-10 05:40:52 +080053{
Harald Welte59698fb2010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +080057}
58
59static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
71#if 0
72/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
77#endif
78
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Weltec61a90e2011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte59b04682009-06-10 05:40:52 +080083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +080089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte59b04682009-06-10 05:40:52 +080099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
103 fill_om_hdr(oh, len+sizeof(*foh));
104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte9cfc9352009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800115}
116
Harald Welte607044f2011-09-26 23:43:23 +0200117int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200118{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200119 msg->l2h = msg->data;
120
121 if (!msg->dst) {
122 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
123 return -EINVAL;
124 }
125
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200126 return abis_sendmsg(msg);
127}
128
Harald Welte59b04682009-06-10 05:40:52 +0800129/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100130static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800131{
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200132 msg->dst = bts->oml_link;
Harald Welte59b04682009-06-10 05:40:52 +0800133
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100134 /* queue OML messages */
135 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
136 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200137 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100138 } else {
139 msgb_enqueue(&bts->abis_queue, msg);
140 return 0;
141 }
142
143}
144
145int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
146{
147 OBSC_NM_W_ACK_CB(msg) = 1;
148 return abis_nm_queue_msg(bts, msg);
149}
150
151static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 0;
154 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800155}
156
157static int abis_nm_rcvmsg_sw(struct msgb *mb);
158
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100159int nm_is_running(struct gsm_nm_state *s) {
160 return (s->operational == NM_OPSTATE_ENABLED) && (
161 (s->availability == NM_AVSTATE_OK) ||
162 (s->availability == 0xff)
163 );
164}
165
Harald Welte59b04682009-06-10 05:40:52 +0800166/* Update the administrative state of a given object in our in-memory data
167 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200168static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
169 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800170{
171 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100172 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800173
Harald Weltea348c082011-03-06 21:20:38 +0100174 memset(&nsd, 0, sizeof(nsd));
175
Harald Weltec6ed9282011-06-06 18:31:20 +0200176 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100177 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100178 return -EINVAL;
Harald Weltec6ed9282011-06-06 18:31:20 +0200179 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800180 if (!nm_state)
181 return -1;
182
183 new_state = *nm_state;
184 new_state.administrative = adm_state;
185
Harald Welteb03c4482011-03-06 22:11:32 +0100186 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100187 nsd.obj_class = obj_class;
188 nsd.old_state = nm_state;
189 nsd.new_state = &new_state;
190 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200191 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800192
193 nm_state->administrative = adm_state;
194
Harald Welte4c826f72011-01-14 15:55:42 +0100195 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800196}
197
198static int abis_nm_rx_statechg_rep(struct msgb *mb)
199{
200 struct abis_om_hdr *oh = msgb_l2(mb);
201 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200202 struct e1inp_sign_link *sign_link = mb->dst;
203 struct gsm_bts *bts = sign_link->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +0800204 struct tlv_parsed tp;
205 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800206
207 DEBUGPC(DNM, "STATE CHG: ");
208
209 memset(&new_state, 0, sizeof(new_state));
210
Harald Weltec6ed9282011-06-06 18:31:20 +0200211 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800212 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100213 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800214 return -EINVAL;
215 }
216
217 new_state = *nm_state;
218
Harald Welte59698fb2010-01-10 18:01:52 +0100219 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800220 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
221 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200222 DEBUGPC(DNM, "OP_STATE=%s ",
223 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800224 }
225 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
226 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
227 new_state.availability = 0xff;
228 else
229 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Weltec61a90e2011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
231 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800232 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100233 } else
234 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800235 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
236 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200238 get_value_string(abis_nm_adm_state_names,
239 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800240 }
241 DEBUGPC(DNM, "\n");
242
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100243 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
244 new_state.operational != nm_state->operational ||
245 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800246 /* Update the operational state of a given object in our in-memory data
247 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100248 struct nm_statechg_signal_data nsd;
Harald Weltec6ed9282011-06-06 18:31:20 +0200249 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100250 nsd.obj_class = foh->obj_class;
251 nsd.old_state = nm_state;
252 nsd.new_state = &new_state;
253 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100254 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200255 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100256 nm_state->operational = new_state.operational;
257 nm_state->availability = new_state.availability;
258 if (nm_state->administrative == 0)
259 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800260 }
261#if 0
262 if (op_state == 1) {
263 /* try to enable objects that are disabled */
264 abis_nm_opstart(bts, foh->obj_class,
265 foh->obj_inst.bts_nr,
266 foh->obj_inst.trx_nr,
267 foh->obj_inst.ts_nr);
268 }
269#endif
270 return 0;
271}
272
273static int rx_fail_evt_rep(struct msgb *mb)
274{
275 struct abis_om_hdr *oh = msgb_l2(mb);
276 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200277 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800278 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100279 const uint8_t *p_val;
280 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800281
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200282 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800283
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200284 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800285
286 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-05-22 22:45:37 +0200287 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
288 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800289 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200290 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
291 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100292 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
293 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200294 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100295 }
296 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
297 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
298 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
299 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100301 talloc_free(p_text);
302 }
303 }
Harald Welte59b04682009-06-10 05:40:52 +0800304
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200305 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800306
307 return 0;
308}
309
310static int abis_nm_rcvmsg_report(struct msgb *mb)
311{
312 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200313 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800314
Harald Weltec61a90e2011-05-22 22:45:37 +0200315 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800316
317 //nmh->cfg->report_cb(mb, foh);
318
319 switch (mt) {
320 case NM_MT_STATECHG_EVENT_REP:
321 return abis_nm_rx_statechg_rep(mb);
322 break;
323 case NM_MT_SW_ACTIVATED_REP:
324 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200325 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800326 break;
327 case NM_MT_FAILURE_EVENT_REP:
328 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200329 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800330 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200331 case NM_MT_TEST_REP:
332 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200334 break;
Harald Welte59b04682009-06-10 05:40:52 +0800335 default:
336 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
337 break;
338
339 };
340
341 return 0;
342}
343
344/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200345static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
346 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800347{
348 struct abis_om_hdr *oh;
349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200350 uint8_t len = swdesc_len;
351 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800352
353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
354 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
355
356 trailer = msgb_put(msg, swdesc_len);
357 memcpy(trailer, sw_desc, swdesc_len);
358
359 return abis_nm_sendmsg(bts, msg);
360}
361
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200362static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100363{
364 static const struct tlv_definition sw_descr_def = {
365 .def = {
366 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
367 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
368 },
369 };
370
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200371 uint8_t tag;
372 uint16_t tag_len;
373 const uint8_t *val;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100374 int ofs = 0, len;
375
376 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
377 * nested nature and the fact you have to assume it contains only two sub
378 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
379
380 if (sw_descr[0] != NM_ATT_SW_DESCR) {
381 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
382 return -1;
383 }
384 ofs += 1;
385
386 len = tlv_parse_one(&tag, &tag_len, &val,
387 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
388 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
389 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
390 return -2;
391 }
392 ofs += len;
393
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
396 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
397 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
398 return -3;
399 }
400 ofs += len;
401
402 return ofs;
403}
404
Harald Welte59b04682009-06-10 05:40:52 +0800405static int abis_nm_rx_sw_act_req(struct msgb *mb)
406{
407 struct abis_om_hdr *oh = msgb_l2(mb);
408 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200409 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200410 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200411 const uint8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100412 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800413
Harald Weltec61a90e2011-05-22 22:45:37 +0200414 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200415
416 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800417
Harald Welte3055e332010-03-14 15:37:43 +0800418 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800419
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200420 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800421 foh->obj_inst.bts_nr,
422 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800423 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800424 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100425 if (ret != 0) {
426 LOGP(DNM, LOGL_ERROR,
427 "Sending SW ActReq ACK failed: %d\n", ret);
428 return ret;
429 }
Harald Welte59b04682009-06-10 05:40:52 +0800430
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200431 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200432 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
433 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
434 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100435 LOGP(DNM, LOGL_ERROR,
436 "SW config not found! Can't continue.\n");
Mike Haben322fc582009-10-01 14:56:13 +0200437 return -EINVAL;
438 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200439 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200440 }
441
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100442 /* Use the first SW_DESCR present in SW config */
443 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
444 if (sw_descr_len < 0)
445 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200446
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200447 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800448 foh->obj_inst.bts_nr,
449 foh->obj_inst.trx_nr,
450 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100451 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800452}
453
454/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
455static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
456{
457 struct abis_om_hdr *oh = msgb_l2(mb);
458 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200459 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800460 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200461 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800462
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200463 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800464 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
465 return -EINVAL;
466
467 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
468
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200469 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800470}
471
472static int abis_nm_rx_lmt_event(struct msgb *mb)
473{
474 struct abis_om_hdr *oh = msgb_l2(mb);
475 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200476 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800477 struct tlv_parsed tp;
478
479 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200480 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800481 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
482 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200483 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800484 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
485 }
486 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
487 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200488 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800489 DEBUGPC(DNM, "Level=%u ", level);
490 }
491 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
492 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
493 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
494 DEBUGPC(DNM, "Username=%s ", name);
495 }
496 DEBUGPC(DNM, "\n");
497 /* FIXME: parse LMT LOGON TIME */
498 return 0;
499}
500
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200501void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100502{
503 int wait = 0;
504 struct msgb *msg;
505 /* the queue is empty */
506 while (!llist_empty(&bts->abis_queue)) {
507 msg = msgb_dequeue(&bts->abis_queue);
508 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200509 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100510
511 if (wait)
512 break;
513 }
514
515 bts->abis_nm_pend = wait;
516}
517
Harald Welte59b04682009-06-10 05:40:52 +0800518/* Receive a OML NM Message from BTS */
519static int abis_nm_rcvmsg_fom(struct msgb *mb)
520{
521 struct abis_om_hdr *oh = msgb_l2(mb);
522 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200523 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200524 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100525 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800526
527 /* check for unsolicited message */
528 if (is_report(mt))
529 return abis_nm_rcvmsg_report(mb);
530
Harald Weltec61a90e2011-05-22 22:45:37 +0200531 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800532 return abis_nm_rcvmsg_sw(mb);
533
Harald Weltec61a90e2011-05-22 22:45:37 +0200534 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800535 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800536 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200537
Harald Weltec61a90e2011-05-22 22:45:37 +0200538 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200539
Harald Weltec61a90e2011-05-22 22:45:37 +0200540 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800541
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200542 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800543 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200544 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200545 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800546 else
547 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200548
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800549 nack_data.msg = mb;
550 nack_data.mt = mt;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200551 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200552 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200553 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800554 }
555#if 0
556 /* check if last message is to be acked */
557 if (is_ack_nack(nmh->last_msgtype)) {
558 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100559 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800560 /* we got our ACK, continue sending the next msg */
561 } else if (mt == MT_NACK(nmh->last_msgtype)) {
562 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100563 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800564 /* FIXME: somehow signal this to the caller */
565 } else {
566 /* really strange things happen */
567 return -EINVAL;
568 }
569 }
570#endif
571
572 switch (mt) {
573 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100574 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800575 break;
576 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100577 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800578 break;
579 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100580 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800581 break;
Harald Welte204317e2009-08-06 17:58:31 +0200582 case NM_MT_CONN_MDROP_LINK_ACK:
583 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
584 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100585 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200586 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100587 break;
588 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200589 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100590 break;
Harald Welte08011e22011-03-04 13:41:31 +0100591 case NM_MT_SET_BTS_ATTR_ACK:
592 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200593 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
594 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Welte08011e22011-03-04 13:41:31 +0100595 }
596 break;
Harald Welte59b04682009-06-10 05:40:52 +0800597 }
598
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200599 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100600 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800601}
602
603static int abis_nm_rx_ipacc(struct msgb *mb);
604
605static int abis_nm_rcvmsg_manuf(struct msgb *mb)
606{
607 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200608 struct e1inp_sign_link *sign_link = mb->dst;
609 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800610
611 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100612 case GSM_BTS_TYPE_NANOBTS:
Harald Welte35ac0e42012-07-02 19:51:55 +0200613 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte59b04682009-06-10 05:40:52 +0800614 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200615 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800616 break;
617 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100618 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
619 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800620 rc = 0;
621 break;
622 }
623
624 return rc;
625}
626
627/* High-Level API */
628/* Entry-point where L2 OML from BTS enters the NM code */
629int abis_nm_rcvmsg(struct msgb *msg)
630{
631 struct abis_om_hdr *oh = msgb_l2(msg);
632 int rc = 0;
633
634 /* Various consistency checks */
635 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100636 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800637 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +0200638 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
639 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800640 }
641 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100642 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800643 oh->sequence);
644 return -EINVAL;
645 }
646#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200647 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800648 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
649 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100650 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800651 oh->length + sizeof(*oh), l2_len);
652 return -EINVAL;
653 }
654 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100655 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 +0800656#endif
657 msg->l3h = (unsigned char *)oh + sizeof(*oh);
658
659 switch (oh->mdisc) {
660 case ABIS_OM_MDISC_FOM:
661 rc = abis_nm_rcvmsg_fom(msg);
662 break;
663 case ABIS_OM_MDISC_MANUF:
664 rc = abis_nm_rcvmsg_manuf(msg);
665 break;
666 case ABIS_OM_MDISC_MMI:
667 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100668 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800669 oh->mdisc);
670 break;
671 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100672 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800673 oh->mdisc);
674 return -EINVAL;
675 }
676
677 msgb_free(msg);
678 return rc;
679}
680
681#if 0
682/* initialized all resources */
683struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
684{
685 struct abis_nm_h *nmh;
686
687 nmh = malloc(sizeof(*nmh));
688 if (!nmh)
689 return NULL;
690
691 nmh->cfg = cfg;
692
693 return nmh;
694}
695
696/* free all resources */
697void abis_nm_fini(struct abis_nm_h *nmh)
698{
699 free(nmh);
700}
701#endif
702
703/* Here we are trying to define a high-level API that can be used by
704 * the actual BSC implementation. However, the architecture is currently
705 * still under design. Ideally the calls to this API would be synchronous,
706 * while the underlying stack behind the APi runs in a traditional select
707 * based state machine.
708 */
709
710/* 6.2 Software Load: */
711enum sw_state {
712 SW_STATE_NONE,
713 SW_STATE_WAIT_INITACK,
714 SW_STATE_WAIT_SEGACK,
715 SW_STATE_WAIT_ENDACK,
716 SW_STATE_WAIT_ACTACK,
717 SW_STATE_ERROR,
718};
719
720struct abis_nm_sw {
721 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800722 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800723 gsm_cbfn *cbfn;
724 void *cb_data;
725 int forced;
726
727 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200728 uint8_t obj_class;
729 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800730
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200731 uint8_t file_id[255];
732 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800733
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200734 uint8_t file_version[255];
735 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800736
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200737 uint8_t window_size;
738 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800739
740 int fd;
741 FILE *stream;
742 enum sw_state state;
743 int last_seg;
744};
745
746static struct abis_nm_sw g_sw;
747
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100748static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
749{
750 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
751 msgb_v_put(msg, NM_ATT_SW_DESCR);
752 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
753 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
754 sw->file_version);
755 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
756 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
757 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
758 sw->file_version);
759 } else {
760 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
761 }
762}
763
Harald Welte59b04682009-06-10 05:40:52 +0800764/* 6.2.1 / 8.3.1: Load Data Initiate */
765static int sw_load_init(struct abis_nm_sw *sw)
766{
767 struct abis_om_hdr *oh;
768 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200769 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800770
771 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
772 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
773 sw->obj_instance[0], sw->obj_instance[1],
774 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100775
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100776 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800777 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
778
779 return abis_nm_sendmsg(sw->bts, msg);
780}
781
782static int is_last_line(FILE *stream)
783{
784 char next_seg_buf[256];
785 long pos;
786
787 /* check if we're sending the last line */
788 pos = ftell(stream);
789 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
790 fseek(stream, pos, SEEK_SET);
791 return 1;
792 }
793
794 fseek(stream, pos, SEEK_SET);
795 return 0;
796}
797
798/* 6.2.2 / 8.3.2 Load Data Segment */
799static int sw_load_segment(struct abis_nm_sw *sw)
800{
801 struct abis_om_hdr *oh;
802 struct msgb *msg = nm_msgb_alloc();
803 char seg_buf[256];
804 char *line_buf = seg_buf+2;
805 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200806 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800807
808 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
809
810 switch (sw->bts->type) {
811 case GSM_BTS_TYPE_BS11:
812 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
813 perror("fgets reading segment");
814 return -EINVAL;
815 }
816 seg_buf[0] = 0x00;
817
818 /* check if we're sending the last line */
819 sw->last_seg = is_last_line(sw->stream);
820 if (sw->last_seg)
821 seg_buf[1] = 0;
822 else
823 seg_buf[1] = 1 + sw->seg_in_window++;
824
825 len = strlen(line_buf) + 2;
826 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200827 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800828 /* BS11 wants CR + LF in excess of the TLV length !?! */
829 tlv[1] -= 2;
830
831 /* we only now know the exact length for the OM hdr */
832 len = strlen(line_buf)+2;
833 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100834 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200835 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100836 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
837 if (len < 0) {
838 perror("read failed");
839 return -EINVAL;
840 }
841
842 if (len != IPACC_SEGMENT_SIZE)
843 sw->last_seg = 1;
844
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100845 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200846 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100847 len += 3;
848 break;
849 }
Harald Welte59b04682009-06-10 05:40:52 +0800850 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100851 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800852 /* FIXME: Other BTS types */
853 return -1;
854 }
855
856 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
857 sw->obj_instance[0], sw->obj_instance[1],
858 sw->obj_instance[2]);
859
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100860 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800861}
862
863/* 6.2.4 / 8.3.4 Load Data End */
864static int sw_load_end(struct abis_nm_sw *sw)
865{
866 struct abis_om_hdr *oh;
867 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200868 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800869
870 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
871 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
872 sw->obj_instance[0], sw->obj_instance[1],
873 sw->obj_instance[2]);
874
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100875 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800876 return abis_nm_sendmsg(sw->bts, msg);
877}
878
879/* Activate the specified software into the BTS */
880static int sw_activate(struct abis_nm_sw *sw)
881{
882 struct abis_om_hdr *oh;
883 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200884 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800885
886 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
887 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
888 sw->obj_instance[0], sw->obj_instance[1],
889 sw->obj_instance[2]);
890
891 /* FIXME: this is BS11 specific format */
892 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
893 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
894 sw->file_version);
895
896 return abis_nm_sendmsg(sw->bts, msg);
897}
898
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100899struct sdp_firmware {
900 char magic[4];
901 char more_magic[4];
902 unsigned int header_length;
903 unsigned int file_length;
904} __attribute__ ((packed));
905
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100906static int parse_sdp_header(struct abis_nm_sw *sw)
907{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100908 struct sdp_firmware firmware_header;
909 int rc;
910 struct stat stat;
911
912 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
913 if (rc != sizeof(firmware_header)) {
914 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
915 return -1;
916 }
917
918 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
919 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
920 return -1;
921 }
922
923 if (firmware_header.more_magic[0] != 0x10 ||
924 firmware_header.more_magic[1] != 0x02 ||
925 firmware_header.more_magic[2] != 0x00 ||
926 firmware_header.more_magic[3] != 0x00) {
927 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
928 return -1;
929 }
930
931
932 if (fstat(sw->fd, &stat) == -1) {
933 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
934 return -1;
935 }
936
937 if (ntohl(firmware_header.file_length) != stat.st_size) {
938 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
939 return -1;
940 }
941
942 /* go back to the start as we checked the whole filesize.. */
943 lseek(sw->fd, 0l, SEEK_SET);
944 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
945 "There might be checksums in the file that are not\n"
946 "verified and incomplete firmware might be flashed.\n"
947 "There is absolutely no WARRANTY that flashing will\n"
948 "work.\n");
949 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100950}
951
Harald Welte59b04682009-06-10 05:40:52 +0800952static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
953{
954 char file_id[12+1];
955 char file_version[80+1];
956 int rc;
957
958 sw->fd = open(fname, O_RDONLY);
959 if (sw->fd < 0)
960 return sw->fd;
961
962 switch (sw->bts->type) {
963 case GSM_BTS_TYPE_BS11:
964 sw->stream = fdopen(sw->fd, "r");
965 if (!sw->stream) {
966 perror("fdopen");
967 return -1;
968 }
969 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200970 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +0800971 file_id, file_version);
972 if (rc != 2) {
973 perror("parsing header line of software file");
974 return -1;
975 }
976 strcpy((char *)sw->file_id, file_id);
977 sw->file_id_len = strlen(file_id);
978 strcpy((char *)sw->file_version, file_version);
979 sw->file_version_len = strlen(file_version);
980 /* rewind to start of file */
981 rewind(sw->stream);
982 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100983 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100984 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100985 rc = parse_sdp_header(sw);
986 if (rc < 0) {
987 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
988 return -1;
989 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100990
991 strcpy((char *)sw->file_id, "id");
992 sw->file_id_len = 3;
993 strcpy((char *)sw->file_version, "version");
994 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100995 break;
Harald Welte59b04682009-06-10 05:40:52 +0800996 default:
997 /* We don't know how to treat them yet */
998 close(sw->fd);
999 return -EINVAL;
1000 }
1001
1002 return 0;
1003}
1004
1005static void sw_close_file(struct abis_nm_sw *sw)
1006{
1007 switch (sw->bts->type) {
1008 case GSM_BTS_TYPE_BS11:
1009 fclose(sw->stream);
1010 break;
1011 default:
1012 close(sw->fd);
1013 break;
1014 }
1015}
1016
1017/* Fill the window */
1018static int sw_fill_window(struct abis_nm_sw *sw)
1019{
1020 int rc;
1021
1022 while (sw->seg_in_window < sw->window_size) {
1023 rc = sw_load_segment(sw);
1024 if (rc < 0)
1025 return rc;
1026 if (sw->last_seg)
1027 break;
1028 }
1029 return 0;
1030}
1031
1032/* callback function from abis_nm_rcvmsg() handler */
1033static int abis_nm_rcvmsg_sw(struct msgb *mb)
1034{
1035 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001036 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001037 int rc = -1;
1038 struct abis_nm_sw *sw = &g_sw;
1039 enum sw_state old_state = sw->state;
1040
1041 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1042
1043 switch (sw->state) {
1044 case SW_STATE_WAIT_INITACK:
1045 switch (foh->msg_type) {
1046 case NM_MT_LOAD_INIT_ACK:
1047 /* fill window with segments */
1048 if (sw->cbfn)
1049 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1050 NM_MT_LOAD_INIT_ACK, mb,
1051 sw->cb_data, NULL);
1052 rc = sw_fill_window(sw);
1053 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001054 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001055 break;
1056 case NM_MT_LOAD_INIT_NACK:
1057 if (sw->forced) {
1058 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1059 "Init NACK\n");
1060 if (sw->cbfn)
1061 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1062 NM_MT_LOAD_INIT_ACK, mb,
1063 sw->cb_data, NULL);
1064 rc = sw_fill_window(sw);
1065 sw->state = SW_STATE_WAIT_SEGACK;
1066 } else {
1067 DEBUGP(DNM, "Software Load Init NACK\n");
1068 /* FIXME: cause */
1069 if (sw->cbfn)
1070 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1071 NM_MT_LOAD_INIT_NACK, mb,
1072 sw->cb_data, NULL);
1073 sw->state = SW_STATE_ERROR;
1074 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001075 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001076 break;
1077 }
1078 break;
1079 case SW_STATE_WAIT_SEGACK:
1080 switch (foh->msg_type) {
1081 case NM_MT_LOAD_SEG_ACK:
1082 if (sw->cbfn)
1083 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1084 NM_MT_LOAD_SEG_ACK, mb,
1085 sw->cb_data, NULL);
1086 sw->seg_in_window = 0;
1087 if (!sw->last_seg) {
1088 /* fill window with more segments */
1089 rc = sw_fill_window(sw);
1090 sw->state = SW_STATE_WAIT_SEGACK;
1091 } else {
1092 /* end the transfer */
1093 sw->state = SW_STATE_WAIT_ENDACK;
1094 rc = sw_load_end(sw);
1095 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001096 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001097 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001098 case NM_MT_LOAD_ABORT:
1099 if (sw->cbfn)
1100 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1101 NM_MT_LOAD_ABORT, mb,
1102 sw->cb_data, NULL);
1103 break;
Harald Welte59b04682009-06-10 05:40:52 +08001104 }
1105 break;
1106 case SW_STATE_WAIT_ENDACK:
1107 switch (foh->msg_type) {
1108 case NM_MT_LOAD_END_ACK:
1109 sw_close_file(sw);
1110 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1111 sw->bts->nr);
1112 sw->state = SW_STATE_NONE;
1113 if (sw->cbfn)
1114 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1115 NM_MT_LOAD_END_ACK, mb,
1116 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001117 rc = 0;
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 case NM_MT_LOAD_END_NACK:
1121 if (sw->forced) {
1122 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1123 "End NACK\n");
1124 sw->state = SW_STATE_NONE;
1125 if (sw->cbfn)
1126 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1127 NM_MT_LOAD_END_ACK, mb,
1128 sw->cb_data, NULL);
1129 } else {
1130 DEBUGP(DNM, "Software Load End NACK\n");
1131 /* FIXME: cause */
1132 sw->state = SW_STATE_ERROR;
1133 if (sw->cbfn)
1134 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1135 NM_MT_LOAD_END_NACK, mb,
1136 sw->cb_data, NULL);
1137 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001138 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001139 break;
1140 }
1141 case SW_STATE_WAIT_ACTACK:
1142 switch (foh->msg_type) {
1143 case NM_MT_ACTIVATE_SW_ACK:
1144 /* we're done */
1145 DEBUGP(DNM, "Activate Software DONE!\n");
1146 sw->state = SW_STATE_NONE;
1147 rc = 0;
1148 if (sw->cbfn)
1149 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1150 NM_MT_ACTIVATE_SW_ACK, mb,
1151 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001152 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001153 break;
1154 case NM_MT_ACTIVATE_SW_NACK:
1155 DEBUGP(DNM, "Activate Software NACK\n");
1156 /* FIXME: cause */
1157 sw->state = SW_STATE_ERROR;
1158 if (sw->cbfn)
1159 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1160 NM_MT_ACTIVATE_SW_NACK, mb,
1161 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001162 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001163 break;
1164 }
1165 case SW_STATE_NONE:
1166 switch (foh->msg_type) {
1167 case NM_MT_ACTIVATE_SW_ACK:
1168 rc = 0;
1169 break;
1170 }
1171 break;
1172 case SW_STATE_ERROR:
1173 break;
1174 }
1175
1176 if (rc)
1177 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1178 foh->msg_type, old_state, sw->state);
1179
1180 return rc;
1181}
1182
1183/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001184int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001185 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001186 gsm_cbfn *cbfn, void *cb_data)
1187{
1188 struct abis_nm_sw *sw = &g_sw;
1189 int rc;
1190
1191 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1192 bts->nr, fname);
1193
1194 if (sw->state != SW_STATE_NONE)
1195 return -EBUSY;
1196
1197 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001198 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001199
1200 switch (bts->type) {
1201 case GSM_BTS_TYPE_BS11:
1202 sw->obj_class = NM_OC_SITE_MANAGER;
1203 sw->obj_instance[0] = 0xff;
1204 sw->obj_instance[1] = 0xff;
1205 sw->obj_instance[2] = 0xff;
1206 break;
1207 case GSM_BTS_TYPE_NANOBTS:
1208 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001209 sw->obj_instance[0] = sw->bts->nr;
1210 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001211 sw->obj_instance[2] = 0xff;
1212 break;
1213 case GSM_BTS_TYPE_UNKNOWN:
1214 default:
1215 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1216 return -1;
1217 break;
1218 }
Harald Welte59b04682009-06-10 05:40:52 +08001219 sw->window_size = win_size;
1220 sw->state = SW_STATE_WAIT_INITACK;
1221 sw->cbfn = cbfn;
1222 sw->cb_data = cb_data;
1223 sw->forced = forced;
1224
1225 rc = sw_open_file(sw, fname);
1226 if (rc < 0) {
1227 sw->state = SW_STATE_NONE;
1228 return rc;
1229 }
1230
1231 return sw_load_init(sw);
1232}
1233
1234int abis_nm_software_load_status(struct gsm_bts *bts)
1235{
1236 struct abis_nm_sw *sw = &g_sw;
1237 struct stat st;
1238 int rc, percent;
1239
1240 rc = fstat(sw->fd, &st);
1241 if (rc < 0) {
1242 perror("ERROR during stat");
1243 return rc;
1244 }
1245
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001246 if (sw->stream)
1247 percent = (ftell(sw->stream) * 100) / st.st_size;
1248 else
1249 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001250 return percent;
1251}
1252
1253/* Activate the specified software into the BTS */
1254int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1255 gsm_cbfn *cbfn, void *cb_data)
1256{
1257 struct abis_nm_sw *sw = &g_sw;
1258 int rc;
1259
1260 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1261 bts->nr, fname);
1262
1263 if (sw->state != SW_STATE_NONE)
1264 return -EBUSY;
1265
1266 sw->bts = bts;
1267 sw->obj_class = NM_OC_SITE_MANAGER;
1268 sw->obj_instance[0] = 0xff;
1269 sw->obj_instance[1] = 0xff;
1270 sw->obj_instance[2] = 0xff;
1271 sw->state = SW_STATE_WAIT_ACTACK;
1272 sw->cbfn = cbfn;
1273 sw->cb_data = cb_data;
1274
1275 /* Open the file in order to fill some sw struct members */
1276 rc = sw_open_file(sw, fname);
1277 if (rc < 0) {
1278 sw->state = SW_STATE_NONE;
1279 return rc;
1280 }
1281 sw_close_file(sw);
1282
1283 return sw_activate(sw);
1284}
1285
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001286static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1287 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001288{
1289 ch->attrib = NM_ATT_ABIS_CHANNEL;
1290 ch->bts_port = bts_port;
1291 ch->timeslot = ts_nr;
1292 ch->subslot = subslot_nr;
1293}
1294
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001295int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1296 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1297 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001298{
1299 struct abis_om_hdr *oh;
1300 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001301 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001302 struct msgb *msg = nm_msgb_alloc();
1303
1304 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1305 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1306 bts->bts_nr, trx_nr, 0xff);
1307
1308 msgb_tv_put(msg, NM_ATT_TEI, tei);
1309
1310 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1311 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1312
1313 return abis_nm_sendmsg(bts, msg);
1314}
1315
1316/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1317int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001318 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001319{
1320 struct gsm_bts *bts = trx->bts;
1321 struct abis_om_hdr *oh;
1322 struct abis_nm_channel *ch;
1323 struct msgb *msg = nm_msgb_alloc();
1324
1325 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1326 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1327 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1328
1329 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1330 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1331
1332 return abis_nm_sendmsg(bts, msg);
1333}
1334
1335#if 0
1336int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1337 struct abis_nm_abis_channel *chan)
1338{
1339}
1340#endif
1341
1342int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001343 uint8_t e1_port, uint8_t e1_timeslot,
1344 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001345{
1346 struct gsm_bts *bts = ts->trx->bts;
1347 struct abis_om_hdr *oh;
1348 struct abis_nm_channel *ch;
1349 struct msgb *msg = nm_msgb_alloc();
1350
1351 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1352 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1353 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1354
1355 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1356 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1357
1358 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1359 gsm_ts_name(ts),
1360 e1_port, e1_timeslot, e1_subslot);
1361
1362 return abis_nm_sendmsg(bts, msg);
1363}
1364
1365#if 0
1366int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1367 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001368 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001369{
1370}
1371#endif
1372
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001373/* Chapter 8.11.1 */
1374int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1375 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1376 uint8_t *attr, uint8_t attr_len)
1377{
1378 struct abis_om_hdr *oh;
1379 struct msgb *msg = nm_msgb_alloc();
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001380
1381 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1382
1383 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1384 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1385 bts_nr, trx_nr, ts_nr);
1386 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1387
1388 return abis_nm_sendmsg(bts, msg);
1389}
1390
Harald Welte59b04682009-06-10 05:40:52 +08001391/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001392int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001393{
1394 struct abis_om_hdr *oh;
1395 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001396 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001397
1398 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1399
1400 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1401 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1402 cur = msgb_put(msg, attr_len);
1403 memcpy(cur, attr, attr_len);
1404
1405 return abis_nm_sendmsg(bts, msg);
1406}
1407
1408/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001409int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001410{
1411 struct abis_om_hdr *oh;
1412 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001413 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001414
1415 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1416
1417 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1418 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1419 trx->bts->bts_nr, trx->nr, 0xff);
1420 cur = msgb_put(msg, attr_len);
1421 memcpy(cur, attr, attr_len);
1422
1423 return abis_nm_sendmsg(trx->bts, msg);
1424}
1425
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001426static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Weltef2eb2782009-08-09 21:49:48 +02001427{
1428 int i;
1429
1430 /* As it turns out, the BS-11 has some very peculiar restrictions
1431 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301432 switch (ts->trx->bts->type) {
1433 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001434 switch (chan_comb) {
1435 case NM_CHANC_TCHHalf:
1436 case NM_CHANC_TCHHalf2:
1437 /* not supported */
1438 return -EINVAL;
1439 case NM_CHANC_SDCCH:
1440 /* only one SDCCH/8 per TRX */
1441 for (i = 0; i < TRX_NR_TS; i++) {
1442 if (i == ts->nr)
1443 continue;
1444 if (ts->trx->ts[i].nm_chan_comb ==
1445 NM_CHANC_SDCCH)
1446 return -EINVAL;
1447 }
1448 /* not allowed for TS0 of BCCH-TRX */
1449 if (ts->trx == ts->trx->bts->c0 &&
1450 ts->nr == 0)
1451 return -EINVAL;
1452 /* not on the same TRX that has a BCCH+SDCCH4
1453 * combination */
1454 if (ts->trx == ts->trx->bts->c0 &&
1455 (ts->trx->ts[0].nm_chan_comb == 5 ||
1456 ts->trx->ts[0].nm_chan_comb == 8))
1457 return -EINVAL;
1458 break;
1459 case NM_CHANC_mainBCCH:
1460 case NM_CHANC_BCCHComb:
1461 /* allowed only for TS0 of C0 */
1462 if (ts->trx != ts->trx->bts->c0 ||
1463 ts->nr != 0)
1464 return -EINVAL;
1465 break;
1466 case NM_CHANC_BCCH:
1467 /* allowed only for TS 2/4/6 of C0 */
1468 if (ts->trx != ts->trx->bts->c0)
1469 return -EINVAL;
1470 if (ts->nr != 2 && ts->nr != 4 &&
1471 ts->nr != 6)
1472 return -EINVAL;
1473 break;
1474 case 8: /* this is not like 08.58, but in fact
1475 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1476 /* FIXME: only one CBCH allowed per cell */
1477 break;
1478 }
Harald Welte76ba8812009-12-02 02:45:23 +05301479 break;
1480 case GSM_BTS_TYPE_NANOBTS:
1481 switch (ts->nr) {
1482 case 0:
1483 if (ts->trx->nr == 0) {
1484 /* only on TRX0 */
1485 switch (chan_comb) {
1486 case NM_CHANC_BCCH:
1487 case NM_CHANC_mainBCCH:
1488 case NM_CHANC_BCCHComb:
1489 return 0;
1490 break;
1491 default:
1492 return -EINVAL;
1493 }
1494 } else {
1495 switch (chan_comb) {
1496 case NM_CHANC_TCHFull:
1497 case NM_CHANC_TCHHalf:
1498 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1499 return 0;
1500 default:
1501 return -EINVAL;
1502 }
1503 }
1504 break;
1505 case 1:
1506 if (ts->trx->nr == 0) {
1507 switch (chan_comb) {
1508 case NM_CHANC_SDCCH_CBCH:
1509 if (ts->trx->ts[0].nm_chan_comb ==
1510 NM_CHANC_mainBCCH)
1511 return 0;
1512 return -EINVAL;
1513 case NM_CHANC_SDCCH:
1514 case NM_CHANC_TCHFull:
1515 case NM_CHANC_TCHHalf:
1516 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1517 case NM_CHANC_IPAC_TCHFull_PDCH:
1518 return 0;
1519 }
1520 } else {
1521 switch (chan_comb) {
1522 case NM_CHANC_SDCCH:
1523 case NM_CHANC_TCHFull:
1524 case NM_CHANC_TCHHalf:
1525 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1526 return 0;
1527 default:
1528 return -EINVAL;
1529 }
1530 }
1531 break;
1532 case 2:
1533 case 3:
1534 case 4:
1535 case 5:
1536 case 6:
1537 case 7:
1538 switch (chan_comb) {
1539 case NM_CHANC_TCHFull:
1540 case NM_CHANC_TCHHalf:
1541 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1542 return 0;
1543 case NM_CHANC_IPAC_PDCH:
1544 case NM_CHANC_IPAC_TCHFull_PDCH:
1545 if (ts->trx->nr == 0)
1546 return 0;
1547 else
1548 return -EINVAL;
1549 }
1550 break;
1551 }
1552 return -EINVAL;
Harald Welte35ac0e42012-07-02 19:51:55 +02001553 case GSM_BTS_TYPE_OSMO_SYSMO:
1554 /* no known restrictions */
1555 return 0;
Harald Welte76ba8812009-12-02 02:45:23 +05301556 default:
1557 /* unknown BTS type */
1558 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001559 }
1560 return 0;
1561}
1562
Harald Welte59b04682009-06-10 05:40:52 +08001563/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001564int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001565{
1566 struct gsm_bts *bts = ts->trx->bts;
1567 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001568 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001569 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001570 uint8_t len = 2 + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001571
1572 if (bts->type == GSM_BTS_TYPE_BS11)
1573 len += 4 + 2 + 2 + 3;
1574
1575 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001576 if (verify_chan_comb(ts, chan_comb) < 0) {
1577 msgb_free(msg);
1578 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1579 return -EINVAL;
1580 }
1581 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001582
1583 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1584 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1585 NM_OC_CHANNEL, bts->bts_nr,
1586 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001587 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001588 if (ts->hopping.enabled) {
1589 unsigned int i;
1590 uint8_t *len;
1591
Harald Welte67104d12009-09-12 13:05:33 +02001592 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1593 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001594
1595 /* build the ARFCN list */
1596 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1597 len = msgb_put(msg, 1);
1598 *len = 0;
1599 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1600 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1601 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001602 /* At least BS-11 wants a TLV16 here */
1603 if (bts->type == GSM_BTS_TYPE_BS11)
1604 *len += 1;
1605 else
1606 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001607 }
1608 }
Harald Welte59b04682009-06-10 05:40:52 +08001609 }
Harald Welte85771a42011-05-30 12:09:13 +02001610 if (ts->tsc == -1)
1611 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1612 else
1613 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001614 if (bts->type == GSM_BTS_TYPE_BS11)
1615 msgb_tlv_put(msg, 0x59, 1, &zero);
1616
1617 return abis_nm_sendmsg(bts, msg);
1618}
1619
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001620int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1621 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001622{
1623 struct abis_om_hdr *oh;
1624 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001625 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1626 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001627
1628 if (nack) {
1629 len += 2;
1630 msgtype = NM_MT_SW_ACT_REQ_NACK;
1631 }
1632
1633 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1634 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1635
1636 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001637 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001638 memcpy(ptr, attr, att_len);
1639 }
1640 if (nack)
1641 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1642
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001643 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001644}
1645
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001646int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001647{
1648 struct msgb *msg = nm_msgb_alloc();
1649 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001650 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001651
1652 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1653 fill_om_hdr(oh, len);
1654 data = msgb_put(msg, len);
1655 memcpy(data, rawmsg, len);
1656
1657 return abis_nm_sendmsg(bts, msg);
1658}
1659
1660/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001661static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001662{
1663 struct abis_om_hdr *oh;
1664 struct msgb *msg = nm_msgb_alloc();
1665
1666 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1667 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1668 0xff, 0xff, 0xff);
1669
1670 return abis_nm_sendmsg(bts, msg);
1671}
1672
1673/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001674int 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 +08001675{
1676 struct abis_om_hdr *oh;
1677 struct msgb *msg = nm_msgb_alloc();
1678
Harald Welte59b04682009-06-10 05:40:52 +08001679 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1680 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1681
Harald Weltec61a90e2011-05-22 22:45:37 +02001682 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001683 DEBUGPC(DNM, "Sending OPSTART\n");
1684
Harald Welte59b04682009-06-10 05:40:52 +08001685 return abis_nm_sendmsg(bts, msg);
1686}
1687
1688/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001689int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1690 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001691{
1692 struct abis_om_hdr *oh;
1693 struct msgb *msg = nm_msgb_alloc();
1694
1695 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1696 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1697 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1698
1699 return abis_nm_sendmsg(bts, msg);
1700}
1701
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001702int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1703 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001704{
1705 struct abis_om_hdr *oh;
1706 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001707 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001708
1709 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1710 e1_port0, ts0, e1_port1, ts1);
1711
1712 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1713 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1714 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1715
1716 attr = msgb_put(msg, 3);
1717 attr[0] = NM_ATT_MDROP_LINK;
1718 attr[1] = e1_port0;
1719 attr[2] = ts0;
1720
1721 attr = msgb_put(msg, 3);
1722 attr[0] = NM_ATT_MDROP_NEXT;
1723 attr[1] = e1_port1;
1724 attr[2] = ts1;
1725
1726 return abis_nm_sendmsg(bts, msg);
1727}
Harald Welte59b04682009-06-10 05:40:52 +08001728
Harald Welte0bf8e302009-08-08 00:02:36 +02001729/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001730int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1731 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1732 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001733{
1734 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001735
Harald Weltec61a90e2011-05-22 22:45:37 +02001736 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001737
1738 if (!msg)
1739 msg = nm_msgb_alloc();
1740
1741 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1742 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1743 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1744 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001745 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001746
1747 return abis_nm_sendmsg(bts, msg);
1748}
1749
Harald Welte59b04682009-06-10 05:40:52 +08001750int abis_nm_event_reports(struct gsm_bts *bts, int on)
1751{
1752 if (on == 0)
1753 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1754 else
1755 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1756}
1757
1758/* Siemens (or BS-11) specific commands */
1759
1760int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1761{
1762 if (reconnect == 0)
1763 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1764 else
1765 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1766}
1767
1768int abis_nm_bs11_restart(struct gsm_bts *bts)
1769{
1770 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1771}
1772
1773
1774struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001775 uint16_t year;
1776 uint8_t month;
1777 uint8_t day;
1778 uint8_t hour;
1779 uint8_t min;
1780 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001781} __attribute__((packed));
1782
1783
1784void get_bs11_date_time(struct bs11_date_time *aet)
1785{
1786 time_t t;
1787 struct tm *tm;
1788
1789 t = time(NULL);
1790 tm = localtime(&t);
1791 aet->sec = tm->tm_sec;
1792 aet->min = tm->tm_min;
1793 aet->hour = tm->tm_hour;
1794 aet->day = tm->tm_mday;
1795 aet->month = tm->tm_mon;
1796 aet->year = htons(1900 + tm->tm_year);
1797}
1798
1799int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1800{
1801 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1802}
1803
1804int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1805{
1806 if (begin)
1807 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1808 else
1809 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1810}
1811
1812int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001813 enum abis_bs11_objtype type, uint8_t idx,
1814 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001815{
1816 struct abis_om_hdr *oh;
1817 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001818 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001819
1820 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1821 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1822 NM_OC_BS11, type, 0, idx);
1823 cur = msgb_put(msg, attr_len);
1824 memcpy(cur, attr, attr_len);
1825
1826 return abis_nm_sendmsg(bts, msg);
1827}
1828
1829int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001830 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001831{
1832 struct abis_om_hdr *oh;
1833 struct msgb *msg = nm_msgb_alloc();
1834
1835 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1836 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1837 NM_OC_BS11, type, 0, idx);
1838
1839 return abis_nm_sendmsg(bts, msg);
1840}
1841
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001842int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001843{
1844 struct abis_om_hdr *oh;
1845 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001846 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001847
1848 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1849 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1850 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1851 msgb_tlv_put(msg, 0x99, 1, &zero);
1852
1853 return abis_nm_sendmsg(bts, msg);
1854}
1855
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001856int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001857{
1858 struct abis_om_hdr *oh;
1859 struct msgb *msg = nm_msgb_alloc();
1860
1861 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1862 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001863 idx, 0xff, 0xff);
1864
1865 return abis_nm_sendmsg(bts, msg);
1866}
1867
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001868int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001869{
1870 struct abis_om_hdr *oh;
1871 struct msgb *msg = nm_msgb_alloc();
1872
1873 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1874 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1875 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001876
1877 return abis_nm_sendmsg(bts, msg);
1878}
1879
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001880static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001881int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1882{
1883 struct abis_om_hdr *oh;
1884 struct msgb *msg = nm_msgb_alloc();
1885
1886 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1887 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1888 0xff, 0xff, 0xff);
1889 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1890
1891 return abis_nm_sendmsg(bts, msg);
1892}
1893
1894/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001895int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1896 uint8_t e1_timeslot, uint8_t e1_subslot,
1897 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001898{
1899 struct abis_om_hdr *oh;
1900 struct abis_nm_channel *ch;
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, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1905 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1906
1907 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1908 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1909 msgb_tv_put(msg, NM_ATT_TEI, tei);
1910
1911 return abis_nm_sendmsg(bts, msg);
1912}
1913
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001914int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08001915{
1916 struct abis_om_hdr *oh;
1917 struct msgb *msg = nm_msgb_alloc();
1918
1919 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1920 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
1921 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1922 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1923
1924 return abis_nm_sendmsg(trx->bts, msg);
1925}
1926
1927int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1928{
1929 struct abis_om_hdr *oh;
1930 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001931 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08001932
1933 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1934 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1935 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1936 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1937
1938 return abis_nm_sendmsg(trx->bts, msg);
1939}
1940
1941int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1942{
1943 struct abis_om_hdr *oh;
1944 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001945 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08001946
1947 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1948 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1949 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
1950 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1951
1952 return abis_nm_sendmsg(bts, msg);
1953}
1954
1955int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1956{
1957 struct abis_om_hdr *oh;
1958 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001959 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08001960 NM_ATT_BS11_CCLK_TYPE };
1961
1962 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1963 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1964 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1965 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1966
1967 return abis_nm_sendmsg(bts, msg);
1968
1969}
1970
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001971//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08001972
1973int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
1974{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001975 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1976}
1977
Daniel Willmannbf2ca572010-01-07 00:46:26 +01001978int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1979{
1980 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1981}
1982
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001983int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001984{
Harald Welte59b04682009-06-10 05:40:52 +08001985 struct abis_om_hdr *oh;
1986 struct msgb *msg = nm_msgb_alloc();
1987 struct bs11_date_time bdt;
1988
1989 get_bs11_date_time(&bdt);
1990
1991 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1992 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001993 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001994 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08001995 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
1996 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1997 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001998 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08001999 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002000 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002001 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002002 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002003 } else {
2004 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2005 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2006 }
2007
2008 return abis_nm_sendmsg(bts, msg);
2009}
2010
2011int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2012{
2013 struct abis_om_hdr *oh;
2014 struct msgb *msg;
2015
2016 if (strlen(password) != 10)
2017 return -EINVAL;
2018
2019 msg = nm_msgb_alloc();
2020 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2021 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2022 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002023 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002024
2025 return abis_nm_sendmsg(bts, msg);
2026}
2027
2028/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2029int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2030{
2031 struct abis_om_hdr *oh;
2032 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002033 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002034
2035 msg = nm_msgb_alloc();
2036 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2037 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2038 BS11_OBJ_LI, 0x00, 0x00);
2039
2040 if (locked)
2041 tlv_value = BS11_LI_PLL_LOCKED;
2042 else
2043 tlv_value = BS11_LI_PLL_STANDALONE;
2044
2045 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2046
2047 return abis_nm_sendmsg(bts, msg);
2048}
2049
Daniel Willmann10b07db2010-01-07 00:54:01 +01002050/* Set the calibration value of the PLL (work value/set value)
2051 * It depends on the login which one is changed */
2052int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2053{
2054 struct abis_om_hdr *oh;
2055 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002056 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002057
2058 msg = nm_msgb_alloc();
2059 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2060 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2061 BS11_OBJ_TRX1, 0x00, 0x00);
2062
2063 tlv_value[0] = value>>8;
2064 tlv_value[1] = value&0xff;
2065
2066 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2067
2068 return abis_nm_sendmsg(bts, msg);
2069}
2070
Harald Welte59b04682009-06-10 05:40:52 +08002071int abis_nm_bs11_get_state(struct gsm_bts *bts)
2072{
2073 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2074}
2075
2076/* BS11 SWL */
2077
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002078void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002079
Harald Welte59b04682009-06-10 05:40:52 +08002080struct abis_nm_bs11_sw {
2081 struct gsm_bts *bts;
2082 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002083 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002084 int forced;
2085 struct llist_head file_list;
2086 gsm_cbfn *user_cb; /* specified by the user */
2087};
2088static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2089
2090struct file_list_entry {
2091 struct llist_head list;
2092 char fname[PATH_MAX];
2093};
2094
2095struct file_list_entry *fl_dequeue(struct llist_head *queue)
2096{
2097 struct llist_head *lh;
2098
2099 if (llist_empty(queue))
2100 return NULL;
2101
2102 lh = queue->next;
2103 llist_del(lh);
2104
2105 return llist_entry(lh, struct file_list_entry, list);
2106}
2107
2108static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2109{
2110 char linebuf[255];
2111 struct llist_head *lh, *lh2;
2112 FILE *swl;
2113 int rc = 0;
2114
2115 swl = fopen(bs11_sw->swl_fname, "r");
2116 if (!swl)
2117 return -ENODEV;
2118
2119 /* zero the stale file list, if any */
2120 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2121 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002122 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002123 }
2124
2125 while (fgets(linebuf, sizeof(linebuf), swl)) {
2126 char file_id[12+1];
2127 char file_version[80+1];
2128 struct file_list_entry *fle;
2129 static char dir[PATH_MAX];
2130
2131 if (strlen(linebuf) < 4)
2132 continue;
2133
2134 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2135 if (rc < 0) {
2136 perror("ERR parsing SWL file");
2137 rc = -EINVAL;
2138 goto out;
2139 }
2140 if (rc < 2)
2141 continue;
2142
Harald Welte857e00d2009-06-26 20:25:23 +02002143 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002144 if (!fle) {
2145 rc = -ENOMEM;
2146 goto out;
2147 }
Harald Welte59b04682009-06-10 05:40:52 +08002148
2149 /* construct new filename */
2150 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2151 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2152 strcat(fle->fname, "/");
2153 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2154
2155 llist_add_tail(&fle->list, &bs11_sw->file_list);
2156 }
2157
2158out:
2159 fclose(swl);
2160 return rc;
2161}
2162
2163/* bs11 swload specific callback, passed to abis_nm core swload */
2164static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2165 struct msgb *msg, void *data, void *param)
2166{
2167 struct abis_nm_bs11_sw *bs11_sw = data;
2168 struct file_list_entry *fle;
2169 int rc = 0;
2170
2171 switch (event) {
2172 case NM_MT_LOAD_END_ACK:
2173 fle = fl_dequeue(&bs11_sw->file_list);
2174 if (fle) {
2175 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002176 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002177 bs11_sw->win_size,
2178 bs11_sw->forced,
2179 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002180 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002181 } else {
2182 /* activate the SWL */
2183 rc = abis_nm_software_activate(bs11_sw->bts,
2184 bs11_sw->swl_fname,
2185 bs11_swload_cbfn,
2186 bs11_sw);
2187 }
2188 break;
2189 case NM_MT_LOAD_SEG_ACK:
2190 case NM_MT_LOAD_END_NACK:
2191 case NM_MT_LOAD_INIT_ACK:
2192 case NM_MT_LOAD_INIT_NACK:
2193 case NM_MT_ACTIVATE_SW_NACK:
2194 case NM_MT_ACTIVATE_SW_ACK:
2195 default:
2196 /* fallthrough to the user callback */
2197 if (bs11_sw->user_cb)
2198 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2199 break;
2200 }
2201
2202 return rc;
2203}
2204
2205/* Siemens provides a SWL file that is a mere listing of all the other
2206 * files that are part of a software release. We need to upload first
2207 * the list file, and then each file that is listed in the list file */
2208int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002209 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002210{
2211 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2212 struct file_list_entry *fle;
2213 int rc = 0;
2214
2215 INIT_LLIST_HEAD(&bs11_sw->file_list);
2216 bs11_sw->bts = bts;
2217 bs11_sw->win_size = win_size;
2218 bs11_sw->user_cb = cbfn;
2219 bs11_sw->forced = forced;
2220
2221 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2222 rc = bs11_read_swl_file(bs11_sw);
2223 if (rc < 0)
2224 return rc;
2225
2226 /* dequeue next item in file list */
2227 fle = fl_dequeue(&bs11_sw->file_list);
2228 if (!fle)
2229 return -EINVAL;
2230
2231 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002232 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002233 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002234 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002235 return rc;
2236}
2237
2238#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002239static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002240 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2241 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2242 NM_ATT_BS11_LMT_USER_NAME,
2243
2244 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2245
2246 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2247
2248 NM_ATT_BS11_SW_LOAD_STORED };
2249
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002250static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002251 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2252 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2253 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2254 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2255#endif
2256
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002257static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002258 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2259 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2260 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2261
2262int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2263{
2264 struct abis_om_hdr *oh;
2265 struct msgb *msg = nm_msgb_alloc();
2266
2267 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2268 /* SiemensHW CCTRL object */
2269 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2270 0x03, 0x00, 0x00);
2271 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2272
2273 return abis_nm_sendmsg(bts, msg);
2274}
2275
2276int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2277{
2278 struct abis_om_hdr *oh;
2279 struct msgb *msg = nm_msgb_alloc();
2280 struct bs11_date_time aet;
2281
2282 get_bs11_date_time(&aet);
2283 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2284 /* SiemensHW CCTRL object */
2285 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2286 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002287 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002288
2289 return abis_nm_sendmsg(bts, msg);
2290}
2291
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002292int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002293{
2294 struct abis_om_hdr *oh;
2295 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002296 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002297
2298 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2299 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2300 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2301 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2302
2303 return abis_nm_sendmsg(bts, msg);
2304}
2305
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002306int 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 +02002307{
2308 struct abis_om_hdr *oh;
2309 struct msgb *msg = nm_msgb_alloc();
2310 struct bs11_date_time aet;
2311
2312 get_bs11_date_time(&aet);
2313 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2314 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2315 bport, 0xff, 0x02);
2316 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2317
2318 return abis_nm_sendmsg(bts, msg);
2319}
2320
Harald Welte59b04682009-06-10 05:40:52 +08002321/* ip.access nanoBTS specific commands */
2322static const char ipaccess_magic[] = "com.ipaccess";
2323
2324
2325static int abis_nm_rx_ipacc(struct msgb *msg)
2326{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002327 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002328 struct abis_om_hdr *oh = msgb_l2(msg);
2329 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002330 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002331 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002332 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002333 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002334
2335 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002336 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002337 return -EINVAL;
2338 }
2339
2340 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002341 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002342
Harald Weltec61a90e2011-05-22 22:45:37 +02002343 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002344
Harald Welte5aeedd42009-10-19 22:11:11 +02002345 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002346
2347 switch (foh->msg_type) {
2348 case NM_MT_IPACC_RSL_CONNECT_ACK:
2349 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002350 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2351 memcpy(&addr,
2352 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2353
2354 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2355 }
Harald Welte4206d982009-07-12 09:33:54 +02002356 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002357 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002358 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002359 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002360 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2361 DEBUGPC(DNM, "STREAM=0x%02x ",
2362 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002363 DEBUGPC(DNM, "\n");
2364 break;
2365 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002366 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002367 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002368 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002369 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002370 else
2371 DEBUGPC(DNM, "\n");
2372 break;
2373 case NM_MT_IPACC_SET_NVATTR_ACK:
2374 DEBUGPC(DNM, "SET NVATTR ACK\n");
2375 /* FIXME: decode and show the actual attributes */
2376 break;
2377 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002378 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002379 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002380 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002381 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002382 else
Harald Weltede4477a2009-12-24 12:20:20 +01002383 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002384 break;
Harald Welte21460f02009-07-03 11:26:45 +02002385 case NM_MT_IPACC_GET_NVATTR_ACK:
2386 DEBUGPC(DNM, "GET NVATTR ACK\n");
2387 /* FIXME: decode and show the actual attributes */
2388 break;
2389 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002390 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002391 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002392 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002393 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002394 else
Harald Weltede4477a2009-12-24 12:20:20 +01002395 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002396 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002397 case NM_MT_IPACC_SET_ATTR_ACK:
2398 DEBUGPC(DNM, "SET ATTR ACK\n");
2399 break;
2400 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002401 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002402 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002403 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002404 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002405 else
Harald Weltede4477a2009-12-24 12:20:20 +01002406 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002407 break;
Harald Welte59b04682009-06-10 05:40:52 +08002408 default:
2409 DEBUGPC(DNM, "unknown\n");
2410 break;
2411 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002412
2413 /* signal handling */
2414 switch (foh->msg_type) {
2415 case NM_MT_IPACC_RSL_CONNECT_NACK:
2416 case NM_MT_IPACC_SET_NVATTR_NACK:
2417 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002418 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 +01002419 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002420 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002421 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002422 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002423 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 +01002424 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002425 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002426 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002427 default:
2428 break;
2429 }
2430
Harald Welte59b04682009-06-10 05:40:52 +08002431 return 0;
2432}
2433
2434/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002435int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2436 uint8_t obj_class, uint8_t bts_nr,
2437 uint8_t trx_nr, uint8_t ts_nr,
2438 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002439{
2440 struct msgb *msg = nm_msgb_alloc();
2441 struct abis_om_hdr *oh;
2442 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002443 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002444
2445 /* construct the 12.21 OM header, observe the erroneous length */
2446 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2447 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2448 oh->mdisc = ABIS_OM_MDISC_MANUF;
2449
2450 /* add the ip.access magic */
2451 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2452 *data++ = sizeof(ipaccess_magic);
2453 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2454
2455 /* fill the 12.21 FOM header */
2456 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2457 foh->msg_type = msg_type;
2458 foh->obj_class = obj_class;
2459 foh->obj_inst.bts_nr = bts_nr;
2460 foh->obj_inst.trx_nr = trx_nr;
2461 foh->obj_inst.ts_nr = ts_nr;
2462
2463 if (attr && attr_len) {
2464 data = msgb_put(msg, attr_len);
2465 memcpy(data, attr, attr_len);
2466 }
2467
2468 return abis_nm_sendmsg(bts, msg);
2469}
2470
2471/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002472int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002473 int attr_len)
2474{
Harald Weltef12c1052010-01-07 20:39:42 +01002475 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2476 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002477 attr_len);
2478}
2479
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002480int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002481 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002482{
2483 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002484 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002485 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2486 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2487
2488 int attr_len = sizeof(attr);
2489
2490 ia.s_addr = htonl(ip);
2491 attr[1] = stream;
2492 attr[3] = port >> 8;
2493 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002494 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002495
2496 /* if ip == 0, we use the default IP */
2497 if (ip == 0)
2498 attr_len -= 5;
2499
2500 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002501 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002502
2503 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2504 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2505 trx->nr, 0xff, attr, attr_len);
2506}
2507
Harald Welte59b04682009-06-10 05:40:52 +08002508/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002509int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002510{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002511 struct abis_om_hdr *oh;
2512 struct msgb *msg = nm_msgb_alloc();
2513
2514 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2515 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2516 trx->bts->nr, trx->nr, 0xff);
2517
2518 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002519}
Harald Welte0dfc6232009-10-24 10:20:41 +02002520
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002521int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2522 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2523 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002524{
2525 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2526 obj_class, bts_nr, trx_nr, ts_nr,
2527 attr, attr_len);
2528}
Harald Weltebeeae412009-11-12 14:48:42 +01002529
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002530void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002531{
2532 /* we simply reuse the GSM48 function and overwrite the RAC
2533 * with the Cell ID */
2534 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002535 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002536}
2537
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002538void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2539{
2540 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2541
Harald Welte69f6f812011-05-30 12:07:53 +02002542 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002543 if (!trx->bts || !trx->bts->oml_link)
2544 return;
2545
2546 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2547 trx->bts->bts_nr, trx->nr, 0xff,
2548 new_state);
2549}
2550
Harald Welte453141f2010-03-25 11:45:30 +08002551static const struct value_string ipacc_testres_names[] = {
2552 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2553 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2554 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2555 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2556 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2557 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002558};
2559
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002560const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002561{
Harald Welte453141f2010-03-25 11:45:30 +08002562 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002563}
2564
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002565void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002566{
2567 cid->mcc = (buf[0] & 0xf) * 100;
2568 cid->mcc += (buf[0] >> 4) * 10;
2569 cid->mcc += (buf[1] & 0xf) * 1;
2570
2571 if (buf[1] >> 4 == 0xf) {
2572 cid->mnc = (buf[2] & 0xf) * 10;
2573 cid->mnc += (buf[2] >> 4) * 1;
2574 } else {
2575 cid->mnc = (buf[2] & 0xf) * 100;
2576 cid->mnc += (buf[2] >> 4) * 10;
2577 cid->mnc += (buf[1] >> 4) * 1;
2578 }
2579
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002580 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2581 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002582}
2583
Harald Weltebeeae412009-11-12 14:48:42 +01002584/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002585int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002586{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002587 uint8_t *cur = buf;
Holger Hans Peter Freyther1a9f3ee2012-09-11 11:55:03 +02002588 uint16_t len __attribute__((unused));
Harald Weltebeeae412009-11-12 14:48:42 +01002589
Harald Welteb784df82010-07-22 18:14:36 +02002590 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002591
2592 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2593 return -EINVAL;
2594 cur++;
2595
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002596 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002597 cur += 2;
2598
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002599 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002600 cur += 2;
2601
2602 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2603 binf->freq_qual = *cur >> 2;
2604
Harald Welteb784df82010-07-22 18:14:36 +02002605 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002606 binf->arfcn |= *cur++;
2607
2608 if (binf->info_type & IPAC_BINF_RXLEV)
2609 binf->rx_lev = *cur & 0x3f;
2610 cur++;
2611
2612 if (binf->info_type & IPAC_BINF_RXQUAL)
2613 binf->rx_qual = *cur & 0x7;
2614 cur++;
2615
2616 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002617 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002618 cur += 2;
2619
2620 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002621 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002622 cur += 2;
2623
2624 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002625 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002626 cur += 4;
2627
Harald Welte22cb81f2010-07-30 22:34:42 +02002628#if 0
2629 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002630 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002631#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002632 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002633 cur++;
2634
Harald Weltebfc21092009-11-13 11:56:05 +01002635 ipac_parse_cgi(&binf->cgi, cur);
2636 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002637
2638 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2639 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2640 cur += sizeof(binf->ba_list_si2);
2641 }
2642
2643 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2644 memcpy(binf->ba_list_si2bis, cur,
2645 sizeof(binf->ba_list_si2bis));
2646 cur += sizeof(binf->ba_list_si2bis);
2647 }
2648
2649 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2650 memcpy(binf->ba_list_si2ter, cur,
2651 sizeof(binf->ba_list_si2ter));
2652 cur += sizeof(binf->ba_list_si2ter);
2653 }
2654
2655 return 0;
2656}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002657
2658void abis_nm_clear_queue(struct gsm_bts *bts)
2659{
2660 struct msgb *msg;
2661
2662 while (!llist_empty(&bts->abis_queue)) {
2663 msg = msgb_dequeue(&bts->abis_queue);
2664 msgb_free(msg);
2665 }
2666
2667 bts->abis_nm_pend = 0;
2668}