blob: c29e21b3d2879e942bab8f4148a843e4c207e6b2 [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte59b04682009-06-10 05:40:52 +080011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
Harald Welte59b04682009-06-10 05:40:52 +080033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Weltec61a90e2011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080043#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte59b04682009-06-10 05:40:52 +080047
48#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080051
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte59b04682009-06-10 05:40:52 +080053{
Harald Welte59698fb2010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +080057}
58
59static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
71#if 0
72/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
77#endif
78
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Weltec61a90e2011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte59b04682009-06-10 05:40:52 +080083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +080089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte59b04682009-06-10 05:40:52 +080099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
103 fill_om_hdr(oh, len+sizeof(*foh));
104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte9cfc9352009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800115}
116
Harald Welte607044f2011-09-26 23:43:23 +0200117int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200118{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200119 msg->l2h = msg->data;
120
121 if (!msg->dst) {
122 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
123 return -EINVAL;
124 }
125
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200126 return abis_sendmsg(msg);
127}
128
Harald Welte59b04682009-06-10 05:40:52 +0800129/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100130static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800131{
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200132 msg->dst = bts->oml_link;
Harald Welte59b04682009-06-10 05:40:52 +0800133
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100134 /* queue OML messages */
135 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
136 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200137 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100138 } else {
139 msgb_enqueue(&bts->abis_queue, msg);
140 return 0;
141 }
142
143}
144
145int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
146{
147 OBSC_NM_W_ACK_CB(msg) = 1;
148 return abis_nm_queue_msg(bts, msg);
149}
150
151static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 0;
154 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800155}
156
157static int abis_nm_rcvmsg_sw(struct msgb *mb);
158
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100159int nm_is_running(struct gsm_nm_state *s) {
160 return (s->operational == NM_OPSTATE_ENABLED) && (
161 (s->availability == NM_AVSTATE_OK) ||
162 (s->availability == 0xff)
163 );
164}
165
Harald Welte59b04682009-06-10 05:40:52 +0800166/* Update the administrative state of a given object in our in-memory data
167 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200168static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
169 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800170{
171 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100172 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800173
Harald Weltea348c082011-03-06 21:20:38 +0100174 memset(&nsd, 0, sizeof(nsd));
175
Harald Weltec6ed9282011-06-06 18:31:20 +0200176 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100177 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100178 return -EINVAL;
Harald Weltec6ed9282011-06-06 18:31:20 +0200179 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800180 if (!nm_state)
181 return -1;
182
183 new_state = *nm_state;
184 new_state.administrative = adm_state;
185
Harald Welteb03c4482011-03-06 22:11:32 +0100186 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100187 nsd.obj_class = obj_class;
188 nsd.old_state = nm_state;
189 nsd.new_state = &new_state;
190 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200191 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800192
193 nm_state->administrative = adm_state;
194
Harald Welte4c826f72011-01-14 15:55:42 +0100195 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800196}
197
198static int abis_nm_rx_statechg_rep(struct msgb *mb)
199{
200 struct abis_om_hdr *oh = msgb_l2(mb);
201 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200202 struct e1inp_sign_link *sign_link = mb->dst;
203 struct gsm_bts *bts = sign_link->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +0800204 struct tlv_parsed tp;
205 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800206
207 DEBUGPC(DNM, "STATE CHG: ");
208
209 memset(&new_state, 0, sizeof(new_state));
210
Harald Weltec6ed9282011-06-06 18:31:20 +0200211 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800212 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100213 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800214 return -EINVAL;
215 }
216
217 new_state = *nm_state;
218
Harald Welte59698fb2010-01-10 18:01:52 +0100219 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800220 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
221 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200222 DEBUGPC(DNM, "OP_STATE=%s ",
223 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800224 }
225 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
226 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
227 new_state.availability = 0xff;
228 else
229 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Weltec61a90e2011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
231 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800232 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100233 } else
234 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800235 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
236 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200238 get_value_string(abis_nm_adm_state_names,
239 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800240 }
241 DEBUGPC(DNM, "\n");
242
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100243 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
244 new_state.operational != nm_state->operational ||
245 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800246 /* Update the operational state of a given object in our in-memory data
247 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100248 struct nm_statechg_signal_data nsd;
Harald Weltec6ed9282011-06-06 18:31:20 +0200249 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100250 nsd.obj_class = foh->obj_class;
251 nsd.old_state = nm_state;
252 nsd.new_state = &new_state;
253 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100254 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200255 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100256 nm_state->operational = new_state.operational;
257 nm_state->availability = new_state.availability;
258 if (nm_state->administrative == 0)
259 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800260 }
261#if 0
262 if (op_state == 1) {
263 /* try to enable objects that are disabled */
264 abis_nm_opstart(bts, foh->obj_class,
265 foh->obj_inst.bts_nr,
266 foh->obj_inst.trx_nr,
267 foh->obj_inst.ts_nr);
268 }
269#endif
270 return 0;
271}
272
273static int rx_fail_evt_rep(struct msgb *mb)
274{
275 struct abis_om_hdr *oh = msgb_l2(mb);
276 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200277 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800278 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100279 const uint8_t *p_val;
280 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800281
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200282 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800283
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200284 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800285
286 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-05-22 22:45:37 +0200287 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
288 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800289 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200290 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
291 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100292 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
293 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200294 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100295 }
296 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
297 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
298 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
299 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100301 talloc_free(p_text);
302 }
303 }
Harald Welte59b04682009-06-10 05:40:52 +0800304
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200305 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800306
307 return 0;
308}
309
310static int abis_nm_rcvmsg_report(struct msgb *mb)
311{
312 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200313 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800314
Harald Weltec61a90e2011-05-22 22:45:37 +0200315 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800316
317 //nmh->cfg->report_cb(mb, foh);
318
319 switch (mt) {
320 case NM_MT_STATECHG_EVENT_REP:
321 return abis_nm_rx_statechg_rep(mb);
322 break;
323 case NM_MT_SW_ACTIVATED_REP:
324 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200325 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800326 break;
327 case NM_MT_FAILURE_EVENT_REP:
328 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200329 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800330 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200331 case NM_MT_TEST_REP:
332 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200334 break;
Harald Welte59b04682009-06-10 05:40:52 +0800335 default:
336 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
337 break;
338
339 };
340
341 return 0;
342}
343
344/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200345static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
346 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800347{
348 struct abis_om_hdr *oh;
349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200350 uint8_t len = swdesc_len;
351 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800352
353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
354 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
355
356 trailer = msgb_put(msg, swdesc_len);
357 memcpy(trailer, sw_desc, swdesc_len);
358
359 return abis_nm_sendmsg(bts, msg);
360}
361
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100362int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
363 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100364{
365 static const struct tlv_definition sw_descr_def = {
366 .def = {
367 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
368 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
369 },
370 };
371
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100372 size_t pos = 0;
373 int desc_pos = 0;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100374
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100375 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
376 uint8_t tag;
377 uint16_t tag_len;
378 const uint8_t *val;
379 int len;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100380
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100381 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
382 desc[desc_pos].start = &sw_descr[pos];
383
384 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
385 * nested nature and the fact you have to assume it contains only two sub
386 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
387 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
388 LOGP(DNM, LOGL_ERROR,
389 "SW_DESCR attribute identifier not found!\n");
390 return -1;
391 }
392
393 pos += 1;
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
396 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
397 LOGP(DNM, LOGL_ERROR,
398 "FILE_ID attribute identifier not found!\n");
399 return -2;
400 }
401 desc[desc_pos].file_id = val;
402 desc[desc_pos].file_id_len = tag_len;
403 pos += len;
404
405
406 len = tlv_parse_one(&tag, &tag_len, &val,
407 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
408 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
409 LOGP(DNM, LOGL_ERROR,
410 "FILE_VERSION attribute identifier not found!\n");
411 return -3;
412 }
413 desc[desc_pos].file_ver = val;
414 desc[desc_pos].file_ver_len = tag_len;
415 pos += len;
416
417 /* final size */
418 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100419 }
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100420
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100421 return desc_pos;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100422}
423
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100424int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
425 const size_t size)
426{
427 int res = 0;
428 int i;
429
430 for (i = 1; i < size; ++i) {
431 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
432 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
433 res = i;
434 }
435 }
436
437 return res;
438}
439
Harald Welte59b04682009-06-10 05:40:52 +0800440static int abis_nm_rx_sw_act_req(struct msgb *mb)
441{
442 struct abis_om_hdr *oh = msgb_l2(mb);
443 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200444 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200445 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200446 const uint8_t *sw_config;
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100447 int ret, sw_config_len, len;
448 struct abis_nm_sw_descr sw_descr[5];
Harald Welte59b04682009-06-10 05:40:52 +0800449
Harald Weltec61a90e2011-05-22 22:45:37 +0200450 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200451
452 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800453
Harald Welte3055e332010-03-14 15:37:43 +0800454 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800455
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200456 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800457 foh->obj_inst.bts_nr,
458 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800459 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800460 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100461 if (ret != 0) {
462 LOGP(DNM, LOGL_ERROR,
463 "Sending SW ActReq ACK failed: %d\n", ret);
464 return ret;
465 }
Harald Welte59b04682009-06-10 05:40:52 +0800466
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200467 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200468 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
469 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
470 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100471 LOGP(DNM, LOGL_ERROR,
472 "SW config not found! Can't continue.\n");
Mike Haben322fc582009-10-01 14:56:13 +0200473 return -EINVAL;
474 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200475 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200476 }
477
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100478 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100479 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100480 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100481 if (len <= 0) {
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100482 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100483 return -EINVAL;
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100484 }
Mike Haben322fc582009-10-01 14:56:13 +0200485
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100486 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
487 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
488
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200489 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800490 foh->obj_inst.bts_nr,
491 foh->obj_inst.trx_nr,
492 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100493 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte59b04682009-06-10 05:40:52 +0800494}
495
496/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
497static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
498{
499 struct abis_om_hdr *oh = msgb_l2(mb);
500 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200501 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800502 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200503 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800504
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200505 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800506 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
507 return -EINVAL;
508
509 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
510
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200511 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800512}
513
514static int abis_nm_rx_lmt_event(struct msgb *mb)
515{
516 struct abis_om_hdr *oh = msgb_l2(mb);
517 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200518 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800519 struct tlv_parsed tp;
520
521 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200522 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800523 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
524 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200525 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800526 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
527 }
528 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
529 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200530 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800531 DEBUGPC(DNM, "Level=%u ", level);
532 }
533 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
534 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
535 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
536 DEBUGPC(DNM, "Username=%s ", name);
537 }
538 DEBUGPC(DNM, "\n");
539 /* FIXME: parse LMT LOGON TIME */
540 return 0;
541}
542
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200543void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100544{
545 int wait = 0;
546 struct msgb *msg;
547 /* the queue is empty */
548 while (!llist_empty(&bts->abis_queue)) {
549 msg = msgb_dequeue(&bts->abis_queue);
550 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200551 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100552
553 if (wait)
554 break;
555 }
556
557 bts->abis_nm_pend = wait;
558}
559
Harald Welte59b04682009-06-10 05:40:52 +0800560/* Receive a OML NM Message from BTS */
561static int abis_nm_rcvmsg_fom(struct msgb *mb)
562{
563 struct abis_om_hdr *oh = msgb_l2(mb);
564 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200565 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200566 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100567 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800568
569 /* check for unsolicited message */
570 if (is_report(mt))
571 return abis_nm_rcvmsg_report(mb);
572
Harald Weltec61a90e2011-05-22 22:45:37 +0200573 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800574 return abis_nm_rcvmsg_sw(mb);
575
Harald Weltec61a90e2011-05-22 22:45:37 +0200576 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800577 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800578 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200579
Harald Weltec61a90e2011-05-22 22:45:37 +0200580 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200581
Harald Weltec61a90e2011-05-22 22:45:37 +0200582 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800583
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200584 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800585 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200586 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200587 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800588 else
589 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200590
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800591 nack_data.msg = mb;
592 nack_data.mt = mt;
Holger Hans Peter Freyther70f1e472012-11-11 18:26:23 +0100593 nack_data.bts = sign_link->trx->bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200594 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200595 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200596 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800597 }
598#if 0
599 /* check if last message is to be acked */
600 if (is_ack_nack(nmh->last_msgtype)) {
601 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100602 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800603 /* we got our ACK, continue sending the next msg */
604 } else if (mt == MT_NACK(nmh->last_msgtype)) {
605 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100606 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800607 /* FIXME: somehow signal this to the caller */
608 } else {
609 /* really strange things happen */
610 return -EINVAL;
611 }
612 }
613#endif
614
615 switch (mt) {
616 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100617 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800618 break;
619 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100620 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800621 break;
622 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100623 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800624 break;
Harald Welte204317e2009-08-06 17:58:31 +0200625 case NM_MT_CONN_MDROP_LINK_ACK:
626 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
627 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100628 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200629 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100630 break;
631 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200632 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100633 break;
Harald Welte08011e22011-03-04 13:41:31 +0100634 case NM_MT_SET_BTS_ATTR_ACK:
Harald Welte08011e22011-03-04 13:41:31 +0100635 break;
Harald Welte59b04682009-06-10 05:40:52 +0800636 }
637
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200638 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100639 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800640}
641
642static int abis_nm_rx_ipacc(struct msgb *mb);
643
644static int abis_nm_rcvmsg_manuf(struct msgb *mb)
645{
646 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200647 struct e1inp_sign_link *sign_link = mb->dst;
648 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800649
650 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100651 case GSM_BTS_TYPE_NANOBTS:
Harald Welte35ac0e42012-07-02 19:51:55 +0200652 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte59b04682009-06-10 05:40:52 +0800653 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200654 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800655 break;
656 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100657 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
658 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800659 rc = 0;
660 break;
661 }
662
663 return rc;
664}
665
666/* High-Level API */
667/* Entry-point where L2 OML from BTS enters the NM code */
668int abis_nm_rcvmsg(struct msgb *msg)
669{
670 struct abis_om_hdr *oh = msgb_l2(msg);
671 int rc = 0;
672
673 /* Various consistency checks */
674 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100675 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800676 oh->placement);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200677 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
678 rc = -EINVAL;
679 goto err;
680 }
Harald Welte59b04682009-06-10 05:40:52 +0800681 }
682 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100683 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800684 oh->sequence);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200685 rc = -EINVAL;
686 goto err;
Harald Welte59b04682009-06-10 05:40:52 +0800687 }
688#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200689 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800690 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
691 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100692 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800693 oh->length + sizeof(*oh), l2_len);
694 return -EINVAL;
695 }
696 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100697 LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
Harald Welte59b04682009-06-10 05:40:52 +0800698#endif
699 msg->l3h = (unsigned char *)oh + sizeof(*oh);
700
701 switch (oh->mdisc) {
702 case ABIS_OM_MDISC_FOM:
703 rc = abis_nm_rcvmsg_fom(msg);
704 break;
705 case ABIS_OM_MDISC_MANUF:
706 rc = abis_nm_rcvmsg_manuf(msg);
707 break;
708 case ABIS_OM_MDISC_MMI:
709 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100710 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800711 oh->mdisc);
712 break;
713 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100714 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800715 oh->mdisc);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200716 rc = -EINVAL;
717 break;
Harald Welte59b04682009-06-10 05:40:52 +0800718 }
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200719err:
Harald Welte59b04682009-06-10 05:40:52 +0800720 msgb_free(msg);
721 return rc;
722}
723
724#if 0
725/* initialized all resources */
726struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
727{
728 struct abis_nm_h *nmh;
729
730 nmh = malloc(sizeof(*nmh));
731 if (!nmh)
732 return NULL;
733
734 nmh->cfg = cfg;
735
736 return nmh;
737}
738
739/* free all resources */
740void abis_nm_fini(struct abis_nm_h *nmh)
741{
742 free(nmh);
743}
744#endif
745
746/* Here we are trying to define a high-level API that can be used by
747 * the actual BSC implementation. However, the architecture is currently
748 * still under design. Ideally the calls to this API would be synchronous,
749 * while the underlying stack behind the APi runs in a traditional select
750 * based state machine.
751 */
752
753/* 6.2 Software Load: */
754enum sw_state {
755 SW_STATE_NONE,
756 SW_STATE_WAIT_INITACK,
757 SW_STATE_WAIT_SEGACK,
758 SW_STATE_WAIT_ENDACK,
759 SW_STATE_WAIT_ACTACK,
760 SW_STATE_ERROR,
761};
762
763struct abis_nm_sw {
764 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800765 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800766 gsm_cbfn *cbfn;
767 void *cb_data;
768 int forced;
769
770 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200771 uint8_t obj_class;
772 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800773
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200774 uint8_t file_id[255];
775 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800776
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200777 uint8_t file_version[255];
778 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800779
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200780 uint8_t window_size;
781 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800782
783 int fd;
784 FILE *stream;
785 enum sw_state state;
786 int last_seg;
787};
788
789static struct abis_nm_sw g_sw;
790
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100791static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
792{
793 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
794 msgb_v_put(msg, NM_ATT_SW_DESCR);
795 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
796 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
797 sw->file_version);
798 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
799 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
800 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
801 sw->file_version);
802 } else {
803 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
804 }
805}
806
Harald Welte59b04682009-06-10 05:40:52 +0800807/* 6.2.1 / 8.3.1: Load Data Initiate */
808static int sw_load_init(struct abis_nm_sw *sw)
809{
810 struct abis_om_hdr *oh;
811 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200812 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800813
814 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
815 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
816 sw->obj_instance[0], sw->obj_instance[1],
817 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100818
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100819 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800820 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
821
822 return abis_nm_sendmsg(sw->bts, msg);
823}
824
825static int is_last_line(FILE *stream)
826{
827 char next_seg_buf[256];
828 long pos;
829
830 /* check if we're sending the last line */
831 pos = ftell(stream);
Holger Hans Peter Freyther4c11d0b2014-04-04 11:48:32 +0200832
833 /* Did ftell fail? Then we are at the end for sure */
834 if (pos < 0)
835 return 1;
836
Harald Welte59b04682009-06-10 05:40:52 +0800837 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
838 fseek(stream, pos, SEEK_SET);
839 return 1;
840 }
841
842 fseek(stream, pos, SEEK_SET);
843 return 0;
844}
845
846/* 6.2.2 / 8.3.2 Load Data Segment */
847static int sw_load_segment(struct abis_nm_sw *sw)
848{
849 struct abis_om_hdr *oh;
850 struct msgb *msg = nm_msgb_alloc();
851 char seg_buf[256];
852 char *line_buf = seg_buf+2;
853 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200854 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800855
856 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
857
858 switch (sw->bts->type) {
859 case GSM_BTS_TYPE_BS11:
860 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
861 perror("fgets reading segment");
862 return -EINVAL;
863 }
864 seg_buf[0] = 0x00;
865
866 /* check if we're sending the last line */
867 sw->last_seg = is_last_line(sw->stream);
868 if (sw->last_seg)
869 seg_buf[1] = 0;
870 else
871 seg_buf[1] = 1 + sw->seg_in_window++;
872
873 len = strlen(line_buf) + 2;
874 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200875 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800876 /* BS11 wants CR + LF in excess of the TLV length !?! */
877 tlv[1] -= 2;
878
879 /* we only now know the exact length for the OM hdr */
880 len = strlen(line_buf)+2;
881 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100882 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200883 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100884 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
885 if (len < 0) {
886 perror("read failed");
887 return -EINVAL;
888 }
889
890 if (len != IPACC_SEGMENT_SIZE)
891 sw->last_seg = 1;
892
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100893 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200894 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100895 len += 3;
896 break;
897 }
Harald Welte59b04682009-06-10 05:40:52 +0800898 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100899 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800900 /* FIXME: Other BTS types */
901 return -1;
902 }
903
904 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
905 sw->obj_instance[0], sw->obj_instance[1],
906 sw->obj_instance[2]);
907
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100908 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800909}
910
911/* 6.2.4 / 8.3.4 Load Data End */
912static int sw_load_end(struct abis_nm_sw *sw)
913{
914 struct abis_om_hdr *oh;
915 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200916 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800917
918 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
919 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
920 sw->obj_instance[0], sw->obj_instance[1],
921 sw->obj_instance[2]);
922
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100923 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800924 return abis_nm_sendmsg(sw->bts, msg);
925}
926
927/* Activate the specified software into the BTS */
928static int sw_activate(struct abis_nm_sw *sw)
929{
930 struct abis_om_hdr *oh;
931 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200932 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800933
934 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
935 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
936 sw->obj_instance[0], sw->obj_instance[1],
937 sw->obj_instance[2]);
938
939 /* FIXME: this is BS11 specific format */
940 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
941 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
942 sw->file_version);
943
944 return abis_nm_sendmsg(sw->bts, msg);
945}
946
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100947struct sdp_firmware {
948 char magic[4];
949 char more_magic[4];
950 unsigned int header_length;
951 unsigned int file_length;
952} __attribute__ ((packed));
953
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100954static int parse_sdp_header(struct abis_nm_sw *sw)
955{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100956 struct sdp_firmware firmware_header;
957 int rc;
958 struct stat stat;
959
960 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
961 if (rc != sizeof(firmware_header)) {
962 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
963 return -1;
964 }
965
966 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
967 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
968 return -1;
969 }
970
971 if (firmware_header.more_magic[0] != 0x10 ||
972 firmware_header.more_magic[1] != 0x02 ||
973 firmware_header.more_magic[2] != 0x00 ||
974 firmware_header.more_magic[3] != 0x00) {
975 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
976 return -1;
977 }
978
979
980 if (fstat(sw->fd, &stat) == -1) {
981 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
982 return -1;
983 }
984
985 if (ntohl(firmware_header.file_length) != stat.st_size) {
986 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
987 return -1;
988 }
989
990 /* go back to the start as we checked the whole filesize.. */
991 lseek(sw->fd, 0l, SEEK_SET);
992 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
993 "There might be checksums in the file that are not\n"
994 "verified and incomplete firmware might be flashed.\n"
995 "There is absolutely no WARRANTY that flashing will\n"
996 "work.\n");
997 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100998}
999
Harald Welte59b04682009-06-10 05:40:52 +08001000static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1001{
1002 char file_id[12+1];
1003 char file_version[80+1];
1004 int rc;
1005
1006 sw->fd = open(fname, O_RDONLY);
1007 if (sw->fd < 0)
1008 return sw->fd;
1009
1010 switch (sw->bts->type) {
1011 case GSM_BTS_TYPE_BS11:
1012 sw->stream = fdopen(sw->fd, "r");
1013 if (!sw->stream) {
1014 perror("fdopen");
1015 return -1;
1016 }
1017 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001018 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001019 file_id, file_version);
1020 if (rc != 2) {
1021 perror("parsing header line of software file");
1022 return -1;
1023 }
1024 strcpy((char *)sw->file_id, file_id);
1025 sw->file_id_len = strlen(file_id);
1026 strcpy((char *)sw->file_version, file_version);
1027 sw->file_version_len = strlen(file_version);
1028 /* rewind to start of file */
1029 rewind(sw->stream);
1030 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001031 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001032 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001033 rc = parse_sdp_header(sw);
1034 if (rc < 0) {
1035 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1036 return -1;
1037 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001038
1039 strcpy((char *)sw->file_id, "id");
1040 sw->file_id_len = 3;
1041 strcpy((char *)sw->file_version, "version");
1042 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001043 break;
Harald Welte59b04682009-06-10 05:40:52 +08001044 default:
1045 /* We don't know how to treat them yet */
1046 close(sw->fd);
1047 return -EINVAL;
1048 }
1049
1050 return 0;
1051}
1052
1053static void sw_close_file(struct abis_nm_sw *sw)
1054{
1055 switch (sw->bts->type) {
1056 case GSM_BTS_TYPE_BS11:
1057 fclose(sw->stream);
1058 break;
1059 default:
1060 close(sw->fd);
1061 break;
1062 }
1063}
1064
1065/* Fill the window */
1066static int sw_fill_window(struct abis_nm_sw *sw)
1067{
1068 int rc;
1069
1070 while (sw->seg_in_window < sw->window_size) {
1071 rc = sw_load_segment(sw);
1072 if (rc < 0)
1073 return rc;
1074 if (sw->last_seg)
1075 break;
1076 }
1077 return 0;
1078}
1079
1080/* callback function from abis_nm_rcvmsg() handler */
1081static int abis_nm_rcvmsg_sw(struct msgb *mb)
1082{
1083 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001084 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001085 int rc = -1;
1086 struct abis_nm_sw *sw = &g_sw;
1087 enum sw_state old_state = sw->state;
1088
1089 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1090
1091 switch (sw->state) {
1092 case SW_STATE_WAIT_INITACK:
1093 switch (foh->msg_type) {
1094 case NM_MT_LOAD_INIT_ACK:
1095 /* fill window with segments */
1096 if (sw->cbfn)
1097 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1098 NM_MT_LOAD_INIT_ACK, mb,
1099 sw->cb_data, NULL);
1100 rc = sw_fill_window(sw);
1101 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001102 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001103 break;
1104 case NM_MT_LOAD_INIT_NACK:
1105 if (sw->forced) {
1106 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1107 "Init NACK\n");
1108 if (sw->cbfn)
1109 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1110 NM_MT_LOAD_INIT_ACK, mb,
1111 sw->cb_data, NULL);
1112 rc = sw_fill_window(sw);
1113 sw->state = SW_STATE_WAIT_SEGACK;
1114 } else {
1115 DEBUGP(DNM, "Software Load Init NACK\n");
1116 /* FIXME: cause */
1117 if (sw->cbfn)
1118 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1119 NM_MT_LOAD_INIT_NACK, mb,
1120 sw->cb_data, NULL);
1121 sw->state = SW_STATE_ERROR;
1122 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001123 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001124 break;
1125 }
1126 break;
1127 case SW_STATE_WAIT_SEGACK:
1128 switch (foh->msg_type) {
1129 case NM_MT_LOAD_SEG_ACK:
1130 if (sw->cbfn)
1131 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1132 NM_MT_LOAD_SEG_ACK, mb,
1133 sw->cb_data, NULL);
1134 sw->seg_in_window = 0;
1135 if (!sw->last_seg) {
1136 /* fill window with more segments */
1137 rc = sw_fill_window(sw);
1138 sw->state = SW_STATE_WAIT_SEGACK;
1139 } else {
1140 /* end the transfer */
1141 sw->state = SW_STATE_WAIT_ENDACK;
1142 rc = sw_load_end(sw);
1143 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001144 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001145 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001146 case NM_MT_LOAD_ABORT:
1147 if (sw->cbfn)
1148 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1149 NM_MT_LOAD_ABORT, mb,
1150 sw->cb_data, NULL);
1151 break;
Harald Welte59b04682009-06-10 05:40:52 +08001152 }
1153 break;
1154 case SW_STATE_WAIT_ENDACK:
1155 switch (foh->msg_type) {
1156 case NM_MT_LOAD_END_ACK:
1157 sw_close_file(sw);
1158 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1159 sw->bts->nr);
1160 sw->state = SW_STATE_NONE;
1161 if (sw->cbfn)
1162 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1163 NM_MT_LOAD_END_ACK, mb,
1164 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001165 rc = 0;
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 case NM_MT_LOAD_END_NACK:
1169 if (sw->forced) {
1170 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1171 "End NACK\n");
1172 sw->state = SW_STATE_NONE;
1173 if (sw->cbfn)
1174 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1175 NM_MT_LOAD_END_ACK, mb,
1176 sw->cb_data, NULL);
1177 } else {
1178 DEBUGP(DNM, "Software Load End NACK\n");
1179 /* FIXME: cause */
1180 sw->state = SW_STATE_ERROR;
1181 if (sw->cbfn)
1182 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1183 NM_MT_LOAD_END_NACK, mb,
1184 sw->cb_data, NULL);
1185 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001186 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001187 break;
1188 }
1189 case SW_STATE_WAIT_ACTACK:
1190 switch (foh->msg_type) {
1191 case NM_MT_ACTIVATE_SW_ACK:
1192 /* we're done */
1193 DEBUGP(DNM, "Activate Software DONE!\n");
1194 sw->state = SW_STATE_NONE;
1195 rc = 0;
1196 if (sw->cbfn)
1197 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1198 NM_MT_ACTIVATE_SW_ACK, mb,
1199 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001200 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001201 break;
1202 case NM_MT_ACTIVATE_SW_NACK:
1203 DEBUGP(DNM, "Activate Software NACK\n");
1204 /* FIXME: cause */
1205 sw->state = SW_STATE_ERROR;
1206 if (sw->cbfn)
1207 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1208 NM_MT_ACTIVATE_SW_NACK, mb,
1209 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001210 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001211 break;
1212 }
1213 case SW_STATE_NONE:
1214 switch (foh->msg_type) {
1215 case NM_MT_ACTIVATE_SW_ACK:
1216 rc = 0;
1217 break;
1218 }
1219 break;
1220 case SW_STATE_ERROR:
1221 break;
1222 }
1223
1224 if (rc)
1225 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1226 foh->msg_type, old_state, sw->state);
1227
1228 return rc;
1229}
1230
1231/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001232int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001233 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001234 gsm_cbfn *cbfn, void *cb_data)
1235{
1236 struct abis_nm_sw *sw = &g_sw;
1237 int rc;
1238
1239 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1240 bts->nr, fname);
1241
1242 if (sw->state != SW_STATE_NONE)
1243 return -EBUSY;
1244
1245 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001246 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001247
1248 switch (bts->type) {
1249 case GSM_BTS_TYPE_BS11:
1250 sw->obj_class = NM_OC_SITE_MANAGER;
1251 sw->obj_instance[0] = 0xff;
1252 sw->obj_instance[1] = 0xff;
1253 sw->obj_instance[2] = 0xff;
1254 break;
1255 case GSM_BTS_TYPE_NANOBTS:
1256 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001257 sw->obj_instance[0] = sw->bts->nr;
1258 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001259 sw->obj_instance[2] = 0xff;
1260 break;
1261 case GSM_BTS_TYPE_UNKNOWN:
1262 default:
1263 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1264 return -1;
1265 break;
1266 }
Harald Welte59b04682009-06-10 05:40:52 +08001267 sw->window_size = win_size;
1268 sw->state = SW_STATE_WAIT_INITACK;
1269 sw->cbfn = cbfn;
1270 sw->cb_data = cb_data;
1271 sw->forced = forced;
1272
1273 rc = sw_open_file(sw, fname);
1274 if (rc < 0) {
1275 sw->state = SW_STATE_NONE;
1276 return rc;
1277 }
1278
1279 return sw_load_init(sw);
1280}
1281
1282int abis_nm_software_load_status(struct gsm_bts *bts)
1283{
1284 struct abis_nm_sw *sw = &g_sw;
1285 struct stat st;
1286 int rc, percent;
1287
1288 rc = fstat(sw->fd, &st);
1289 if (rc < 0) {
1290 perror("ERROR during stat");
1291 return rc;
1292 }
1293
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001294 if (sw->stream)
1295 percent = (ftell(sw->stream) * 100) / st.st_size;
1296 else
1297 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001298 return percent;
1299}
1300
1301/* Activate the specified software into the BTS */
1302int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1303 gsm_cbfn *cbfn, void *cb_data)
1304{
1305 struct abis_nm_sw *sw = &g_sw;
1306 int rc;
1307
1308 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1309 bts->nr, fname);
1310
1311 if (sw->state != SW_STATE_NONE)
1312 return -EBUSY;
1313
1314 sw->bts = bts;
1315 sw->obj_class = NM_OC_SITE_MANAGER;
1316 sw->obj_instance[0] = 0xff;
1317 sw->obj_instance[1] = 0xff;
1318 sw->obj_instance[2] = 0xff;
1319 sw->state = SW_STATE_WAIT_ACTACK;
1320 sw->cbfn = cbfn;
1321 sw->cb_data = cb_data;
1322
1323 /* Open the file in order to fill some sw struct members */
1324 rc = sw_open_file(sw, fname);
1325 if (rc < 0) {
1326 sw->state = SW_STATE_NONE;
1327 return rc;
1328 }
1329 sw_close_file(sw);
1330
1331 return sw_activate(sw);
1332}
1333
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001334static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1335 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001336{
1337 ch->attrib = NM_ATT_ABIS_CHANNEL;
1338 ch->bts_port = bts_port;
1339 ch->timeslot = ts_nr;
1340 ch->subslot = subslot_nr;
1341}
1342
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001343int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1344 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1345 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001346{
1347 struct abis_om_hdr *oh;
1348 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001349 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001350 struct msgb *msg = nm_msgb_alloc();
1351
1352 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1353 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1354 bts->bts_nr, trx_nr, 0xff);
1355
1356 msgb_tv_put(msg, NM_ATT_TEI, tei);
1357
1358 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1359 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1360
1361 return abis_nm_sendmsg(bts, msg);
1362}
1363
1364/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1365int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001366 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001367{
1368 struct gsm_bts *bts = trx->bts;
1369 struct abis_om_hdr *oh;
1370 struct abis_nm_channel *ch;
1371 struct msgb *msg = nm_msgb_alloc();
1372
1373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1374 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1375 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1376
1377 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1378 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1379
1380 return abis_nm_sendmsg(bts, msg);
1381}
1382
1383#if 0
1384int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1385 struct abis_nm_abis_channel *chan)
1386{
1387}
1388#endif
1389
1390int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001391 uint8_t e1_port, uint8_t e1_timeslot,
1392 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001393{
1394 struct gsm_bts *bts = ts->trx->bts;
1395 struct abis_om_hdr *oh;
1396 struct abis_nm_channel *ch;
1397 struct msgb *msg = nm_msgb_alloc();
1398
1399 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1400 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1401 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1402
1403 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1404 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1405
1406 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1407 gsm_ts_name(ts),
1408 e1_port, e1_timeslot, e1_subslot);
1409
1410 return abis_nm_sendmsg(bts, msg);
1411}
1412
1413#if 0
1414int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1415 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001416 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001417{
1418}
1419#endif
1420
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001421/* Chapter 8.11.1 */
1422int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1423 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1424 uint8_t *attr, uint8_t attr_len)
1425{
1426 struct abis_om_hdr *oh;
1427 struct msgb *msg = nm_msgb_alloc();
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001428
1429 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1430
1431 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1432 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1433 bts_nr, trx_nr, ts_nr);
1434 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1435
1436 return abis_nm_sendmsg(bts, msg);
1437}
1438
Harald Welte59b04682009-06-10 05:40:52 +08001439/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001440int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001441{
1442 struct abis_om_hdr *oh;
1443 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001444 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001445
1446 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1447
1448 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1449 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1450 cur = msgb_put(msg, attr_len);
1451 memcpy(cur, attr, attr_len);
1452
1453 return abis_nm_sendmsg(bts, msg);
1454}
1455
1456/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001457int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001458{
1459 struct abis_om_hdr *oh;
1460 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001461 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001462
1463 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1464
1465 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1466 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1467 trx->bts->bts_nr, trx->nr, 0xff);
1468 cur = msgb_put(msg, attr_len);
1469 memcpy(cur, attr, attr_len);
1470
1471 return abis_nm_sendmsg(trx->bts, msg);
1472}
1473
Holger Hans Peter Freyther1f672322014-03-26 14:24:42 +01001474int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1475{
1476 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1477 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1478}
1479
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001480static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1481 const char **reason)
Harald Weltef2eb2782009-08-09 21:49:48 +02001482{
1483 int i;
1484
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001485 *reason = "Reason unknown";
1486
Harald Weltef2eb2782009-08-09 21:49:48 +02001487 /* As it turns out, the BS-11 has some very peculiar restrictions
1488 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301489 switch (ts->trx->bts->type) {
1490 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001491 switch (chan_comb) {
1492 case NM_CHANC_TCHHalf:
1493 case NM_CHANC_TCHHalf2:
1494 /* not supported */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001495 *reason = "TCH/H is not supported.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001496 return -EINVAL;
1497 case NM_CHANC_SDCCH:
1498 /* only one SDCCH/8 per TRX */
1499 for (i = 0; i < TRX_NR_TS; i++) {
1500 if (i == ts->nr)
1501 continue;
1502 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001503 NM_CHANC_SDCCH) {
1504 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001505 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001506 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001507 }
1508 /* not allowed for TS0 of BCCH-TRX */
1509 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001510 ts->nr == 0) {
1511 *reason = "SDCCH/8 must be on TS0.";
1512 return -EINVAL;
1513 }
1514
Harald Weltef2eb2782009-08-09 21:49:48 +02001515 /* not on the same TRX that has a BCCH+SDCCH4
1516 * combination */
Holger Hans Peter Freytherfca3eb92013-01-08 19:30:14 +01001517 if (ts->trx != ts->trx->bts->c0 &&
Harald Weltef2eb2782009-08-09 21:49:48 +02001518 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001519 ts->trx->ts[0].nm_chan_comb == 8)) {
1520 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1521 return -EINVAL;
1522 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001523 break;
1524 case NM_CHANC_mainBCCH:
1525 case NM_CHANC_BCCHComb:
1526 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001527 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1528 *reason = "Main BCCH must be on TS0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001529 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001530 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001531 break;
1532 case NM_CHANC_BCCH:
1533 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001534 if (ts->trx != ts->trx->bts->c0) {
1535 *reason = "BCCH must be on C0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001536 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001537 }
1538 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1539 *reason = "BCCH must be on TS 2/4/6.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001540 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001541 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001542 break;
1543 case 8: /* this is not like 08.58, but in fact
1544 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1545 /* FIXME: only one CBCH allowed per cell */
1546 break;
1547 }
Harald Welte76ba8812009-12-02 02:45:23 +05301548 break;
1549 case GSM_BTS_TYPE_NANOBTS:
1550 switch (ts->nr) {
1551 case 0:
1552 if (ts->trx->nr == 0) {
1553 /* only on TRX0 */
1554 switch (chan_comb) {
1555 case NM_CHANC_BCCH:
1556 case NM_CHANC_mainBCCH:
1557 case NM_CHANC_BCCHComb:
1558 return 0;
1559 break;
1560 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001561 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301562 return -EINVAL;
1563 }
1564 } else {
1565 switch (chan_comb) {
1566 case NM_CHANC_TCHFull:
1567 case NM_CHANC_TCHHalf:
1568 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1569 return 0;
1570 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001571 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welte76ba8812009-12-02 02:45:23 +05301572 return -EINVAL;
1573 }
1574 }
1575 break;
1576 case 1:
1577 if (ts->trx->nr == 0) {
1578 switch (chan_comb) {
1579 case NM_CHANC_SDCCH_CBCH:
1580 if (ts->trx->ts[0].nm_chan_comb ==
1581 NM_CHANC_mainBCCH)
1582 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001583 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301584 return -EINVAL;
1585 case NM_CHANC_SDCCH:
1586 case NM_CHANC_TCHFull:
1587 case NM_CHANC_TCHHalf:
1588 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1589 case NM_CHANC_IPAC_TCHFull_PDCH:
1590 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001591 default:
1592 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1593 return -EINVAL;
Harald Welte76ba8812009-12-02 02:45:23 +05301594 }
1595 } else {
1596 switch (chan_comb) {
1597 case NM_CHANC_SDCCH:
1598 case NM_CHANC_TCHFull:
1599 case NM_CHANC_TCHHalf:
1600 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1601 return 0;
1602 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001603 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301604 return -EINVAL;
1605 }
1606 }
1607 break;
1608 case 2:
1609 case 3:
1610 case 4:
1611 case 5:
1612 case 6:
1613 case 7:
1614 switch (chan_comb) {
1615 case NM_CHANC_TCHFull:
1616 case NM_CHANC_TCHHalf:
1617 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1618 return 0;
1619 case NM_CHANC_IPAC_PDCH:
1620 case NM_CHANC_IPAC_TCHFull_PDCH:
1621 if (ts->trx->nr == 0)
1622 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001623 else {
1624 *reason = "PDCH must be on TRX0.";
Harald Welte76ba8812009-12-02 02:45:23 +05301625 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001626 }
Harald Welte76ba8812009-12-02 02:45:23 +05301627 }
1628 break;
1629 }
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001630 *reason = "Unknown combination";
Harald Welte76ba8812009-12-02 02:45:23 +05301631 return -EINVAL;
Harald Welte35ac0e42012-07-02 19:51:55 +02001632 case GSM_BTS_TYPE_OSMO_SYSMO:
1633 /* no known restrictions */
1634 return 0;
Harald Welte76ba8812009-12-02 02:45:23 +05301635 default:
1636 /* unknown BTS type */
1637 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001638 }
1639 return 0;
1640}
1641
Harald Welte59b04682009-06-10 05:40:52 +08001642/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001643int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001644{
1645 struct gsm_bts *bts = ts->trx->bts;
1646 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001647 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001648 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001649 uint8_t len = 2 + 2;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001650 const char *reason = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001651
1652 if (bts->type == GSM_BTS_TYPE_BS11)
1653 len += 4 + 2 + 2 + 3;
1654
1655 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001656 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Weltef2eb2782009-08-09 21:49:48 +02001657 msgb_free(msg);
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001658 LOGP(DNM, LOGL_ERROR,
1659 "Invalid Channel Combination %d on %s. Reason: %s\n",
1660 chan_comb, gsm_ts_name(ts), reason);
Harald Weltef2eb2782009-08-09 21:49:48 +02001661 return -EINVAL;
1662 }
1663 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001664
1665 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1666 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1667 NM_OC_CHANNEL, bts->bts_nr,
1668 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001669 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001670 if (ts->hopping.enabled) {
1671 unsigned int i;
1672 uint8_t *len;
1673
Harald Welte67104d12009-09-12 13:05:33 +02001674 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1675 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001676
1677 /* build the ARFCN list */
1678 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1679 len = msgb_put(msg, 1);
1680 *len = 0;
1681 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1682 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1683 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001684 /* At least BS-11 wants a TLV16 here */
1685 if (bts->type == GSM_BTS_TYPE_BS11)
1686 *len += 1;
1687 else
1688 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001689 }
1690 }
Harald Welte59b04682009-06-10 05:40:52 +08001691 }
Harald Welte025e6c92014-01-19 17:18:21 +01001692 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001693 if (bts->type == GSM_BTS_TYPE_BS11)
1694 msgb_tlv_put(msg, 0x59, 1, &zero);
1695
1696 return abis_nm_sendmsg(bts, msg);
1697}
1698
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001699int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1700 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001701{
1702 struct abis_om_hdr *oh;
1703 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001704 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1705 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001706
1707 if (nack) {
1708 len += 2;
1709 msgtype = NM_MT_SW_ACT_REQ_NACK;
1710 }
1711
1712 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1713 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1714
1715 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001716 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001717 memcpy(ptr, attr, att_len);
1718 }
1719 if (nack)
1720 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1721
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001722 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001723}
1724
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001725int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001726{
1727 struct msgb *msg = nm_msgb_alloc();
1728 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001729 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001730
1731 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1732 fill_om_hdr(oh, len);
1733 data = msgb_put(msg, len);
1734 memcpy(data, rawmsg, len);
1735
1736 return abis_nm_sendmsg(bts, msg);
1737}
1738
1739/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001740static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001741{
1742 struct abis_om_hdr *oh;
1743 struct msgb *msg = nm_msgb_alloc();
1744
1745 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1746 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1747 0xff, 0xff, 0xff);
1748
1749 return abis_nm_sendmsg(bts, msg);
1750}
1751
1752/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001753int 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 +08001754{
1755 struct abis_om_hdr *oh;
1756 struct msgb *msg = nm_msgb_alloc();
1757
Harald Welte59b04682009-06-10 05:40:52 +08001758 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1759 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1760
Harald Weltec61a90e2011-05-22 22:45:37 +02001761 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001762 DEBUGPC(DNM, "Sending OPSTART\n");
1763
Harald Welte59b04682009-06-10 05:40:52 +08001764 return abis_nm_sendmsg(bts, msg);
1765}
1766
1767/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001768int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1769 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001770{
1771 struct abis_om_hdr *oh;
1772 struct msgb *msg = nm_msgb_alloc();
1773
1774 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1775 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1776 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1777
1778 return abis_nm_sendmsg(bts, msg);
1779}
1780
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001781int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1782 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001783{
1784 struct abis_om_hdr *oh;
1785 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001786 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001787
1788 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1789 e1_port0, ts0, e1_port1, ts1);
1790
1791 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1792 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1793 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1794
1795 attr = msgb_put(msg, 3);
1796 attr[0] = NM_ATT_MDROP_LINK;
1797 attr[1] = e1_port0;
1798 attr[2] = ts0;
1799
1800 attr = msgb_put(msg, 3);
1801 attr[0] = NM_ATT_MDROP_NEXT;
1802 attr[1] = e1_port1;
1803 attr[2] = ts1;
1804
1805 return abis_nm_sendmsg(bts, msg);
1806}
Harald Welte59b04682009-06-10 05:40:52 +08001807
Harald Welte0bf8e302009-08-08 00:02:36 +02001808/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001809int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1810 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1811 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001812{
1813 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001814
Harald Weltec61a90e2011-05-22 22:45:37 +02001815 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001816
1817 if (!msg)
1818 msg = nm_msgb_alloc();
1819
1820 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1821 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1822 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1823 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001824 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001825
1826 return abis_nm_sendmsg(bts, msg);
1827}
1828
Harald Welte59b04682009-06-10 05:40:52 +08001829int abis_nm_event_reports(struct gsm_bts *bts, int on)
1830{
1831 if (on == 0)
1832 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1833 else
1834 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1835}
1836
1837/* Siemens (or BS-11) specific commands */
1838
1839int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1840{
1841 if (reconnect == 0)
1842 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1843 else
1844 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1845}
1846
1847int abis_nm_bs11_restart(struct gsm_bts *bts)
1848{
1849 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1850}
1851
1852
1853struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001854 uint16_t year;
1855 uint8_t month;
1856 uint8_t day;
1857 uint8_t hour;
1858 uint8_t min;
1859 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001860} __attribute__((packed));
1861
1862
1863void get_bs11_date_time(struct bs11_date_time *aet)
1864{
1865 time_t t;
1866 struct tm *tm;
1867
1868 t = time(NULL);
1869 tm = localtime(&t);
1870 aet->sec = tm->tm_sec;
1871 aet->min = tm->tm_min;
1872 aet->hour = tm->tm_hour;
1873 aet->day = tm->tm_mday;
1874 aet->month = tm->tm_mon;
1875 aet->year = htons(1900 + tm->tm_year);
1876}
1877
1878int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1879{
1880 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1881}
1882
1883int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1884{
1885 if (begin)
1886 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1887 else
1888 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1889}
1890
1891int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001892 enum abis_bs11_objtype type, uint8_t idx,
1893 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001894{
1895 struct abis_om_hdr *oh;
1896 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001897 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001898
1899 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1900 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1901 NM_OC_BS11, type, 0, idx);
1902 cur = msgb_put(msg, attr_len);
1903 memcpy(cur, attr, attr_len);
1904
1905 return abis_nm_sendmsg(bts, msg);
1906}
1907
1908int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001909 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001910{
1911 struct abis_om_hdr *oh;
1912 struct msgb *msg = nm_msgb_alloc();
1913
1914 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1915 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1916 NM_OC_BS11, type, 0, idx);
1917
1918 return abis_nm_sendmsg(bts, msg);
1919}
1920
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001921int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001922{
1923 struct abis_om_hdr *oh;
1924 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001925 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001926
1927 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1928 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1929 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1930 msgb_tlv_put(msg, 0x99, 1, &zero);
1931
1932 return abis_nm_sendmsg(bts, msg);
1933}
1934
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001935int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001936{
1937 struct abis_om_hdr *oh;
1938 struct msgb *msg = nm_msgb_alloc();
1939
1940 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1941 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001942 idx, 0xff, 0xff);
1943
1944 return abis_nm_sendmsg(bts, msg);
1945}
1946
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001947int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001948{
1949 struct abis_om_hdr *oh;
1950 struct msgb *msg = nm_msgb_alloc();
1951
1952 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1953 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1954 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001955
1956 return abis_nm_sendmsg(bts, msg);
1957}
1958
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001959static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001960int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1961{
1962 struct abis_om_hdr *oh;
1963 struct msgb *msg = nm_msgb_alloc();
1964
1965 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1966 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1967 0xff, 0xff, 0xff);
1968 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1969
1970 return abis_nm_sendmsg(bts, msg);
1971}
1972
1973/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001974int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1975 uint8_t e1_timeslot, uint8_t e1_subslot,
1976 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001977{
1978 struct abis_om_hdr *oh;
1979 struct abis_nm_channel *ch;
1980 struct msgb *msg = nm_msgb_alloc();
1981
1982 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1983 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1984 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1985
1986 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1987 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1988 msgb_tv_put(msg, NM_ATT_TEI, tei);
1989
1990 return abis_nm_sendmsg(bts, msg);
1991}
1992
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001993int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08001994{
1995 struct abis_om_hdr *oh;
1996 struct msgb *msg = nm_msgb_alloc();
1997
1998 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1999 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2000 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2001 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2002
2003 return abis_nm_sendmsg(trx->bts, msg);
2004}
2005
2006int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2007{
2008 struct abis_om_hdr *oh;
2009 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002010 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08002011
2012 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2013 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2014 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2015 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2016
2017 return abis_nm_sendmsg(trx->bts, msg);
2018}
2019
2020int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2021{
2022 struct abis_om_hdr *oh;
2023 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002024 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08002025
2026 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2027 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2028 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2029 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2030
2031 return abis_nm_sendmsg(bts, msg);
2032}
2033
2034int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2035{
2036 struct abis_om_hdr *oh;
2037 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002038 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002039 NM_ATT_BS11_CCLK_TYPE };
2040
2041 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2042 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2043 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2044 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2045
2046 return abis_nm_sendmsg(bts, msg);
2047
2048}
2049
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002050//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002051
2052int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2053{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002054 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2055}
2056
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002057int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2058{
2059 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2060}
2061
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002062int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002063{
Harald Welte59b04682009-06-10 05:40:52 +08002064 struct abis_om_hdr *oh;
2065 struct msgb *msg = nm_msgb_alloc();
2066 struct bs11_date_time bdt;
2067
2068 get_bs11_date_time(&bdt);
2069
2070 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2071 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002072 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002073 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002074 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2075 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2076 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002077 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002078 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002079 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002080 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002081 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002082 } else {
2083 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2084 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2085 }
2086
2087 return abis_nm_sendmsg(bts, msg);
2088}
2089
2090int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2091{
2092 struct abis_om_hdr *oh;
2093 struct msgb *msg;
2094
2095 if (strlen(password) != 10)
2096 return -EINVAL;
2097
2098 msg = nm_msgb_alloc();
2099 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2100 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2101 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002102 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002103
2104 return abis_nm_sendmsg(bts, msg);
2105}
2106
2107/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2108int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
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;
Harald Welte59b04682009-06-10 05:40:52 +08002113
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_LI, 0x00, 0x00);
2118
2119 if (locked)
2120 tlv_value = BS11_LI_PLL_LOCKED;
2121 else
2122 tlv_value = BS11_LI_PLL_STANDALONE;
2123
2124 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
Daniel Willmann10b07db2010-01-07 00:54:01 +01002129/* Set the calibration value of the PLL (work value/set value)
2130 * It depends on the login which one is changed */
2131int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2132{
2133 struct abis_om_hdr *oh;
2134 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002135 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002136
2137 msg = nm_msgb_alloc();
2138 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2139 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2140 BS11_OBJ_TRX1, 0x00, 0x00);
2141
2142 tlv_value[0] = value>>8;
2143 tlv_value[1] = value&0xff;
2144
2145 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2146
2147 return abis_nm_sendmsg(bts, msg);
2148}
2149
Harald Welte59b04682009-06-10 05:40:52 +08002150int abis_nm_bs11_get_state(struct gsm_bts *bts)
2151{
2152 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2153}
2154
2155/* BS11 SWL */
2156
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002157void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002158
Harald Welte59b04682009-06-10 05:40:52 +08002159struct abis_nm_bs11_sw {
2160 struct gsm_bts *bts;
2161 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002162 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002163 int forced;
2164 struct llist_head file_list;
2165 gsm_cbfn *user_cb; /* specified by the user */
2166};
2167static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2168
2169struct file_list_entry {
2170 struct llist_head list;
2171 char fname[PATH_MAX];
2172};
2173
2174struct file_list_entry *fl_dequeue(struct llist_head *queue)
2175{
2176 struct llist_head *lh;
2177
2178 if (llist_empty(queue))
2179 return NULL;
2180
2181 lh = queue->next;
2182 llist_del(lh);
2183
2184 return llist_entry(lh, struct file_list_entry, list);
2185}
2186
2187static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2188{
2189 char linebuf[255];
2190 struct llist_head *lh, *lh2;
2191 FILE *swl;
2192 int rc = 0;
2193
2194 swl = fopen(bs11_sw->swl_fname, "r");
2195 if (!swl)
2196 return -ENODEV;
2197
2198 /* zero the stale file list, if any */
2199 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2200 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002201 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002202 }
2203
2204 while (fgets(linebuf, sizeof(linebuf), swl)) {
2205 char file_id[12+1];
2206 char file_version[80+1];
2207 struct file_list_entry *fle;
2208 static char dir[PATH_MAX];
2209
2210 if (strlen(linebuf) < 4)
2211 continue;
2212
2213 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2214 if (rc < 0) {
2215 perror("ERR parsing SWL file");
2216 rc = -EINVAL;
2217 goto out;
2218 }
2219 if (rc < 2)
2220 continue;
2221
Harald Welte857e00d2009-06-26 20:25:23 +02002222 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002223 if (!fle) {
2224 rc = -ENOMEM;
2225 goto out;
2226 }
Harald Welte59b04682009-06-10 05:40:52 +08002227
2228 /* construct new filename */
2229 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2230 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2231 strcat(fle->fname, "/");
2232 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2233
2234 llist_add_tail(&fle->list, &bs11_sw->file_list);
2235 }
2236
2237out:
2238 fclose(swl);
2239 return rc;
2240}
2241
2242/* bs11 swload specific callback, passed to abis_nm core swload */
2243static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2244 struct msgb *msg, void *data, void *param)
2245{
2246 struct abis_nm_bs11_sw *bs11_sw = data;
2247 struct file_list_entry *fle;
2248 int rc = 0;
2249
2250 switch (event) {
2251 case NM_MT_LOAD_END_ACK:
2252 fle = fl_dequeue(&bs11_sw->file_list);
2253 if (fle) {
2254 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002255 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002256 bs11_sw->win_size,
2257 bs11_sw->forced,
2258 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002259 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002260 } else {
2261 /* activate the SWL */
2262 rc = abis_nm_software_activate(bs11_sw->bts,
2263 bs11_sw->swl_fname,
2264 bs11_swload_cbfn,
2265 bs11_sw);
2266 }
2267 break;
2268 case NM_MT_LOAD_SEG_ACK:
2269 case NM_MT_LOAD_END_NACK:
2270 case NM_MT_LOAD_INIT_ACK:
2271 case NM_MT_LOAD_INIT_NACK:
2272 case NM_MT_ACTIVATE_SW_NACK:
2273 case NM_MT_ACTIVATE_SW_ACK:
2274 default:
2275 /* fallthrough to the user callback */
2276 if (bs11_sw->user_cb)
2277 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2278 break;
2279 }
2280
2281 return rc;
2282}
2283
2284/* Siemens provides a SWL file that is a mere listing of all the other
2285 * files that are part of a software release. We need to upload first
2286 * the list file, and then each file that is listed in the list file */
2287int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002288 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002289{
2290 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2291 struct file_list_entry *fle;
2292 int rc = 0;
2293
2294 INIT_LLIST_HEAD(&bs11_sw->file_list);
2295 bs11_sw->bts = bts;
2296 bs11_sw->win_size = win_size;
2297 bs11_sw->user_cb = cbfn;
2298 bs11_sw->forced = forced;
2299
2300 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2301 rc = bs11_read_swl_file(bs11_sw);
2302 if (rc < 0)
2303 return rc;
2304
2305 /* dequeue next item in file list */
2306 fle = fl_dequeue(&bs11_sw->file_list);
2307 if (!fle)
2308 return -EINVAL;
2309
2310 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002311 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002312 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002313 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002314 return rc;
2315}
2316
2317#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002318static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002319 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2320 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2321 NM_ATT_BS11_LMT_USER_NAME,
2322
2323 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2324
2325 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2326
2327 NM_ATT_BS11_SW_LOAD_STORED };
2328
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002329static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002330 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2331 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2332 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2333 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2334#endif
2335
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002336static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002337 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2338 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2339 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2340
2341int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2342{
2343 struct abis_om_hdr *oh;
2344 struct msgb *msg = nm_msgb_alloc();
2345
2346 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2347 /* SiemensHW CCTRL object */
2348 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2349 0x03, 0x00, 0x00);
2350 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2351
2352 return abis_nm_sendmsg(bts, msg);
2353}
2354
2355int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2356{
2357 struct abis_om_hdr *oh;
2358 struct msgb *msg = nm_msgb_alloc();
2359 struct bs11_date_time aet;
2360
2361 get_bs11_date_time(&aet);
2362 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2363 /* SiemensHW CCTRL object */
2364 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2365 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002366 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002367
2368 return abis_nm_sendmsg(bts, msg);
2369}
2370
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002371int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002372{
2373 struct abis_om_hdr *oh;
2374 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002375 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002376
2377 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2378 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2379 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2380 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2381
2382 return abis_nm_sendmsg(bts, msg);
2383}
2384
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002385int 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 +02002386{
2387 struct abis_om_hdr *oh;
2388 struct msgb *msg = nm_msgb_alloc();
2389 struct bs11_date_time aet;
2390
2391 get_bs11_date_time(&aet);
2392 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2393 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2394 bport, 0xff, 0x02);
2395 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2396
2397 return abis_nm_sendmsg(bts, msg);
2398}
2399
Harald Welte59b04682009-06-10 05:40:52 +08002400/* ip.access nanoBTS specific commands */
2401static const char ipaccess_magic[] = "com.ipaccess";
2402
2403
2404static int abis_nm_rx_ipacc(struct msgb *msg)
2405{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002406 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002407 struct abis_om_hdr *oh = msgb_l2(msg);
2408 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002409 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002410 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002411 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002412 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002413
2414 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002415 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002416 return -EINVAL;
2417 }
2418
2419 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002420 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002421
Harald Weltec61a90e2011-05-22 22:45:37 +02002422 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002423
Harald Welte5aeedd42009-10-19 22:11:11 +02002424 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002425
2426 switch (foh->msg_type) {
2427 case NM_MT_IPACC_RSL_CONNECT_ACK:
2428 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002429 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2430 memcpy(&addr,
2431 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2432
2433 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2434 }
Harald Welte4206d982009-07-12 09:33:54 +02002435 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002436 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002437 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002438 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002439 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2440 DEBUGPC(DNM, "STREAM=0x%02x ",
2441 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002442 DEBUGPC(DNM, "\n");
2443 break;
2444 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002445 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002446 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002447 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002448 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002449 else
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002450 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002451 break;
2452 case NM_MT_IPACC_SET_NVATTR_ACK:
2453 DEBUGPC(DNM, "SET NVATTR ACK\n");
2454 /* FIXME: decode and show the actual attributes */
2455 break;
2456 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002457 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002458 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 Welte59b04682009-06-10 05:40:52 +08002461 else
Harald Weltede4477a2009-12-24 12:20:20 +01002462 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002463 break;
Harald Welte21460f02009-07-03 11:26:45 +02002464 case NM_MT_IPACC_GET_NVATTR_ACK:
2465 DEBUGPC(DNM, "GET NVATTR ACK\n");
2466 /* FIXME: decode and show the actual attributes */
2467 break;
2468 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002469 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002470 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002471 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002472 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002473 else
Harald Weltede4477a2009-12-24 12:20:20 +01002474 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002475 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002476 case NM_MT_IPACC_SET_ATTR_ACK:
2477 DEBUGPC(DNM, "SET ATTR ACK\n");
2478 break;
2479 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002480 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002481 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002482 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002483 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002484 else
Harald Weltede4477a2009-12-24 12:20:20 +01002485 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002486 break;
Harald Welte59b04682009-06-10 05:40:52 +08002487 default:
2488 DEBUGPC(DNM, "unknown\n");
2489 break;
2490 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002491
2492 /* signal handling */
2493 switch (foh->msg_type) {
2494 case NM_MT_IPACC_RSL_CONNECT_NACK:
2495 case NM_MT_IPACC_SET_NVATTR_NACK:
2496 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002497 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 +01002498 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002499 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002500 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002501 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002502 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 +01002503 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002504 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002505 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002506 default:
2507 break;
2508 }
2509
Harald Welte59b04682009-06-10 05:40:52 +08002510 return 0;
2511}
2512
2513/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002514int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2515 uint8_t obj_class, uint8_t bts_nr,
2516 uint8_t trx_nr, uint8_t ts_nr,
2517 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002518{
2519 struct msgb *msg = nm_msgb_alloc();
2520 struct abis_om_hdr *oh;
2521 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002522 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002523
2524 /* construct the 12.21 OM header, observe the erroneous length */
2525 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2526 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2527 oh->mdisc = ABIS_OM_MDISC_MANUF;
2528
2529 /* add the ip.access magic */
2530 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2531 *data++ = sizeof(ipaccess_magic);
2532 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2533
2534 /* fill the 12.21 FOM header */
2535 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2536 foh->msg_type = msg_type;
2537 foh->obj_class = obj_class;
2538 foh->obj_inst.bts_nr = bts_nr;
2539 foh->obj_inst.trx_nr = trx_nr;
2540 foh->obj_inst.ts_nr = ts_nr;
2541
2542 if (attr && attr_len) {
2543 data = msgb_put(msg, attr_len);
2544 memcpy(data, attr, attr_len);
2545 }
2546
2547 return abis_nm_sendmsg(bts, msg);
2548}
2549
2550/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002551int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002552 int attr_len)
2553{
Harald Weltef12c1052010-01-07 20:39:42 +01002554 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2555 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002556 attr_len);
2557}
2558
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002559int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002560 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002561{
2562 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002563 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002564 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2565 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2566
2567 int attr_len = sizeof(attr);
2568
2569 ia.s_addr = htonl(ip);
2570 attr[1] = stream;
2571 attr[3] = port >> 8;
2572 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002573 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002574
2575 /* if ip == 0, we use the default IP */
2576 if (ip == 0)
2577 attr_len -= 5;
2578
2579 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002580 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002581
2582 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2583 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2584 trx->nr, 0xff, attr, attr_len);
2585}
2586
Harald Welte59b04682009-06-10 05:40:52 +08002587/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002588int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002589{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002590 struct abis_om_hdr *oh;
2591 struct msgb *msg = nm_msgb_alloc();
2592
2593 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2594 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2595 trx->bts->nr, trx->nr, 0xff);
2596
2597 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002598}
Harald Welte0dfc6232009-10-24 10:20:41 +02002599
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002600int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2601 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2602 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002603{
2604 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2605 obj_class, bts_nr, trx_nr, ts_nr,
2606 attr, attr_len);
2607}
Harald Weltebeeae412009-11-12 14:48:42 +01002608
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002609void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002610{
2611 /* we simply reuse the GSM48 function and overwrite the RAC
2612 * with the Cell ID */
2613 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002614 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002615}
2616
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002617void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2618{
2619 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2620
Harald Welte69f6f812011-05-30 12:07:53 +02002621 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002622 if (!trx->bts || !trx->bts->oml_link)
2623 return;
2624
2625 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2626 trx->bts->bts_nr, trx->nr, 0xff,
2627 new_state);
2628}
2629
Harald Welte453141f2010-03-25 11:45:30 +08002630static const struct value_string ipacc_testres_names[] = {
2631 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2632 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2633 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2634 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2635 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2636 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002637};
2638
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002639const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002640{
Harald Welte453141f2010-03-25 11:45:30 +08002641 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002642}
2643
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002644void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002645{
2646 cid->mcc = (buf[0] & 0xf) * 100;
2647 cid->mcc += (buf[0] >> 4) * 10;
2648 cid->mcc += (buf[1] & 0xf) * 1;
2649
2650 if (buf[1] >> 4 == 0xf) {
2651 cid->mnc = (buf[2] & 0xf) * 10;
2652 cid->mnc += (buf[2] >> 4) * 1;
2653 } else {
2654 cid->mnc = (buf[2] & 0xf) * 100;
2655 cid->mnc += (buf[2] >> 4) * 10;
2656 cid->mnc += (buf[1] >> 4) * 1;
2657 }
2658
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002659 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2660 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002661}
2662
Harald Weltebeeae412009-11-12 14:48:42 +01002663/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002664int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002665{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002666 uint8_t *cur = buf;
Holger Hans Peter Freyther1a9f3ee2012-09-11 11:55:03 +02002667 uint16_t len __attribute__((unused));
Harald Weltebeeae412009-11-12 14:48:42 +01002668
Harald Welteb784df82010-07-22 18:14:36 +02002669 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002670
2671 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2672 return -EINVAL;
2673 cur++;
2674
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002675 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002676 cur += 2;
2677
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002678 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002679 cur += 2;
2680
2681 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2682 binf->freq_qual = *cur >> 2;
2683
Harald Welteb784df82010-07-22 18:14:36 +02002684 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002685 binf->arfcn |= *cur++;
2686
2687 if (binf->info_type & IPAC_BINF_RXLEV)
2688 binf->rx_lev = *cur & 0x3f;
2689 cur++;
2690
2691 if (binf->info_type & IPAC_BINF_RXQUAL)
2692 binf->rx_qual = *cur & 0x7;
2693 cur++;
2694
2695 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002696 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002697 cur += 2;
2698
2699 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002700 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002701 cur += 2;
2702
2703 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002704 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002705 cur += 4;
2706
Harald Welte22cb81f2010-07-30 22:34:42 +02002707#if 0
2708 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002709 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002710#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002711 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002712 cur++;
2713
Harald Weltebfc21092009-11-13 11:56:05 +01002714 ipac_parse_cgi(&binf->cgi, cur);
2715 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002716
2717 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2718 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2719 cur += sizeof(binf->ba_list_si2);
2720 }
2721
2722 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2723 memcpy(binf->ba_list_si2bis, cur,
2724 sizeof(binf->ba_list_si2bis));
2725 cur += sizeof(binf->ba_list_si2bis);
2726 }
2727
2728 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2729 memcpy(binf->ba_list_si2ter, cur,
2730 sizeof(binf->ba_list_si2ter));
2731 cur += sizeof(binf->ba_list_si2ter);
2732 }
2733
2734 return 0;
2735}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002736
2737void abis_nm_clear_queue(struct gsm_bts *bts)
2738{
2739 struct msgb *msg;
2740
2741 while (!llist_empty(&bts->abis_queue)) {
2742 msg = msgb_dequeue(&bts->abis_queue);
2743 msgb_free(msg);
2744 }
2745
2746 bts->abis_nm_pend = 0;
2747}