blob: c05e2f94f82a56fc12c98d87b771c5586adfd4cb [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 Freytherffd0f222014-04-04 12:56:34 +020096static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +020097 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;
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +0200109 return foh;
Harald Welte59b04682009-06-10 05:40:52 +0800110}
111
112static struct msgb *nm_msgb_alloc(void)
113{
Harald Welte9cfc9352009-06-26 19:39:35 +0200114 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
115 "OML");
Harald Welte59b04682009-06-10 05:40:52 +0800116}
117
Harald Welte607044f2011-09-26 23:43:23 +0200118int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200119{
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200120 msg->l2h = msg->data;
121
122 if (!msg->dst) {
123 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
124 return -EINVAL;
125 }
126
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200127 return abis_sendmsg(msg);
128}
129
Harald Welte59b04682009-06-10 05:40:52 +0800130/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100131static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte59b04682009-06-10 05:40:52 +0800132{
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200133 msg->dst = bts->oml_link;
Harald Welte59b04682009-06-10 05:40:52 +0800134
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100135 /* queue OML messages */
136 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
137 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200138 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100139 } else {
140 msgb_enqueue(&bts->abis_queue, msg);
141 return 0;
142 }
143
144}
145
146int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
147{
148 OBSC_NM_W_ACK_CB(msg) = 1;
149 return abis_nm_queue_msg(bts, msg);
150}
151
152static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
153{
154 OBSC_NM_W_ACK_CB(msg) = 0;
155 return abis_nm_queue_msg(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800156}
157
158static int abis_nm_rcvmsg_sw(struct msgb *mb);
159
Sylvain Munautca3e04f2010-01-02 16:32:17 +0100160int nm_is_running(struct gsm_nm_state *s) {
161 return (s->operational == NM_OPSTATE_ENABLED) && (
162 (s->availability == NM_AVSTATE_OK) ||
163 (s->availability == 0xff)
164 );
165}
166
Harald Welte59b04682009-06-10 05:40:52 +0800167/* Update the administrative state of a given object in our in-memory data
168 * structures and send an event to the higher layer */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200169static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
170 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Welte59b04682009-06-10 05:40:52 +0800171{
172 struct gsm_nm_state *nm_state, new_state;
Harald Welte4c826f72011-01-14 15:55:42 +0100173 struct nm_statechg_signal_data nsd;
Harald Welte59b04682009-06-10 05:40:52 +0800174
Harald Weltea348c082011-03-06 21:20:38 +0100175 memset(&nsd, 0, sizeof(nsd));
176
Harald Weltec6ed9282011-06-06 18:31:20 +0200177 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100178 if (!nsd.obj)
Harald Welte3d9ecf72009-11-13 12:10:18 +0100179 return -EINVAL;
Harald Weltec6ed9282011-06-06 18:31:20 +0200180 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800181 if (!nm_state)
182 return -1;
183
184 new_state = *nm_state;
185 new_state.administrative = adm_state;
186
Harald Welteb03c4482011-03-06 22:11:32 +0100187 nsd.bts = bts;
Harald Welte4c826f72011-01-14 15:55:42 +0100188 nsd.obj_class = obj_class;
189 nsd.old_state = nm_state;
190 nsd.new_state = &new_state;
191 nsd.obj_inst = obj_inst;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200192 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welte59b04682009-06-10 05:40:52 +0800193
194 nm_state->administrative = adm_state;
195
Harald Welte4c826f72011-01-14 15:55:42 +0100196 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800197}
198
199static int abis_nm_rx_statechg_rep(struct msgb *mb)
200{
201 struct abis_om_hdr *oh = msgb_l2(mb);
202 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200203 struct e1inp_sign_link *sign_link = mb->dst;
204 struct gsm_bts *bts = sign_link->trx->bts;
Harald Welte59b04682009-06-10 05:40:52 +0800205 struct tlv_parsed tp;
206 struct gsm_nm_state *nm_state, new_state;
Harald Welte59b04682009-06-10 05:40:52 +0800207
208 DEBUGPC(DNM, "STATE CHG: ");
209
210 memset(&new_state, 0, sizeof(new_state));
211
Harald Weltec6ed9282011-06-06 18:31:20 +0200212 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Welte59b04682009-06-10 05:40:52 +0800213 if (!nm_state) {
Harald Welte3d9ecf72009-11-13 12:10:18 +0100214 DEBUGPC(DNM, "unknown object class\n");
Harald Welte59b04682009-06-10 05:40:52 +0800215 return -EINVAL;
216 }
217
218 new_state = *nm_state;
219
Harald Welte59698fb2010-01-10 18:01:52 +0100220 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800221 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
222 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200223 DEBUGPC(DNM, "OP_STATE=%s ",
224 abis_nm_opstate_name(new_state.operational));
Harald Welte59b04682009-06-10 05:40:52 +0800225 }
226 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
227 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
228 new_state.availability = 0xff;
229 else
230 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Weltec61a90e2011-05-22 22:45:37 +0200231 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
232 abis_nm_avail_name(new_state.availability),
Harald Welte59b04682009-06-10 05:40:52 +0800233 new_state.availability);
Sylvain Munaut035e3702010-01-02 16:35:26 +0100234 } else
235 new_state.availability = 0xff;
Harald Welte59b04682009-06-10 05:40:52 +0800236 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
237 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Weltec61a90e2011-05-22 22:45:37 +0200238 DEBUGPC(DNM, "ADM=%2s ",
Harald Welte73e69942011-05-23 20:42:26 +0200239 get_value_string(abis_nm_adm_state_names,
240 new_state.administrative));
Harald Welte59b04682009-06-10 05:40:52 +0800241 }
242 DEBUGPC(DNM, "\n");
243
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100244 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
245 new_state.operational != nm_state->operational ||
246 new_state.availability != nm_state->availability) {
Harald Welte59b04682009-06-10 05:40:52 +0800247 /* Update the operational state of a given object in our in-memory data
248 * structures and send an event to the higher layer */
Harald Welte4c826f72011-01-14 15:55:42 +0100249 struct nm_statechg_signal_data nsd;
Harald Weltec6ed9282011-06-06 18:31:20 +0200250 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Welte4c826f72011-01-14 15:55:42 +0100251 nsd.obj_class = foh->obj_class;
252 nsd.old_state = nm_state;
253 nsd.new_state = &new_state;
254 nsd.obj_inst = &foh->obj_inst;
Harald Welteb03c4482011-03-06 22:11:32 +0100255 nsd.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200256 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freyther677bb2f2009-12-31 03:05:52 +0100257 nm_state->operational = new_state.operational;
258 nm_state->availability = new_state.availability;
259 if (nm_state->administrative == 0)
260 nm_state->administrative = new_state.administrative;
Harald Welte59b04682009-06-10 05:40:52 +0800261 }
262#if 0
263 if (op_state == 1) {
264 /* try to enable objects that are disabled */
265 abis_nm_opstart(bts, foh->obj_class,
266 foh->obj_inst.bts_nr,
267 foh->obj_inst.trx_nr,
268 foh->obj_inst.ts_nr);
269 }
270#endif
271 return 0;
272}
273
274static int rx_fail_evt_rep(struct msgb *mb)
275{
276 struct abis_om_hdr *oh = msgb_l2(mb);
277 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200278 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800279 struct tlv_parsed tp;
Dieter Spaarf5888a72011-02-18 11:06:51 +0100280 const uint8_t *p_val;
281 char *p_text;
Harald Welte59b04682009-06-10 05:40:52 +0800282
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200283 LOGPC(DNM, LOGL_ERROR, "Failure Event Report ");
Harald Welte59b04682009-06-10 05:40:52 +0800284
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200285 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800286
287 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
Harald Weltec61a90e2011-05-22 22:45:37 +0200288 LOGPC(DNM, LOGL_ERROR, "Type=%s ",
289 abis_nm_event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
Harald Welte59b04682009-06-10 05:40:52 +0800290 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
Harald Weltec61a90e2011-05-22 22:45:37 +0200291 LOGPC(DNM, LOGL_ERROR, "Severity=%s ",
292 abis_nm_severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
Dieter Spaarf5888a72011-02-18 11:06:51 +0100293 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
294 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200295 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 +0100296 }
297 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
298 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
299 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
300 if (p_text) {
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200301 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s ", p_text);
Dieter Spaarf5888a72011-02-18 11:06:51 +0100302 talloc_free(p_text);
303 }
304 }
Harald Welte59b04682009-06-10 05:40:52 +0800305
Holger Hans Peter Freytherf569b2f2011-04-26 09:29:01 +0200306 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +0800307
308 return 0;
309}
310
311static int abis_nm_rcvmsg_report(struct msgb *mb)
312{
313 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200314 uint8_t mt = foh->msg_type;
Harald Welte59b04682009-06-10 05:40:52 +0800315
Harald Weltec61a90e2011-05-22 22:45:37 +0200316 abis_nm_debugp_foh(DNM, foh);
Harald Welte59b04682009-06-10 05:40:52 +0800317
318 //nmh->cfg->report_cb(mb, foh);
319
320 switch (mt) {
321 case NM_MT_STATECHG_EVENT_REP:
322 return abis_nm_rx_statechg_rep(mb);
323 break;
324 case NM_MT_SW_ACTIVATED_REP:
325 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200326 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800327 break;
328 case NM_MT_FAILURE_EVENT_REP:
329 rx_fail_evt_rep(mb);
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200330 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Welte59b04682009-06-10 05:40:52 +0800331 break;
Harald Welte0bf8e302009-08-08 00:02:36 +0200332 case NM_MT_TEST_REP:
333 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200334 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Welte0bf8e302009-08-08 00:02:36 +0200335 break;
Harald Welte59b04682009-06-10 05:40:52 +0800336 default:
337 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
338 break;
339
340 };
341
342 return 0;
343}
344
345/* Activate the specified software into the BTS */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200346static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
347 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte59b04682009-06-10 05:40:52 +0800348{
349 struct abis_om_hdr *oh;
350 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200351 uint8_t len = swdesc_len;
352 uint8_t *trailer;
Harald Welte59b04682009-06-10 05:40:52 +0800353
354 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
355 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
356
357 trailer = msgb_put(msg, swdesc_len);
358 memcpy(trailer, sw_desc, swdesc_len);
359
360 return abis_nm_sendmsg(bts, msg);
361}
362
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100363int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
364 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100365{
366 static const struct tlv_definition sw_descr_def = {
367 .def = {
368 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
369 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
370 },
371 };
372
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100373 size_t pos = 0;
374 int desc_pos = 0;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100375
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100376 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
377 uint8_t tag;
378 uint16_t tag_len;
379 const uint8_t *val;
380 int len;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100381
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100382 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
383 desc[desc_pos].start = &sw_descr[pos];
384
385 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
386 * nested nature and the fact you have to assume it contains only two sub
387 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
388 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
389 LOGP(DNM, LOGL_ERROR,
390 "SW_DESCR attribute identifier not found!\n");
391 return -1;
392 }
393
394 pos += 1;
395 len = tlv_parse_one(&tag, &tag_len, &val,
396 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
397 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
398 LOGP(DNM, LOGL_ERROR,
399 "FILE_ID attribute identifier not found!\n");
400 return -2;
401 }
402 desc[desc_pos].file_id = val;
403 desc[desc_pos].file_id_len = tag_len;
404 pos += len;
405
406
407 len = tlv_parse_one(&tag, &tag_len, &val,
408 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
409 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
410 LOGP(DNM, LOGL_ERROR,
411 "FILE_VERSION attribute identifier not found!\n");
412 return -3;
413 }
414 desc[desc_pos].file_ver = val;
415 desc[desc_pos].file_ver_len = tag_len;
416 pos += len;
417
418 /* final size */
419 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100420 }
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100421
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100422 return desc_pos;
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100423}
424
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100425int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
426 const size_t size)
427{
428 int res = 0;
429 int i;
430
431 for (i = 1; i < size; ++i) {
432 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
433 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
434 res = i;
435 }
436 }
437
438 return res;
439}
440
Harald Welte59b04682009-06-10 05:40:52 +0800441static int abis_nm_rx_sw_act_req(struct msgb *mb)
442{
443 struct abis_om_hdr *oh = msgb_l2(mb);
444 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200445 struct e1inp_sign_link *sign_link = mb->dst;
Mike Haben322fc582009-10-01 14:56:13 +0200446 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200447 const uint8_t *sw_config;
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100448 int ret, sw_config_len, len;
449 struct abis_nm_sw_descr sw_descr[5];
Harald Welte59b04682009-06-10 05:40:52 +0800450
Harald Weltec61a90e2011-05-22 22:45:37 +0200451 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +0200452
453 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte59b04682009-06-10 05:40:52 +0800454
Harald Welte3055e332010-03-14 15:37:43 +0800455 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte59b04682009-06-10 05:40:52 +0800456
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200457 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800458 foh->obj_inst.bts_nr,
459 foh->obj_inst.trx_nr,
Harald Welte3055e332010-03-14 15:37:43 +0800460 foh->obj_inst.ts_nr, 0,
Harald Welte59b04682009-06-10 05:40:52 +0800461 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100462 if (ret != 0) {
463 LOGP(DNM, LOGL_ERROR,
464 "Sending SW ActReq ACK failed: %d\n", ret);
465 return ret;
466 }
Harald Welte59b04682009-06-10 05:40:52 +0800467
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200468 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Haben322fc582009-10-01 14:56:13 +0200469 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
470 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
471 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freyther22ef5552012-02-03 19:48:30 +0100472 LOGP(DNM, LOGL_ERROR,
473 "SW config not found! Can't continue.\n");
Mike Haben322fc582009-10-01 14:56:13 +0200474 return -EINVAL;
475 } else {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200476 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Haben322fc582009-10-01 14:56:13 +0200477 }
478
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100479 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100480 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100481 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100482 if (len <= 0) {
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100483 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munaut7e3edbf2009-10-25 17:48:42 +0100484 return -EINVAL;
Holger Hans Peter Freyther23e80002012-11-22 14:59:46 +0100485 }
Mike Haben322fc582009-10-01 14:56:13 +0200486
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100487 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
488 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
489
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200490 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte59b04682009-06-10 05:40:52 +0800491 foh->obj_inst.bts_nr,
492 foh->obj_inst.trx_nr,
493 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther3cb44092012-11-22 19:04:10 +0100494 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte59b04682009-06-10 05:40:52 +0800495}
496
497/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
498static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
499{
500 struct abis_om_hdr *oh = msgb_l2(mb);
501 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200502 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800503 struct tlv_parsed tp;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200504 uint8_t adm_state;
Harald Welte59b04682009-06-10 05:40:52 +0800505
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200506 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800507 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
508 return -EINVAL;
509
510 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
511
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200512 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Welte59b04682009-06-10 05:40:52 +0800513}
514
515static int abis_nm_rx_lmt_event(struct msgb *mb)
516{
517 struct abis_om_hdr *oh = msgb_l2(mb);
518 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200519 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +0800520 struct tlv_parsed tp;
521
522 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200523 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800524 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
525 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200526 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welte59b04682009-06-10 05:40:52 +0800527 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
528 }
529 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
530 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200531 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welte59b04682009-06-10 05:40:52 +0800532 DEBUGPC(DNM, "Level=%u ", level);
533 }
534 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
535 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
536 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
537 DEBUGPC(DNM, "Username=%s ", name);
538 }
539 DEBUGPC(DNM, "\n");
540 /* FIXME: parse LMT LOGON TIME */
541 return 0;
542}
543
Pablo Neira Ayuso42e41df2011-08-17 22:44:07 +0200544void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100545{
546 int wait = 0;
547 struct msgb *msg;
548 /* the queue is empty */
549 while (!llist_empty(&bts->abis_queue)) {
550 msg = msgb_dequeue(&bts->abis_queue);
551 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte607044f2011-09-26 23:43:23 +0200552 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100553
554 if (wait)
555 break;
556 }
557
558 bts->abis_nm_pend = wait;
559}
560
Harald Welte59b04682009-06-10 05:40:52 +0800561/* Receive a OML NM Message from BTS */
562static int abis_nm_rcvmsg_fom(struct msgb *mb)
563{
564 struct abis_om_hdr *oh = msgb_l2(mb);
565 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200566 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200567 uint8_t mt = foh->msg_type;
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100568 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
569 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100570 int ret = 0;
Harald Welte59b04682009-06-10 05:40:52 +0800571
572 /* check for unsolicited message */
573 if (is_report(mt))
574 return abis_nm_rcvmsg_report(mb);
575
Harald Weltec61a90e2011-05-22 22:45:37 +0200576 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte59b04682009-06-10 05:40:52 +0800577 return abis_nm_rcvmsg_sw(mb);
578
Harald Weltec61a90e2011-05-22 22:45:37 +0200579 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800580 struct nm_nack_signal_data nack_data;
Harald Welte59b04682009-06-10 05:40:52 +0800581 struct tlv_parsed tp;
Harald Welte935d10b2009-10-08 20:18:59 +0200582
Harald Weltec61a90e2011-05-22 22:45:37 +0200583 abis_nm_debugp_foh(DNM, foh);
Harald Welte935d10b2009-10-08 20:18:59 +0200584
Harald Weltec61a90e2011-05-22 22:45:37 +0200585 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte59b04682009-06-10 05:40:52 +0800586
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100587 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +0800588 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +0200589 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +0200590 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +0800591 else
592 DEBUGPC(DNM, "\n");
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200593
Holger Hans Peter Freytherdfea6c82010-07-14 02:08:35 +0800594 nack_data.msg = mb;
595 nack_data.mt = mt;
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100596 nack_data.bts = bts;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200597 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100598 abis_nm_queue_send_next(bts);
Holger Hans Peter Freytherefedf942009-06-10 10:48:14 +0200599 return 0;
Harald Welte59b04682009-06-10 05:40:52 +0800600 }
601#if 0
602 /* check if last message is to be acked */
603 if (is_ack_nack(nmh->last_msgtype)) {
604 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Weltede4477a2009-12-24 12:20:20 +0100605 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800606 /* we got our ACK, continue sending the next msg */
607 } else if (mt == MT_NACK(nmh->last_msgtype)) {
608 /* we got a NACK, signal this to the caller */
Harald Weltede4477a2009-12-24 12:20:20 +0100609 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +0800610 /* FIXME: somehow signal this to the caller */
611 } else {
612 /* really strange things happen */
613 return -EINVAL;
614 }
615 }
616#endif
617
618 switch (mt) {
619 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100620 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800621 break;
622 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100623 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800624 break;
625 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100626 ret = abis_nm_rx_lmt_event(mb);
Harald Welte59b04682009-06-10 05:40:52 +0800627 break;
Harald Welte204317e2009-08-06 17:58:31 +0200628 case NM_MT_CONN_MDROP_LINK_ACK:
629 DEBUGP(DNM, "CONN MDROP LINK ACK\n");
630 break;
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100631 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200632 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100633 break;
634 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +0200635 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther9ef8e5a2009-12-30 09:00:01 +0100636 break;
Harald Welte08011e22011-03-04 13:41:31 +0100637 case NM_MT_SET_BTS_ATTR_ACK:
Harald Welte08011e22011-03-04 13:41:31 +0100638 break;
Harald Welte59b04682009-06-10 05:40:52 +0800639 }
640
Jacob Erlbeck38c33fc2014-11-10 08:30:31 +0100641 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100642 return ret;
Harald Welte59b04682009-06-10 05:40:52 +0800643}
644
645static int abis_nm_rx_ipacc(struct msgb *mb);
646
647static int abis_nm_rcvmsg_manuf(struct msgb *mb)
648{
649 int rc;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200650 struct e1inp_sign_link *sign_link = mb->dst;
651 int bts_type = sign_link->trx->bts->type;
Harald Welte59b04682009-06-10 05:40:52 +0800652
653 switch (bts_type) {
Mike Haben66e0ba02009-10-02 12:19:34 +0100654 case GSM_BTS_TYPE_NANOBTS:
Harald Welte35ac0e42012-07-02 19:51:55 +0200655 case GSM_BTS_TYPE_OSMO_SYSMO:
Harald Welte59b04682009-06-10 05:40:52 +0800656 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +0200657 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +0800658 break;
659 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100660 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
661 "BTS type (%u)\n", bts_type);
Harald Welte59b04682009-06-10 05:40:52 +0800662 rc = 0;
663 break;
664 }
665
666 return rc;
667}
668
669/* High-Level API */
670/* Entry-point where L2 OML from BTS enters the NM code */
671int abis_nm_rcvmsg(struct msgb *msg)
672{
673 struct abis_om_hdr *oh = msgb_l2(msg);
674 int rc = 0;
675
676 /* Various consistency checks */
677 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100678 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte59b04682009-06-10 05:40:52 +0800679 oh->placement);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200680 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
681 rc = -EINVAL;
682 goto err;
683 }
Harald Welte59b04682009-06-10 05:40:52 +0800684 }
685 if (oh->sequence != 0) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100686 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte59b04682009-06-10 05:40:52 +0800687 oh->sequence);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200688 rc = -EINVAL;
689 goto err;
Harald Welte59b04682009-06-10 05:40:52 +0800690 }
691#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200692 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Harald Welte59b04682009-06-10 05:40:52 +0800693 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
694 if (oh->length + hlen > l2_len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100695 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte59b04682009-06-10 05:40:52 +0800696 oh->length + sizeof(*oh), l2_len);
697 return -EINVAL;
698 }
699 if (oh->length + hlen < l2_len)
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100700 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 +0800701#endif
702 msg->l3h = (unsigned char *)oh + sizeof(*oh);
703
704 switch (oh->mdisc) {
705 case ABIS_OM_MDISC_FOM:
706 rc = abis_nm_rcvmsg_fom(msg);
707 break;
708 case ABIS_OM_MDISC_MANUF:
709 rc = abis_nm_rcvmsg_manuf(msg);
710 break;
711 case ABIS_OM_MDISC_MMI:
712 case ABIS_OM_MDISC_TRAU:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100713 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800714 oh->mdisc);
715 break;
716 default:
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100717 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte59b04682009-06-10 05:40:52 +0800718 oh->mdisc);
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200719 rc = -EINVAL;
720 break;
Harald Welte59b04682009-06-10 05:40:52 +0800721 }
Pablo Neira Ayusod96c8c02012-10-18 19:03:52 +0200722err:
Harald Welte59b04682009-06-10 05:40:52 +0800723 msgb_free(msg);
724 return rc;
725}
726
727#if 0
728/* initialized all resources */
729struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
730{
731 struct abis_nm_h *nmh;
732
733 nmh = malloc(sizeof(*nmh));
734 if (!nmh)
735 return NULL;
736
737 nmh->cfg = cfg;
738
739 return nmh;
740}
741
742/* free all resources */
743void abis_nm_fini(struct abis_nm_h *nmh)
744{
745 free(nmh);
746}
747#endif
748
749/* Here we are trying to define a high-level API that can be used by
750 * the actual BSC implementation. However, the architecture is currently
751 * still under design. Ideally the calls to this API would be synchronous,
752 * while the underlying stack behind the APi runs in a traditional select
753 * based state machine.
754 */
755
756/* 6.2 Software Load: */
757enum sw_state {
758 SW_STATE_NONE,
759 SW_STATE_WAIT_INITACK,
760 SW_STATE_WAIT_SEGACK,
761 SW_STATE_WAIT_ENDACK,
762 SW_STATE_WAIT_ACTACK,
763 SW_STATE_ERROR,
764};
765
766struct abis_nm_sw {
767 struct gsm_bts *bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +0800768 int trx_nr;
Harald Welte59b04682009-06-10 05:40:52 +0800769 gsm_cbfn *cbfn;
770 void *cb_data;
771 int forced;
772
773 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200774 uint8_t obj_class;
775 uint8_t obj_instance[3];
Harald Welte59b04682009-06-10 05:40:52 +0800776
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200777 uint8_t file_id[255];
778 uint8_t file_id_len;
Harald Welte59b04682009-06-10 05:40:52 +0800779
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200780 uint8_t file_version[255];
781 uint8_t file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800782
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200783 uint8_t window_size;
784 uint8_t seg_in_window;
Harald Welte59b04682009-06-10 05:40:52 +0800785
786 int fd;
787 FILE *stream;
788 enum sw_state state;
789 int last_seg;
790};
791
792static struct abis_nm_sw g_sw;
793
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100794static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
795{
796 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
797 msgb_v_put(msg, NM_ATT_SW_DESCR);
798 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
799 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
800 sw->file_version);
801 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
802 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
803 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
804 sw->file_version);
805 } else {
806 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
807 }
808}
809
Harald Welte59b04682009-06-10 05:40:52 +0800810/* 6.2.1 / 8.3.1: Load Data Initiate */
811static int sw_load_init(struct abis_nm_sw *sw)
812{
813 struct abis_om_hdr *oh;
814 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200815 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800816
817 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
818 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
819 sw->obj_instance[0], sw->obj_instance[1],
820 sw->obj_instance[2]);
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +0100821
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100822 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800823 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
824
825 return abis_nm_sendmsg(sw->bts, msg);
826}
827
828static int is_last_line(FILE *stream)
829{
830 char next_seg_buf[256];
831 long pos;
832
833 /* check if we're sending the last line */
834 pos = ftell(stream);
Holger Hans Peter Freyther4c11d0b2014-04-04 11:48:32 +0200835
836 /* Did ftell fail? Then we are at the end for sure */
837 if (pos < 0)
838 return 1;
839
Harald Welte59b04682009-06-10 05:40:52 +0800840 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
841 fseek(stream, pos, SEEK_SET);
842 return 1;
843 }
844
845 fseek(stream, pos, SEEK_SET);
846 return 0;
847}
848
849/* 6.2.2 / 8.3.2 Load Data Segment */
850static int sw_load_segment(struct abis_nm_sw *sw)
851{
852 struct abis_om_hdr *oh;
853 struct msgb *msg = nm_msgb_alloc();
854 char seg_buf[256];
855 char *line_buf = seg_buf+2;
856 unsigned char *tlv;
Harald Welted1989782011-07-16 13:03:29 +0200857 int len;
Harald Welte59b04682009-06-10 05:40:52 +0800858
859 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
860
861 switch (sw->bts->type) {
862 case GSM_BTS_TYPE_BS11:
863 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
864 perror("fgets reading segment");
865 return -EINVAL;
866 }
867 seg_buf[0] = 0x00;
868
869 /* check if we're sending the last line */
870 sw->last_seg = is_last_line(sw->stream);
871 if (sw->last_seg)
872 seg_buf[1] = 0;
873 else
874 seg_buf[1] = 1 + sw->seg_in_window++;
875
876 len = strlen(line_buf) + 2;
877 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200878 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte59b04682009-06-10 05:40:52 +0800879 /* BS11 wants CR + LF in excess of the TLV length !?! */
880 tlv[1] -= 2;
881
882 /* we only now know the exact length for the OM hdr */
883 len = strlen(line_buf)+2;
884 break;
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100885 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusob1d5a692011-05-07 12:12:48 +0200886 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100887 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
888 if (len < 0) {
889 perror("read failed");
890 return -EINVAL;
891 }
892
893 if (len != IPACC_SEGMENT_SIZE)
894 sw->last_seg = 1;
895
Holger Hans Peter Freyther679a2eb2009-12-28 11:28:51 +0100896 ++sw->seg_in_window;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200897 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freytherb5f54482009-12-28 10:04:26 +0100898 len += 3;
899 break;
900 }
Harald Welte59b04682009-06-10 05:40:52 +0800901 default:
Holger Hans Peter Freytherf8ea6172009-12-28 09:21:18 +0100902 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte59b04682009-06-10 05:40:52 +0800903 /* FIXME: Other BTS types */
904 return -1;
905 }
906
907 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
908 sw->obj_instance[0], sw->obj_instance[1],
909 sw->obj_instance[2]);
910
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +0100911 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800912}
913
914/* 6.2.4 / 8.3.4 Load Data End */
915static int sw_load_end(struct abis_nm_sw *sw)
916{
917 struct abis_om_hdr *oh;
918 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200919 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800920
921 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
922 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
923 sw->obj_instance[0], sw->obj_instance[1],
924 sw->obj_instance[2]);
925
Holger Hans Peter Freytherd617f562009-12-30 09:23:48 +0100926 sw_add_file_id_and_ver(sw, msg);
Harald Welte59b04682009-06-10 05:40:52 +0800927 return abis_nm_sendmsg(sw->bts, msg);
928}
929
930/* Activate the specified software into the BTS */
931static int sw_activate(struct abis_nm_sw *sw)
932{
933 struct abis_om_hdr *oh;
934 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +0200935 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte59b04682009-06-10 05:40:52 +0800936
937 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
938 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
939 sw->obj_instance[0], sw->obj_instance[1],
940 sw->obj_instance[2]);
941
942 /* FIXME: this is BS11 specific format */
943 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
944 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
945 sw->file_version);
946
947 return abis_nm_sendmsg(sw->bts, msg);
948}
949
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100950struct sdp_firmware {
951 char magic[4];
952 char more_magic[4];
953 unsigned int header_length;
954 unsigned int file_length;
955} __attribute__ ((packed));
956
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +0100957static int parse_sdp_header(struct abis_nm_sw *sw)
958{
Holger Hans Peter Freythera3ae06b2009-12-28 07:28:43 +0100959 struct sdp_firmware firmware_header;
960 int rc;
961 struct stat stat;
962
963 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
964 if (rc != sizeof(firmware_header)) {
965 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
966 return -1;
967 }
968
969 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
970 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
971 return -1;
972 }
973
974 if (firmware_header.more_magic[0] != 0x10 ||
975 firmware_header.more_magic[1] != 0x02 ||
976 firmware_header.more_magic[2] != 0x00 ||
977 firmware_header.more_magic[3] != 0x00) {
978 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
979 return -1;
980 }
981
982
983 if (fstat(sw->fd, &stat) == -1) {
984 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
985 return -1;
986 }
987
988 if (ntohl(firmware_header.file_length) != stat.st_size) {
989 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
990 return -1;
991 }
992
993 /* go back to the start as we checked the whole filesize.. */
994 lseek(sw->fd, 0l, SEEK_SET);
995 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
996 "There might be checksums in the file that are not\n"
997 "verified and incomplete firmware might be flashed.\n"
998 "There is absolutely no WARRANTY that flashing will\n"
999 "work.\n");
1000 return 0;
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001001}
1002
Harald Welte59b04682009-06-10 05:40:52 +08001003static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1004{
1005 char file_id[12+1];
1006 char file_version[80+1];
1007 int rc;
1008
1009 sw->fd = open(fname, O_RDONLY);
1010 if (sw->fd < 0)
1011 return sw->fd;
1012
1013 switch (sw->bts->type) {
1014 case GSM_BTS_TYPE_BS11:
1015 sw->stream = fdopen(sw->fd, "r");
1016 if (!sw->stream) {
1017 perror("fdopen");
1018 return -1;
1019 }
1020 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02001021 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte59b04682009-06-10 05:40:52 +08001022 file_id, file_version);
1023 if (rc != 2) {
1024 perror("parsing header line of software file");
1025 return -1;
1026 }
1027 strcpy((char *)sw->file_id, file_id);
1028 sw->file_id_len = strlen(file_id);
1029 strcpy((char *)sw->file_version, file_version);
1030 sw->file_version_len = strlen(file_version);
1031 /* rewind to start of file */
1032 rewind(sw->stream);
1033 break;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001034 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001035 /* TODO: extract that from the filename or content */
Holger Hans Peter Freytherb5c03d32009-12-23 08:06:31 +01001036 rc = parse_sdp_header(sw);
1037 if (rc < 0) {
1038 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1039 return -1;
1040 }
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001041
1042 strcpy((char *)sw->file_id, "id");
1043 sw->file_id_len = 3;
1044 strcpy((char *)sw->file_version, "version");
1045 sw->file_version_len = 8;
Holger Hans Peter Freytherdfdced02009-12-23 07:26:57 +01001046 break;
Harald Welte59b04682009-06-10 05:40:52 +08001047 default:
1048 /* We don't know how to treat them yet */
1049 close(sw->fd);
1050 return -EINVAL;
1051 }
1052
1053 return 0;
1054}
1055
1056static void sw_close_file(struct abis_nm_sw *sw)
1057{
1058 switch (sw->bts->type) {
1059 case GSM_BTS_TYPE_BS11:
1060 fclose(sw->stream);
1061 break;
1062 default:
1063 close(sw->fd);
1064 break;
1065 }
1066}
1067
1068/* Fill the window */
1069static int sw_fill_window(struct abis_nm_sw *sw)
1070{
1071 int rc;
1072
1073 while (sw->seg_in_window < sw->window_size) {
1074 rc = sw_load_segment(sw);
1075 if (rc < 0)
1076 return rc;
1077 if (sw->last_seg)
1078 break;
1079 }
1080 return 0;
1081}
1082
1083/* callback function from abis_nm_rcvmsg() handler */
1084static int abis_nm_rcvmsg_sw(struct msgb *mb)
1085{
1086 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001087 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte59b04682009-06-10 05:40:52 +08001088 int rc = -1;
1089 struct abis_nm_sw *sw = &g_sw;
1090 enum sw_state old_state = sw->state;
1091
1092 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
1093
1094 switch (sw->state) {
1095 case SW_STATE_WAIT_INITACK:
1096 switch (foh->msg_type) {
1097 case NM_MT_LOAD_INIT_ACK:
1098 /* fill window with segments */
1099 if (sw->cbfn)
1100 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1101 NM_MT_LOAD_INIT_ACK, mb,
1102 sw->cb_data, NULL);
1103 rc = sw_fill_window(sw);
1104 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001105 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001106 break;
1107 case NM_MT_LOAD_INIT_NACK:
1108 if (sw->forced) {
1109 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1110 "Init NACK\n");
1111 if (sw->cbfn)
1112 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1113 NM_MT_LOAD_INIT_ACK, mb,
1114 sw->cb_data, NULL);
1115 rc = sw_fill_window(sw);
1116 sw->state = SW_STATE_WAIT_SEGACK;
1117 } else {
1118 DEBUGP(DNM, "Software Load Init NACK\n");
1119 /* FIXME: cause */
1120 if (sw->cbfn)
1121 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1122 NM_MT_LOAD_INIT_NACK, mb,
1123 sw->cb_data, NULL);
1124 sw->state = SW_STATE_ERROR;
1125 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001126 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001127 break;
1128 }
1129 break;
1130 case SW_STATE_WAIT_SEGACK:
1131 switch (foh->msg_type) {
1132 case NM_MT_LOAD_SEG_ACK:
1133 if (sw->cbfn)
1134 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1135 NM_MT_LOAD_SEG_ACK, mb,
1136 sw->cb_data, NULL);
1137 sw->seg_in_window = 0;
1138 if (!sw->last_seg) {
1139 /* fill window with more segments */
1140 rc = sw_fill_window(sw);
1141 sw->state = SW_STATE_WAIT_SEGACK;
1142 } else {
1143 /* end the transfer */
1144 sw->state = SW_STATE_WAIT_ENDACK;
1145 rc = sw_load_end(sw);
1146 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001147 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001148 break;
Holger Hans Peter Freyther61f814d2009-12-28 12:23:02 +01001149 case NM_MT_LOAD_ABORT:
1150 if (sw->cbfn)
1151 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1152 NM_MT_LOAD_ABORT, mb,
1153 sw->cb_data, NULL);
1154 break;
Harald Welte59b04682009-06-10 05:40:52 +08001155 }
1156 break;
1157 case SW_STATE_WAIT_ENDACK:
1158 switch (foh->msg_type) {
1159 case NM_MT_LOAD_END_ACK:
1160 sw_close_file(sw);
1161 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1162 sw->bts->nr);
1163 sw->state = SW_STATE_NONE;
1164 if (sw->cbfn)
1165 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1166 NM_MT_LOAD_END_ACK, mb,
1167 sw->cb_data, NULL);
Holger Hans Peter Freyther99300722009-12-28 11:48:12 +01001168 rc = 0;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001169 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001170 break;
1171 case NM_MT_LOAD_END_NACK:
1172 if (sw->forced) {
1173 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1174 "End NACK\n");
1175 sw->state = SW_STATE_NONE;
1176 if (sw->cbfn)
1177 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1178 NM_MT_LOAD_END_ACK, mb,
1179 sw->cb_data, NULL);
1180 } else {
1181 DEBUGP(DNM, "Software Load End NACK\n");
1182 /* FIXME: cause */
1183 sw->state = SW_STATE_ERROR;
1184 if (sw->cbfn)
1185 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1186 NM_MT_LOAD_END_NACK, mb,
1187 sw->cb_data, NULL);
1188 }
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001189 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001190 break;
1191 }
1192 case SW_STATE_WAIT_ACTACK:
1193 switch (foh->msg_type) {
1194 case NM_MT_ACTIVATE_SW_ACK:
1195 /* we're done */
1196 DEBUGP(DNM, "Activate Software DONE!\n");
1197 sw->state = SW_STATE_NONE;
1198 rc = 0;
1199 if (sw->cbfn)
1200 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1201 NM_MT_ACTIVATE_SW_ACK, mb,
1202 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001203 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001204 break;
1205 case NM_MT_ACTIVATE_SW_NACK:
1206 DEBUGP(DNM, "Activate Software NACK\n");
1207 /* FIXME: cause */
1208 sw->state = SW_STATE_ERROR;
1209 if (sw->cbfn)
1210 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1211 NM_MT_ACTIVATE_SW_NACK, mb,
1212 sw->cb_data, NULL);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02001213 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte59b04682009-06-10 05:40:52 +08001214 break;
1215 }
1216 case SW_STATE_NONE:
1217 switch (foh->msg_type) {
1218 case NM_MT_ACTIVATE_SW_ACK:
1219 rc = 0;
1220 break;
1221 }
1222 break;
1223 case SW_STATE_ERROR:
1224 break;
1225 }
1226
1227 if (rc)
1228 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
1229 foh->msg_type, old_state, sw->state);
1230
1231 return rc;
1232}
1233
1234/* Load the specified software into the BTS */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001235int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001236 uint8_t win_size, int forced,
Harald Welte59b04682009-06-10 05:40:52 +08001237 gsm_cbfn *cbfn, void *cb_data)
1238{
1239 struct abis_nm_sw *sw = &g_sw;
1240 int rc;
1241
1242 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1243 bts->nr, fname);
1244
1245 if (sw->state != SW_STATE_NONE)
1246 return -EBUSY;
1247
1248 sw->bts = bts;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001249 sw->trx_nr = trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001250
1251 switch (bts->type) {
1252 case GSM_BTS_TYPE_BS11:
1253 sw->obj_class = NM_OC_SITE_MANAGER;
1254 sw->obj_instance[0] = 0xff;
1255 sw->obj_instance[1] = 0xff;
1256 sw->obj_instance[2] = 0xff;
1257 break;
1258 case GSM_BTS_TYPE_NANOBTS:
1259 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08001260 sw->obj_instance[0] = sw->bts->nr;
1261 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freyther38907002009-12-28 09:02:41 +01001262 sw->obj_instance[2] = 0xff;
1263 break;
1264 case GSM_BTS_TYPE_UNKNOWN:
1265 default:
1266 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1267 return -1;
1268 break;
1269 }
Harald Welte59b04682009-06-10 05:40:52 +08001270 sw->window_size = win_size;
1271 sw->state = SW_STATE_WAIT_INITACK;
1272 sw->cbfn = cbfn;
1273 sw->cb_data = cb_data;
1274 sw->forced = forced;
1275
1276 rc = sw_open_file(sw, fname);
1277 if (rc < 0) {
1278 sw->state = SW_STATE_NONE;
1279 return rc;
1280 }
1281
1282 return sw_load_init(sw);
1283}
1284
1285int abis_nm_software_load_status(struct gsm_bts *bts)
1286{
1287 struct abis_nm_sw *sw = &g_sw;
1288 struct stat st;
1289 int rc, percent;
1290
1291 rc = fstat(sw->fd, &st);
1292 if (rc < 0) {
1293 perror("ERROR during stat");
1294 return rc;
1295 }
1296
Holger Hans Peter Freyther876a06b2009-12-28 10:16:54 +01001297 if (sw->stream)
1298 percent = (ftell(sw->stream) * 100) / st.st_size;
1299 else
1300 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte59b04682009-06-10 05:40:52 +08001301 return percent;
1302}
1303
1304/* Activate the specified software into the BTS */
1305int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1306 gsm_cbfn *cbfn, void *cb_data)
1307{
1308 struct abis_nm_sw *sw = &g_sw;
1309 int rc;
1310
1311 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1312 bts->nr, fname);
1313
1314 if (sw->state != SW_STATE_NONE)
1315 return -EBUSY;
1316
1317 sw->bts = bts;
1318 sw->obj_class = NM_OC_SITE_MANAGER;
1319 sw->obj_instance[0] = 0xff;
1320 sw->obj_instance[1] = 0xff;
1321 sw->obj_instance[2] = 0xff;
1322 sw->state = SW_STATE_WAIT_ACTACK;
1323 sw->cbfn = cbfn;
1324 sw->cb_data = cb_data;
1325
1326 /* Open the file in order to fill some sw struct members */
1327 rc = sw_open_file(sw, fname);
1328 if (rc < 0) {
1329 sw->state = SW_STATE_NONE;
1330 return rc;
1331 }
1332 sw_close_file(sw);
1333
1334 return sw_activate(sw);
1335}
1336
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001337static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1338 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte59b04682009-06-10 05:40:52 +08001339{
1340 ch->attrib = NM_ATT_ABIS_CHANNEL;
1341 ch->bts_port = bts_port;
1342 ch->timeslot = ts_nr;
1343 ch->subslot = subslot_nr;
1344}
1345
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001346int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1347 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1348 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001349{
1350 struct abis_om_hdr *oh;
1351 struct abis_nm_channel *ch;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001352 uint8_t len = sizeof(*ch) + 2;
Harald Welte59b04682009-06-10 05:40:52 +08001353 struct msgb *msg = nm_msgb_alloc();
1354
1355 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1356 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1357 bts->bts_nr, trx_nr, 0xff);
1358
1359 msgb_tv_put(msg, NM_ATT_TEI, tei);
1360
1361 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1362 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1363
1364 return abis_nm_sendmsg(bts, msg);
1365}
1366
1367/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1368int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001369 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001370{
1371 struct gsm_bts *bts = trx->bts;
1372 struct abis_om_hdr *oh;
1373 struct abis_nm_channel *ch;
1374 struct msgb *msg = nm_msgb_alloc();
1375
1376 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1377 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
1378 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1379
1380 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1381 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1382
1383 return abis_nm_sendmsg(bts, msg);
1384}
1385
1386#if 0
1387int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1388 struct abis_nm_abis_channel *chan)
1389{
1390}
1391#endif
1392
1393int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001394 uint8_t e1_port, uint8_t e1_timeslot,
1395 uint8_t e1_subslot)
Harald Welte59b04682009-06-10 05:40:52 +08001396{
1397 struct gsm_bts *bts = ts->trx->bts;
1398 struct abis_om_hdr *oh;
1399 struct abis_nm_channel *ch;
1400 struct msgb *msg = nm_msgb_alloc();
1401
1402 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1403 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
1404 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
1405
1406 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1407 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1408
1409 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1410 gsm_ts_name(ts),
1411 e1_port, e1_timeslot, e1_subslot);
1412
1413 return abis_nm_sendmsg(bts, msg);
1414}
1415
1416#if 0
1417int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1418 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001419 uint8_t subchan)
Harald Welte59b04682009-06-10 05:40:52 +08001420{
1421}
1422#endif
1423
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001424/* Chapter 8.11.1 */
1425int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1426 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1427 uint8_t *attr, uint8_t attr_len)
1428{
1429 struct abis_om_hdr *oh;
1430 struct msgb *msg = nm_msgb_alloc();
Harald Welte2ec3a7b2012-08-14 19:15:57 +02001431
1432 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1433
1434 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1435 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1436 bts_nr, trx_nr, ts_nr);
1437 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1438
1439 return abis_nm_sendmsg(bts, msg);
1440}
1441
Harald Welte59b04682009-06-10 05:40:52 +08001442/* Chapter 8.6.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001443int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001444{
1445 struct abis_om_hdr *oh;
1446 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001447 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001448
1449 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1450
1451 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1452 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
1453 cur = msgb_put(msg, attr_len);
1454 memcpy(cur, attr, attr_len);
1455
1456 return abis_nm_sendmsg(bts, msg);
1457}
1458
1459/* Chapter 8.6.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001460int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08001461{
1462 struct abis_om_hdr *oh;
1463 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001464 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001465
1466 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1467
1468 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1469 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
1470 trx->bts->bts_nr, trx->nr, 0xff);
1471 cur = msgb_put(msg, attr_len);
1472 memcpy(cur, attr, attr_len);
1473
1474 return abis_nm_sendmsg(trx->bts, msg);
1475}
1476
Holger Hans Peter Freyther1f672322014-03-26 14:24:42 +01001477int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1478{
1479 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1480 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1481}
1482
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001483static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1484 const char **reason)
Harald Weltef2eb2782009-08-09 21:49:48 +02001485{
1486 int i;
1487
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001488 *reason = "Reason unknown";
1489
Harald Weltef2eb2782009-08-09 21:49:48 +02001490 /* As it turns out, the BS-11 has some very peculiar restrictions
1491 * on the channel combinations it allows */
Harald Welte76ba8812009-12-02 02:45:23 +05301492 switch (ts->trx->bts->type) {
1493 case GSM_BTS_TYPE_BS11:
Harald Weltef2eb2782009-08-09 21:49:48 +02001494 switch (chan_comb) {
1495 case NM_CHANC_TCHHalf:
1496 case NM_CHANC_TCHHalf2:
1497 /* not supported */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001498 *reason = "TCH/H is not supported.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001499 return -EINVAL;
1500 case NM_CHANC_SDCCH:
1501 /* only one SDCCH/8 per TRX */
1502 for (i = 0; i < TRX_NR_TS; i++) {
1503 if (i == ts->nr)
1504 continue;
1505 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001506 NM_CHANC_SDCCH) {
1507 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001508 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001509 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001510 }
1511 /* not allowed for TS0 of BCCH-TRX */
1512 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001513 ts->nr == 0) {
1514 *reason = "SDCCH/8 must be on TS0.";
1515 return -EINVAL;
1516 }
1517
Harald Weltef2eb2782009-08-09 21:49:48 +02001518 /* not on the same TRX that has a BCCH+SDCCH4
1519 * combination */
Holger Hans Peter Freytherfca3eb92013-01-08 19:30:14 +01001520 if (ts->trx != ts->trx->bts->c0 &&
Harald Weltef2eb2782009-08-09 21:49:48 +02001521 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001522 ts->trx->ts[0].nm_chan_comb == 8)) {
1523 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1524 return -EINVAL;
1525 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001526 break;
1527 case NM_CHANC_mainBCCH:
1528 case NM_CHANC_BCCHComb:
1529 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001530 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1531 *reason = "Main BCCH must be on TS0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001532 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001533 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001534 break;
1535 case NM_CHANC_BCCH:
1536 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001537 if (ts->trx != ts->trx->bts->c0) {
1538 *reason = "BCCH must be on C0.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001539 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001540 }
1541 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1542 *reason = "BCCH must be on TS 2/4/6.";
Harald Weltef2eb2782009-08-09 21:49:48 +02001543 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001544 }
Harald Weltef2eb2782009-08-09 21:49:48 +02001545 break;
1546 case 8: /* this is not like 08.58, but in fact
1547 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1548 /* FIXME: only one CBCH allowed per cell */
1549 break;
1550 }
Harald Welte76ba8812009-12-02 02:45:23 +05301551 break;
1552 case GSM_BTS_TYPE_NANOBTS:
1553 switch (ts->nr) {
1554 case 0:
1555 if (ts->trx->nr == 0) {
1556 /* only on TRX0 */
1557 switch (chan_comb) {
1558 case NM_CHANC_BCCH:
1559 case NM_CHANC_mainBCCH:
1560 case NM_CHANC_BCCHComb:
1561 return 0;
1562 break;
1563 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001564 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301565 return -EINVAL;
1566 }
1567 } else {
1568 switch (chan_comb) {
1569 case NM_CHANC_TCHFull:
1570 case NM_CHANC_TCHHalf:
1571 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1572 return 0;
1573 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001574 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welte76ba8812009-12-02 02:45:23 +05301575 return -EINVAL;
1576 }
1577 }
1578 break;
1579 case 1:
1580 if (ts->trx->nr == 0) {
1581 switch (chan_comb) {
1582 case NM_CHANC_SDCCH_CBCH:
1583 if (ts->trx->ts[0].nm_chan_comb ==
1584 NM_CHANC_mainBCCH)
1585 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001586 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301587 return -EINVAL;
1588 case NM_CHANC_SDCCH:
1589 case NM_CHANC_TCHFull:
1590 case NM_CHANC_TCHHalf:
1591 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1592 case NM_CHANC_IPAC_TCHFull_PDCH:
1593 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001594 default:
1595 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1596 return -EINVAL;
Harald Welte76ba8812009-12-02 02:45:23 +05301597 }
1598 } else {
1599 switch (chan_comb) {
1600 case NM_CHANC_SDCCH:
1601 case NM_CHANC_TCHFull:
1602 case NM_CHANC_TCHHalf:
1603 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1604 return 0;
1605 default:
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001606 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welte76ba8812009-12-02 02:45:23 +05301607 return -EINVAL;
1608 }
1609 }
1610 break;
1611 case 2:
1612 case 3:
1613 case 4:
1614 case 5:
1615 case 6:
1616 case 7:
1617 switch (chan_comb) {
1618 case NM_CHANC_TCHFull:
1619 case NM_CHANC_TCHHalf:
1620 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1621 return 0;
1622 case NM_CHANC_IPAC_PDCH:
1623 case NM_CHANC_IPAC_TCHFull_PDCH:
1624 if (ts->trx->nr == 0)
1625 return 0;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001626 else {
1627 *reason = "PDCH must be on TRX0.";
Harald Welte76ba8812009-12-02 02:45:23 +05301628 return -EINVAL;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001629 }
Harald Welte76ba8812009-12-02 02:45:23 +05301630 }
1631 break;
1632 }
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001633 *reason = "Unknown combination";
Harald Welte76ba8812009-12-02 02:45:23 +05301634 return -EINVAL;
Harald Welte35ac0e42012-07-02 19:51:55 +02001635 case GSM_BTS_TYPE_OSMO_SYSMO:
1636 /* no known restrictions */
1637 return 0;
Harald Welte76ba8812009-12-02 02:45:23 +05301638 default:
1639 /* unknown BTS type */
1640 return 0;
Harald Weltef2eb2782009-08-09 21:49:48 +02001641 }
1642 return 0;
1643}
1644
Harald Welte59b04682009-06-10 05:40:52 +08001645/* Chapter 8.6.3 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001646int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte59b04682009-06-10 05:40:52 +08001647{
1648 struct gsm_bts *bts = ts->trx->bts;
1649 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001650 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001651 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001652 uint8_t len = 2 + 2;
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001653 const char *reason = NULL;
Harald Welte59b04682009-06-10 05:40:52 +08001654
1655 if (bts->type == GSM_BTS_TYPE_BS11)
1656 len += 4 + 2 + 2 + 3;
1657
1658 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001659 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Weltef2eb2782009-08-09 21:49:48 +02001660 msgb_free(msg);
Holger Hans Peter Freyther8bb8e802012-09-17 15:49:16 +02001661 LOGP(DNM, LOGL_ERROR,
1662 "Invalid Channel Combination %d on %s. Reason: %s\n",
1663 chan_comb, gsm_ts_name(ts), reason);
Harald Weltef2eb2782009-08-09 21:49:48 +02001664 return -EINVAL;
1665 }
1666 ts->nm_chan_comb = chan_comb;
Harald Welte59b04682009-06-10 05:40:52 +08001667
1668 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1669 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
1670 NM_OC_CHANNEL, bts->bts_nr,
1671 ts->trx->nr, ts->nr);
Harald Welte59b04682009-06-10 05:40:52 +08001672 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea42a93f2010-06-14 22:26:10 +02001673 if (ts->hopping.enabled) {
1674 unsigned int i;
1675 uint8_t *len;
1676
Harald Welte67104d12009-09-12 13:05:33 +02001677 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1678 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea42a93f2010-06-14 22:26:10 +02001679
1680 /* build the ARFCN list */
1681 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1682 len = msgb_put(msg, 1);
1683 *len = 0;
1684 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1685 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1686 msgb_put_u16(msg, i);
laforgedcc63bb2010-06-20 15:20:02 +02001687 /* At least BS-11 wants a TLV16 here */
1688 if (bts->type == GSM_BTS_TYPE_BS11)
1689 *len += 1;
1690 else
1691 *len += sizeof(uint16_t);
Harald Weltea42a93f2010-06-14 22:26:10 +02001692 }
1693 }
Harald Welte59b04682009-06-10 05:40:52 +08001694 }
Harald Welte025e6c92014-01-19 17:18:21 +01001695 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Welte59b04682009-06-10 05:40:52 +08001696 if (bts->type == GSM_BTS_TYPE_BS11)
1697 msgb_tlv_put(msg, 0x59, 1, &zero);
1698
1699 return abis_nm_sendmsg(bts, msg);
1700}
1701
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001702int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1703 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte59b04682009-06-10 05:40:52 +08001704{
1705 struct abis_om_hdr *oh;
1706 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001707 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1708 uint8_t len = att_len;
Harald Welte59b04682009-06-10 05:40:52 +08001709
1710 if (nack) {
1711 len += 2;
1712 msgtype = NM_MT_SW_ACT_REQ_NACK;
1713 }
1714
1715 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1716 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1717
1718 if (attr) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001719 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte59b04682009-06-10 05:40:52 +08001720 memcpy(ptr, attr, att_len);
1721 }
1722 if (nack)
1723 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
1724
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01001725 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08001726}
1727
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001728int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte59b04682009-06-10 05:40:52 +08001729{
1730 struct msgb *msg = nm_msgb_alloc();
1731 struct abis_om_hdr *oh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001732 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08001733
1734 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1735 fill_om_hdr(oh, len);
1736 data = msgb_put(msg, len);
1737 memcpy(data, rawmsg, len);
1738
1739 return abis_nm_sendmsg(bts, msg);
1740}
1741
1742/* Siemens specific commands */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001743static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte59b04682009-06-10 05:40:52 +08001744{
1745 struct abis_om_hdr *oh;
1746 struct msgb *msg = nm_msgb_alloc();
1747
1748 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1749 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
1750 0xff, 0xff, 0xff);
1751
1752 return abis_nm_sendmsg(bts, msg);
1753}
1754
1755/* Chapter 8.9.2 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001756int 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 +08001757{
1758 struct abis_om_hdr *oh;
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001759 struct abis_om_fom_hdr *foh;
Harald Welte59b04682009-06-10 05:40:52 +08001760 struct msgb *msg = nm_msgb_alloc();
1761
Harald Welte59b04682009-06-10 05:40:52 +08001762 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001763 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte59b04682009-06-10 05:40:52 +08001764
Holger Hans Peter Freytherffd0f222014-04-04 12:56:34 +02001765 abis_nm_debugp_foh(DNM, foh);
Harald Welteb7284a92009-10-20 09:56:18 +02001766 DEBUGPC(DNM, "Sending OPSTART\n");
1767
Harald Welte59b04682009-06-10 05:40:52 +08001768 return abis_nm_sendmsg(bts, msg);
1769}
1770
1771/* Chapter 8.8.5 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001772int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1773 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte59b04682009-06-10 05:40:52 +08001774{
1775 struct abis_om_hdr *oh;
1776 struct msgb *msg = nm_msgb_alloc();
1777
1778 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1779 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1780 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1781
1782 return abis_nm_sendmsg(bts, msg);
1783}
1784
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001785int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1786 uint8_t e1_port1, uint8_t ts1)
Harald Welte204317e2009-08-06 17:58:31 +02001787{
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 *attr;
Harald Welte204317e2009-08-06 17:58:31 +02001791
1792 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1793 e1_port0, ts0, e1_port1, ts1);
1794
1795 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1796 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1797 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1798
1799 attr = msgb_put(msg, 3);
1800 attr[0] = NM_ATT_MDROP_LINK;
1801 attr[1] = e1_port0;
1802 attr[2] = ts0;
1803
1804 attr = msgb_put(msg, 3);
1805 attr[0] = NM_ATT_MDROP_NEXT;
1806 attr[1] = e1_port1;
1807 attr[2] = ts1;
1808
1809 return abis_nm_sendmsg(bts, msg);
1810}
Harald Welte59b04682009-06-10 05:40:52 +08001811
Harald Welte0bf8e302009-08-08 00:02:36 +02001812/* Chapter 8.7.1 */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001813int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1814 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1815 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Welte0bf8e302009-08-08 00:02:36 +02001816{
1817 struct abis_om_hdr *oh;
Harald Welte0bf8e302009-08-08 00:02:36 +02001818
Harald Weltec61a90e2011-05-22 22:45:37 +02001819 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welteb31c9df2010-03-06 11:38:05 +01001820
1821 if (!msg)
1822 msg = nm_msgb_alloc();
1823
1824 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1825 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1826 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1827 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Welte0bf8e302009-08-08 00:02:36 +02001828 obj_class, bts_nr, trx_nr, ts_nr);
Harald Welte0bf8e302009-08-08 00:02:36 +02001829
1830 return abis_nm_sendmsg(bts, msg);
1831}
1832
Harald Welte59b04682009-06-10 05:40:52 +08001833int abis_nm_event_reports(struct gsm_bts *bts, int on)
1834{
1835 if (on == 0)
1836 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
1837 else
1838 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
1839}
1840
1841/* Siemens (or BS-11) specific commands */
1842
1843int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1844{
1845 if (reconnect == 0)
1846 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1847 else
1848 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1849}
1850
1851int abis_nm_bs11_restart(struct gsm_bts *bts)
1852{
1853 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1854}
1855
1856
1857struct bs11_date_time {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001858 uint16_t year;
1859 uint8_t month;
1860 uint8_t day;
1861 uint8_t hour;
1862 uint8_t min;
1863 uint8_t sec;
Harald Welte59b04682009-06-10 05:40:52 +08001864} __attribute__((packed));
1865
1866
1867void get_bs11_date_time(struct bs11_date_time *aet)
1868{
1869 time_t t;
1870 struct tm *tm;
1871
1872 t = time(NULL);
1873 tm = localtime(&t);
1874 aet->sec = tm->tm_sec;
1875 aet->min = tm->tm_min;
1876 aet->hour = tm->tm_hour;
1877 aet->day = tm->tm_mday;
1878 aet->month = tm->tm_mon;
1879 aet->year = htons(1900 + tm->tm_year);
1880}
1881
1882int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
1883{
1884 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
1885}
1886
1887int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
1888{
1889 if (begin)
1890 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
1891 else
1892 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
1893}
1894
1895int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001896 enum abis_bs11_objtype type, uint8_t idx,
1897 uint8_t attr_len, const uint8_t *attr)
Harald Welte59b04682009-06-10 05:40:52 +08001898{
1899 struct abis_om_hdr *oh;
1900 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001901 uint8_t *cur;
Harald Welte59b04682009-06-10 05:40:52 +08001902
1903 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1904 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
1905 NM_OC_BS11, type, 0, idx);
1906 cur = msgb_put(msg, attr_len);
1907 memcpy(cur, attr, attr_len);
1908
1909 return abis_nm_sendmsg(bts, msg);
1910}
1911
1912int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001913 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001914{
1915 struct abis_om_hdr *oh;
1916 struct msgb *msg = nm_msgb_alloc();
1917
1918 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1919 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1920 NM_OC_BS11, type, 0, idx);
1921
1922 return abis_nm_sendmsg(bts, msg);
1923}
1924
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001925int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001926{
1927 struct abis_om_hdr *oh;
1928 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001929 uint8_t zero = 0x00;
Harald Welte59b04682009-06-10 05:40:52 +08001930
1931 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1932 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
1933 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1934 msgb_tlv_put(msg, 0x99, 1, &zero);
1935
1936 return abis_nm_sendmsg(bts, msg);
1937}
1938
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001939int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte59b04682009-06-10 05:40:52 +08001940{
1941 struct abis_om_hdr *oh;
1942 struct msgb *msg = nm_msgb_alloc();
1943
1944 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1945 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann5655afe2009-08-10 11:49:36 +02001946 idx, 0xff, 0xff);
1947
1948 return abis_nm_sendmsg(bts, msg);
1949}
1950
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001951int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann5655afe2009-08-10 11:49:36 +02001952{
1953 struct abis_om_hdr *oh;
1954 struct msgb *msg = nm_msgb_alloc();
1955
1956 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1957 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1958 idx, 0xff, 0xff);
Harald Welte59b04682009-06-10 05:40:52 +08001959
1960 return abis_nm_sendmsg(bts, msg);
1961}
1962
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001963static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte59b04682009-06-10 05:40:52 +08001964int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1965{
1966 struct abis_om_hdr *oh;
1967 struct msgb *msg = nm_msgb_alloc();
1968
1969 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1970 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1971 0xff, 0xff, 0xff);
1972 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1973
1974 return abis_nm_sendmsg(bts, msg);
1975}
1976
1977/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001978int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
1979 uint8_t e1_timeslot, uint8_t e1_subslot,
1980 uint8_t tei)
Harald Welte59b04682009-06-10 05:40:52 +08001981{
1982 struct abis_om_hdr *oh;
1983 struct abis_nm_channel *ch;
1984 struct msgb *msg = nm_msgb_alloc();
1985
1986 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1987 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
1988 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
1989
1990 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1991 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1992 msgb_tv_put(msg, NM_ATT_TEI, tei);
1993
1994 return abis_nm_sendmsg(bts, msg);
1995}
1996
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02001997int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte59b04682009-06-10 05:40:52 +08001998{
1999 struct abis_om_hdr *oh;
2000 struct msgb *msg = nm_msgb_alloc();
2001
2002 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2003 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
2004 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2005 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2006
2007 return abis_nm_sendmsg(trx->bts, msg);
2008}
2009
2010int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2011{
2012 struct abis_om_hdr *oh;
2013 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002014 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte59b04682009-06-10 05:40:52 +08002015
2016 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2017 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2018 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2019 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2020
2021 return abis_nm_sendmsg(trx->bts, msg);
2022}
2023
2024int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2025{
2026 struct abis_om_hdr *oh;
2027 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002028 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welte59b04682009-06-10 05:40:52 +08002029
2030 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2031 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2032 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
2033 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2034
2035 return abis_nm_sendmsg(bts, msg);
2036}
2037
2038int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2039{
2040 struct abis_om_hdr *oh;
2041 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002042 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welte59b04682009-06-10 05:40:52 +08002043 NM_ATT_BS11_CCLK_TYPE };
2044
2045 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2046 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2047 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2048 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2049
2050 return abis_nm_sendmsg(bts, msg);
2051
2052}
2053
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002054//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte59b04682009-06-10 05:40:52 +08002055
2056int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
2057{
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002058 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2059}
2060
Daniel Willmannbf2ca572010-01-07 00:46:26 +01002061int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2062{
2063 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2064}
2065
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002066int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002067{
Harald Welte59b04682009-06-10 05:40:52 +08002068 struct abis_om_hdr *oh;
2069 struct msgb *msg = nm_msgb_alloc();
2070 struct bs11_date_time bdt;
2071
2072 get_bs11_date_time(&bdt);
2073
2074 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2075 if (on) {
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002076 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002077 + 1 + strlen(name);
Harald Welte59b04682009-06-10 05:40:52 +08002078 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
2079 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2080 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002081 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte59b04682009-06-10 05:40:52 +08002082 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmanncb8f2502010-01-07 00:43:11 +01002083 1, &level);
Harald Welte59b04682009-06-10 05:40:52 +08002084 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002085 strlen(name), (uint8_t *)name);
Harald Welte59b04682009-06-10 05:40:52 +08002086 } else {
2087 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
2088 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
2089 }
2090
2091 return abis_nm_sendmsg(bts, msg);
2092}
2093
2094int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2095{
2096 struct abis_om_hdr *oh;
2097 struct msgb *msg;
2098
2099 if (strlen(password) != 10)
2100 return -EINVAL;
2101
2102 msg = nm_msgb_alloc();
2103 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2104 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
2105 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002106 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte59b04682009-06-10 05:40:52 +08002107
2108 return abis_nm_sendmsg(bts, msg);
2109}
2110
2111/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2112int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2113{
2114 struct abis_om_hdr *oh;
2115 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002116 uint8_t tlv_value;
Harald Welte59b04682009-06-10 05:40:52 +08002117
2118 msg = nm_msgb_alloc();
2119 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2120 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2121 BS11_OBJ_LI, 0x00, 0x00);
2122
2123 if (locked)
2124 tlv_value = BS11_LI_PLL_LOCKED;
2125 else
2126 tlv_value = BS11_LI_PLL_STANDALONE;
2127
2128 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
2129
2130 return abis_nm_sendmsg(bts, msg);
2131}
2132
Daniel Willmann10b07db2010-01-07 00:54:01 +01002133/* Set the calibration value of the PLL (work value/set value)
2134 * It depends on the login which one is changed */
2135int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2136{
2137 struct abis_om_hdr *oh;
2138 struct msgb *msg;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002139 uint8_t tlv_value[2];
Daniel Willmann10b07db2010-01-07 00:54:01 +01002140
2141 msg = nm_msgb_alloc();
2142 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2143 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2144 BS11_OBJ_TRX1, 0x00, 0x00);
2145
2146 tlv_value[0] = value>>8;
2147 tlv_value[1] = value&0xff;
2148
2149 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2150
2151 return abis_nm_sendmsg(bts, msg);
2152}
2153
Harald Welte59b04682009-06-10 05:40:52 +08002154int abis_nm_bs11_get_state(struct gsm_bts *bts)
2155{
2156 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2157}
2158
2159/* BS11 SWL */
2160
Harald Welte (local)8751ee92009-08-15 02:30:58 +02002161void *tall_fle_ctx;
Harald Weltea8379772009-06-20 22:36:41 +02002162
Harald Welte59b04682009-06-10 05:40:52 +08002163struct abis_nm_bs11_sw {
2164 struct gsm_bts *bts;
2165 char swl_fname[PATH_MAX];
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002166 uint8_t win_size;
Harald Welte59b04682009-06-10 05:40:52 +08002167 int forced;
2168 struct llist_head file_list;
2169 gsm_cbfn *user_cb; /* specified by the user */
2170};
2171static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2172
2173struct file_list_entry {
2174 struct llist_head list;
2175 char fname[PATH_MAX];
2176};
2177
2178struct file_list_entry *fl_dequeue(struct llist_head *queue)
2179{
2180 struct llist_head *lh;
2181
2182 if (llist_empty(queue))
2183 return NULL;
2184
2185 lh = queue->next;
2186 llist_del(lh);
2187
2188 return llist_entry(lh, struct file_list_entry, list);
2189}
2190
2191static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2192{
2193 char linebuf[255];
2194 struct llist_head *lh, *lh2;
2195 FILE *swl;
2196 int rc = 0;
2197
2198 swl = fopen(bs11_sw->swl_fname, "r");
2199 if (!swl)
2200 return -ENODEV;
2201
2202 /* zero the stale file list, if any */
2203 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2204 llist_del(lh);
Harald Weltea8379772009-06-20 22:36:41 +02002205 talloc_free(lh);
Harald Welte59b04682009-06-10 05:40:52 +08002206 }
2207
2208 while (fgets(linebuf, sizeof(linebuf), swl)) {
2209 char file_id[12+1];
2210 char file_version[80+1];
2211 struct file_list_entry *fle;
2212 static char dir[PATH_MAX];
2213
2214 if (strlen(linebuf) < 4)
2215 continue;
2216
2217 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2218 if (rc < 0) {
2219 perror("ERR parsing SWL file");
2220 rc = -EINVAL;
2221 goto out;
2222 }
2223 if (rc < 2)
2224 continue;
2225
Harald Welte857e00d2009-06-26 20:25:23 +02002226 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte59b04682009-06-10 05:40:52 +08002227 if (!fle) {
2228 rc = -ENOMEM;
2229 goto out;
2230 }
Harald Welte59b04682009-06-10 05:40:52 +08002231
2232 /* construct new filename */
2233 strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
2234 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2235 strcat(fle->fname, "/");
2236 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
2237
2238 llist_add_tail(&fle->list, &bs11_sw->file_list);
2239 }
2240
2241out:
2242 fclose(swl);
2243 return rc;
2244}
2245
2246/* bs11 swload specific callback, passed to abis_nm core swload */
2247static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2248 struct msgb *msg, void *data, void *param)
2249{
2250 struct abis_nm_bs11_sw *bs11_sw = data;
2251 struct file_list_entry *fle;
2252 int rc = 0;
2253
2254 switch (event) {
2255 case NM_MT_LOAD_END_ACK:
2256 fle = fl_dequeue(&bs11_sw->file_list);
2257 if (fle) {
2258 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002259 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte59b04682009-06-10 05:40:52 +08002260 bs11_sw->win_size,
2261 bs11_sw->forced,
2262 &bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002263 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002264 } else {
2265 /* activate the SWL */
2266 rc = abis_nm_software_activate(bs11_sw->bts,
2267 bs11_sw->swl_fname,
2268 bs11_swload_cbfn,
2269 bs11_sw);
2270 }
2271 break;
2272 case NM_MT_LOAD_SEG_ACK:
2273 case NM_MT_LOAD_END_NACK:
2274 case NM_MT_LOAD_INIT_ACK:
2275 case NM_MT_LOAD_INIT_NACK:
2276 case NM_MT_ACTIVATE_SW_NACK:
2277 case NM_MT_ACTIVATE_SW_ACK:
2278 default:
2279 /* fallthrough to the user callback */
2280 if (bs11_sw->user_cb)
2281 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
2282 break;
2283 }
2284
2285 return rc;
2286}
2287
2288/* Siemens provides a SWL file that is a mere listing of all the other
2289 * files that are part of a software release. We need to upload first
2290 * the list file, and then each file that is listed in the list file */
2291int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002292 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte59b04682009-06-10 05:40:52 +08002293{
2294 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2295 struct file_list_entry *fle;
2296 int rc = 0;
2297
2298 INIT_LLIST_HEAD(&bs11_sw->file_list);
2299 bs11_sw->bts = bts;
2300 bs11_sw->win_size = win_size;
2301 bs11_sw->user_cb = cbfn;
2302 bs11_sw->forced = forced;
2303
2304 strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
2305 rc = bs11_read_swl_file(bs11_sw);
2306 if (rc < 0)
2307 return rc;
2308
2309 /* dequeue next item in file list */
2310 fle = fl_dequeue(&bs11_sw->file_list);
2311 if (!fle)
2312 return -EINVAL;
2313
2314 /* start download the next file of our file list */
Holger Hans Peter Freyther2b4083a2010-05-12 23:51:46 +08002315 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte59b04682009-06-10 05:40:52 +08002316 bs11_swload_cbfn, bs11_sw);
Harald Welteb6328b92009-08-06 15:44:18 +02002317 talloc_free(fle);
Harald Welte59b04682009-06-10 05:40:52 +08002318 return rc;
2319}
2320
2321#if 0
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002322static uint8_t req_attr_btse[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002323 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2324 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2325 NM_ATT_BS11_LMT_USER_NAME,
2326
2327 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2328
2329 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2330
2331 NM_ATT_BS11_SW_LOAD_STORED };
2332
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002333static uint8_t req_attr_btsm[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002334 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2335 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2336 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2337 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
2338#endif
2339
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002340static uint8_t req_attr[] = {
Harald Welte59b04682009-06-10 05:40:52 +08002341 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2342 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
2343 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
2344
2345int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2346{
2347 struct abis_om_hdr *oh;
2348 struct msgb *msg = nm_msgb_alloc();
2349
2350 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2351 /* SiemensHW CCTRL object */
2352 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2353 0x03, 0x00, 0x00);
2354 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2355
2356 return abis_nm_sendmsg(bts, msg);
2357}
2358
2359int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2360{
2361 struct abis_om_hdr *oh;
2362 struct msgb *msg = nm_msgb_alloc();
2363 struct bs11_date_time aet;
2364
2365 get_bs11_date_time(&aet);
2366 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2367 /* SiemensHW CCTRL object */
2368 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2369 0xff, 0xff, 0xff);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002370 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte59b04682009-06-10 05:40:52 +08002371
2372 return abis_nm_sendmsg(bts, msg);
2373}
2374
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002375int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Welte30534c52010-12-14 12:52:16 +01002376{
2377 struct abis_om_hdr *oh;
2378 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002379 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Welte30534c52010-12-14 12:52:16 +01002380
2381 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2382 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2383 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2384 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2385
2386 return abis_nm_sendmsg(bts, msg);
2387}
2388
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002389int 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 +02002390{
2391 struct abis_om_hdr *oh;
2392 struct msgb *msg = nm_msgb_alloc();
2393 struct bs11_date_time aet;
2394
2395 get_bs11_date_time(&aet);
2396 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2397 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2398 bport, 0xff, 0x02);
2399 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2400
2401 return abis_nm_sendmsg(bts, msg);
2402}
2403
Harald Welte59b04682009-06-10 05:40:52 +08002404/* ip.access nanoBTS specific commands */
2405static const char ipaccess_magic[] = "com.ipaccess";
2406
2407
2408static int abis_nm_rx_ipacc(struct msgb *msg)
2409{
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002410 struct in_addr addr;
Harald Welte59b04682009-06-10 05:40:52 +08002411 struct abis_om_hdr *oh = msgb_l2(msg);
2412 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002413 uint8_t idstrlen = oh->data[0];
Harald Welte59b04682009-06-10 05:40:52 +08002414 struct tlv_parsed tp;
Holger Hans Peter Freyther0fc5ab42009-12-30 08:38:43 +01002415 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002416 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte59b04682009-06-10 05:40:52 +08002417
2418 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltede4477a2009-12-24 12:20:20 +01002419 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte59b04682009-06-10 05:40:52 +08002420 return -EINVAL;
2421 }
2422
2423 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002424 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte59b04682009-06-10 05:40:52 +08002425
Harald Weltec61a90e2011-05-22 22:45:37 +02002426 abis_nm_debugp_foh(DNM, foh);
Harald Weltefd579d52009-10-19 21:46:54 +02002427
Harald Welte5aeedd42009-10-19 22:11:11 +02002428 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte59b04682009-06-10 05:40:52 +08002429
2430 switch (foh->msg_type) {
2431 case NM_MT_IPACC_RSL_CONNECT_ACK:
2432 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freytherd3b6f942010-06-21 10:22:26 +08002433 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2434 memcpy(&addr,
2435 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2436
2437 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2438 }
Harald Welte4206d982009-07-12 09:33:54 +02002439 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte59b04682009-06-10 05:40:52 +08002440 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002441 ntohs(*((uint16_t *)
Harald Welte4206d982009-07-12 09:33:54 +02002442 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte0eccfd02009-10-19 22:49:33 +02002443 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2444 DEBUGPC(DNM, "STREAM=0x%02x ",
2445 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte59b04682009-06-10 05:40:52 +08002446 DEBUGPC(DNM, "\n");
2447 break;
2448 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002449 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002450 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002451 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002452 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002453 else
Alexander Chemerisf3f3d302013-10-06 23:35:39 +02002454 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002455 break;
2456 case NM_MT_IPACC_SET_NVATTR_ACK:
2457 DEBUGPC(DNM, "SET NVATTR ACK\n");
2458 /* FIXME: decode and show the actual attributes */
2459 break;
2460 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002461 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte59b04682009-06-10 05:40:52 +08002462 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002463 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002464 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte59b04682009-06-10 05:40:52 +08002465 else
Harald Weltede4477a2009-12-24 12:20:20 +01002466 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte59b04682009-06-10 05:40:52 +08002467 break;
Harald Welte21460f02009-07-03 11:26:45 +02002468 case NM_MT_IPACC_GET_NVATTR_ACK:
2469 DEBUGPC(DNM, "GET NVATTR ACK\n");
2470 /* FIXME: decode and show the actual attributes */
2471 break;
2472 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002473 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte21460f02009-07-03 11:26:45 +02002474 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002475 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002476 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte21460f02009-07-03 11:26:45 +02002477 else
Harald Weltede4477a2009-12-24 12:20:20 +01002478 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte21460f02009-07-03 11:26:45 +02002479 break;
Harald Weltec76a2172009-10-08 20:15:24 +02002480 case NM_MT_IPACC_SET_ATTR_ACK:
2481 DEBUGPC(DNM, "SET ATTR ACK\n");
2482 break;
2483 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltede4477a2009-12-24 12:20:20 +01002484 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Weltec76a2172009-10-08 20:15:24 +02002485 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002486 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Weltec61a90e2011-05-22 22:45:37 +02002487 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Weltec76a2172009-10-08 20:15:24 +02002488 else
Harald Weltede4477a2009-12-24 12:20:20 +01002489 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Weltec76a2172009-10-08 20:15:24 +02002490 break;
Harald Welte59b04682009-06-10 05:40:52 +08002491 default:
2492 DEBUGPC(DNM, "unknown\n");
2493 break;
2494 }
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002495
2496 /* signal handling */
2497 switch (foh->msg_type) {
2498 case NM_MT_IPACC_RSL_CONNECT_NACK:
2499 case NM_MT_IPACC_SET_NVATTR_NACK:
2500 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002501 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 +01002502 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002503 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002504 break;
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002505 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso88c9bba2011-08-17 22:43:54 +02002506 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 +01002507 signal.msg_type = foh->msg_type;
Pablo Neira Ayusoef717c62011-05-06 12:12:31 +02002508 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther257b8db2009-12-29 11:26:38 +01002509 break;
Holger Hans Peter Freyther72baef32009-07-07 12:40:07 +02002510 default:
2511 break;
2512 }
2513
Harald Welte59b04682009-06-10 05:40:52 +08002514 return 0;
2515}
2516
2517/* send an ip-access manufacturer specific message */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002518int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2519 uint8_t obj_class, uint8_t bts_nr,
2520 uint8_t trx_nr, uint8_t ts_nr,
2521 uint8_t *attr, int attr_len)
Harald Welte59b04682009-06-10 05:40:52 +08002522{
2523 struct msgb *msg = nm_msgb_alloc();
2524 struct abis_om_hdr *oh;
2525 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002526 uint8_t *data;
Harald Welte59b04682009-06-10 05:40:52 +08002527
2528 /* construct the 12.21 OM header, observe the erroneous length */
2529 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2530 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2531 oh->mdisc = ABIS_OM_MDISC_MANUF;
2532
2533 /* add the ip.access magic */
2534 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2535 *data++ = sizeof(ipaccess_magic);
2536 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2537
2538 /* fill the 12.21 FOM header */
2539 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2540 foh->msg_type = msg_type;
2541 foh->obj_class = obj_class;
2542 foh->obj_inst.bts_nr = bts_nr;
2543 foh->obj_inst.trx_nr = trx_nr;
2544 foh->obj_inst.ts_nr = ts_nr;
2545
2546 if (attr && attr_len) {
2547 data = msgb_put(msg, attr_len);
2548 memcpy(data, attr, attr_len);
2549 }
2550
2551 return abis_nm_sendmsg(bts, msg);
2552}
2553
2554/* set some attributes in NVRAM */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002555int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte59b04682009-06-10 05:40:52 +08002556 int attr_len)
2557{
Harald Weltef12c1052010-01-07 20:39:42 +01002558 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2559 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte59b04682009-06-10 05:40:52 +08002560 attr_len);
2561}
2562
Holger Hans Peter Freyther71135142010-03-29 08:47:44 +02002563int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002564 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte5aeedd42009-10-19 22:11:11 +02002565{
2566 struct in_addr ia;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002567 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte5aeedd42009-10-19 22:11:11 +02002568 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2569 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2570
2571 int attr_len = sizeof(attr);
2572
2573 ia.s_addr = htonl(ip);
2574 attr[1] = stream;
2575 attr[3] = port >> 8;
2576 attr[4] = port & 0xff;
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002577 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte5aeedd42009-10-19 22:11:11 +02002578
2579 /* if ip == 0, we use the default IP */
2580 if (ip == 0)
2581 attr_len -= 5;
2582
2583 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte6947c882009-10-19 22:50:30 +02002584 inet_ntoa(ia), port, stream);
Harald Welte5aeedd42009-10-19 22:11:11 +02002585
2586 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2587 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2588 trx->nr, 0xff, attr, attr_len);
2589}
2590
Harald Welte59b04682009-06-10 05:40:52 +08002591/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002592int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte59b04682009-06-10 05:40:52 +08002593{
Holger Hans Peter Freyther37783842010-05-12 23:34:51 +08002594 struct abis_om_hdr *oh;
2595 struct msgb *msg = nm_msgb_alloc();
2596
2597 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2598 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2599 trx->bts->nr, trx->nr, 0xff);
2600
2601 return abis_nm_sendmsg(trx->bts, msg);
Harald Welte59b04682009-06-10 05:40:52 +08002602}
Harald Welte0dfc6232009-10-24 10:20:41 +02002603
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002604int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2605 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2606 uint8_t *attr, uint8_t attr_len)
Harald Welte0dfc6232009-10-24 10:20:41 +02002607{
2608 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2609 obj_class, bts_nr, trx_nr, ts_nr,
2610 attr, attr_len);
2611}
Harald Weltebeeae412009-11-12 14:48:42 +01002612
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002613void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte3055e332010-03-14 15:37:43 +08002614{
2615 /* we simply reuse the GSM48 function and overwrite the RAC
2616 * with the Cell ID */
2617 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002618 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte3055e332010-03-14 15:37:43 +08002619}
2620
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002621void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2622{
2623 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2624
Harald Welte69f6f812011-05-30 12:07:53 +02002625 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther1c8b4802009-11-11 11:54:24 +01002626 if (!trx->bts || !trx->bts->oml_link)
2627 return;
2628
2629 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2630 trx->bts->bts_nr, trx->nr, 0xff,
2631 new_state);
2632}
2633
Harald Welte453141f2010-03-25 11:45:30 +08002634static const struct value_string ipacc_testres_names[] = {
2635 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2636 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2637 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2638 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2639 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2640 { 0, NULL }
Harald Weltebeeae412009-11-12 14:48:42 +01002641};
2642
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002643const char *ipacc_testres_name(uint8_t res)
Harald Weltebeeae412009-11-12 14:48:42 +01002644{
Harald Welte453141f2010-03-25 11:45:30 +08002645 return get_value_string(ipacc_testres_names, res);
Harald Weltebeeae412009-11-12 14:48:42 +01002646}
2647
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002648void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Weltebfc21092009-11-13 11:56:05 +01002649{
2650 cid->mcc = (buf[0] & 0xf) * 100;
2651 cid->mcc += (buf[0] >> 4) * 10;
2652 cid->mcc += (buf[1] & 0xf) * 1;
2653
2654 if (buf[1] >> 4 == 0xf) {
2655 cid->mnc = (buf[2] & 0xf) * 10;
2656 cid->mnc += (buf[2] >> 4) * 1;
2657 } else {
2658 cid->mnc = (buf[2] & 0xf) * 100;
2659 cid->mnc += (buf[2] >> 4) * 10;
2660 cid->mnc += (buf[1] >> 4) * 1;
2661 }
2662
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002663 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2664 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Weltebfc21092009-11-13 11:56:05 +01002665}
2666
Harald Weltebeeae412009-11-12 14:48:42 +01002667/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002668int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Weltebeeae412009-11-12 14:48:42 +01002669{
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002670 uint8_t *cur = buf;
Holger Hans Peter Freyther1a9f3ee2012-09-11 11:55:03 +02002671 uint16_t len __attribute__((unused));
Harald Weltebeeae412009-11-12 14:48:42 +01002672
Harald Welteb784df82010-07-22 18:14:36 +02002673 memset(binf, 0, sizeof(*binf));
Harald Weltebeeae412009-11-12 14:48:42 +01002674
2675 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2676 return -EINVAL;
2677 cur++;
2678
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002679 len = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002680 cur += 2;
2681
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002682 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002683 cur += 2;
2684
2685 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2686 binf->freq_qual = *cur >> 2;
2687
Harald Welteb784df82010-07-22 18:14:36 +02002688 binf->arfcn = (*cur++ & 3) << 8;
Harald Weltebeeae412009-11-12 14:48:42 +01002689 binf->arfcn |= *cur++;
2690
2691 if (binf->info_type & IPAC_BINF_RXLEV)
2692 binf->rx_lev = *cur & 0x3f;
2693 cur++;
2694
2695 if (binf->info_type & IPAC_BINF_RXQUAL)
2696 binf->rx_qual = *cur & 0x7;
2697 cur++;
2698
2699 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002700 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002701 cur += 2;
2702
2703 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002704 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002705 cur += 2;
2706
2707 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freyther7eb8a9a2011-04-18 17:04:00 +02002708 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Weltebeeae412009-11-12 14:48:42 +01002709 cur += 4;
2710
Harald Welte22cb81f2010-07-30 22:34:42 +02002711#if 0
2712 /* Somehow this is not set correctly */
Harald Weltebeeae412009-11-12 14:48:42 +01002713 if (binf->info_type & IPAC_BINF_BSIC)
Harald Welte22cb81f2010-07-30 22:34:42 +02002714#endif
Harald Welte161b4be2009-11-13 14:41:52 +01002715 binf->bsic = *cur & 0x3f;
Harald Weltebeeae412009-11-12 14:48:42 +01002716 cur++;
2717
Harald Weltebfc21092009-11-13 11:56:05 +01002718 ipac_parse_cgi(&binf->cgi, cur);
2719 cur += 7;
Harald Weltebeeae412009-11-12 14:48:42 +01002720
2721 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2722 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2723 cur += sizeof(binf->ba_list_si2);
2724 }
2725
2726 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2727 memcpy(binf->ba_list_si2bis, cur,
2728 sizeof(binf->ba_list_si2bis));
2729 cur += sizeof(binf->ba_list_si2bis);
2730 }
2731
2732 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2733 memcpy(binf->ba_list_si2ter, cur,
2734 sizeof(binf->ba_list_si2ter));
2735 cur += sizeof(binf->ba_list_si2ter);
2736 }
2737
2738 return 0;
2739}
Holger Hans Peter Freyther2a6bffe2010-11-15 20:50:42 +01002740
2741void abis_nm_clear_queue(struct gsm_bts *bts)
2742{
2743 struct msgb *msg;
2744
2745 while (!llist_empty(&bts->abis_queue)) {
2746 msg = msgb_dequeue(&bts->abis_queue);
2747 msgb_free(msg);
2748 }
2749
2750 bts->abis_nm_pend = 0;
2751}