blob: 7485a6ccef4460d7230699961e079f36828221a9 [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte59b04682009-06-10 05:40:52 +080011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
Harald Welte59b04682009-06-10 05:40:52 +080033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Weltec61a90e2011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080043#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte59b04682009-06-10 05:40:52 +080047
48#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080051
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte59b04682009-06-10 05:40:52 +080053{
Harald Welte59698fb2010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +080057}
58
59static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
71#if 0
72/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
77#endif
78
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Weltec61a90e2011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte59b04682009-06-10 05:40:52 +080083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +080089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte59b04682009-06-10 05:40:52 +080099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
103 fill_om_hdr(oh, len+sizeof(*foh));
104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte9cfc9352009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800115}
116
Harald Welte607044f2011-09-26 23:43:23 +0200117int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200118{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200119 msg->l2h = msg->data;
120
121 if (!msg->dst) {
122 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
123 return -EINVAL;
124 }
125
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200126 return abis_sendmsg(msg);
127}
128
Harald Welte59b04682009-06-10 05:40:52 +0800129/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100130static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800131{
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200132 msg->dst = bts->oml_link;
Harald Welte59b04682009-06-10 05:40:52 +0800133
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100134 /* queue OML messages */
135 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
136 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200137 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100138 } else {
139 msgb_enqueue(&bts->abis_queue, msg);
140 return 0;
141 }
142
143}
144
145int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
146{
147 OBSC_NM_W_ACK_CB(msg) = 1;
148 return abis_nm_queue_msg(bts, msg);
149}
150
151static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 0;
154 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800155}
156
157static int abis_nm_rcvmsg_sw(struct msgb *mb);
158
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100159int nm_is_running(struct gsm_nm_state *s) {
160 return (s->operational == NM_OPSTATE_ENABLED) && (
161 (s->availability == NM_AVSTATE_OK) ||
162 (s->availability == 0xff)
163 );
164}
165
Harald Welte59b04682009-06-10 05:40:52 +0800166/* Update the administrative state of a given object in our in-memory data
167 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200168static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
169 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800170{
171 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100172 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800173
Harald Weltea348c082011-03-06 21:20:38 +0100174 memset(&nsd, 0, sizeof(nsd));
175
Harald Weltec6ed9282011-06-06 18:31:20 +0200176 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100177 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100178 return -EINVAL;
Harald Weltec6ed9282011-06-06 18:31:20 +0200179 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800180 if (!nm_state)
181 return -1;
182
183 new_state = *nm_state;
184 new_state.administrative = adm_state;
185
Harald Welteb03c4482011-03-06 22:11:32 +0100186 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100187 nsd.obj_class = obj_class;
188 nsd.old_state = nm_state;
189 nsd.new_state = &new_state;
190 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200191 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800192
193 nm_state->administrative = adm_state;
194
Harald Welte4c826f72011-01-14 15:55:42 +0100195 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800196}
197
198static int abis_nm_rx_statechg_rep(struct msgb *mb)
199{
200 struct abis_om_hdr *oh = msgb_l2(mb);
201 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200202 struct e1inp_sign_link *sign_link = mb->dst;
203 struct gsm_bts *bts = sign_link->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +0800204 struct tlv_parsed tp;
205 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800206
207 DEBUGPC(DNM, "STATE CHG: ");
208
209 memset(&new_state, 0, sizeof(new_state));
210
Harald Weltec6ed9282011-06-06 18:31:20 +0200211 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800212 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100213 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800214 return -EINVAL;
215 }
216
217 new_state = *nm_state;
218
Harald Welte59698fb2010-01-10 18:01:52 +0100219 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800220 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
221 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200222 DEBUGPC(DNM, "OP_STATE=%s ",
223 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800224 }
225 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
226 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
227 new_state.availability = 0xff;
228 else
229 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Weltec61a90e2011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
231 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800232 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100233 } else
234 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800235 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
236 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200238 get_value_string(abis_nm_adm_state_names,
239 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800240 }
241 DEBUGPC(DNM, "\n");
242
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100243 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
244 new_state.operational != nm_state->operational ||
245 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800246 /* Update the operational state of a given object in our in-memory data
247 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100248 struct nm_statechg_signal_data nsd;
Harald Weltec6ed9282011-06-06 18:31:20 +0200249 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100250 nsd.obj_class = foh->obj_class;
251 nsd.old_state = nm_state;
252 nsd.new_state = &new_state;
253 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100254 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200255 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100256 nm_state->operational = new_state.operational;
257 nm_state->availability = new_state.availability;
258 if (nm_state->administrative == 0)
259 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800260 }
261#if 0
262 if (op_state == 1) {
263 /* try to enable objects that are disabled */
264 abis_nm_opstart(bts, foh->obj_class,
265 foh->obj_inst.bts_nr,
266 foh->obj_inst.trx_nr,
267 foh->obj_inst.ts_nr);
268 }
269#endif
270 return 0;
271}
272
273static int rx_fail_evt_rep(struct msgb *mb)
274{
275 struct abis_om_hdr *oh = msgb_l2(mb);
276 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200277 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800278 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100279 const uint8_t *p_val;
280 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800281
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200282 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800283
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200284 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800285
286 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-05-22 22:45:37 +0200287 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
288 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800289 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200290 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
291 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100292 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
293 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200294 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100295 }
296 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
297 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
298 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
299 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100301 talloc_free(p_text);
302 }
303 }
Harald Welte59b04682009-06-10 05:40:52 +0800304
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200305 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800306
307 return 0;
308}
309
310static int abis_nm_rcvmsg_report(struct msgb *mb)
311{
312 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200313 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800314
Harald Weltec61a90e2011-05-22 22:45:37 +0200315 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800316
317 //nmh->cfg->report_cb(mb, foh);
318
319 switch (mt) {
320 case NM_MT_STATECHG_EVENT_REP:
321 return abis_nm_rx_statechg_rep(mb);
322 break;
323 case NM_MT_SW_ACTIVATED_REP:
324 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200325 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800326 break;
327 case NM_MT_FAILURE_EVENT_REP:
328 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200329 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800330 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200331 case NM_MT_TEST_REP:
332 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200334 break;
Harald Welte59b04682009-06-10 05:40:52 +0800335 default:
336 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
337 break;
338
339 };
340
341 return 0;
342}
343
344/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200345static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
346 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800347{
348 struct abis_om_hdr *oh;
349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200350 uint8_t len = swdesc_len;
351 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800352
353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
354 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
355
356 trailer = msgb_put(msg, swdesc_len);
357 memcpy(trailer, sw_desc, swdesc_len);
358
359 return abis_nm_sendmsg(bts, msg);
360}
361
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100362int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
363 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100364{
365 static const struct tlv_definition sw_descr_def = {
366 .def = {
367 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
368 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
369 },
370 };
371
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100372 size_t pos = 0;
373 int desc_pos = 0;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100374
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100375 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
376 uint8_t tag;
377 uint16_t tag_len;
378 const uint8_t *val;
379 int len;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100380
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100381 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
382 desc[desc_pos].start = &sw_descr[pos];
383
384 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
385 * nested nature and the fact you have to assume it contains only two sub
386 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
387 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
388 LOGP(DNM, LOGL_ERROR,
389 "SW_DESCR attribute identifier not found!\n");
390 return -1;
391 }
392
393 pos += 1;
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
396 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
397 LOGP(DNM, LOGL_ERROR,
398 "FILE_ID attribute identifier not found!\n");
399 return -2;
400 }
401 desc[desc_pos].file_id = val;
402 desc[desc_pos].file_id_len = tag_len;
403 pos += len;
404
405
406 len = tlv_parse_one(&tag, &tag_len, &val,
407 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
408 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
409 LOGP(DNM, LOGL_ERROR,
410 "FILE_VERSION attribute identifier not found!\n");
411 return -3;
412 }
413 desc[desc_pos].file_ver = val;
414 desc[desc_pos].file_ver_len = tag_len;
415 pos += len;
416
417 /* final size */
418 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100419 }
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100420
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100421 return desc_pos;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100422}
423
Harald Welte59b04682009-06-10 05:40:52 +0800424static int abis_nm_rx_sw_act_req(struct msgb *mb)
425{
426 struct abis_om_hdr *oh = msgb_l2(mb);
427 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200428 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200429 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200430 const uint8_t *sw_config;
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100431 int ret, sw_config_len;
432 struct abis_nm_sw_descr sw_descr[1];
Harald Welte59b04682009-06-10 05:40:52 +0800433
Harald Weltec61a90e2011-05-22 22:45:37 +0200434 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200435
436 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800437
Harald Welte3055e332010-03-14 15:37:43 +0800438 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800439
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200440 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800441 foh->obj_inst.bts_nr,
442 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800443 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800444 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100445 if (ret != 0) {
446 LOGP(DNM, LOGL_ERROR,
447 "Sending SW ActReq ACK failed: %d\n", ret);
448 return ret;
449 }
Harald Welte59b04682009-06-10 05:40:52 +0800450
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200451 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200452 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
453 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
454 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100455 LOGP(DNM, LOGL_ERROR,
456 "SW config not found! Can't continue.\n");
Mike Haben322fc582009-10-01 14:56:13 +0200457 return -EINVAL;
458 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200459 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200460 }
461
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100462 /* Parse up to two sw descriptions from the data */
463 ret = abis_nm_parse_sw_config(sw_config, sw_config_len,
464 &sw_descr[0], ARRAY_SIZE(sw_descr));
465 if (ret <= 0) {
466 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100467 return -EINVAL;
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100468 }
Mike Haben322fc582009-10-01 14:56:13 +0200469
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200470 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800471 foh->obj_inst.bts_nr,
472 foh->obj_inst.trx_nr,
473 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100474 sw_descr[0].start, sw_descr[0].len);
Harald Welte59b04682009-06-10 05:40:52 +0800475}
476
477/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
478static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
479{
480 struct abis_om_hdr *oh = msgb_l2(mb);
481 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200482 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800483 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200484 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800485
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200486 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800487 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
488 return -EINVAL;
489
490 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
491
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200492 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800493}
494
495static int abis_nm_rx_lmt_event(struct msgb *mb)
496{
497 struct abis_om_hdr *oh = msgb_l2(mb);
498 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200499 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800500 struct tlv_parsed tp;
501
502 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200503 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800504 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
505 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200506 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800507 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
508 }
509 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
510 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200511 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800512 DEBUGPC(DNM, "Level=%u ", level);
513 }
514 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
515 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
516 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
517 DEBUGPC(DNM, "Username=%s ", name);
518 }
519 DEBUGPC(DNM, "\n");
520 /* FIXME: parse LMT LOGON TIME */
521 return 0;
522}
523
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200524void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100525{
526 int wait = 0;
527 struct msgb *msg;
528 /* the queue is empty */
529 while (!llist_empty(&bts->abis_queue)) {
530 msg = msgb_dequeue(&bts->abis_queue);
531 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200532 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100533
534 if (wait)
535 break;
536 }
537
538 bts->abis_nm_pend = wait;
539}
540
Harald Welte59b04682009-06-10 05:40:52 +0800541/* Receive a OML NM Message from BTS */
542static int abis_nm_rcvmsg_fom(struct msgb *mb)
543{
544 struct abis_om_hdr *oh = msgb_l2(mb);
545 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200546 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200547 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100548 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800549
550 /* check for unsolicited message */
551 if (is_report(mt))
552 return abis_nm_rcvmsg_report(mb);
553
Harald Weltec61a90e2011-05-22 22:45:37 +0200554 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800555 return abis_nm_rcvmsg_sw(mb);
556
Harald Weltec61a90e2011-05-22 22:45:37 +0200557 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800558 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800559 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200560
Harald Weltec61a90e2011-05-22 22:45:37 +0200561 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200562
Harald Weltec61a90e2011-05-22 22:45:37 +0200563 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800564
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200565 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800566 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200567 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200568 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800569 else
570 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200571
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800572 nack_data.msg = mb;
573 nack_data.mt = mt;
Holger Hans Peter Freyther70f1e472012-11-11 18:26:23 +0100574 nack_data.bts = sign_link->trx->bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200575 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200576 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200577 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800578 }
579#if 0
580 /* check if last message is to be acked */
581 if (is_ack_nack(nmh->last_msgtype)) {
582 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100583 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800584 /* we got our ACK, continue sending the next msg */
585 } else if (mt == MT_NACK(nmh->last_msgtype)) {
586 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100587 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800588 /* FIXME: somehow signal this to the caller */
589 } else {
590 /* really strange things happen */
591 return -EINVAL;
592 }
593 }
594#endif
595
596 switch (mt) {
597 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100598 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800599 break;
600 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100601 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800602 break;
603 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100604 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800605 break;
Harald Welte204317e2009-08-06 17:58:31 +0200606 case NM_MT_CONN_MDROP_LINK_ACK:
607 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
608 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100609 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200610 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100611 break;
612 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200613 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100614 break;
Harald Welte08011e22011-03-04 13:41:31 +0100615 case NM_MT_SET_BTS_ATTR_ACK:
616 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200617 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
618 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Welte08011e22011-03-04 13:41:31 +0100619 }
620 break;
Harald Welte59b04682009-06-10 05:40:52 +0800621 }
622
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200623 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100624 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800625}
626
627static int abis_nm_rx_ipacc(struct msgb *mb);
628
629static int abis_nm_rcvmsg_manuf(struct msgb *mb)
630{
631 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200632 struct e1inp_sign_link *sign_link = mb->dst;
633 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800634
635 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100636 case GSM_BTS_TYPE_NANOBTS:
Harald Welte35ac0e42012-07-02 19:51:55 +0200637 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte59b04682009-06-10 05:40:52 +0800638 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200639 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800640 break;
641 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100642 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
643 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800644 rc = 0;
645 break;
646 }
647
648 return rc;
649}
650
651/* High-Level API */
652/* Entry-point where L2 OML from BTS enters the NM code */
653int abis_nm_rcvmsg(struct msgb *msg)
654{
655 struct abis_om_hdr *oh = msgb_l2(msg);
656 int rc = 0;
657
658 /* Various consistency checks */
659 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100660 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800661 oh->placement);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200662 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
663 rc = -EINVAL;
664 goto err;
665 }
Harald Welte59b04682009-06-10 05:40:52 +0800666 }
667 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100668 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800669 oh->sequence);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200670 rc = -EINVAL;
671 goto err;
Harald Welte59b04682009-06-10 05:40:52 +0800672 }
673#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200674 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800675 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
676 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100677 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800678 oh->length + sizeof(*oh), l2_len);
679 return -EINVAL;
680 }
681 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100682 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 +0800683#endif
684 msg->l3h = (unsigned char *)oh + sizeof(*oh);
685
686 switch (oh->mdisc) {
687 case ABIS_OM_MDISC_FOM:
688 rc = abis_nm_rcvmsg_fom(msg);
689 break;
690 case ABIS_OM_MDISC_MANUF:
691 rc = abis_nm_rcvmsg_manuf(msg);
692 break;
693 case ABIS_OM_MDISC_MMI:
694 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100695 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800696 oh->mdisc);
697 break;
698 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100699 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800700 oh->mdisc);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200701 rc = -EINVAL;
702 break;
Harald Welte59b04682009-06-10 05:40:52 +0800703 }
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200704err:
Harald Welte59b04682009-06-10 05:40:52 +0800705 msgb_free(msg);
706 return rc;
707}
708
709#if 0
710/* initialized all resources */
711struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
712{
713 struct abis_nm_h *nmh;
714
715 nmh = malloc(sizeof(*nmh));
716 if (!nmh)
717 return NULL;
718
719 nmh->cfg = cfg;
720
721 return nmh;
722}
723
724/* free all resources */
725void abis_nm_fini(struct abis_nm_h *nmh)
726{
727 free(nmh);
728}
729#endif
730
731/* Here we are trying to define a high-level API that can be used by
732 * the actual BSC implementation. However, the architecture is currently
733 * still under design. Ideally the calls to this API would be synchronous,
734 * while the underlying stack behind the APi runs in a traditional select
735 * based state machine.
736 */
737
738/* 6.2 Software Load: */
739enum sw_state {
740 SW_STATE_NONE,
741 SW_STATE_WAIT_INITACK,
742 SW_STATE_WAIT_SEGACK,
743 SW_STATE_WAIT_ENDACK,
744 SW_STATE_WAIT_ACTACK,
745 SW_STATE_ERROR,
746};
747
748struct abis_nm_sw {
749 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800750 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800751 gsm_cbfn *cbfn;
752 void *cb_data;
753 int forced;
754
755 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200756 uint8_t obj_class;
757 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800758
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200759 uint8_t file_id[255];
760 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800761
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200762 uint8_t file_version[255];
763 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800764
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200765 uint8_t window_size;
766 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800767
768 int fd;
769 FILE *stream;
770 enum sw_state state;
771 int last_seg;
772};
773
774static struct abis_nm_sw g_sw;
775
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100776static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
777{
778 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
779 msgb_v_put(msg, NM_ATT_SW_DESCR);
780 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
781 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
782 sw->file_version);
783 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
784 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
785 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
786 sw->file_version);
787 } else {
788 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
789 }
790}
791
Harald Welte59b04682009-06-10 05:40:52 +0800792/* 6.2.1 / 8.3.1: Load Data Initiate */
793static int sw_load_init(struct abis_nm_sw *sw)
794{
795 struct abis_om_hdr *oh;
796 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200797 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800798
799 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
800 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
801 sw->obj_instance[0], sw->obj_instance[1],
802 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100803
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100804 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800805 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
806
807 return abis_nm_sendmsg(sw->bts, msg);
808}
809
810static int is_last_line(FILE *stream)
811{
812 char next_seg_buf[256];
813 long pos;
814
815 /* check if we're sending the last line */
816 pos = ftell(stream);
817 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
818 fseek(stream, pos, SEEK_SET);
819 return 1;
820 }
821
822 fseek(stream, pos, SEEK_SET);
823 return 0;
824}
825
826/* 6.2.2 / 8.3.2 Load Data Segment */
827static int sw_load_segment(struct abis_nm_sw *sw)
828{
829 struct abis_om_hdr *oh;
830 struct msgb *msg = nm_msgb_alloc();
831 char seg_buf[256];
832 char *line_buf = seg_buf+2;
833 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200834 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800835
836 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
837
838 switch (sw->bts->type) {
839 case GSM_BTS_TYPE_BS11:
840 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
841 perror("fgets reading segment");
842 return -EINVAL;
843 }
844 seg_buf[0] = 0x00;
845
846 /* check if we're sending the last line */
847 sw->last_seg = is_last_line(sw->stream);
848 if (sw->last_seg)
849 seg_buf[1] = 0;
850 else
851 seg_buf[1] = 1 + sw->seg_in_window++;
852
853 len = strlen(line_buf) + 2;
854 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200855 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800856 /* BS11 wants CR + LF in excess of the TLV length !?! */
857 tlv[1] -= 2;
858
859 /* we only now know the exact length for the OM hdr */
860 len = strlen(line_buf)+2;
861 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100862 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200863 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100864 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
865 if (len < 0) {
866 perror("read failed");
867 return -EINVAL;
868 }
869
870 if (len != IPACC_SEGMENT_SIZE)
871 sw->last_seg = 1;
872
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100873 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200874 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100875 len += 3;
876 break;
877 }
Harald Welte59b04682009-06-10 05:40:52 +0800878 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100879 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800880 /* FIXME: Other BTS types */
881 return -1;
882 }
883
884 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
885 sw->obj_instance[0], sw->obj_instance[1],
886 sw->obj_instance[2]);
887
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100888 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800889}
890
891/* 6.2.4 / 8.3.4 Load Data End */
892static int sw_load_end(struct abis_nm_sw *sw)
893{
894 struct abis_om_hdr *oh;
895 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200896 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800897
898 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
899 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
900 sw->obj_instance[0], sw->obj_instance[1],
901 sw->obj_instance[2]);
902
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100903 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800904 return abis_nm_sendmsg(sw->bts, msg);
905}
906
907/* Activate the specified software into the BTS */
908static int sw_activate(struct abis_nm_sw *sw)
909{
910 struct abis_om_hdr *oh;
911 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200912 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800913
914 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
915 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
916 sw->obj_instance[0], sw->obj_instance[1],
917 sw->obj_instance[2]);
918
919 /* FIXME: this is BS11 specific format */
920 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
921 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
922 sw->file_version);
923
924 return abis_nm_sendmsg(sw->bts, msg);
925}
926
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100927struct sdp_firmware {
928 char magic[4];
929 char more_magic[4];
930 unsigned int header_length;
931 unsigned int file_length;
932} __attribute__ ((packed));
933
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100934static int parse_sdp_header(struct abis_nm_sw *sw)
935{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100936 struct sdp_firmware firmware_header;
937 int rc;
938 struct stat stat;
939
940 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
941 if (rc != sizeof(firmware_header)) {
942 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
943 return -1;
944 }
945
946 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
947 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
948 return -1;
949 }
950
951 if (firmware_header.more_magic[0] != 0x10 ||
952 firmware_header.more_magic[1] != 0x02 ||
953 firmware_header.more_magic[2] != 0x00 ||
954 firmware_header.more_magic[3] != 0x00) {
955 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
956 return -1;
957 }
958
959
960 if (fstat(sw->fd, &stat) == -1) {
961 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
962 return -1;
963 }
964
965 if (ntohl(firmware_header.file_length) != stat.st_size) {
966 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
967 return -1;
968 }
969
970 /* go back to the start as we checked the whole filesize.. */
971 lseek(sw->fd, 0l, SEEK_SET);
972 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
973 "There might be checksums in the file that are not\n"
974 "verified and incomplete firmware might be flashed.\n"
975 "There is absolutely no WARRANTY that flashing will\n"
976 "work.\n");
977 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100978}
979
Harald Welte59b04682009-06-10 05:40:52 +0800980static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
981{
982 char file_id[12+1];
983 char file_version[80+1];
984 int rc;
985
986 sw->fd = open(fname, O_RDONLY);
987 if (sw->fd < 0)
988 return sw->fd;
989
990 switch (sw->bts->type) {
991 case GSM_BTS_TYPE_BS11:
992 sw->stream = fdopen(sw->fd, "r");
993 if (!sw->stream) {
994 perror("fdopen");
995 return -1;
996 }
997 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200998 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +0800999 file_id, file_version);
1000 if (rc != 2) {
1001 perror("parsing header line of software file");
1002 return -1;
1003 }
1004 strcpy((char *)sw->file_id, file_id);
1005 sw->file_id_len = strlen(file_id);
1006 strcpy((char *)sw->file_version, file_version);
1007 sw->file_version_len = strlen(file_version);
1008 /* rewind to start of file */
1009 rewind(sw->stream);
1010 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001011 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001012 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001013 rc = parse_sdp_header(sw);
1014 if (rc < 0) {
1015 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1016 return -1;
1017 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001018
1019 strcpy((char *)sw->file_id, "id");
1020 sw->file_id_len = 3;
1021 strcpy((char *)sw->file_version, "version");
1022 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001023 break;
Harald Welte59b04682009-06-10 05:40:52 +08001024 default:
1025 /* We don't know how to treat them yet */
1026 close(sw->fd);
1027 return -EINVAL;
1028 }
1029
1030 return 0;
1031}
1032
1033static void sw_close_file(struct abis_nm_sw *sw)
1034{
1035 switch (sw->bts->type) {
1036 case GSM_BTS_TYPE_BS11:
1037 fclose(sw->stream);
1038 break;
1039 default:
1040 close(sw->fd);
1041 break;
1042 }
1043}
1044
1045/* Fill the window */
1046static int sw_fill_window(struct abis_nm_sw *sw)
1047{
1048 int rc;
1049
1050 while (sw->seg_in_window < sw->window_size) {
1051 rc = sw_load_segment(sw);
1052 if (rc < 0)
1053 return rc;
1054 if (sw->last_seg)
1055 break;
1056 }
1057 return 0;
1058}
1059
1060/* callback function from abis_nm_rcvmsg() handler */
1061static int abis_nm_rcvmsg_sw(struct msgb *mb)
1062{
1063 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001064 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001065 int rc = -1;
1066 struct abis_nm_sw *sw = &g_sw;
1067 enum sw_state old_state = sw->state;
1068
1069 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1070
1071 switch (sw->state) {
1072 case SW_STATE_WAIT_INITACK:
1073 switch (foh->msg_type) {
1074 case NM_MT_LOAD_INIT_ACK:
1075 /* fill window with segments */
1076 if (sw->cbfn)
1077 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1078 NM_MT_LOAD_INIT_ACK, mb,
1079 sw->cb_data, NULL);
1080 rc = sw_fill_window(sw);
1081 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001082 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001083 break;
1084 case NM_MT_LOAD_INIT_NACK:
1085 if (sw->forced) {
1086 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1087 "Init NACK\n");
1088 if (sw->cbfn)
1089 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1090 NM_MT_LOAD_INIT_ACK, mb,
1091 sw->cb_data, NULL);
1092 rc = sw_fill_window(sw);
1093 sw->state = SW_STATE_WAIT_SEGACK;
1094 } else {
1095 DEBUGP(DNM, "Software Load Init NACK\n");
1096 /* FIXME: cause */
1097 if (sw->cbfn)
1098 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1099 NM_MT_LOAD_INIT_NACK, mb,
1100 sw->cb_data, NULL);
1101 sw->state = SW_STATE_ERROR;
1102 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001103 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001104 break;
1105 }
1106 break;
1107 case SW_STATE_WAIT_SEGACK:
1108 switch (foh->msg_type) {
1109 case NM_MT_LOAD_SEG_ACK:
1110 if (sw->cbfn)
1111 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1112 NM_MT_LOAD_SEG_ACK, mb,
1113 sw->cb_data, NULL);
1114 sw->seg_in_window = 0;
1115 if (!sw->last_seg) {
1116 /* fill window with more segments */
1117 rc = sw_fill_window(sw);
1118 sw->state = SW_STATE_WAIT_SEGACK;
1119 } else {
1120 /* end the transfer */
1121 sw->state = SW_STATE_WAIT_ENDACK;
1122 rc = sw_load_end(sw);
1123 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001124 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001125 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001126 case NM_MT_LOAD_ABORT:
1127 if (sw->cbfn)
1128 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1129 NM_MT_LOAD_ABORT, mb,
1130 sw->cb_data, NULL);
1131 break;
Harald Welte59b04682009-06-10 05:40:52 +08001132 }
1133 break;
1134 case SW_STATE_WAIT_ENDACK:
1135 switch (foh->msg_type) {
1136 case NM_MT_LOAD_END_ACK:
1137 sw_close_file(sw);
1138 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1139 sw->bts->nr);
1140 sw->state = SW_STATE_NONE;
1141 if (sw->cbfn)
1142 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1143 NM_MT_LOAD_END_ACK, mb,
1144 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001145 rc = 0;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001146 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001147 break;
1148 case NM_MT_LOAD_END_NACK:
1149 if (sw->forced) {
1150 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1151 "End NACK\n");
1152 sw->state = SW_STATE_NONE;
1153 if (sw->cbfn)
1154 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1155 NM_MT_LOAD_END_ACK, mb,
1156 sw->cb_data, NULL);
1157 } else {
1158 DEBUGP(DNM, "Software Load End NACK\n");
1159 /* FIXME: cause */
1160 sw->state = SW_STATE_ERROR;
1161 if (sw->cbfn)
1162 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1163 NM_MT_LOAD_END_NACK, mb,
1164 sw->cb_data, NULL);
1165 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001166 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001167 break;
1168 }
1169 case SW_STATE_WAIT_ACTACK:
1170 switch (foh->msg_type) {
1171 case NM_MT_ACTIVATE_SW_ACK:
1172 /* we're done */
1173 DEBUGP(DNM, "Activate Software DONE!\n");
1174 sw->state = SW_STATE_NONE;
1175 rc = 0;
1176 if (sw->cbfn)
1177 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1178 NM_MT_ACTIVATE_SW_ACK, mb,
1179 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001180 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001181 break;
1182 case NM_MT_ACTIVATE_SW_NACK:
1183 DEBUGP(DNM, "Activate Software NACK\n");
1184 /* FIXME: cause */
1185 sw->state = SW_STATE_ERROR;
1186 if (sw->cbfn)
1187 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1188 NM_MT_ACTIVATE_SW_NACK, mb,
1189 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001190 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001191 break;
1192 }
1193 case SW_STATE_NONE:
1194 switch (foh->msg_type) {
1195 case NM_MT_ACTIVATE_SW_ACK:
1196 rc = 0;
1197 break;
1198 }
1199 break;
1200 case SW_STATE_ERROR:
1201 break;
1202 }
1203
1204 if (rc)
1205 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1206 foh->msg_type, old_state, sw->state);
1207
1208 return rc;
1209}
1210
1211/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001212int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001213 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001214 gsm_cbfn *cbfn, void *cb_data)
1215{
1216 struct abis_nm_sw *sw = &g_sw;
1217 int rc;
1218
1219 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1220 bts->nr, fname);
1221
1222 if (sw->state != SW_STATE_NONE)
1223 return -EBUSY;
1224
1225 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001226 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001227
1228 switch (bts->type) {
1229 case GSM_BTS_TYPE_BS11:
1230 sw->obj_class = NM_OC_SITE_MANAGER;
1231 sw->obj_instance[0] = 0xff;
1232 sw->obj_instance[1] = 0xff;
1233 sw->obj_instance[2] = 0xff;
1234 break;
1235 case GSM_BTS_TYPE_NANOBTS:
1236 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001237 sw->obj_instance[0] = sw->bts->nr;
1238 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001239 sw->obj_instance[2] = 0xff;
1240 break;
1241 case GSM_BTS_TYPE_UNKNOWN:
1242 default:
1243 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1244 return -1;
1245 break;
1246 }
Harald Welte59b04682009-06-10 05:40:52 +08001247 sw->window_size = win_size;
1248 sw->state = SW_STATE_WAIT_INITACK;
1249 sw->cbfn = cbfn;
1250 sw->cb_data = cb_data;
1251 sw->forced = forced;
1252
1253 rc = sw_open_file(sw, fname);
1254 if (rc < 0) {
1255 sw->state = SW_STATE_NONE;
1256 return rc;
1257 }
1258
1259 return sw_load_init(sw);
1260}
1261
1262int abis_nm_software_load_status(struct gsm_bts *bts)
1263{
1264 struct abis_nm_sw *sw = &g_sw;
1265 struct stat st;
1266 int rc, percent;
1267
1268 rc = fstat(sw->fd, &st);
1269 if (rc < 0) {
1270 perror("ERROR during stat");
1271 return rc;
1272 }
1273
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001274 if (sw->stream)
1275 percent = (ftell(sw->stream) * 100) / st.st_size;
1276 else
1277 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001278 return percent;
1279}
1280
1281/* Activate the specified software into the BTS */
1282int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1283 gsm_cbfn *cbfn, void *cb_data)
1284{
1285 struct abis_nm_sw *sw = &g_sw;
1286 int rc;
1287
1288 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1289 bts->nr, fname);
1290
1291 if (sw->state != SW_STATE_NONE)
1292 return -EBUSY;
1293
1294 sw->bts = bts;
1295 sw->obj_class = NM_OC_SITE_MANAGER;
1296 sw->obj_instance[0] = 0xff;
1297 sw->obj_instance[1] = 0xff;
1298 sw->obj_instance[2] = 0xff;
1299 sw->state = SW_STATE_WAIT_ACTACK;
1300 sw->cbfn = cbfn;
1301 sw->cb_data = cb_data;
1302
1303 /* Open the file in order to fill some sw struct members */
1304 rc = sw_open_file(sw, fname);
1305 if (rc < 0) {
1306 sw->state = SW_STATE_NONE;
1307 return rc;
1308 }
1309 sw_close_file(sw);
1310
1311 return sw_activate(sw);
1312}
1313
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001314static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1315 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001316{
1317 ch->attrib = NM_ATT_ABIS_CHANNEL;
1318 ch->bts_port = bts_port;
1319 ch->timeslot = ts_nr;
1320 ch->subslot = subslot_nr;
1321}
1322
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001323int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1324 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1325 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001326{
1327 struct abis_om_hdr *oh;
1328 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001329 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001330 struct msgb *msg = nm_msgb_alloc();
1331
1332 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1333 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1334 bts->bts_nr, trx_nr, 0xff);
1335
1336 msgb_tv_put(msg, NM_ATT_TEI, tei);
1337
1338 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1339 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1340
1341 return abis_nm_sendmsg(bts, msg);
1342}
1343
1344/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1345int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001346 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001347{
1348 struct gsm_bts *bts = trx->bts;
1349 struct abis_om_hdr *oh;
1350 struct abis_nm_channel *ch;
1351 struct msgb *msg = nm_msgb_alloc();
1352
1353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1354 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1355 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1356
1357 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1358 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1359
1360 return abis_nm_sendmsg(bts, msg);
1361}
1362
1363#if 0
1364int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1365 struct abis_nm_abis_channel *chan)
1366{
1367}
1368#endif
1369
1370int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001371 uint8_t e1_port, uint8_t e1_timeslot,
1372 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001373{
1374 struct gsm_bts *bts = ts->trx->bts;
1375 struct abis_om_hdr *oh;
1376 struct abis_nm_channel *ch;
1377 struct msgb *msg = nm_msgb_alloc();
1378
1379 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1380 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1381 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1382
1383 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1384 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1385
1386 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1387 gsm_ts_name(ts),
1388 e1_port, e1_timeslot, e1_subslot);
1389
1390 return abis_nm_sendmsg(bts, msg);
1391}
1392
1393#if 0
1394int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1395 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001396 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001397{
1398}
1399#endif
1400
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001401/* Chapter 8.11.1 */
1402int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1403 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1404 uint8_t *attr, uint8_t attr_len)
1405{
1406 struct abis_om_hdr *oh;
1407 struct msgb *msg = nm_msgb_alloc();
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001408
1409 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1410
1411 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1412 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1413 bts_nr, trx_nr, ts_nr);
1414 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1415
1416 return abis_nm_sendmsg(bts, msg);
1417}
1418
Harald Welte59b04682009-06-10 05:40:52 +08001419/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001420int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001421{
1422 struct abis_om_hdr *oh;
1423 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001424 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001425
1426 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1427
1428 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1429 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1430 cur = msgb_put(msg, attr_len);
1431 memcpy(cur, attr, attr_len);
1432
1433 return abis_nm_sendmsg(bts, msg);
1434}
1435
1436/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001437int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001438{
1439 struct abis_om_hdr *oh;
1440 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001441 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001442
1443 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1444
1445 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1446 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1447 trx->bts->bts_nr, trx->nr, 0xff);
1448 cur = msgb_put(msg, attr_len);
1449 memcpy(cur, attr, attr_len);
1450
1451 return abis_nm_sendmsg(trx->bts, msg);
1452}
1453
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001454static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1455 const char **reason)
Harald Weltef2eb2782009-08-09 21:49:48 +02001456{
1457 int i;
1458
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001459 *reason = "Reason unknown";
1460
Harald Weltef2eb2782009-08-09 21:49:48 +02001461 /* As it turns out, the BS-11 has some very peculiar restrictions
1462 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301463 switch (ts->trx->bts->type) {
1464 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001465 switch (chan_comb) {
1466 case NM_CHANC_TCHHalf:
1467 case NM_CHANC_TCHHalf2:
1468 /* not supported */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001469 *reason = "TCH/H is not supported.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001470 return -EINVAL;
1471 case NM_CHANC_SDCCH:
1472 /* only one SDCCH/8 per TRX */
1473 for (i = 0; i < TRX_NR_TS; i++) {
1474 if (i == ts->nr)
1475 continue;
1476 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001477 NM_CHANC_SDCCH) {
1478 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001479 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001480 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001481 }
1482 /* not allowed for TS0 of BCCH-TRX */
1483 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001484 ts->nr == 0) {
1485 *reason = "SDCCH/8 must be on TS0.";
1486 return -EINVAL;
1487 }
1488
Harald Weltef2eb2782009-08-09 21:49:48 +02001489 /* not on the same TRX that has a BCCH+SDCCH4
1490 * combination */
1491 if (ts->trx == ts->trx->bts->c0 &&
1492 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001493 ts->trx->ts[0].nm_chan_comb == 8)) {
1494 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1495 return -EINVAL;
1496 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001497 break;
1498 case NM_CHANC_mainBCCH:
1499 case NM_CHANC_BCCHComb:
1500 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001501 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1502 *reason = "Main BCCH must be on TS0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001503 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001504 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001505 break;
1506 case NM_CHANC_BCCH:
1507 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001508 if (ts->trx != ts->trx->bts->c0) {
1509 *reason = "BCCH must be on C0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001510 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001511 }
1512 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1513 *reason = "BCCH must be on TS 2/4/6.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001514 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001515 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001516 break;
1517 case 8: /* this is not like 08.58, but in fact
1518 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1519 /* FIXME: only one CBCH allowed per cell */
1520 break;
1521 }
Harald Welte76ba8812009-12-02 02:45:23 +05301522 break;
1523 case GSM_BTS_TYPE_NANOBTS:
1524 switch (ts->nr) {
1525 case 0:
1526 if (ts->trx->nr == 0) {
1527 /* only on TRX0 */
1528 switch (chan_comb) {
1529 case NM_CHANC_BCCH:
1530 case NM_CHANC_mainBCCH:
1531 case NM_CHANC_BCCHComb:
1532 return 0;
1533 break;
1534 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001535 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301536 return -EINVAL;
1537 }
1538 } else {
1539 switch (chan_comb) {
1540 case NM_CHANC_TCHFull:
1541 case NM_CHANC_TCHHalf:
1542 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1543 return 0;
1544 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001545 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welte76ba8812009-12-02 02:45:23 +05301546 return -EINVAL;
1547 }
1548 }
1549 break;
1550 case 1:
1551 if (ts->trx->nr == 0) {
1552 switch (chan_comb) {
1553 case NM_CHANC_SDCCH_CBCH:
1554 if (ts->trx->ts[0].nm_chan_comb ==
1555 NM_CHANC_mainBCCH)
1556 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001557 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301558 return -EINVAL;
1559 case NM_CHANC_SDCCH:
1560 case NM_CHANC_TCHFull:
1561 case NM_CHANC_TCHHalf:
1562 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1563 case NM_CHANC_IPAC_TCHFull_PDCH:
1564 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001565 default:
1566 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1567 return -EINVAL;
Harald Welte76ba8812009-12-02 02:45:23 +05301568 }
1569 } else {
1570 switch (chan_comb) {
1571 case NM_CHANC_SDCCH:
1572 case NM_CHANC_TCHFull:
1573 case NM_CHANC_TCHHalf:
1574 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1575 return 0;
1576 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001577 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301578 return -EINVAL;
1579 }
1580 }
1581 break;
1582 case 2:
1583 case 3:
1584 case 4:
1585 case 5:
1586 case 6:
1587 case 7:
1588 switch (chan_comb) {
1589 case NM_CHANC_TCHFull:
1590 case NM_CHANC_TCHHalf:
1591 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1592 return 0;
1593 case NM_CHANC_IPAC_PDCH:
1594 case NM_CHANC_IPAC_TCHFull_PDCH:
1595 if (ts->trx->nr == 0)
1596 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001597 else {
1598 *reason = "PDCH must be on TRX0.";
Harald Welte76ba8812009-12-02 02:45:23 +05301599 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001600 }
Harald Welte76ba8812009-12-02 02:45:23 +05301601 }
1602 break;
1603 }
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001604 *reason = "Unknown combination";
Harald Welte76ba8812009-12-02 02:45:23 +05301605 return -EINVAL;
Harald Welte35ac0e42012-07-02 19:51:55 +02001606 case GSM_BTS_TYPE_OSMO_SYSMO:
1607 /* no known restrictions */
1608 return 0;
Harald Welte76ba8812009-12-02 02:45:23 +05301609 default:
1610 /* unknown BTS type */
1611 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001612 }
1613 return 0;
1614}
1615
Harald Welte59b04682009-06-10 05:40:52 +08001616/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001617int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001618{
1619 struct gsm_bts *bts = ts->trx->bts;
1620 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001621 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001622 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001623 uint8_t len = 2 + 2;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001624 const char *reason = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001625
1626 if (bts->type == GSM_BTS_TYPE_BS11)
1627 len += 4 + 2 + 2 + 3;
1628
1629 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001630 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Weltef2eb2782009-08-09 21:49:48 +02001631 msgb_free(msg);
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001632 LOGP(DNM, LOGL_ERROR,
1633 "Invalid Channel Combination %d on %s. Reason: %s\n",
1634 chan_comb, gsm_ts_name(ts), reason);
Harald Weltef2eb2782009-08-09 21:49:48 +02001635 return -EINVAL;
1636 }
1637 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001638
1639 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1640 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1641 NM_OC_CHANNEL, bts->bts_nr,
1642 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001643 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001644 if (ts->hopping.enabled) {
1645 unsigned int i;
1646 uint8_t *len;
1647
Harald Welte67104d12009-09-12 13:05:33 +02001648 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1649 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001650
1651 /* build the ARFCN list */
1652 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1653 len = msgb_put(msg, 1);
1654 *len = 0;
1655 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1656 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1657 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001658 /* At least BS-11 wants a TLV16 here */
1659 if (bts->type == GSM_BTS_TYPE_BS11)
1660 *len += 1;
1661 else
1662 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001663 }
1664 }
Harald Welte59b04682009-06-10 05:40:52 +08001665 }
Harald Welte85771a42011-05-30 12:09:13 +02001666 if (ts->tsc == -1)
1667 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1668 else
1669 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001670 if (bts->type == GSM_BTS_TYPE_BS11)
1671 msgb_tlv_put(msg, 0x59, 1, &zero);
1672
1673 return abis_nm_sendmsg(bts, msg);
1674}
1675
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001676int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1677 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001678{
1679 struct abis_om_hdr *oh;
1680 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001681 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1682 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001683
1684 if (nack) {
1685 len += 2;
1686 msgtype = NM_MT_SW_ACT_REQ_NACK;
1687 }
1688
1689 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1690 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1691
1692 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001693 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001694 memcpy(ptr, attr, att_len);
1695 }
1696 if (nack)
1697 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1698
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001699 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001700}
1701
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001702int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001703{
1704 struct msgb *msg = nm_msgb_alloc();
1705 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001706 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001707
1708 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1709 fill_om_hdr(oh, len);
1710 data = msgb_put(msg, len);
1711 memcpy(data, rawmsg, len);
1712
1713 return abis_nm_sendmsg(bts, msg);
1714}
1715
1716/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001717static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001718{
1719 struct abis_om_hdr *oh;
1720 struct msgb *msg = nm_msgb_alloc();
1721
1722 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1723 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1724 0xff, 0xff, 0xff);
1725
1726 return abis_nm_sendmsg(bts, msg);
1727}
1728
1729/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001730int 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 +08001731{
1732 struct abis_om_hdr *oh;
1733 struct msgb *msg = nm_msgb_alloc();
1734
Harald Welte59b04682009-06-10 05:40:52 +08001735 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1736 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1737
Harald Weltec61a90e2011-05-22 22:45:37 +02001738 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001739 DEBUGPC(DNM, "Sending OPSTART\n");
1740
Harald Welte59b04682009-06-10 05:40:52 +08001741 return abis_nm_sendmsg(bts, msg);
1742}
1743
1744/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001745int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1746 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001747{
1748 struct abis_om_hdr *oh;
1749 struct msgb *msg = nm_msgb_alloc();
1750
1751 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1752 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1753 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1754
1755 return abis_nm_sendmsg(bts, msg);
1756}
1757
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001758int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1759 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001760{
1761 struct abis_om_hdr *oh;
1762 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001763 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001764
1765 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1766 e1_port0, ts0, e1_port1, ts1);
1767
1768 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1769 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1770 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1771
1772 attr = msgb_put(msg, 3);
1773 attr[0] = NM_ATT_MDROP_LINK;
1774 attr[1] = e1_port0;
1775 attr[2] = ts0;
1776
1777 attr = msgb_put(msg, 3);
1778 attr[0] = NM_ATT_MDROP_NEXT;
1779 attr[1] = e1_port1;
1780 attr[2] = ts1;
1781
1782 return abis_nm_sendmsg(bts, msg);
1783}
Harald Welte59b04682009-06-10 05:40:52 +08001784
Harald Welte0bf8e302009-08-08 00:02:36 +02001785/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001786int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1787 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1788 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001789{
1790 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001791
Harald Weltec61a90e2011-05-22 22:45:37 +02001792 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001793
1794 if (!msg)
1795 msg = nm_msgb_alloc();
1796
1797 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1798 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1799 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1800 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001801 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001802
1803 return abis_nm_sendmsg(bts, msg);
1804}
1805
Harald Welte59b04682009-06-10 05:40:52 +08001806int abis_nm_event_reports(struct gsm_bts *bts, int on)
1807{
1808 if (on == 0)
1809 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1810 else
1811 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1812}
1813
1814/* Siemens (or BS-11) specific commands */
1815
1816int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1817{
1818 if (reconnect == 0)
1819 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1820 else
1821 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1822}
1823
1824int abis_nm_bs11_restart(struct gsm_bts *bts)
1825{
1826 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1827}
1828
1829
1830struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001831 uint16_t year;
1832 uint8_t month;
1833 uint8_t day;
1834 uint8_t hour;
1835 uint8_t min;
1836 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001837} __attribute__((packed));
1838
1839
1840void get_bs11_date_time(struct bs11_date_time *aet)
1841{
1842 time_t t;
1843 struct tm *tm;
1844
1845 t = time(NULL);
1846 tm = localtime(&t);
1847 aet->sec = tm->tm_sec;
1848 aet->min = tm->tm_min;
1849 aet->hour = tm->tm_hour;
1850 aet->day = tm->tm_mday;
1851 aet->month = tm->tm_mon;
1852 aet->year = htons(1900 + tm->tm_year);
1853}
1854
1855int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1856{
1857 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1858}
1859
1860int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1861{
1862 if (begin)
1863 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1864 else
1865 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1866}
1867
1868int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001869 enum abis_bs11_objtype type, uint8_t idx,
1870 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001871{
1872 struct abis_om_hdr *oh;
1873 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001874 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001875
1876 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1877 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1878 NM_OC_BS11, type, 0, idx);
1879 cur = msgb_put(msg, attr_len);
1880 memcpy(cur, attr, attr_len);
1881
1882 return abis_nm_sendmsg(bts, msg);
1883}
1884
1885int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001886 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001887{
1888 struct abis_om_hdr *oh;
1889 struct msgb *msg = nm_msgb_alloc();
1890
1891 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1892 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1893 NM_OC_BS11, type, 0, idx);
1894
1895 return abis_nm_sendmsg(bts, msg);
1896}
1897
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001898int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001899{
1900 struct abis_om_hdr *oh;
1901 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001902 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001903
1904 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1905 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1906 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1907 msgb_tlv_put(msg, 0x99, 1, &zero);
1908
1909 return abis_nm_sendmsg(bts, msg);
1910}
1911
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001912int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001913{
1914 struct abis_om_hdr *oh;
1915 struct msgb *msg = nm_msgb_alloc();
1916
1917 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1918 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001919 idx, 0xff, 0xff);
1920
1921 return abis_nm_sendmsg(bts, msg);
1922}
1923
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001924int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001925{
1926 struct abis_om_hdr *oh;
1927 struct msgb *msg = nm_msgb_alloc();
1928
1929 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1930 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1931 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001932
1933 return abis_nm_sendmsg(bts, msg);
1934}
1935
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001936static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001937int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1938{
1939 struct abis_om_hdr *oh;
1940 struct msgb *msg = nm_msgb_alloc();
1941
1942 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1943 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1944 0xff, 0xff, 0xff);
1945 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1946
1947 return abis_nm_sendmsg(bts, msg);
1948}
1949
1950/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001951int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1952 uint8_t e1_timeslot, uint8_t e1_subslot,
1953 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001954{
1955 struct abis_om_hdr *oh;
1956 struct abis_nm_channel *ch;
1957 struct msgb *msg = nm_msgb_alloc();
1958
1959 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1960 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1961 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1962
1963 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1964 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1965 msgb_tv_put(msg, NM_ATT_TEI, tei);
1966
1967 return abis_nm_sendmsg(bts, msg);
1968}
1969
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001970int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08001971{
1972 struct abis_om_hdr *oh;
1973 struct msgb *msg = nm_msgb_alloc();
1974
1975 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1976 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
1977 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1978 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1979
1980 return abis_nm_sendmsg(trx->bts, msg);
1981}
1982
1983int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1984{
1985 struct abis_om_hdr *oh;
1986 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001987 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08001988
1989 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1990 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1991 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1992 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1993
1994 return abis_nm_sendmsg(trx->bts, msg);
1995}
1996
1997int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1998{
1999 struct abis_om_hdr *oh;
2000 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002001 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08002002
2003 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2004 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2005 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2006 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2007
2008 return abis_nm_sendmsg(bts, msg);
2009}
2010
2011int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2012{
2013 struct abis_om_hdr *oh;
2014 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002015 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002016 NM_ATT_BS11_CCLK_TYPE };
2017
2018 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2019 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2020 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2021 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2022
2023 return abis_nm_sendmsg(bts, msg);
2024
2025}
2026
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002027//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002028
2029int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2030{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002031 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2032}
2033
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002034int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2035{
2036 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2037}
2038
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002039int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002040{
Harald Welte59b04682009-06-10 05:40:52 +08002041 struct abis_om_hdr *oh;
2042 struct msgb *msg = nm_msgb_alloc();
2043 struct bs11_date_time bdt;
2044
2045 get_bs11_date_time(&bdt);
2046
2047 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2048 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002049 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002050 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002051 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2052 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2053 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002054 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002055 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002056 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002057 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002058 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002059 } else {
2060 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2061 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2062 }
2063
2064 return abis_nm_sendmsg(bts, msg);
2065}
2066
2067int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2068{
2069 struct abis_om_hdr *oh;
2070 struct msgb *msg;
2071
2072 if (strlen(password) != 10)
2073 return -EINVAL;
2074
2075 msg = nm_msgb_alloc();
2076 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2077 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2078 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002079 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002080
2081 return abis_nm_sendmsg(bts, msg);
2082}
2083
2084/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2085int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2086{
2087 struct abis_om_hdr *oh;
2088 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002089 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002090
2091 msg = nm_msgb_alloc();
2092 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2093 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2094 BS11_OBJ_LI, 0x00, 0x00);
2095
2096 if (locked)
2097 tlv_value = BS11_LI_PLL_LOCKED;
2098 else
2099 tlv_value = BS11_LI_PLL_STANDALONE;
2100
2101 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2102
2103 return abis_nm_sendmsg(bts, msg);
2104}
2105
Daniel Willmann10b07db2010-01-07 00:54:01 +01002106/* Set the calibration value of the PLL (work value/set value)
2107 * It depends on the login which one is changed */
2108int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2109{
2110 struct abis_om_hdr *oh;
2111 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002112 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002113
2114 msg = nm_msgb_alloc();
2115 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2116 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2117 BS11_OBJ_TRX1, 0x00, 0x00);
2118
2119 tlv_value[0] = value>>8;
2120 tlv_value[1] = value&0xff;
2121
2122 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2123
2124 return abis_nm_sendmsg(bts, msg);
2125}
2126
Harald Welte59b04682009-06-10 05:40:52 +08002127int abis_nm_bs11_get_state(struct gsm_bts *bts)
2128{
2129 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2130}
2131
2132/* BS11 SWL */
2133
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002134void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002135
Harald Welte59b04682009-06-10 05:40:52 +08002136struct abis_nm_bs11_sw {
2137 struct gsm_bts *bts;
2138 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002139 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002140 int forced;
2141 struct llist_head file_list;
2142 gsm_cbfn *user_cb; /* specified by the user */
2143};
2144static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2145
2146struct file_list_entry {
2147 struct llist_head list;
2148 char fname[PATH_MAX];
2149};
2150
2151struct file_list_entry *fl_dequeue(struct llist_head *queue)
2152{
2153 struct llist_head *lh;
2154
2155 if (llist_empty(queue))
2156 return NULL;
2157
2158 lh = queue->next;
2159 llist_del(lh);
2160
2161 return llist_entry(lh, struct file_list_entry, list);
2162}
2163
2164static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2165{
2166 char linebuf[255];
2167 struct llist_head *lh, *lh2;
2168 FILE *swl;
2169 int rc = 0;
2170
2171 swl = fopen(bs11_sw->swl_fname, "r");
2172 if (!swl)
2173 return -ENODEV;
2174
2175 /* zero the stale file list, if any */
2176 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2177 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002178 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002179 }
2180
2181 while (fgets(linebuf, sizeof(linebuf), swl)) {
2182 char file_id[12+1];
2183 char file_version[80+1];
2184 struct file_list_entry *fle;
2185 static char dir[PATH_MAX];
2186
2187 if (strlen(linebuf) < 4)
2188 continue;
2189
2190 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2191 if (rc < 0) {
2192 perror("ERR parsing SWL file");
2193 rc = -EINVAL;
2194 goto out;
2195 }
2196 if (rc < 2)
2197 continue;
2198
Harald Welte857e00d2009-06-26 20:25:23 +02002199 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002200 if (!fle) {
2201 rc = -ENOMEM;
2202 goto out;
2203 }
Harald Welte59b04682009-06-10 05:40:52 +08002204
2205 /* construct new filename */
2206 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2207 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2208 strcat(fle->fname, "/");
2209 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2210
2211 llist_add_tail(&fle->list, &bs11_sw->file_list);
2212 }
2213
2214out:
2215 fclose(swl);
2216 return rc;
2217}
2218
2219/* bs11 swload specific callback, passed to abis_nm core swload */
2220static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2221 struct msgb *msg, void *data, void *param)
2222{
2223 struct abis_nm_bs11_sw *bs11_sw = data;
2224 struct file_list_entry *fle;
2225 int rc = 0;
2226
2227 switch (event) {
2228 case NM_MT_LOAD_END_ACK:
2229 fle = fl_dequeue(&bs11_sw->file_list);
2230 if (fle) {
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(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002233 bs11_sw->win_size,
2234 bs11_sw->forced,
2235 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002236 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002237 } else {
2238 /* activate the SWL */
2239 rc = abis_nm_software_activate(bs11_sw->bts,
2240 bs11_sw->swl_fname,
2241 bs11_swload_cbfn,
2242 bs11_sw);
2243 }
2244 break;
2245 case NM_MT_LOAD_SEG_ACK:
2246 case NM_MT_LOAD_END_NACK:
2247 case NM_MT_LOAD_INIT_ACK:
2248 case NM_MT_LOAD_INIT_NACK:
2249 case NM_MT_ACTIVATE_SW_NACK:
2250 case NM_MT_ACTIVATE_SW_ACK:
2251 default:
2252 /* fallthrough to the user callback */
2253 if (bs11_sw->user_cb)
2254 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2255 break;
2256 }
2257
2258 return rc;
2259}
2260
2261/* Siemens provides a SWL file that is a mere listing of all the other
2262 * files that are part of a software release. We need to upload first
2263 * the list file, and then each file that is listed in the list file */
2264int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002265 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002266{
2267 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2268 struct file_list_entry *fle;
2269 int rc = 0;
2270
2271 INIT_LLIST_HEAD(&bs11_sw->file_list);
2272 bs11_sw->bts = bts;
2273 bs11_sw->win_size = win_size;
2274 bs11_sw->user_cb = cbfn;
2275 bs11_sw->forced = forced;
2276
2277 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2278 rc = bs11_read_swl_file(bs11_sw);
2279 if (rc < 0)
2280 return rc;
2281
2282 /* dequeue next item in file list */
2283 fle = fl_dequeue(&bs11_sw->file_list);
2284 if (!fle)
2285 return -EINVAL;
2286
2287 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002288 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002289 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002290 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002291 return rc;
2292}
2293
2294#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002295static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002296 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2297 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2298 NM_ATT_BS11_LMT_USER_NAME,
2299
2300 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2301
2302 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2303
2304 NM_ATT_BS11_SW_LOAD_STORED };
2305
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002306static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002307 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2308 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2309 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2310 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2311#endif
2312
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002313static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002314 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2315 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2316 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2317
2318int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2319{
2320 struct abis_om_hdr *oh;
2321 struct msgb *msg = nm_msgb_alloc();
2322
2323 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2324 /* SiemensHW CCTRL object */
2325 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2326 0x03, 0x00, 0x00);
2327 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2328
2329 return abis_nm_sendmsg(bts, msg);
2330}
2331
2332int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2333{
2334 struct abis_om_hdr *oh;
2335 struct msgb *msg = nm_msgb_alloc();
2336 struct bs11_date_time aet;
2337
2338 get_bs11_date_time(&aet);
2339 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2340 /* SiemensHW CCTRL object */
2341 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2342 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002343 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002344
2345 return abis_nm_sendmsg(bts, msg);
2346}
2347
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002348int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002349{
2350 struct abis_om_hdr *oh;
2351 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002352 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002353
2354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2355 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2356 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2357 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2358
2359 return abis_nm_sendmsg(bts, msg);
2360}
2361
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002362int 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 +02002363{
2364 struct abis_om_hdr *oh;
2365 struct msgb *msg = nm_msgb_alloc();
2366 struct bs11_date_time aet;
2367
2368 get_bs11_date_time(&aet);
2369 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2370 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2371 bport, 0xff, 0x02);
2372 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2373
2374 return abis_nm_sendmsg(bts, msg);
2375}
2376
Harald Welte59b04682009-06-10 05:40:52 +08002377/* ip.access nanoBTS specific commands */
2378static const char ipaccess_magic[] = "com.ipaccess";
2379
2380
2381static int abis_nm_rx_ipacc(struct msgb *msg)
2382{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002383 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002384 struct abis_om_hdr *oh = msgb_l2(msg);
2385 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002386 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002387 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002388 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002389 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002390
2391 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002392 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002393 return -EINVAL;
2394 }
2395
2396 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002397 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002398
Harald Weltec61a90e2011-05-22 22:45:37 +02002399 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002400
Harald Welte5aeedd42009-10-19 22:11:11 +02002401 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002402
2403 switch (foh->msg_type) {
2404 case NM_MT_IPACC_RSL_CONNECT_ACK:
2405 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002406 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2407 memcpy(&addr,
2408 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2409
2410 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2411 }
Harald Welte4206d982009-07-12 09:33:54 +02002412 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002413 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002414 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002415 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002416 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2417 DEBUGPC(DNM, "STREAM=0x%02x ",
2418 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002419 DEBUGPC(DNM, "\n");
2420 break;
2421 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002422 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002423 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002424 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002425 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002426 else
2427 DEBUGPC(DNM, "\n");
2428 break;
2429 case NM_MT_IPACC_SET_NVATTR_ACK:
2430 DEBUGPC(DNM, "SET NVATTR ACK\n");
2431 /* FIXME: decode and show the actual attributes */
2432 break;
2433 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002434 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002435 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002436 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002437 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002438 else
Harald Weltede4477a2009-12-24 12:20:20 +01002439 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002440 break;
Harald Welte21460f02009-07-03 11:26:45 +02002441 case NM_MT_IPACC_GET_NVATTR_ACK:
2442 DEBUGPC(DNM, "GET NVATTR ACK\n");
2443 /* FIXME: decode and show the actual attributes */
2444 break;
2445 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002446 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002447 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002448 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002449 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002450 else
Harald Weltede4477a2009-12-24 12:20:20 +01002451 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002452 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002453 case NM_MT_IPACC_SET_ATTR_ACK:
2454 DEBUGPC(DNM, "SET ATTR ACK\n");
2455 break;
2456 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002457 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002458 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002459 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002460 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002461 else
Harald Weltede4477a2009-12-24 12:20:20 +01002462 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002463 break;
Harald Welte59b04682009-06-10 05:40:52 +08002464 default:
2465 DEBUGPC(DNM, "unknown\n");
2466 break;
2467 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002468
2469 /* signal handling */
2470 switch (foh->msg_type) {
2471 case NM_MT_IPACC_RSL_CONNECT_NACK:
2472 case NM_MT_IPACC_SET_NVATTR_NACK:
2473 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002474 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 +01002475 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002476 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002477 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002478 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002479 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 +01002480 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002481 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002482 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002483 default:
2484 break;
2485 }
2486
Harald Welte59b04682009-06-10 05:40:52 +08002487 return 0;
2488}
2489
2490/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002491int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2492 uint8_t obj_class, uint8_t bts_nr,
2493 uint8_t trx_nr, uint8_t ts_nr,
2494 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002495{
2496 struct msgb *msg = nm_msgb_alloc();
2497 struct abis_om_hdr *oh;
2498 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002499 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002500
2501 /* construct the 12.21 OM header, observe the erroneous length */
2502 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2503 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2504 oh->mdisc = ABIS_OM_MDISC_MANUF;
2505
2506 /* add the ip.access magic */
2507 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2508 *data++ = sizeof(ipaccess_magic);
2509 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2510
2511 /* fill the 12.21 FOM header */
2512 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2513 foh->msg_type = msg_type;
2514 foh->obj_class = obj_class;
2515 foh->obj_inst.bts_nr = bts_nr;
2516 foh->obj_inst.trx_nr = trx_nr;
2517 foh->obj_inst.ts_nr = ts_nr;
2518
2519 if (attr && attr_len) {
2520 data = msgb_put(msg, attr_len);
2521 memcpy(data, attr, attr_len);
2522 }
2523
2524 return abis_nm_sendmsg(bts, msg);
2525}
2526
2527/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002528int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002529 int attr_len)
2530{
Harald Weltef12c1052010-01-07 20:39:42 +01002531 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2532 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002533 attr_len);
2534}
2535
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002536int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002537 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002538{
2539 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002540 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002541 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2542 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2543
2544 int attr_len = sizeof(attr);
2545
2546 ia.s_addr = htonl(ip);
2547 attr[1] = stream;
2548 attr[3] = port >> 8;
2549 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002550 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002551
2552 /* if ip == 0, we use the default IP */
2553 if (ip == 0)
2554 attr_len -= 5;
2555
2556 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002557 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002558
2559 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2560 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2561 trx->nr, 0xff, attr, attr_len);
2562}
2563
Harald Welte59b04682009-06-10 05:40:52 +08002564/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002565int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002566{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002567 struct abis_om_hdr *oh;
2568 struct msgb *msg = nm_msgb_alloc();
2569
2570 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2571 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2572 trx->bts->nr, trx->nr, 0xff);
2573
2574 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002575}
Harald Welte0dfc6232009-10-24 10:20:41 +02002576
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002577int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2578 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2579 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002580{
2581 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2582 obj_class, bts_nr, trx_nr, ts_nr,
2583 attr, attr_len);
2584}
Harald Weltebeeae412009-11-12 14:48:42 +01002585
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002586void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002587{
2588 /* we simply reuse the GSM48 function and overwrite the RAC
2589 * with the Cell ID */
2590 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002591 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002592}
2593
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002594void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2595{
2596 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2597
Harald Welte69f6f812011-05-30 12:07:53 +02002598 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002599 if (!trx->bts || !trx->bts->oml_link)
2600 return;
2601
2602 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2603 trx->bts->bts_nr, trx->nr, 0xff,
2604 new_state);
2605}
2606
Harald Welte453141f2010-03-25 11:45:30 +08002607static const struct value_string ipacc_testres_names[] = {
2608 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2609 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2610 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2611 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2612 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2613 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002614};
2615
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002616const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002617{
Harald Welte453141f2010-03-25 11:45:30 +08002618 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002619}
2620
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002621void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002622{
2623 cid->mcc = (buf[0] & 0xf) * 100;
2624 cid->mcc += (buf[0] >> 4) * 10;
2625 cid->mcc += (buf[1] & 0xf) * 1;
2626
2627 if (buf[1] >> 4 == 0xf) {
2628 cid->mnc = (buf[2] & 0xf) * 10;
2629 cid->mnc += (buf[2] >> 4) * 1;
2630 } else {
2631 cid->mnc = (buf[2] & 0xf) * 100;
2632 cid->mnc += (buf[2] >> 4) * 10;
2633 cid->mnc += (buf[1] >> 4) * 1;
2634 }
2635
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002636 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2637 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002638}
2639
Harald Weltebeeae412009-11-12 14:48:42 +01002640/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002641int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002642{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002643 uint8_t *cur = buf;
Holger Hans Peter Freyther1a9f3ee2012-09-11 11:55:03 +02002644 uint16_t len __attribute__((unused));
Harald Weltebeeae412009-11-12 14:48:42 +01002645
Harald Welteb784df82010-07-22 18:14:36 +02002646 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002647
2648 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2649 return -EINVAL;
2650 cur++;
2651
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002652 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002653 cur += 2;
2654
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002655 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002656 cur += 2;
2657
2658 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2659 binf->freq_qual = *cur >> 2;
2660
Harald Welteb784df82010-07-22 18:14:36 +02002661 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002662 binf->arfcn |= *cur++;
2663
2664 if (binf->info_type & IPAC_BINF_RXLEV)
2665 binf->rx_lev = *cur & 0x3f;
2666 cur++;
2667
2668 if (binf->info_type & IPAC_BINF_RXQUAL)
2669 binf->rx_qual = *cur & 0x7;
2670 cur++;
2671
2672 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002673 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002674 cur += 2;
2675
2676 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002677 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002678 cur += 2;
2679
2680 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002681 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002682 cur += 4;
2683
Harald Welte22cb81f2010-07-30 22:34:42 +02002684#if 0
2685 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002686 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002687#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002688 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002689 cur++;
2690
Harald Weltebfc21092009-11-13 11:56:05 +01002691 ipac_parse_cgi(&binf->cgi, cur);
2692 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002693
2694 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2695 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2696 cur += sizeof(binf->ba_list_si2);
2697 }
2698
2699 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2700 memcpy(binf->ba_list_si2bis, cur,
2701 sizeof(binf->ba_list_si2bis));
2702 cur += sizeof(binf->ba_list_si2bis);
2703 }
2704
2705 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2706 memcpy(binf->ba_list_si2ter, cur,
2707 sizeof(binf->ba_list_si2ter));
2708 cur += sizeof(binf->ba_list_si2ter);
2709 }
2710
2711 return 0;
2712}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002713
2714void abis_nm_clear_queue(struct gsm_bts *bts)
2715{
2716 struct msgb *msg;
2717
2718 while (!llist_empty(&bts->abis_queue)) {
2719 msg = msgb_dequeue(&bts->abis_queue);
2720 msgb_free(msg);
2721 }
2722
2723 bts->abis_nm_pend = 0;
2724}