blob: a01826bd563fa100e072f0c4e46f45e3f49ce2c5 [file] [log] [blame]
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte59b04682009-06-10 05:40:52 +08002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte0e3e88e2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte59b04682009-06-10 05:40:52 +080011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte0e3e88e2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte59b04682009-06-10 05:40:52 +080017 *
Harald Welte0e3e88e2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte59b04682009-06-10 05:40:52 +080020 *
21 */
22
23
24#include <errno.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <libgen.h>
30#include <time.h>
31#include <limits.h>
32
Harald Welte59b04682009-06-10 05:40:52 +080033#include <sys/stat.h>
34#include <netinet/in.h>
35#include <arpa/inet.h>
36
37#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Harald Weltec61a90e2011-05-22 22:45:37 +020041#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayusodd5fff42011-03-22 16:47:59 +010042#include <osmocom/core/talloc.h>
Harald Welte59b04682009-06-10 05:40:52 +080043#include <openbsc/abis_nm.h>
44#include <openbsc/misdn.h>
45#include <openbsc/signal.h>
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +020046#include <osmocom/abis/e1_input.h>
Harald Welte59b04682009-06-10 05:40:52 +080047
48#define OM_ALLOC_SIZE 1024
49#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +010050#define IPACC_SEGMENT_SIZE 245
Harald Welte59b04682009-06-10 05:40:52 +080051
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020052int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte59b04682009-06-10 05:40:52 +080053{
Harald Welte59698fb2010-01-10 18:01:52 +010054 if (!bts->model)
55 return -EIO;
56 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte59b04682009-06-10 05:40:52 +080057}
58
59static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
60{
61 int i;
62
63 for (i = 0; i < size; i++) {
64 if (arr[i] == mt)
65 return 1;
66 }
67
68 return 0;
69}
70
71#if 0
72/* is this msgtype the usual ACK/NACK type ? */
73static int is_ack_nack(enum abis_nm_msgtype mt)
74{
75 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
76}
77#endif
78
79/* is this msgtype a report ? */
80static int is_report(enum abis_nm_msgtype mt)
81{
Harald Weltec61a90e2011-05-22 22:45:37 +020082 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte59b04682009-06-10 05:40:52 +080083}
84
85#define MT_ACK(x) (x+1)
86#define MT_NACK(x) (x+2)
87
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020088static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte59b04682009-06-10 05:40:52 +080089{
90 oh->mdisc = ABIS_OM_MDISC_FOM;
91 oh->placement = ABIS_OM_PLACEMENT_ONLY;
92 oh->sequence = 0;
93 oh->length = len;
94}
95
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020096static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
97 uint8_t msg_type, uint8_t obj_class,
98 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte59b04682009-06-10 05:40:52 +080099{
100 struct abis_om_fom_hdr *foh =
101 (struct abis_om_fom_hdr *) oh->data;
102
103 fill_om_hdr(oh, len+sizeof(*foh));
104 foh->msg_type = msg_type;
105 foh->obj_class = obj_class;
106 foh->obj_inst.bts_nr = bts_nr;
107 foh->obj_inst.trx_nr = trx_nr;
108 foh->obj_inst.ts_nr = ts_nr;
109}
110
111static struct msgb *nm_msgb_alloc(void)
112{
Harald Welte9cfc9352009-06-26 19:39:35 +0200113 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
114 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800115}
116
Harald Welte607044f2011-09-26 23:43:23 +0200117int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200118{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200119 msg->l2h = msg->data;
120
121 if (!msg->dst) {
122 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
123 return -EINVAL;
124 }
125
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200126 return abis_sendmsg(msg);
127}
128
Harald Welte59b04682009-06-10 05:40:52 +0800129/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100130static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800131{
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200132 msg->dst = bts->oml_link;
Harald Welte59b04682009-06-10 05:40:52 +0800133
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100134 /* queue OML messages */
135 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
136 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200137 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100138 } else {
139 msgb_enqueue(&bts->abis_queue, msg);
140 return 0;
141 }
142
143}
144
145int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
146{
147 OBSC_NM_W_ACK_CB(msg) = 1;
148 return abis_nm_queue_msg(bts, msg);
149}
150
151static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
152{
153 OBSC_NM_W_ACK_CB(msg) = 0;
154 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800155}
156
157static int abis_nm_rcvmsg_sw(struct msgb *mb);
158
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100159int nm_is_running(struct gsm_nm_state *s) {
160 return (s->operational == NM_OPSTATE_ENABLED) && (
161 (s->availability == NM_AVSTATE_OK) ||
162 (s->availability == 0xff)
163 );
164}
165
Harald Welte59b04682009-06-10 05:40:52 +0800166/* Update the administrative state of a given object in our in-memory data
167 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200168static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
169 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800170{
171 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100172 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800173
Harald Weltea348c082011-03-06 21:20:38 +0100174 memset(&nsd, 0, sizeof(nsd));
175
Harald Weltec6ed9282011-06-06 18:31:20 +0200176 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100177 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100178 return -EINVAL;
Harald Weltec6ed9282011-06-06 18:31:20 +0200179 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800180 if (!nm_state)
181 return -1;
182
183 new_state = *nm_state;
184 new_state.administrative = adm_state;
185
Harald Welteb03c4482011-03-06 22:11:32 +0100186 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100187 nsd.obj_class = obj_class;
188 nsd.old_state = nm_state;
189 nsd.new_state = &new_state;
190 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200191 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800192
193 nm_state->administrative = adm_state;
194
Harald Welte4c826f72011-01-14 15:55:42 +0100195 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800196}
197
198static int abis_nm_rx_statechg_rep(struct msgb *mb)
199{
200 struct abis_om_hdr *oh = msgb_l2(mb);
201 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200202 struct e1inp_sign_link *sign_link = mb->dst;
203 struct gsm_bts *bts = sign_link->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +0800204 struct tlv_parsed tp;
205 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800206
207 DEBUGPC(DNM, "STATE CHG: ");
208
209 memset(&new_state, 0, sizeof(new_state));
210
Harald Weltec6ed9282011-06-06 18:31:20 +0200211 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800212 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100213 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800214 return -EINVAL;
215 }
216
217 new_state = *nm_state;
218
Harald Welte59698fb2010-01-10 18:01:52 +0100219 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800220 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
221 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200222 DEBUGPC(DNM, "OP_STATE=%s ",
223 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800224 }
225 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
226 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
227 new_state.availability = 0xff;
228 else
229 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Weltec61a90e2011-05-22 22:45:37 +0200230 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
231 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800232 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100233 } else
234 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800235 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
236 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200238 get_value_string(abis_nm_adm_state_names,
239 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800240 }
241 DEBUGPC(DNM, "\n");
242
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100243 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
244 new_state.operational != nm_state->operational ||
245 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800246 /* Update the operational state of a given object in our in-memory data
247 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100248 struct nm_statechg_signal_data nsd;
Harald Weltec6ed9282011-06-06 18:31:20 +0200249 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100250 nsd.obj_class = foh->obj_class;
251 nsd.old_state = nm_state;
252 nsd.new_state = &new_state;
253 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100254 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200255 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100256 nm_state->operational = new_state.operational;
257 nm_state->availability = new_state.availability;
258 if (nm_state->administrative == 0)
259 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800260 }
261#if 0
262 if (op_state == 1) {
263 /* try to enable objects that are disabled */
264 abis_nm_opstart(bts, foh->obj_class,
265 foh->obj_inst.bts_nr,
266 foh->obj_inst.trx_nr,
267 foh->obj_inst.ts_nr);
268 }
269#endif
270 return 0;
271}
272
273static int rx_fail_evt_rep(struct msgb *mb)
274{
275 struct abis_om_hdr *oh = msgb_l2(mb);
276 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200277 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800278 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100279 const uint8_t *p_val;
280 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800281
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200282 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800283
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200284 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800285
286 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-05-22 22:45:37 +0200287 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
288 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800289 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200290 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
291 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100292 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
293 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200294 LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100295 }
296 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
297 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
298 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
299 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100301 talloc_free(p_text);
302 }
303 }
Harald Welte59b04682009-06-10 05:40:52 +0800304
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200305 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800306
307 return 0;
308}
309
310static int abis_nm_rcvmsg_report(struct msgb *mb)
311{
312 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200313 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800314
Harald Weltec61a90e2011-05-22 22:45:37 +0200315 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800316
317 //nmh->cfg->report_cb(mb, foh);
318
319 switch (mt) {
320 case NM_MT_STATECHG_EVENT_REP:
321 return abis_nm_rx_statechg_rep(mb);
322 break;
323 case NM_MT_SW_ACTIVATED_REP:
324 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200325 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800326 break;
327 case NM_MT_FAILURE_EVENT_REP:
328 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200329 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800330 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200331 case NM_MT_TEST_REP:
332 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200333 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200334 break;
Harald Welte59b04682009-06-10 05:40:52 +0800335 default:
336 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
337 break;
338
339 };
340
341 return 0;
342}
343
344/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200345static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
346 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800347{
348 struct abis_om_hdr *oh;
349 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200350 uint8_t len = swdesc_len;
351 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800352
353 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
354 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
355
356 trailer = msgb_put(msg, swdesc_len);
357 memcpy(trailer, sw_desc, swdesc_len);
358
359 return abis_nm_sendmsg(bts, msg);
360}
361
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200362static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100363{
364 static const struct tlv_definition sw_descr_def = {
365 .def = {
366 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
367 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
368 },
369 };
370
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200371 uint8_t tag;
372 uint16_t tag_len;
373 const uint8_t *val;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100374 int ofs = 0, len;
375
376 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
377 * nested nature and the fact you have to assume it contains only two sub
378 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
379
380 if (sw_descr[0] != NM_ATT_SW_DESCR) {
381 DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
382 return -1;
383 }
384 ofs += 1;
385
386 len = tlv_parse_one(&tag, &tag_len, &val,
387 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
388 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
389 DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
390 return -2;
391 }
392 ofs += len;
393
394 len = tlv_parse_one(&tag, &tag_len, &val,
395 &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
396 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
397 DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
398 return -3;
399 }
400 ofs += len;
401
402 return ofs;
403}
404
Harald Welte59b04682009-06-10 05:40:52 +0800405static int abis_nm_rx_sw_act_req(struct msgb *mb)
406{
407 struct abis_om_hdr *oh = msgb_l2(mb);
408 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200409 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200410 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200411 const uint8_t *sw_config;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100412 int ret, sw_config_len, sw_descr_len;
Harald Welte59b04682009-06-10 05:40:52 +0800413
Harald Weltec61a90e2011-05-22 22:45:37 +0200414 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200415
416 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800417
Harald Welte3055e332010-03-14 15:37:43 +0800418 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800419
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200420 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800421 foh->obj_inst.bts_nr,
422 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800423 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800424 foh->data, oh->length-sizeof(*foh));
425
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200426 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200427 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
428 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
429 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
430 DEBUGP(DNM, "SW config not found! Can't continue.\n");
431 return -EINVAL;
432 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200433 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200434 }
435
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100436 /* Use the first SW_DESCR present in SW config */
437 sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
438 if (sw_descr_len < 0)
439 return -EINVAL;
Mike Haben322fc582009-10-01 14:56:13 +0200440
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200441 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800442 foh->obj_inst.bts_nr,
443 foh->obj_inst.trx_nr,
444 foh->obj_inst.ts_nr,
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100445 sw_config, sw_descr_len);
Harald Welte59b04682009-06-10 05:40:52 +0800446}
447
448/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
449static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
450{
451 struct abis_om_hdr *oh = msgb_l2(mb);
452 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200453 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800454 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200455 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800456
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200457 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800458 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
459 return -EINVAL;
460
461 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
462
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200463 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800464}
465
466static int abis_nm_rx_lmt_event(struct msgb *mb)
467{
468 struct abis_om_hdr *oh = msgb_l2(mb);
469 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200470 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800471 struct tlv_parsed tp;
472
473 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200474 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800475 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
476 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200477 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800478 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
479 }
480 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
481 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200482 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800483 DEBUGPC(DNM, "Level=%u ", level);
484 }
485 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
486 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
487 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
488 DEBUGPC(DNM, "Username=%s ", name);
489 }
490 DEBUGPC(DNM, "\n");
491 /* FIXME: parse LMT LOGON TIME */
492 return 0;
493}
494
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200495void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100496{
497 int wait = 0;
498 struct msgb *msg;
499 /* the queue is empty */
500 while (!llist_empty(&bts->abis_queue)) {
501 msg = msgb_dequeue(&bts->abis_queue);
502 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200503 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100504
505 if (wait)
506 break;
507 }
508
509 bts->abis_nm_pend = wait;
510}
511
Harald Welte59b04682009-06-10 05:40:52 +0800512/* Receive a OML NM Message from BTS */
513static int abis_nm_rcvmsg_fom(struct msgb *mb)
514{
515 struct abis_om_hdr *oh = msgb_l2(mb);
516 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200517 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200518 uint8_t mt = foh->msg_type;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100519 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800520
521 /* check for unsolicited message */
522 if (is_report(mt))
523 return abis_nm_rcvmsg_report(mb);
524
Harald Weltec61a90e2011-05-22 22:45:37 +0200525 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800526 return abis_nm_rcvmsg_sw(mb);
527
Harald Weltec61a90e2011-05-22 22:45:37 +0200528 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800529 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800530 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200531
Harald Weltec61a90e2011-05-22 22:45:37 +0200532 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200533
Harald Weltec61a90e2011-05-22 22:45:37 +0200534 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800535
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200536 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800537 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200538 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200539 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800540 else
541 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200542
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800543 nack_data.msg = mb;
544 nack_data.mt = mt;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200545 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200546 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200547 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800548 }
549#if 0
550 /* check if last message is to be acked */
551 if (is_ack_nack(nmh->last_msgtype)) {
552 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100553 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800554 /* we got our ACK, continue sending the next msg */
555 } else if (mt == MT_NACK(nmh->last_msgtype)) {
556 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100557 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800558 /* FIXME: somehow signal this to the caller */
559 } else {
560 /* really strange things happen */
561 return -EINVAL;
562 }
563 }
564#endif
565
566 switch (mt) {
567 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100568 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800569 break;
570 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100571 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800572 break;
573 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100574 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800575 break;
Harald Welte204317e2009-08-06 17:58:31 +0200576 case NM_MT_CONN_MDROP_LINK_ACK:
577 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
578 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100579 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200580 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100581 break;
582 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200583 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100584 break;
Harald Welte08011e22011-03-04 13:41:31 +0100585 case NM_MT_SET_BTS_ATTR_ACK:
586 /* The HSL wants an OPSTART _after_ the SI has been set */
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200587 if (sign_link->trx->bts->type == GSM_BTS_TYPE_HSL_FEMTO) {
588 abis_nm_opstart(sign_link->trx->bts, NM_OC_BTS, 255, 255, 255);
Harald Welte08011e22011-03-04 13:41:31 +0100589 }
590 break;
Harald Welte59b04682009-06-10 05:40:52 +0800591 }
592
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200593 abis_nm_queue_send_next(sign_link->trx->bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100594 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800595}
596
597static int abis_nm_rx_ipacc(struct msgb *mb);
598
599static int abis_nm_rcvmsg_manuf(struct msgb *mb)
600{
601 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200602 struct e1inp_sign_link *sign_link = mb->dst;
603 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800604
605 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100606 case GSM_BTS_TYPE_NANOBTS:
Harald Welte59b04682009-06-10 05:40:52 +0800607 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200608 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800609 break;
610 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100611 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
612 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800613 rc = 0;
614 break;
615 }
616
617 return rc;
618}
619
620/* High-Level API */
621/* Entry-point where L2 OML from BTS enters the NM code */
622int abis_nm_rcvmsg(struct msgb *msg)
623{
624 struct abis_om_hdr *oh = msgb_l2(msg);
625 int rc = 0;
626
627 /* Various consistency checks */
628 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100629 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800630 oh->placement);
Harald Welte8b39d732010-07-22 20:12:09 +0200631 if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
632 return -EINVAL;
Harald Welte59b04682009-06-10 05:40:52 +0800633 }
634 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100635 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800636 oh->sequence);
637 return -EINVAL;
638 }
639#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200640 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800641 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
642 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100643 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800644 oh->length + sizeof(*oh), l2_len);
645 return -EINVAL;
646 }
647 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100648 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 +0800649#endif
650 msg->l3h = (unsigned char *)oh + sizeof(*oh);
651
652 switch (oh->mdisc) {
653 case ABIS_OM_MDISC_FOM:
654 rc = abis_nm_rcvmsg_fom(msg);
655 break;
656 case ABIS_OM_MDISC_MANUF:
657 rc = abis_nm_rcvmsg_manuf(msg);
658 break;
659 case ABIS_OM_MDISC_MMI:
660 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100661 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800662 oh->mdisc);
663 break;
664 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100665 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800666 oh->mdisc);
667 return -EINVAL;
668 }
669
670 msgb_free(msg);
671 return rc;
672}
673
674#if 0
675/* initialized all resources */
676struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
677{
678 struct abis_nm_h *nmh;
679
680 nmh = malloc(sizeof(*nmh));
681 if (!nmh)
682 return NULL;
683
684 nmh->cfg = cfg;
685
686 return nmh;
687}
688
689/* free all resources */
690void abis_nm_fini(struct abis_nm_h *nmh)
691{
692 free(nmh);
693}
694#endif
695
696/* Here we are trying to define a high-level API that can be used by
697 * the actual BSC implementation. However, the architecture is currently
698 * still under design. Ideally the calls to this API would be synchronous,
699 * while the underlying stack behind the APi runs in a traditional select
700 * based state machine.
701 */
702
703/* 6.2 Software Load: */
704enum sw_state {
705 SW_STATE_NONE,
706 SW_STATE_WAIT_INITACK,
707 SW_STATE_WAIT_SEGACK,
708 SW_STATE_WAIT_ENDACK,
709 SW_STATE_WAIT_ACTACK,
710 SW_STATE_ERROR,
711};
712
713struct abis_nm_sw {
714 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800715 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800716 gsm_cbfn *cbfn;
717 void *cb_data;
718 int forced;
719
720 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200721 uint8_t obj_class;
722 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800723
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200724 uint8_t file_id[255];
725 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800726
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200727 uint8_t file_version[255];
728 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800729
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200730 uint8_t window_size;
731 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800732
733 int fd;
734 FILE *stream;
735 enum sw_state state;
736 int last_seg;
737};
738
739static struct abis_nm_sw g_sw;
740
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100741static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
742{
743 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
744 msgb_v_put(msg, NM_ATT_SW_DESCR);
745 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
746 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
747 sw->file_version);
748 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
749 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
750 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
751 sw->file_version);
752 } else {
753 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
754 }
755}
756
Harald Welte59b04682009-06-10 05:40:52 +0800757/* 6.2.1 / 8.3.1: Load Data Initiate */
758static int sw_load_init(struct abis_nm_sw *sw)
759{
760 struct abis_om_hdr *oh;
761 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200762 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800763
764 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
765 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
766 sw->obj_instance[0], sw->obj_instance[1],
767 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100768
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100769 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800770 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
771
772 return abis_nm_sendmsg(sw->bts, msg);
773}
774
775static int is_last_line(FILE *stream)
776{
777 char next_seg_buf[256];
778 long pos;
779
780 /* check if we're sending the last line */
781 pos = ftell(stream);
782 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
783 fseek(stream, pos, SEEK_SET);
784 return 1;
785 }
786
787 fseek(stream, pos, SEEK_SET);
788 return 0;
789}
790
791/* 6.2.2 / 8.3.2 Load Data Segment */
792static int sw_load_segment(struct abis_nm_sw *sw)
793{
794 struct abis_om_hdr *oh;
795 struct msgb *msg = nm_msgb_alloc();
796 char seg_buf[256];
797 char *line_buf = seg_buf+2;
798 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200799 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800800
801 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
802
803 switch (sw->bts->type) {
804 case GSM_BTS_TYPE_BS11:
805 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
806 perror("fgets reading segment");
807 return -EINVAL;
808 }
809 seg_buf[0] = 0x00;
810
811 /* check if we're sending the last line */
812 sw->last_seg = is_last_line(sw->stream);
813 if (sw->last_seg)
814 seg_buf[1] = 0;
815 else
816 seg_buf[1] = 1 + sw->seg_in_window++;
817
818 len = strlen(line_buf) + 2;
819 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200820 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800821 /* BS11 wants CR + LF in excess of the TLV length !?! */
822 tlv[1] -= 2;
823
824 /* we only now know the exact length for the OM hdr */
825 len = strlen(line_buf)+2;
826 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100827 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200828 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100829 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
830 if (len < 0) {
831 perror("read failed");
832 return -EINVAL;
833 }
834
835 if (len != IPACC_SEGMENT_SIZE)
836 sw->last_seg = 1;
837
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100838 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200839 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100840 len += 3;
841 break;
842 }
Harald Welte59b04682009-06-10 05:40:52 +0800843 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100844 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800845 /* FIXME: Other BTS types */
846 return -1;
847 }
848
849 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
850 sw->obj_instance[0], sw->obj_instance[1],
851 sw->obj_instance[2]);
852
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100853 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800854}
855
856/* 6.2.4 / 8.3.4 Load Data End */
857static int sw_load_end(struct abis_nm_sw *sw)
858{
859 struct abis_om_hdr *oh;
860 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200861 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800862
863 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
864 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
865 sw->obj_instance[0], sw->obj_instance[1],
866 sw->obj_instance[2]);
867
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100868 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800869 return abis_nm_sendmsg(sw->bts, msg);
870}
871
872/* Activate the specified software into the BTS */
873static int sw_activate(struct abis_nm_sw *sw)
874{
875 struct abis_om_hdr *oh;
876 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200877 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800878
879 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
880 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
881 sw->obj_instance[0], sw->obj_instance[1],
882 sw->obj_instance[2]);
883
884 /* FIXME: this is BS11 specific format */
885 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
886 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
887 sw->file_version);
888
889 return abis_nm_sendmsg(sw->bts, msg);
890}
891
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100892struct sdp_firmware {
893 char magic[4];
894 char more_magic[4];
895 unsigned int header_length;
896 unsigned int file_length;
897} __attribute__ ((packed));
898
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100899static int parse_sdp_header(struct abis_nm_sw *sw)
900{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100901 struct sdp_firmware firmware_header;
902 int rc;
903 struct stat stat;
904
905 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
906 if (rc != sizeof(firmware_header)) {
907 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
908 return -1;
909 }
910
911 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
912 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
913 return -1;
914 }
915
916 if (firmware_header.more_magic[0] != 0x10 ||
917 firmware_header.more_magic[1] != 0x02 ||
918 firmware_header.more_magic[2] != 0x00 ||
919 firmware_header.more_magic[3] != 0x00) {
920 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
921 return -1;
922 }
923
924
925 if (fstat(sw->fd, &stat) == -1) {
926 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
927 return -1;
928 }
929
930 if (ntohl(firmware_header.file_length) != stat.st_size) {
931 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
932 return -1;
933 }
934
935 /* go back to the start as we checked the whole filesize.. */
936 lseek(sw->fd, 0l, SEEK_SET);
937 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
938 "There might be checksums in the file that are not\n"
939 "verified and incomplete firmware might be flashed.\n"
940 "There is absolutely no WARRANTY that flashing will\n"
941 "work.\n");
942 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100943}
944
Harald Welte59b04682009-06-10 05:40:52 +0800945static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
946{
947 char file_id[12+1];
948 char file_version[80+1];
949 int rc;
950
951 sw->fd = open(fname, O_RDONLY);
952 if (sw->fd < 0)
953 return sw->fd;
954
955 switch (sw->bts->type) {
956 case GSM_BTS_TYPE_BS11:
957 sw->stream = fdopen(sw->fd, "r");
958 if (!sw->stream) {
959 perror("fdopen");
960 return -1;
961 }
962 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200963 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +0800964 file_id, file_version);
965 if (rc != 2) {
966 perror("parsing header line of software file");
967 return -1;
968 }
969 strcpy((char *)sw->file_id, file_id);
970 sw->file_id_len = strlen(file_id);
971 strcpy((char *)sw->file_version, file_version);
972 sw->file_version_len = strlen(file_version);
973 /* rewind to start of file */
974 rewind(sw->stream);
975 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100976 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100977 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100978 rc = parse_sdp_header(sw);
979 if (rc < 0) {
980 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
981 return -1;
982 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100983
984 strcpy((char *)sw->file_id, "id");
985 sw->file_id_len = 3;
986 strcpy((char *)sw->file_version, "version");
987 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +0100988 break;
Harald Welte59b04682009-06-10 05:40:52 +0800989 default:
990 /* We don't know how to treat them yet */
991 close(sw->fd);
992 return -EINVAL;
993 }
994
995 return 0;
996}
997
998static void sw_close_file(struct abis_nm_sw *sw)
999{
1000 switch (sw->bts->type) {
1001 case GSM_BTS_TYPE_BS11:
1002 fclose(sw->stream);
1003 break;
1004 default:
1005 close(sw->fd);
1006 break;
1007 }
1008}
1009
1010/* Fill the window */
1011static int sw_fill_window(struct abis_nm_sw *sw)
1012{
1013 int rc;
1014
1015 while (sw->seg_in_window < sw->window_size) {
1016 rc = sw_load_segment(sw);
1017 if (rc < 0)
1018 return rc;
1019 if (sw->last_seg)
1020 break;
1021 }
1022 return 0;
1023}
1024
1025/* callback function from abis_nm_rcvmsg() handler */
1026static int abis_nm_rcvmsg_sw(struct msgb *mb)
1027{
1028 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001029 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001030 int rc = -1;
1031 struct abis_nm_sw *sw = &g_sw;
1032 enum sw_state old_state = sw->state;
1033
1034 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1035
1036 switch (sw->state) {
1037 case SW_STATE_WAIT_INITACK:
1038 switch (foh->msg_type) {
1039 case NM_MT_LOAD_INIT_ACK:
1040 /* fill window with segments */
1041 if (sw->cbfn)
1042 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1043 NM_MT_LOAD_INIT_ACK, mb,
1044 sw->cb_data, NULL);
1045 rc = sw_fill_window(sw);
1046 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001047 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001048 break;
1049 case NM_MT_LOAD_INIT_NACK:
1050 if (sw->forced) {
1051 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1052 "Init NACK\n");
1053 if (sw->cbfn)
1054 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1055 NM_MT_LOAD_INIT_ACK, mb,
1056 sw->cb_data, NULL);
1057 rc = sw_fill_window(sw);
1058 sw->state = SW_STATE_WAIT_SEGACK;
1059 } else {
1060 DEBUGP(DNM, "Software Load Init NACK\n");
1061 /* FIXME: cause */
1062 if (sw->cbfn)
1063 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1064 NM_MT_LOAD_INIT_NACK, mb,
1065 sw->cb_data, NULL);
1066 sw->state = SW_STATE_ERROR;
1067 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001068 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001069 break;
1070 }
1071 break;
1072 case SW_STATE_WAIT_SEGACK:
1073 switch (foh->msg_type) {
1074 case NM_MT_LOAD_SEG_ACK:
1075 if (sw->cbfn)
1076 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1077 NM_MT_LOAD_SEG_ACK, mb,
1078 sw->cb_data, NULL);
1079 sw->seg_in_window = 0;
1080 if (!sw->last_seg) {
1081 /* fill window with more segments */
1082 rc = sw_fill_window(sw);
1083 sw->state = SW_STATE_WAIT_SEGACK;
1084 } else {
1085 /* end the transfer */
1086 sw->state = SW_STATE_WAIT_ENDACK;
1087 rc = sw_load_end(sw);
1088 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001089 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001090 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001091 case NM_MT_LOAD_ABORT:
1092 if (sw->cbfn)
1093 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1094 NM_MT_LOAD_ABORT, mb,
1095 sw->cb_data, NULL);
1096 break;
Harald Welte59b04682009-06-10 05:40:52 +08001097 }
1098 break;
1099 case SW_STATE_WAIT_ENDACK:
1100 switch (foh->msg_type) {
1101 case NM_MT_LOAD_END_ACK:
1102 sw_close_file(sw);
1103 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1104 sw->bts->nr);
1105 sw->state = SW_STATE_NONE;
1106 if (sw->cbfn)
1107 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1108 NM_MT_LOAD_END_ACK, mb,
1109 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001110 rc = 0;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001111 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001112 break;
1113 case NM_MT_LOAD_END_NACK:
1114 if (sw->forced) {
1115 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1116 "End NACK\n");
1117 sw->state = SW_STATE_NONE;
1118 if (sw->cbfn)
1119 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1120 NM_MT_LOAD_END_ACK, mb,
1121 sw->cb_data, NULL);
1122 } else {
1123 DEBUGP(DNM, "Software Load End NACK\n");
1124 /* FIXME: cause */
1125 sw->state = SW_STATE_ERROR;
1126 if (sw->cbfn)
1127 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1128 NM_MT_LOAD_END_NACK, mb,
1129 sw->cb_data, NULL);
1130 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001131 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001132 break;
1133 }
1134 case SW_STATE_WAIT_ACTACK:
1135 switch (foh->msg_type) {
1136 case NM_MT_ACTIVATE_SW_ACK:
1137 /* we're done */
1138 DEBUGP(DNM, "Activate Software DONE!\n");
1139 sw->state = SW_STATE_NONE;
1140 rc = 0;
1141 if (sw->cbfn)
1142 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1143 NM_MT_ACTIVATE_SW_ACK, mb,
1144 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001145 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001146 break;
1147 case NM_MT_ACTIVATE_SW_NACK:
1148 DEBUGP(DNM, "Activate Software NACK\n");
1149 /* FIXME: cause */
1150 sw->state = SW_STATE_ERROR;
1151 if (sw->cbfn)
1152 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1153 NM_MT_ACTIVATE_SW_NACK, mb,
1154 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001155 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001156 break;
1157 }
1158 case SW_STATE_NONE:
1159 switch (foh->msg_type) {
1160 case NM_MT_ACTIVATE_SW_ACK:
1161 rc = 0;
1162 break;
1163 }
1164 break;
1165 case SW_STATE_ERROR:
1166 break;
1167 }
1168
1169 if (rc)
1170 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1171 foh->msg_type, old_state, sw->state);
1172
1173 return rc;
1174}
1175
1176/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001177int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001178 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001179 gsm_cbfn *cbfn, void *cb_data)
1180{
1181 struct abis_nm_sw *sw = &g_sw;
1182 int rc;
1183
1184 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1185 bts->nr, fname);
1186
1187 if (sw->state != SW_STATE_NONE)
1188 return -EBUSY;
1189
1190 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001191 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001192
1193 switch (bts->type) {
1194 case GSM_BTS_TYPE_BS11:
1195 sw->obj_class = NM_OC_SITE_MANAGER;
1196 sw->obj_instance[0] = 0xff;
1197 sw->obj_instance[1] = 0xff;
1198 sw->obj_instance[2] = 0xff;
1199 break;
1200 case GSM_BTS_TYPE_NANOBTS:
1201 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001202 sw->obj_instance[0] = sw->bts->nr;
1203 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001204 sw->obj_instance[2] = 0xff;
1205 break;
1206 case GSM_BTS_TYPE_UNKNOWN:
1207 default:
1208 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1209 return -1;
1210 break;
1211 }
Harald Welte59b04682009-06-10 05:40:52 +08001212 sw->window_size = win_size;
1213 sw->state = SW_STATE_WAIT_INITACK;
1214 sw->cbfn = cbfn;
1215 sw->cb_data = cb_data;
1216 sw->forced = forced;
1217
1218 rc = sw_open_file(sw, fname);
1219 if (rc < 0) {
1220 sw->state = SW_STATE_NONE;
1221 return rc;
1222 }
1223
1224 return sw_load_init(sw);
1225}
1226
1227int abis_nm_software_load_status(struct gsm_bts *bts)
1228{
1229 struct abis_nm_sw *sw = &g_sw;
1230 struct stat st;
1231 int rc, percent;
1232
1233 rc = fstat(sw->fd, &st);
1234 if (rc < 0) {
1235 perror("ERROR during stat");
1236 return rc;
1237 }
1238
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001239 if (sw->stream)
1240 percent = (ftell(sw->stream) * 100) / st.st_size;
1241 else
1242 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001243 return percent;
1244}
1245
1246/* Activate the specified software into the BTS */
1247int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1248 gsm_cbfn *cbfn, void *cb_data)
1249{
1250 struct abis_nm_sw *sw = &g_sw;
1251 int rc;
1252
1253 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1254 bts->nr, fname);
1255
1256 if (sw->state != SW_STATE_NONE)
1257 return -EBUSY;
1258
1259 sw->bts = bts;
1260 sw->obj_class = NM_OC_SITE_MANAGER;
1261 sw->obj_instance[0] = 0xff;
1262 sw->obj_instance[1] = 0xff;
1263 sw->obj_instance[2] = 0xff;
1264 sw->state = SW_STATE_WAIT_ACTACK;
1265 sw->cbfn = cbfn;
1266 sw->cb_data = cb_data;
1267
1268 /* Open the file in order to fill some sw struct members */
1269 rc = sw_open_file(sw, fname);
1270 if (rc < 0) {
1271 sw->state = SW_STATE_NONE;
1272 return rc;
1273 }
1274 sw_close_file(sw);
1275
1276 return sw_activate(sw);
1277}
1278
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001279static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1280 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001281{
1282 ch->attrib = NM_ATT_ABIS_CHANNEL;
1283 ch->bts_port = bts_port;
1284 ch->timeslot = ts_nr;
1285 ch->subslot = subslot_nr;
1286}
1287
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001288int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1289 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1290 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001291{
1292 struct abis_om_hdr *oh;
1293 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001294 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001295 struct msgb *msg = nm_msgb_alloc();
1296
1297 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1298 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1299 bts->bts_nr, trx_nr, 0xff);
1300
1301 msgb_tv_put(msg, NM_ATT_TEI, tei);
1302
1303 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1304 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1305
1306 return abis_nm_sendmsg(bts, msg);
1307}
1308
1309/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1310int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001311 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001312{
1313 struct gsm_bts *bts = trx->bts;
1314 struct abis_om_hdr *oh;
1315 struct abis_nm_channel *ch;
1316 struct msgb *msg = nm_msgb_alloc();
1317
1318 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1319 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1320 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1321
1322 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1323 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1324
1325 return abis_nm_sendmsg(bts, msg);
1326}
1327
1328#if 0
1329int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1330 struct abis_nm_abis_channel *chan)
1331{
1332}
1333#endif
1334
1335int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001336 uint8_t e1_port, uint8_t e1_timeslot,
1337 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001338{
1339 struct gsm_bts *bts = ts->trx->bts;
1340 struct abis_om_hdr *oh;
1341 struct abis_nm_channel *ch;
1342 struct msgb *msg = nm_msgb_alloc();
1343
1344 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1345 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1346 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1347
1348 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1349 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1350
1351 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1352 gsm_ts_name(ts),
1353 e1_port, e1_timeslot, e1_subslot);
1354
1355 return abis_nm_sendmsg(bts, msg);
1356}
1357
1358#if 0
1359int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1360 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001361 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001362{
1363}
1364#endif
1365
1366/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001367int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001368{
1369 struct abis_om_hdr *oh;
1370 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001371 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001372
1373 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1374
1375 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1376 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1377 cur = msgb_put(msg, attr_len);
1378 memcpy(cur, attr, attr_len);
1379
1380 return abis_nm_sendmsg(bts, msg);
1381}
1382
1383/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001384int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001385{
1386 struct abis_om_hdr *oh;
1387 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001388 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001389
1390 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1391
1392 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1393 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1394 trx->bts->bts_nr, trx->nr, 0xff);
1395 cur = msgb_put(msg, attr_len);
1396 memcpy(cur, attr, attr_len);
1397
1398 return abis_nm_sendmsg(trx->bts, msg);
1399}
1400
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001401static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Weltef2eb2782009-08-09 21:49:48 +02001402{
1403 int i;
1404
1405 /* As it turns out, the BS-11 has some very peculiar restrictions
1406 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301407 switch (ts->trx->bts->type) {
1408 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001409 switch (chan_comb) {
1410 case NM_CHANC_TCHHalf:
1411 case NM_CHANC_TCHHalf2:
1412 /* not supported */
1413 return -EINVAL;
1414 case NM_CHANC_SDCCH:
1415 /* only one SDCCH/8 per TRX */
1416 for (i = 0; i < TRX_NR_TS; i++) {
1417 if (i == ts->nr)
1418 continue;
1419 if (ts->trx->ts[i].nm_chan_comb ==
1420 NM_CHANC_SDCCH)
1421 return -EINVAL;
1422 }
1423 /* not allowed for TS0 of BCCH-TRX */
1424 if (ts->trx == ts->trx->bts->c0 &&
1425 ts->nr == 0)
1426 return -EINVAL;
1427 /* not on the same TRX that has a BCCH+SDCCH4
1428 * combination */
1429 if (ts->trx == ts->trx->bts->c0 &&
1430 (ts->trx->ts[0].nm_chan_comb == 5 ||
1431 ts->trx->ts[0].nm_chan_comb == 8))
1432 return -EINVAL;
1433 break;
1434 case NM_CHANC_mainBCCH:
1435 case NM_CHANC_BCCHComb:
1436 /* allowed only for TS0 of C0 */
1437 if (ts->trx != ts->trx->bts->c0 ||
1438 ts->nr != 0)
1439 return -EINVAL;
1440 break;
1441 case NM_CHANC_BCCH:
1442 /* allowed only for TS 2/4/6 of C0 */
1443 if (ts->trx != ts->trx->bts->c0)
1444 return -EINVAL;
1445 if (ts->nr != 2 && ts->nr != 4 &&
1446 ts->nr != 6)
1447 return -EINVAL;
1448 break;
1449 case 8: /* this is not like 08.58, but in fact
1450 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1451 /* FIXME: only one CBCH allowed per cell */
1452 break;
1453 }
Harald Welte76ba8812009-12-02 02:45:23 +05301454 break;
1455 case GSM_BTS_TYPE_NANOBTS:
1456 switch (ts->nr) {
1457 case 0:
1458 if (ts->trx->nr == 0) {
1459 /* only on TRX0 */
1460 switch (chan_comb) {
1461 case NM_CHANC_BCCH:
1462 case NM_CHANC_mainBCCH:
1463 case NM_CHANC_BCCHComb:
1464 return 0;
1465 break;
1466 default:
1467 return -EINVAL;
1468 }
1469 } else {
1470 switch (chan_comb) {
1471 case NM_CHANC_TCHFull:
1472 case NM_CHANC_TCHHalf:
1473 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1474 return 0;
1475 default:
1476 return -EINVAL;
1477 }
1478 }
1479 break;
1480 case 1:
1481 if (ts->trx->nr == 0) {
1482 switch (chan_comb) {
1483 case NM_CHANC_SDCCH_CBCH:
1484 if (ts->trx->ts[0].nm_chan_comb ==
1485 NM_CHANC_mainBCCH)
1486 return 0;
1487 return -EINVAL;
1488 case NM_CHANC_SDCCH:
1489 case NM_CHANC_TCHFull:
1490 case NM_CHANC_TCHHalf:
1491 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1492 case NM_CHANC_IPAC_TCHFull_PDCH:
1493 return 0;
1494 }
1495 } else {
1496 switch (chan_comb) {
1497 case NM_CHANC_SDCCH:
1498 case NM_CHANC_TCHFull:
1499 case NM_CHANC_TCHHalf:
1500 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1501 return 0;
1502 default:
1503 return -EINVAL;
1504 }
1505 }
1506 break;
1507 case 2:
1508 case 3:
1509 case 4:
1510 case 5:
1511 case 6:
1512 case 7:
1513 switch (chan_comb) {
1514 case NM_CHANC_TCHFull:
1515 case NM_CHANC_TCHHalf:
1516 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1517 return 0;
1518 case NM_CHANC_IPAC_PDCH:
1519 case NM_CHANC_IPAC_TCHFull_PDCH:
1520 if (ts->trx->nr == 0)
1521 return 0;
1522 else
1523 return -EINVAL;
1524 }
1525 break;
1526 }
1527 return -EINVAL;
1528 default:
1529 /* unknown BTS type */
1530 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001531 }
1532 return 0;
1533}
1534
Harald Welte59b04682009-06-10 05:40:52 +08001535/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001536int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001537{
1538 struct gsm_bts *bts = ts->trx->bts;
1539 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001540 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001541 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001542 uint8_t len = 2 + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001543
1544 if (bts->type == GSM_BTS_TYPE_BS11)
1545 len += 4 + 2 + 2 + 3;
1546
1547 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Harald Weltef2eb2782009-08-09 21:49:48 +02001548 if (verify_chan_comb(ts, chan_comb) < 0) {
1549 msgb_free(msg);
1550 DEBUGP(DNM, "Invalid Channel Combination!!!\n");
1551 return -EINVAL;
1552 }
1553 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001554
1555 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1556 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1557 NM_OC_CHANNEL, bts->bts_nr,
1558 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001559 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001560 if (ts->hopping.enabled) {
1561 unsigned int i;
1562 uint8_t *len;
1563
Harald Welte67104d12009-09-12 13:05:33 +02001564 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1565 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001566
1567 /* build the ARFCN list */
1568 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1569 len = msgb_put(msg, 1);
1570 *len = 0;
1571 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1572 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1573 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001574 /* At least BS-11 wants a TLV16 here */
1575 if (bts->type == GSM_BTS_TYPE_BS11)
1576 *len += 1;
1577 else
1578 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001579 }
1580 }
Harald Welte59b04682009-06-10 05:40:52 +08001581 }
Harald Welte85771a42011-05-30 12:09:13 +02001582 if (ts->tsc == -1)
1583 msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */
1584 else
1585 msgb_tv_put(msg, NM_ATT_TSC, ts->tsc); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001586 if (bts->type == GSM_BTS_TYPE_BS11)
1587 msgb_tlv_put(msg, 0x59, 1, &zero);
1588
1589 return abis_nm_sendmsg(bts, msg);
1590}
1591
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001592int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1593 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001594{
1595 struct abis_om_hdr *oh;
1596 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001597 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1598 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001599
1600 if (nack) {
1601 len += 2;
1602 msgtype = NM_MT_SW_ACT_REQ_NACK;
1603 }
1604
1605 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1606 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1607
1608 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001609 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001610 memcpy(ptr, attr, att_len);
1611 }
1612 if (nack)
1613 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1614
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001615 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001616}
1617
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001618int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001619{
1620 struct msgb *msg = nm_msgb_alloc();
1621 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001622 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001623
1624 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1625 fill_om_hdr(oh, len);
1626 data = msgb_put(msg, len);
1627 memcpy(data, rawmsg, len);
1628
1629 return abis_nm_sendmsg(bts, msg);
1630}
1631
1632/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001633static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001634{
1635 struct abis_om_hdr *oh;
1636 struct msgb *msg = nm_msgb_alloc();
1637
1638 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1639 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1640 0xff, 0xff, 0xff);
1641
1642 return abis_nm_sendmsg(bts, msg);
1643}
1644
1645/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001646int 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 +08001647{
1648 struct abis_om_hdr *oh;
1649 struct msgb *msg = nm_msgb_alloc();
1650
Harald Welte59b04682009-06-10 05:40:52 +08001651 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1652 fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
1653
Harald Weltec61a90e2011-05-22 22:45:37 +02001654 abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
Harald Welteb7284a92009-10-20 09:56:18 +02001655 DEBUGPC(DNM, "Sending OPSTART\n");
1656
Harald Welte59b04682009-06-10 05:40:52 +08001657 return abis_nm_sendmsg(bts, msg);
1658}
1659
1660/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001661int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1662 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001663{
1664 struct abis_om_hdr *oh;
1665 struct msgb *msg = nm_msgb_alloc();
1666
1667 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1668 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1669 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1670
1671 return abis_nm_sendmsg(bts, msg);
1672}
1673
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001674int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1675 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001676{
1677 struct abis_om_hdr *oh;
1678 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001679 uint8_t *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001680
1681 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1682 e1_port0, ts0, e1_port1, ts1);
1683
1684 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1685 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1686 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1687
1688 attr = msgb_put(msg, 3);
1689 attr[0] = NM_ATT_MDROP_LINK;
1690 attr[1] = e1_port0;
1691 attr[2] = ts0;
1692
1693 attr = msgb_put(msg, 3);
1694 attr[0] = NM_ATT_MDROP_NEXT;
1695 attr[1] = e1_port1;
1696 attr[2] = ts1;
1697
1698 return abis_nm_sendmsg(bts, msg);
1699}
Harald Welte59b04682009-06-10 05:40:52 +08001700
Harald Welte0bf8e302009-08-08 00:02:36 +02001701/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001702int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1703 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1704 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001705{
1706 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001707
Harald Weltec61a90e2011-05-22 22:45:37 +02001708 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001709
1710 if (!msg)
1711 msg = nm_msgb_alloc();
1712
1713 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1714 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1715 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1716 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001717 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001718
1719 return abis_nm_sendmsg(bts, msg);
1720}
1721
Harald Welte59b04682009-06-10 05:40:52 +08001722int abis_nm_event_reports(struct gsm_bts *bts, int on)
1723{
1724 if (on == 0)
1725 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1726 else
1727 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1728}
1729
1730/* Siemens (or BS-11) specific commands */
1731
1732int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1733{
1734 if (reconnect == 0)
1735 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1736 else
1737 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1738}
1739
1740int abis_nm_bs11_restart(struct gsm_bts *bts)
1741{
1742 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1743}
1744
1745
1746struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001747 uint16_t year;
1748 uint8_t month;
1749 uint8_t day;
1750 uint8_t hour;
1751 uint8_t min;
1752 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001753} __attribute__((packed));
1754
1755
1756void get_bs11_date_time(struct bs11_date_time *aet)
1757{
1758 time_t t;
1759 struct tm *tm;
1760
1761 t = time(NULL);
1762 tm = localtime(&t);
1763 aet->sec = tm->tm_sec;
1764 aet->min = tm->tm_min;
1765 aet->hour = tm->tm_hour;
1766 aet->day = tm->tm_mday;
1767 aet->month = tm->tm_mon;
1768 aet->year = htons(1900 + tm->tm_year);
1769}
1770
1771int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1772{
1773 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1774}
1775
1776int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1777{
1778 if (begin)
1779 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1780 else
1781 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1782}
1783
1784int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001785 enum abis_bs11_objtype type, uint8_t idx,
1786 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001787{
1788 struct abis_om_hdr *oh;
1789 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001790 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001791
1792 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1793 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1794 NM_OC_BS11, type, 0, idx);
1795 cur = msgb_put(msg, attr_len);
1796 memcpy(cur, attr, attr_len);
1797
1798 return abis_nm_sendmsg(bts, msg);
1799}
1800
1801int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001802 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001803{
1804 struct abis_om_hdr *oh;
1805 struct msgb *msg = nm_msgb_alloc();
1806
1807 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1808 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1809 NM_OC_BS11, type, 0, idx);
1810
1811 return abis_nm_sendmsg(bts, msg);
1812}
1813
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001814int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001815{
1816 struct abis_om_hdr *oh;
1817 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001818 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001819
1820 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1821 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1822 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1823 msgb_tlv_put(msg, 0x99, 1, &zero);
1824
1825 return abis_nm_sendmsg(bts, msg);
1826}
1827
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001828int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001829{
1830 struct abis_om_hdr *oh;
1831 struct msgb *msg = nm_msgb_alloc();
1832
1833 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1834 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001835 idx, 0xff, 0xff);
1836
1837 return abis_nm_sendmsg(bts, msg);
1838}
1839
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001840int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001841{
1842 struct abis_om_hdr *oh;
1843 struct msgb *msg = nm_msgb_alloc();
1844
1845 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1846 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1847 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001848
1849 return abis_nm_sendmsg(bts, msg);
1850}
1851
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001852static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001853int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1854{
1855 struct abis_om_hdr *oh;
1856 struct msgb *msg = nm_msgb_alloc();
1857
1858 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1859 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1860 0xff, 0xff, 0xff);
1861 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1862
1863 return abis_nm_sendmsg(bts, msg);
1864}
1865
1866/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001867int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1868 uint8_t e1_timeslot, uint8_t e1_subslot,
1869 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001870{
1871 struct abis_om_hdr *oh;
1872 struct abis_nm_channel *ch;
1873 struct msgb *msg = nm_msgb_alloc();
1874
1875 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1876 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1877 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1878
1879 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1880 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1881 msgb_tv_put(msg, NM_ATT_TEI, tei);
1882
1883 return abis_nm_sendmsg(bts, msg);
1884}
1885
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001886int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08001887{
1888 struct abis_om_hdr *oh;
1889 struct msgb *msg = nm_msgb_alloc();
1890
1891 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1892 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
1893 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1894 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
1895
1896 return abis_nm_sendmsg(trx->bts, msg);
1897}
1898
1899int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
1900{
1901 struct abis_om_hdr *oh;
1902 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001903 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08001904
1905 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1906 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1907 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
1908 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
1909
1910 return abis_nm_sendmsg(trx->bts, msg);
1911}
1912
1913int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
1914{
1915 struct abis_om_hdr *oh;
1916 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001917 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08001918
1919 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1920 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1921 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
1922 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1923
1924 return abis_nm_sendmsg(bts, msg);
1925}
1926
1927int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
1928{
1929 struct abis_om_hdr *oh;
1930 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001931 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08001932 NM_ATT_BS11_CCLK_TYPE };
1933
1934 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1935 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
1936 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
1937 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
1938
1939 return abis_nm_sendmsg(bts, msg);
1940
1941}
1942
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001943//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08001944
1945int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
1946{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001947 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
1948}
1949
Daniel Willmannbf2ca572010-01-07 00:46:26 +01001950int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
1951{
1952 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
1953}
1954
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001955int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001956{
Harald Welte59b04682009-06-10 05:40:52 +08001957 struct abis_om_hdr *oh;
1958 struct msgb *msg = nm_msgb_alloc();
1959 struct bs11_date_time bdt;
1960
1961 get_bs11_date_time(&bdt);
1962
1963 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1964 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001965 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001966 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08001967 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
1968 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1969 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001970 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08001971 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01001972 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08001973 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001974 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08001975 } else {
1976 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
1977 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
1978 }
1979
1980 return abis_nm_sendmsg(bts, msg);
1981}
1982
1983int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
1984{
1985 struct abis_om_hdr *oh;
1986 struct msgb *msg;
1987
1988 if (strlen(password) != 10)
1989 return -EINVAL;
1990
1991 msg = nm_msgb_alloc();
1992 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1993 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
1994 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001995 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08001996
1997 return abis_nm_sendmsg(bts, msg);
1998}
1999
2000/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2001int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2002{
2003 struct abis_om_hdr *oh;
2004 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002005 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002006
2007 msg = nm_msgb_alloc();
2008 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2009 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2010 BS11_OBJ_LI, 0x00, 0x00);
2011
2012 if (locked)
2013 tlv_value = BS11_LI_PLL_LOCKED;
2014 else
2015 tlv_value = BS11_LI_PLL_STANDALONE;
2016
2017 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2018
2019 return abis_nm_sendmsg(bts, msg);
2020}
2021
Daniel Willmann10b07db2010-01-07 00:54:01 +01002022/* Set the calibration value of the PLL (work value/set value)
2023 * It depends on the login which one is changed */
2024int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2025{
2026 struct abis_om_hdr *oh;
2027 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002028 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002029
2030 msg = nm_msgb_alloc();
2031 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2032 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2033 BS11_OBJ_TRX1, 0x00, 0x00);
2034
2035 tlv_value[0] = value>>8;
2036 tlv_value[1] = value&0xff;
2037
2038 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2039
2040 return abis_nm_sendmsg(bts, msg);
2041}
2042
Harald Welte59b04682009-06-10 05:40:52 +08002043int abis_nm_bs11_get_state(struct gsm_bts *bts)
2044{
2045 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2046}
2047
2048/* BS11 SWL */
2049
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002050void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002051
Harald Welte59b04682009-06-10 05:40:52 +08002052struct abis_nm_bs11_sw {
2053 struct gsm_bts *bts;
2054 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002055 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002056 int forced;
2057 struct llist_head file_list;
2058 gsm_cbfn *user_cb; /* specified by the user */
2059};
2060static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2061
2062struct file_list_entry {
2063 struct llist_head list;
2064 char fname[PATH_MAX];
2065};
2066
2067struct file_list_entry *fl_dequeue(struct llist_head *queue)
2068{
2069 struct llist_head *lh;
2070
2071 if (llist_empty(queue))
2072 return NULL;
2073
2074 lh = queue->next;
2075 llist_del(lh);
2076
2077 return llist_entry(lh, struct file_list_entry, list);
2078}
2079
2080static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2081{
2082 char linebuf[255];
2083 struct llist_head *lh, *lh2;
2084 FILE *swl;
2085 int rc = 0;
2086
2087 swl = fopen(bs11_sw->swl_fname, "r");
2088 if (!swl)
2089 return -ENODEV;
2090
2091 /* zero the stale file list, if any */
2092 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2093 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002094 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002095 }
2096
2097 while (fgets(linebuf, sizeof(linebuf), swl)) {
2098 char file_id[12+1];
2099 char file_version[80+1];
2100 struct file_list_entry *fle;
2101 static char dir[PATH_MAX];
2102
2103 if (strlen(linebuf) < 4)
2104 continue;
2105
2106 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2107 if (rc < 0) {
2108 perror("ERR parsing SWL file");
2109 rc = -EINVAL;
2110 goto out;
2111 }
2112 if (rc < 2)
2113 continue;
2114
Harald Welte857e00d2009-06-26 20:25:23 +02002115 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002116 if (!fle) {
2117 rc = -ENOMEM;
2118 goto out;
2119 }
Harald Welte59b04682009-06-10 05:40:52 +08002120
2121 /* construct new filename */
2122 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2123 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2124 strcat(fle->fname, "/");
2125 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2126
2127 llist_add_tail(&fle->list, &bs11_sw->file_list);
2128 }
2129
2130out:
2131 fclose(swl);
2132 return rc;
2133}
2134
2135/* bs11 swload specific callback, passed to abis_nm core swload */
2136static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2137 struct msgb *msg, void *data, void *param)
2138{
2139 struct abis_nm_bs11_sw *bs11_sw = data;
2140 struct file_list_entry *fle;
2141 int rc = 0;
2142
2143 switch (event) {
2144 case NM_MT_LOAD_END_ACK:
2145 fle = fl_dequeue(&bs11_sw->file_list);
2146 if (fle) {
2147 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002148 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002149 bs11_sw->win_size,
2150 bs11_sw->forced,
2151 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002152 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002153 } else {
2154 /* activate the SWL */
2155 rc = abis_nm_software_activate(bs11_sw->bts,
2156 bs11_sw->swl_fname,
2157 bs11_swload_cbfn,
2158 bs11_sw);
2159 }
2160 break;
2161 case NM_MT_LOAD_SEG_ACK:
2162 case NM_MT_LOAD_END_NACK:
2163 case NM_MT_LOAD_INIT_ACK:
2164 case NM_MT_LOAD_INIT_NACK:
2165 case NM_MT_ACTIVATE_SW_NACK:
2166 case NM_MT_ACTIVATE_SW_ACK:
2167 default:
2168 /* fallthrough to the user callback */
2169 if (bs11_sw->user_cb)
2170 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2171 break;
2172 }
2173
2174 return rc;
2175}
2176
2177/* Siemens provides a SWL file that is a mere listing of all the other
2178 * files that are part of a software release. We need to upload first
2179 * the list file, and then each file that is listed in the list file */
2180int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002181 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002182{
2183 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2184 struct file_list_entry *fle;
2185 int rc = 0;
2186
2187 INIT_LLIST_HEAD(&bs11_sw->file_list);
2188 bs11_sw->bts = bts;
2189 bs11_sw->win_size = win_size;
2190 bs11_sw->user_cb = cbfn;
2191 bs11_sw->forced = forced;
2192
2193 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2194 rc = bs11_read_swl_file(bs11_sw);
2195 if (rc < 0)
2196 return rc;
2197
2198 /* dequeue next item in file list */
2199 fle = fl_dequeue(&bs11_sw->file_list);
2200 if (!fle)
2201 return -EINVAL;
2202
2203 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002204 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002205 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002206 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002207 return rc;
2208}
2209
2210#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002211static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002212 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2213 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2214 NM_ATT_BS11_LMT_USER_NAME,
2215
2216 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2217
2218 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2219
2220 NM_ATT_BS11_SW_LOAD_STORED };
2221
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002222static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002223 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2224 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2225 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2226 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2227#endif
2228
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002229static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002230 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2231 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2232 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2233
2234int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2235{
2236 struct abis_om_hdr *oh;
2237 struct msgb *msg = nm_msgb_alloc();
2238
2239 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2240 /* SiemensHW CCTRL object */
2241 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2242 0x03, 0x00, 0x00);
2243 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2244
2245 return abis_nm_sendmsg(bts, msg);
2246}
2247
2248int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2249{
2250 struct abis_om_hdr *oh;
2251 struct msgb *msg = nm_msgb_alloc();
2252 struct bs11_date_time aet;
2253
2254 get_bs11_date_time(&aet);
2255 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2256 /* SiemensHW CCTRL object */
2257 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2258 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002259 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002260
2261 return abis_nm_sendmsg(bts, msg);
2262}
2263
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002264int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002265{
2266 struct abis_om_hdr *oh;
2267 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002268 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002269
2270 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2271 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2272 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2273 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2274
2275 return abis_nm_sendmsg(bts, msg);
2276}
2277
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002278int 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 +02002279{
2280 struct abis_om_hdr *oh;
2281 struct msgb *msg = nm_msgb_alloc();
2282 struct bs11_date_time aet;
2283
2284 get_bs11_date_time(&aet);
2285 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2286 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2287 bport, 0xff, 0x02);
2288 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2289
2290 return abis_nm_sendmsg(bts, msg);
2291}
2292
Harald Welte59b04682009-06-10 05:40:52 +08002293/* ip.access nanoBTS specific commands */
2294static const char ipaccess_magic[] = "com.ipaccess";
2295
2296
2297static int abis_nm_rx_ipacc(struct msgb *msg)
2298{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002299 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002300 struct abis_om_hdr *oh = msgb_l2(msg);
2301 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002302 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002303 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002304 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002305 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002306
2307 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002308 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002309 return -EINVAL;
2310 }
2311
2312 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002313 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002314
Harald Weltec61a90e2011-05-22 22:45:37 +02002315 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002316
Harald Welte5aeedd42009-10-19 22:11:11 +02002317 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002318
2319 switch (foh->msg_type) {
2320 case NM_MT_IPACC_RSL_CONNECT_ACK:
2321 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002322 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2323 memcpy(&addr,
2324 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2325
2326 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2327 }
Harald Welte4206d982009-07-12 09:33:54 +02002328 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002329 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002330 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002331 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002332 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2333 DEBUGPC(DNM, "STREAM=0x%02x ",
2334 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002335 DEBUGPC(DNM, "\n");
2336 break;
2337 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002338 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002339 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002340 DEBUGPC(DNM, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002341 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002342 else
2343 DEBUGPC(DNM, "\n");
2344 break;
2345 case NM_MT_IPACC_SET_NVATTR_ACK:
2346 DEBUGPC(DNM, "SET NVATTR ACK\n");
2347 /* FIXME: decode and show the actual attributes */
2348 break;
2349 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002350 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002351 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002352 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002353 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002354 else
Harald Weltede4477a2009-12-24 12:20:20 +01002355 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002356 break;
Harald Welte21460f02009-07-03 11:26:45 +02002357 case NM_MT_IPACC_GET_NVATTR_ACK:
2358 DEBUGPC(DNM, "GET NVATTR ACK\n");
2359 /* FIXME: decode and show the actual attributes */
2360 break;
2361 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002362 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002363 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002364 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002365 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002366 else
Harald Weltede4477a2009-12-24 12:20:20 +01002367 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002368 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002369 case NM_MT_IPACC_SET_ATTR_ACK:
2370 DEBUGPC(DNM, "SET ATTR ACK\n");
2371 break;
2372 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002373 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002374 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002375 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002376 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002377 else
Harald Weltede4477a2009-12-24 12:20:20 +01002378 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002379 break;
Harald Welte59b04682009-06-10 05:40:52 +08002380 default:
2381 DEBUGPC(DNM, "unknown\n");
2382 break;
2383 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002384
2385 /* signal handling */
2386 switch (foh->msg_type) {
2387 case NM_MT_IPACC_RSL_CONNECT_NACK:
2388 case NM_MT_IPACC_SET_NVATTR_NACK:
2389 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002390 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 +01002391 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002392 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002393 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002394 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002395 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 +01002396 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002397 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002398 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002399 default:
2400 break;
2401 }
2402
Harald Welte59b04682009-06-10 05:40:52 +08002403 return 0;
2404}
2405
2406/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002407int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2408 uint8_t obj_class, uint8_t bts_nr,
2409 uint8_t trx_nr, uint8_t ts_nr,
2410 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002411{
2412 struct msgb *msg = nm_msgb_alloc();
2413 struct abis_om_hdr *oh;
2414 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002415 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002416
2417 /* construct the 12.21 OM header, observe the erroneous length */
2418 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2419 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2420 oh->mdisc = ABIS_OM_MDISC_MANUF;
2421
2422 /* add the ip.access magic */
2423 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2424 *data++ = sizeof(ipaccess_magic);
2425 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2426
2427 /* fill the 12.21 FOM header */
2428 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2429 foh->msg_type = msg_type;
2430 foh->obj_class = obj_class;
2431 foh->obj_inst.bts_nr = bts_nr;
2432 foh->obj_inst.trx_nr = trx_nr;
2433 foh->obj_inst.ts_nr = ts_nr;
2434
2435 if (attr && attr_len) {
2436 data = msgb_put(msg, attr_len);
2437 memcpy(data, attr, attr_len);
2438 }
2439
2440 return abis_nm_sendmsg(bts, msg);
2441}
2442
2443/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002444int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002445 int attr_len)
2446{
Harald Weltef12c1052010-01-07 20:39:42 +01002447 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2448 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002449 attr_len);
2450}
2451
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002452int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002453 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002454{
2455 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002456 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002457 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2458 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2459
2460 int attr_len = sizeof(attr);
2461
2462 ia.s_addr = htonl(ip);
2463 attr[1] = stream;
2464 attr[3] = port >> 8;
2465 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002466 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002467
2468 /* if ip == 0, we use the default IP */
2469 if (ip == 0)
2470 attr_len -= 5;
2471
2472 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002473 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002474
2475 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2476 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2477 trx->nr, 0xff, attr, attr_len);
2478}
2479
Harald Welte59b04682009-06-10 05:40:52 +08002480/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002481int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002482{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002483 struct abis_om_hdr *oh;
2484 struct msgb *msg = nm_msgb_alloc();
2485
2486 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2487 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2488 trx->bts->nr, trx->nr, 0xff);
2489
2490 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002491}
Harald Welte0dfc6232009-10-24 10:20:41 +02002492
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002493int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2494 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2495 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002496{
2497 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2498 obj_class, bts_nr, trx_nr, ts_nr,
2499 attr, attr_len);
2500}
Harald Weltebeeae412009-11-12 14:48:42 +01002501
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002502void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002503{
2504 /* we simply reuse the GSM48 function and overwrite the RAC
2505 * with the Cell ID */
2506 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002507 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002508}
2509
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002510void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2511{
2512 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2513
Harald Welte69f6f812011-05-30 12:07:53 +02002514 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002515 if (!trx->bts || !trx->bts->oml_link)
2516 return;
2517
2518 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2519 trx->bts->bts_nr, trx->nr, 0xff,
2520 new_state);
2521}
2522
Harald Welte453141f2010-03-25 11:45:30 +08002523static const struct value_string ipacc_testres_names[] = {
2524 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2525 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2526 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2527 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2528 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2529 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002530};
2531
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002532const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002533{
Harald Welte453141f2010-03-25 11:45:30 +08002534 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002535}
2536
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002537void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002538{
2539 cid->mcc = (buf[0] & 0xf) * 100;
2540 cid->mcc += (buf[0] >> 4) * 10;
2541 cid->mcc += (buf[1] & 0xf) * 1;
2542
2543 if (buf[1] >> 4 == 0xf) {
2544 cid->mnc = (buf[2] & 0xf) * 10;
2545 cid->mnc += (buf[2] >> 4) * 1;
2546 } else {
2547 cid->mnc = (buf[2] & 0xf) * 100;
2548 cid->mnc += (buf[2] >> 4) * 10;
2549 cid->mnc += (buf[1] >> 4) * 1;
2550 }
2551
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002552 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2553 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002554}
2555
Harald Weltebeeae412009-11-12 14:48:42 +01002556/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002557int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002558{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002559 uint8_t *cur = buf;
2560 uint16_t len;
Harald Weltebeeae412009-11-12 14:48:42 +01002561
Harald Welteb784df82010-07-22 18:14:36 +02002562 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002563
2564 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2565 return -EINVAL;
2566 cur++;
2567
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002568 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002569 cur += 2;
2570
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002571 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002572 cur += 2;
2573
2574 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2575 binf->freq_qual = *cur >> 2;
2576
Harald Welteb784df82010-07-22 18:14:36 +02002577 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002578 binf->arfcn |= *cur++;
2579
2580 if (binf->info_type & IPAC_BINF_RXLEV)
2581 binf->rx_lev = *cur & 0x3f;
2582 cur++;
2583
2584 if (binf->info_type & IPAC_BINF_RXQUAL)
2585 binf->rx_qual = *cur & 0x7;
2586 cur++;
2587
2588 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002589 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002590 cur += 2;
2591
2592 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002593 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002594 cur += 2;
2595
2596 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002597 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002598 cur += 4;
2599
Harald Welte22cb81f2010-07-30 22:34:42 +02002600#if 0
2601 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002602 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002603#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002604 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002605 cur++;
2606
Harald Weltebfc21092009-11-13 11:56:05 +01002607 ipac_parse_cgi(&binf->cgi, cur);
2608 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002609
2610 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2611 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2612 cur += sizeof(binf->ba_list_si2);
2613 }
2614
2615 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2616 memcpy(binf->ba_list_si2bis, cur,
2617 sizeof(binf->ba_list_si2bis));
2618 cur += sizeof(binf->ba_list_si2bis);
2619 }
2620
2621 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2622 memcpy(binf->ba_list_si2ter, cur,
2623 sizeof(binf->ba_list_si2ter));
2624 cur += sizeof(binf->ba_list_si2ter);
2625 }
2626
2627 return 0;
2628}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002629
2630void abis_nm_clear_queue(struct gsm_bts *bts)
2631{
2632 struct msgb *msg;
2633
2634 while (!llist_empty(&bts->abis_queue)) {
2635 msg = msgb_dequeue(&bts->abis_queue);
2636 msgb_free(msg);
2637 }
2638
2639 bts->abis_nm_pend = 0;
2640}