blob: aa418cac51756b04901ebdc4e4b43fbdc45e48b3 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-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 Welte52b1f982008-12-23 20:25:15 +000011 * (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 Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-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 Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Neels Hofmeyrc0164792017-09-04 15:15:32 +020037#include <osmocom/bsc/gsm_data.h>
38#include <osmocom/bsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
Maxa5e36932017-01-11 11:51:28 +010040#include <osmocom/gsm/protocol/gsm_12_21.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010041#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020042#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010043#include <osmocom/core/talloc.h>
Neels Hofmeyr93bafb62017-01-13 03:12:08 +010044#include <osmocom/core/utils.h>
Neels Hofmeyrc0164792017-09-04 15:15:32 +020045#include <osmocom/bsc/abis_nm.h>
46#include <osmocom/bsc/misdn.h>
47#include <osmocom/bsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020048#include <osmocom/abis/e1_input.h>
Max115e2672017-11-29 13:21:58 +010049#include <osmocom/bsc/chan_alloc.h>
Philipp Maier8c498fc2018-02-21 13:24:36 +010050#include <osmocom/gsm/bts_features.h>
Harald Welte52b1f982008-12-23 20:25:15 +000051
Harald Welte8470bf22008-12-25 23:28:35 +000052#define OM_ALLOC_SIZE 1024
53#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010054#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000055
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020056int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000057{
Harald Welte39315c42010-01-10 18:01:52 +010058 if (!bts->model)
59 return -EIO;
60 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000061}
Harald Weltee0590df2009-02-15 03:34:15 +000062
Harald Welte52b1f982008-12-23 20:25:15 +000063static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
64{
65 int i;
66
67 for (i = 0; i < size; i++) {
68 if (arr[i] == mt)
69 return 1;
70 }
71
72 return 0;
73}
74
Holger Freytherca362a62009-01-04 21:05:01 +000075#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000076/* is this msgtype the usual ACK/NACK type ? */
77static int is_ack_nack(enum abis_nm_msgtype mt)
78{
79 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
80}
Holger Freytherca362a62009-01-04 21:05:01 +000081#endif
Harald Welte52b1f982008-12-23 20:25:15 +000082
83/* is this msgtype a report ? */
84static int is_report(enum abis_nm_msgtype mt)
85{
Harald Welte15c61722011-05-22 22:45:37 +020086 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000087}
88
89#define MT_ACK(x) (x+1)
90#define MT_NACK(x) (x+2)
91
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020092static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000093{
94 oh->mdisc = ABIS_OM_MDISC_FOM;
95 oh->placement = ABIS_OM_PLACEMENT_ONLY;
96 oh->sequence = 0;
97 oh->length = len;
98}
99
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200100static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200101 uint8_t msg_type, uint8_t obj_class,
102 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000103{
104 struct abis_om_fom_hdr *foh =
105 (struct abis_om_fom_hdr *) oh->data;
106
Harald Welte702d8702008-12-26 20:25:35 +0000107 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000108 foh->msg_type = msg_type;
109 foh->obj_class = obj_class;
110 foh->obj_inst.bts_nr = bts_nr;
111 foh->obj_inst.trx_nr = trx_nr;
112 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200113 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000114}
115
Harald Welte8470bf22008-12-25 23:28:35 +0000116static struct msgb *nm_msgb_alloc(void)
117{
Harald Welte966636f2009-06-26 19:39:35 +0200118 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
119 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000120}
121
Harald Welte15eae8d2011-09-26 23:43:23 +0200122int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200123{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200124 msg->l2h = msg->data;
125
126 if (!msg->dst) {
127 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
128 return -EINVAL;
129 }
130
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200131 return abis_sendmsg(msg);
132}
133
Harald Welte52b1f982008-12-23 20:25:15 +0000134/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100135static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000136{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200137 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000138
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100139 /* queue OML messages */
140 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
141 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200142 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100143 } else {
144 msgb_enqueue(&bts->abis_queue, msg);
145 return 0;
146 }
147
148}
149
150int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
151{
152 OBSC_NM_W_ACK_CB(msg) = 1;
153 return abis_nm_queue_msg(bts, msg);
154}
155
156static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
157{
158 OBSC_NM_W_ACK_CB(msg) = 0;
159 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000160}
161
Harald Welte4724f992009-01-18 18:01:49 +0000162static int abis_nm_rcvmsg_sw(struct msgb *mb);
163
Maxd0ff6942017-11-29 12:45:34 +0100164bool nm_is_running(const struct gsm_nm_state *s) {
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100165 return (s->operational == NM_OPSTATE_ENABLED) && (
166 (s->availability == NM_AVSTATE_OK) ||
167 (s->availability == 0xff)
168 );
169}
170
Harald Weltee0590df2009-02-15 03:34:15 +0000171/* Update the administrative state of a given object in our in-memory data
172 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200173static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
174 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000175{
Harald Welteaeedeb42009-05-01 13:08:14 +0000176 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100177 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000178
Harald Welteaf9b8102011-03-06 21:20:38 +0100179 memset(&nsd, 0, sizeof(nsd));
180
Harald Welte978714d2011-06-06 18:31:20 +0200181 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100182 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100183 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200184 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000185 if (!nm_state)
186 return -1;
187
188 new_state = *nm_state;
189 new_state.administrative = adm_state;
190
Harald Weltef38ca9a2011-03-06 22:11:32 +0100191 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100192 nsd.obj_class = obj_class;
193 nsd.old_state = nm_state;
194 nsd.new_state = &new_state;
195 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200196 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000197
198 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000199
Harald Weltef338a032011-01-14 15:55:42 +0100200 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000201}
202
Harald Welte97ed1e72009-02-06 13:38:02 +0000203static int abis_nm_rx_statechg_rep(struct msgb *mb)
204{
Harald Weltee0590df2009-02-15 03:34:15 +0000205 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000206 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200207 struct e1inp_sign_link *sign_link = mb->dst;
208 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000209 struct tlv_parsed tp;
210 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000211
Harald Welte23897662009-05-01 14:52:51 +0000212 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000213
Harald Welte8b697c72009-06-05 19:18:45 +0000214 memset(&new_state, 0, sizeof(new_state));
215
Harald Welte978714d2011-06-06 18:31:20 +0200216 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000217 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100218 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000219 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000220 }
Harald Weltee0590df2009-02-15 03:34:15 +0000221
222 new_state = *nm_state;
223
Harald Welte39315c42010-01-10 18:01:52 +0100224 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000225 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
226 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200227 DEBUGPC(DNM, "OP_STATE=%s ",
228 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000229 }
230 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000231 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
232 new_state.availability = 0xff;
233 else
234 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200235 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
236 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000237 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100238 } else
239 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000240 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
241 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200242 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200243 get_value_string(abis_nm_adm_state_names,
244 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000245 }
246 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000247
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100248 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
249 new_state.operational != nm_state->operational ||
250 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000251 /* Update the operational state of a given object in our in-memory data
252 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100253 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200254 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100255 nsd.obj_class = foh->obj_class;
256 nsd.old_state = nm_state;
257 nsd.new_state = &new_state;
258 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100259 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200260 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100261 nm_state->operational = new_state.operational;
262 nm_state->availability = new_state.availability;
263 if (nm_state->administrative == 0)
264 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000265 }
266#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000267 if (op_state == 1) {
268 /* try to enable objects that are disabled */
269 abis_nm_opstart(bts, foh->obj_class,
270 foh->obj_inst.bts_nr,
271 foh->obj_inst.trx_nr,
272 foh->obj_inst.ts_nr);
273 }
Harald Weltee0590df2009-02-15 03:34:15 +0000274#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000275 return 0;
276}
277
Maxb1e6b372017-03-15 14:30:21 +0100278static inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type,
279 const char *severity, const uint8_t *p_val,
280 const char *text)
281{
282 enum abis_nm_pcause_type pcause = p_val[0];
283 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
284
285 LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr);
286 if (type)
287 LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type);
288 if (severity)
289 LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity);
290
291 LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
292 get_value_string(abis_nm_pcause_type_names, pcause));
293
294 if (pcause == NM_PCAUSE_T_MANUF)
295 LOGPC(DNM, LOGL_ERROR, "%s, ",
296 get_value_string(abis_mm_event_cause_names, cause));
297 else
298 LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
299
300 if (text) {
301 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text);
302 }
303
304 LOGPC(DNM, LOGL_ERROR, "\n");
305}
306
Maxa18001d2017-04-10 16:47:17 +0200307static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type,
Maxb1e6b372017-03-15 14:30:21 +0100308 const char *severity, const char *text)
309{
310 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
311
312 switch (cause) {
313 case OSMO_EVT_PCU_VERS:
Maxa18001d2017-04-10 16:47:17 +0200314 if (text) {
315 LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text);
316 osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version));
317 } else {
318 LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr);
319 bts->pcu_version[0] = '\0';
320 }
Maxb1e6b372017-03-15 14:30:21 +0100321 break;
322 default:
323 log_oml_fail_rep(bts, type, severity, p_val, text);
324 };
325}
326
Maxa18001d2017-04-10 16:47:17 +0200327static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts)
Harald Welte0db97b22009-05-01 17:22:47 +0000328{
329 struct abis_om_hdr *oh = msgb_l2(mb);
330 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200331 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000332 struct tlv_parsed tp;
Maxb1e6b372017-03-15 14:30:21 +0100333 int rc = 0;
334 const uint8_t *p_val = NULL;
335 char *p_text = NULL;
336 const char *e_type = NULL, *severity = NULL;
Harald Welte0db97b22009-05-01 17:22:47 +0000337
Maxb1e6b372017-03-15 14:30:21 +0100338 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
339 oh->length-sizeof(*foh));
Maxa5e36932017-01-11 11:51:28 +0100340
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100341 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
342 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
Maxb1e6b372017-03-15 14:30:21 +0100343 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val,
344 TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100345 }
Harald Welte0db97b22009-05-01 17:22:47 +0000346
Maxb1e6b372017-03-15 14:30:21 +0100347 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
348 e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
349 NM_ATT_EVENT_TYPE));
Harald Welte0db97b22009-05-01 17:22:47 +0000350
Maxb1e6b372017-03-15 14:30:21 +0100351 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
352 severity = abis_nm_severity_name(*TLVP_VAL(&tp,
353 NM_ATT_SEVERITY));
354
355 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
356 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
357
358 switch (p_val[0]) {
359 case NM_PCAUSE_T_MANUF:
360 handle_manufact_report(bts, p_val, e_type, severity,
361 p_text);
362 break;
363 default:
364 log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
365 };
366 } else {
367 LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without "
368 "Probable Cause?!\n", bts->nr);
369 rc = -EINVAL;
370 }
371
372 if (p_text)
373 talloc_free(p_text);
374
375 return rc;
Harald Welte0db97b22009-05-01 17:22:47 +0000376}
377
Maxb1e6b372017-03-15 14:30:21 +0100378static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
Harald Welte97ed1e72009-02-06 13:38:02 +0000379{
380 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200381 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000382
Harald Welte15c61722011-05-22 22:45:37 +0200383 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000384
Harald Welte97ed1e72009-02-06 13:38:02 +0000385 //nmh->cfg->report_cb(mb, foh);
386
387 switch (mt) {
388 case NM_MT_STATECHG_EVENT_REP:
389 return abis_nm_rx_statechg_rep(mb);
390 break;
Harald Welte34a99682009-02-13 02:41:40 +0000391 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000392 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200393 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000394 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000395 case NM_MT_FAILURE_EVENT_REP:
Maxb1e6b372017-03-15 14:30:21 +0100396 rx_fail_evt_rep(mb, bts);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200397 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000398 break;
Harald Weltec7310382009-08-08 00:02:36 +0200399 case NM_MT_TEST_REP:
400 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200401 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200402 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000403 default:
Harald Welte23897662009-05-01 14:52:51 +0000404 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000405 break;
406
Harald Welte97ed1e72009-02-06 13:38:02 +0000407 };
408
Harald Welte97ed1e72009-02-06 13:38:02 +0000409 return 0;
410}
411
Harald Welte34a99682009-02-13 02:41:40 +0000412/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200413static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
Maxfd2c1f92017-03-24 21:04:57 +0100414 uint8_t i2, const struct abis_nm_sw_desc *sw_desc)
Harald Welte34a99682009-02-13 02:41:40 +0000415{
416 struct abis_om_hdr *oh;
417 struct msgb *msg = nm_msgb_alloc();
Maxfd2c1f92017-03-24 21:04:57 +0100418 uint16_t len = abis_nm_sw_desc_len(sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000419
420 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
421 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
Maxfd2c1f92017-03-24 21:04:57 +0100422 abis_nm_put_sw_desc(msg, sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000423
424 return abis_nm_sendmsg(bts, msg);
425}
426
Maxfd2c1f92017-03-24 21:04:57 +0100427int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr,
428 const size_t size)
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100429{
430 int res = 0;
431 int i;
432
433 for (i = 1; i < size; ++i) {
Maxfd2c1f92017-03-24 21:04:57 +0100434 if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version,
435 OSMO_MIN(sw_descr[i].file_version_len,
436 sw_descr[res].file_version_len)) < 0) {
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100437 res = i;
438 }
439 }
440
441 return res;
442}
443
Max33e13572017-05-29 11:48:29 +0200444static inline bool handle_attr(const struct gsm_bts *bts, enum bts_attribute id, uint8_t *val, uint8_t len)
Maxdefb6c92017-05-15 10:29:54 +0200445{
446 switch (id) {
447 case BTS_TYPE_VARIANT:
Max33e13572017-05-29 11:48:29 +0200448 LOGP(DNM, LOGL_NOTICE, "BTS%u reported variant: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200449 break;
450 case BTS_SUB_MODEL:
Max33e13572017-05-29 11:48:29 +0200451 LOGP(DNM, LOGL_NOTICE, "BTS%u reported submodel: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200452 break;
453 default:
454 return false;
455 }
456 return true;
457}
458
Max33e13572017-05-29 11:48:29 +0200459/* Parse Attribute Response Info - return pointer to the actual content */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100460static inline const uint8_t *parse_attr_resp_info_unreported(uint8_t bts_nr, const uint8_t *ari, uint16_t ari_len, uint16_t *out_len)
Max33e13572017-05-29 11:48:29 +0200461{
462 uint8_t num_unreported = ari[0], i;
463
464 DEBUGP(DNM, "BTS%u Get Attributes Response Info: %u bytes total with %u unreported attributes\n",
465 bts_nr, ari_len, num_unreported);
466
467 /* +1 because we have to account for number of unreported attributes, prefixing the list: */
468 for (i = 0; i < num_unreported; i++)
469 LOGP(DNM, LOGL_ERROR, "BTS%u Attribute %s is unreported\n",
470 bts_nr, get_value_string(abis_nm_att_names, ari[i + 1]));
471
472 /* the data starts right after the list of unreported attributes + space for length of that list */
473 *out_len = ari_len - (num_unreported + 2);
474
475 return ari + num_unreported + 1; /* we have to account for 1st byte with number of unreported attributes */
476}
477
Maxc51c1e72017-06-06 15:40:40 +0200478/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.30 Manufacturer Id */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100479static inline const uint8_t *parse_attr_resp_info_manuf_id(struct gsm_bts *bts, const uint8_t *data, uint16_t *data_len)
Maxc51c1e72017-06-06 15:40:40 +0200480{
481 struct tlv_parsed tp;
482 uint16_t m_id_len = 0;
483 uint8_t adjust = 0, i;
484
485 abis_nm_tlv_parse(&tp, bts, data, *data_len);
486 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_ID, 2)) {
487 m_id_len = TLVP_LEN(&tp, NM_ATT_MANUF_ID);
488
Max5a44d252017-06-13 10:15:58 +0200489 /* log potential BTS feature vector overflow */
490 if (m_id_len > sizeof(bts->_features_data))
Maxc51c1e72017-06-06 15:40:40 +0200491 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: feature vector is truncated to %u bytes\n",
492 bts->nr, MAX_BTS_FEATURES/8);
Maxc51c1e72017-06-06 15:40:40 +0200493
Max5a44d252017-06-13 10:15:58 +0200494 /* check that max. expected BTS attribute is above given feature vector length */
495 if (m_id_len > OSMO_BYTES_FOR_BITS(_NUM_BTS_FEAT))
Maxc51c1e72017-06-06 15:40:40 +0200496 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: reported unexpectedly long (%u bytes) "
497 "feature vector - most likely it was compiled against newer BSC headers. "
498 "Consider upgrading your BSC to later version.\n",
499 bts->nr, m_id_len);
500
Maxa60bb3d2017-06-12 13:45:03 +0200501 memcpy(bts->_features_data, TLVP_VAL(&tp, NM_ATT_MANUF_ID), sizeof(bts->_features_data));
Maxc51c1e72017-06-06 15:40:40 +0200502 adjust = m_id_len + 3; /* adjust for parsed TL16V struct */
503
504 for (i = 0; i < _NUM_BTS_FEAT; i++)
Philipp Maier8c498fc2018-02-21 13:24:36 +0100505 if (osmo_bts_has_feature(&bts->features, i) != osmo_bts_has_feature(&bts->model->features, i))
Maxc51c1e72017-06-06 15:40:40 +0200506 LOGP(DNM, LOGL_NOTICE, "BTS%u feature '%s' reported via OML does not match statically "
507 "set feature: %u != %u. Please fix.\n", bts->nr,
Philipp Maier8c498fc2018-02-21 13:24:36 +0100508 get_value_string(osmo_bts_features_descs, i),
509 osmo_bts_has_feature(&bts->features, i), osmo_bts_has_feature(&bts->model->features, i));
Maxc51c1e72017-06-06 15:40:40 +0200510 }
511
512 *data_len -= adjust;
513
514 return data + adjust;
515}
516
Max33e13572017-05-29 11:48:29 +0200517/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.28 Manufacturer Dependent State */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100518static inline const uint8_t *parse_attr_resp_info_manuf_state(const struct gsm_bts_trx *trx, const uint8_t *data, uint16_t *data_len)
Max33e13572017-05-29 11:48:29 +0200519{
520 struct tlv_parsed tp;
521 const uint8_t *power;
522 uint8_t adjust = 0;
523
524 if (!trx) /* this attribute does not make sense on BTS level, only on TRX level */
525 return data;
526
527 abis_nm_tlv_parse(&tp, trx->bts, data, *data_len);
528 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_STATE, 1)) {
529 power = TLVP_VAL(&tp, NM_ATT_MANUF_STATE);
530 LOGP(DNM, LOGL_NOTICE, "%s Get Attributes Response: nominal power is %u\n", gsm_trx_name(trx), *power);
531 adjust = 2; /* adjust for parsed TV struct */
532 }
533
534 *data_len -= adjust;
535
536 return data + adjust;
537}
538
Maxdefb6c92017-05-15 10:29:54 +0200539/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */
Max33e13572017-05-29 11:48:29 +0200540static int abis_nm_rx_get_attr_resp(struct msgb *mb, const struct gsm_bts_trx *trx)
Maxdefb6c92017-05-15 10:29:54 +0200541{
542 struct abis_om_hdr *oh = msgb_l2(mb);
543 struct abis_om_fom_hdr *foh = msgb_l3(mb);
544 struct e1inp_sign_link *sign_link = mb->dst;
Max33e13572017-05-29 11:48:29 +0200545 struct gsm_bts *bts = trx ? trx->bts : sign_link->trx->bts;
Maxdefb6c92017-05-15 10:29:54 +0200546 struct tlv_parsed tp;
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100547 const uint8_t *data;
548 int i;
Max33e13572017-05-29 11:48:29 +0200549 uint16_t data_len;
Maxdefb6c92017-05-15 10:29:54 +0200550 int rc;
551 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
552
553 abis_nm_debugp_foh(DNM, foh);
554
Max33e13572017-05-29 11:48:29 +0200555 DEBUGPC(DNM, "Get Attributes Response for BTS%u\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200556
Max33e13572017-05-29 11:48:29 +0200557 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
558 if (!TLVP_PRES_LEN(&tp, NM_ATT_GET_ARI, 1)) {
559 LOGP(DNM, LOGL_ERROR, "BTS%u: Get Attributes Response without Response Info?!\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200560 return -EINVAL;
561 }
562
Max33e13572017-05-29 11:48:29 +0200563 data = parse_attr_resp_info_unreported(bts->nr, TLVP_VAL(&tp, NM_ATT_GET_ARI), TLVP_LEN(&tp, NM_ATT_GET_ARI),
564 &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200565
Max33e13572017-05-29 11:48:29 +0200566 data = parse_attr_resp_info_manuf_state(trx, data, &data_len);
Maxc51c1e72017-06-06 15:40:40 +0200567 data = parse_attr_resp_info_manuf_id(bts, data, &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200568
Max33e13572017-05-29 11:48:29 +0200569 /* after parsing manufacturer-specific attributes there's list of replies in form of sw-conf structure: */
570 rc = abis_nm_get_sw_conf(data, data_len, &sw_descr[0], ARRAY_SIZE(sw_descr));
Maxdefb6c92017-05-15 10:29:54 +0200571 if (rc > 0) {
572 for (i = 0; i < rc; i++) {
Max33e13572017-05-29 11:48:29 +0200573 if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id),
574 sw_descr[i].file_version, sw_descr[i].file_version_len))
575 LOGP(DNM, LOGL_NOTICE, "BTS%u: ARI reported sw[%d/%d]: %s is %s\n",
576 bts->nr, i, rc, sw_descr[i].file_id, sw_descr[i].file_version);
Maxdefb6c92017-05-15 10:29:54 +0200577 }
578 } else
Max33e13572017-05-29 11:48:29 +0200579 LOGP(DNM, LOGL_ERROR, "BTS%u: failed to parse SW-Config part of Get Attribute Response Info: %s\n",
580 bts->nr, strerror(-rc));
Maxdefb6c92017-05-15 10:29:54 +0200581
582 return 0;
583}
584
Max1ebf23b2017-05-10 12:21:17 +0200585/* 3GPP TS 52.021 §6.2.5 */
Harald Welte34a99682009-02-13 02:41:40 +0000586static int abis_nm_rx_sw_act_req(struct msgb *mb)
587{
588 struct abis_om_hdr *oh = msgb_l2(mb);
589 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200590 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200591 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200592 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100593 int ret, sw_config_len, len;
Max1ebf23b2017-05-10 12:21:17 +0200594 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
Harald Welte34a99682009-02-13 02:41:40 +0000595
Harald Welte15c61722011-05-22 22:45:37 +0200596 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200597
598 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000599
Harald Welte97a282b2010-03-14 15:37:43 +0800600 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000601
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200602 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000603 foh->obj_inst.bts_nr,
604 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800605 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000606 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100607 if (ret != 0) {
608 LOGP(DNM, LOGL_ERROR,
609 "Sending SW ActReq ACK failed: %d\n", ret);
610 return ret;
611 }
Harald Welte34a99682009-02-13 02:41:40 +0000612
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200613 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200614 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
615 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
616 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100617 LOGP(DNM, LOGL_ERROR,
618 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200619 return -EINVAL;
620 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200621 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200622 }
623
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100624 /* Parse up to two sw descriptions from the data */
Maxfd2c1f92017-03-24 21:04:57 +0100625 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
626 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100627 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100628 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100629 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100630 }
Mike Habena03f9772009-10-01 14:56:13 +0200631
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100632 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
633 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
634
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200635 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000636 foh->obj_inst.bts_nr,
637 foh->obj_inst.trx_nr,
638 foh->obj_inst.ts_nr,
Maxfd2c1f92017-03-24 21:04:57 +0100639 &sw_descr[ret]);
Harald Welte34a99682009-02-13 02:41:40 +0000640}
641
Harald Weltee0590df2009-02-15 03:34:15 +0000642/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
643static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
644{
645 struct abis_om_hdr *oh = msgb_l2(mb);
646 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200647 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000648 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200649 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000650
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200651 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000652 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
653 return -EINVAL;
654
655 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
656
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200657 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000658}
659
Harald Welteee670472009-02-22 21:58:49 +0000660static int abis_nm_rx_lmt_event(struct msgb *mb)
661{
662 struct abis_om_hdr *oh = msgb_l2(mb);
663 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200664 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000665 struct tlv_parsed tp;
666
667 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200668 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000669 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
670 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200671 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000672 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
673 }
674 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
675 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200676 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000677 DEBUGPC(DNM, "Level=%u ", level);
678 }
679 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
680 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
681 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
682 DEBUGPC(DNM, "Username=%s ", name);
683 }
684 DEBUGPC(DNM, "\n");
685 /* FIXME: parse LMT LOGON TIME */
686 return 0;
687}
688
Maxaa954cd2017-11-29 12:18:02 +0100689bool all_trx_rsl_connected_unlocked(const struct gsm_bts *bts)
Max3d049d22017-10-09 17:12:53 +0200690{
691 const struct gsm_bts_trx *trx;
692
Maxaa954cd2017-11-29 12:18:02 +0100693 if (bts->mo.nm_state.administrative == NM_STATE_LOCKED)
694 return false;
695
Max115e2672017-11-29 13:21:58 +0100696 if (bts->gprs.mode != BTS_GPRS_NONE) {
697 if (bts->gprs.cell.mo.nm_state.administrative == NM_STATE_LOCKED)
698 return false;
699
700 if (bts->gprs.nse.mo.nm_state.administrative == NM_STATE_LOCKED)
701 return false;
702
703 if (bts->gprs.nsvc[0].mo.nm_state.administrative == NM_STATE_LOCKED &&
704 bts->gprs.nsvc[1].mo.nm_state.administrative == NM_STATE_LOCKED)
705 return false;
706 }
707
Max3d049d22017-10-09 17:12:53 +0200708 llist_for_each_entry(trx, &bts->trx_list, list) {
709 if (!trx->rsl_link)
710 return false;
Max115e2672017-11-29 13:21:58 +0100711
712 if (!trx_is_usable(trx))
713 return false;
714
Maxaa954cd2017-11-29 12:18:02 +0100715 if (trx->mo.nm_state.administrative == NM_STATE_LOCKED)
716 return false;
Max3d049d22017-10-09 17:12:53 +0200717 }
718
719 return true;
720}
721
Max3d049d22017-10-09 17:12:53 +0200722char *get_model_oml_status(const struct gsm_bts *bts)
723{
724 if (bts->model->oml_status)
725 return bts->model->oml_status(bts);
726
727 return "unknown";
728}
729
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200730void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100731{
732 int wait = 0;
733 struct msgb *msg;
734 /* the queue is empty */
735 while (!llist_empty(&bts->abis_queue)) {
736 msg = msgb_dequeue(&bts->abis_queue);
737 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200738 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100739
740 if (wait)
741 break;
742 }
743
744 bts->abis_nm_pend = wait;
745}
746
Harald Welte52b1f982008-12-23 20:25:15 +0000747/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000748static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000749{
Harald Welte6c96ba52009-05-01 13:03:40 +0000750 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000751 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200752 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200753 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100754 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
755 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100756 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000757
758 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000759 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100760 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000761
Harald Welte15c61722011-05-22 22:45:37 +0200762 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000763 return abis_nm_rcvmsg_sw(mb);
764
Harald Welte15c61722011-05-22 22:45:37 +0200765 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800766 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000767 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200768
Harald Welte15c61722011-05-22 22:45:37 +0200769 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200770
Harald Welte15c61722011-05-22 22:45:37 +0200771 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000772
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100773 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000774 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200775 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200776 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000777 else
778 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200779
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800780 nack_data.msg = mb;
781 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100782 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200783 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100784 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200785 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000786 }
Harald Weltead384642008-12-26 10:20:07 +0000787#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000788 /* check if last message is to be acked */
789 if (is_ack_nack(nmh->last_msgtype)) {
790 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100791 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000792 /* we got our ACK, continue sending the next msg */
793 } else if (mt == MT_NACK(nmh->last_msgtype)) {
794 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100795 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000796 /* FIXME: somehow signal this to the caller */
797 } else {
798 /* really strange things happen */
799 return -EINVAL;
800 }
801 }
Harald Weltead384642008-12-26 10:20:07 +0000802#endif
803
Harald Welte97ed1e72009-02-06 13:38:02 +0000804 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000805 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100806 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000807 break;
Harald Welte34a99682009-02-13 02:41:40 +0000808 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100809 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000810 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000811 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100812 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000813 break;
Max689e7e52017-04-04 19:21:24 +0200814 case NM_MT_OPSTART_ACK:
815 abis_nm_debugp_foh(DNM, foh);
816 DEBUGPC(DNM, "Opstart ACK\n");
817 break;
818 case NM_MT_SET_CHAN_ATTR_ACK:
819 abis_nm_debugp_foh(DNM, foh);
820 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
821 break;
822 case NM_MT_SET_RADIO_ATTR_ACK:
823 abis_nm_debugp_foh(DNM, foh);
824 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
825 break;
Harald Welte1989c082009-08-06 17:58:31 +0200826 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200827 abis_nm_debugp_foh(DNM, foh);
828 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200829 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100830 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200831 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100832 break;
833 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200834 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100835 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100836 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100837 break;
Maxdefb6c92017-05-15 10:29:54 +0200838 case NM_MT_GET_ATTR_RESP:
Max33e13572017-05-29 11:48:29 +0200839 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Maxdefb6c92017-05-15 10:29:54 +0200840 break;
Max689e7e52017-04-04 19:21:24 +0200841 default:
842 abis_nm_debugp_foh(DNM, foh);
843 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
844 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000845 }
846
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100847 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100848 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000849}
850
Harald Welte677c21f2009-02-17 13:22:23 +0000851static int abis_nm_rx_ipacc(struct msgb *mb);
852
853static int abis_nm_rcvmsg_manuf(struct msgb *mb)
854{
855 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200856 struct e1inp_sign_link *sign_link = mb->dst;
857 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000858
859 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100860 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100861 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000862 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200863 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000864 break;
865 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100866 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
867 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000868 rc = 0;
869 break;
870 }
871
872 return rc;
873}
874
Harald Welte52b1f982008-12-23 20:25:15 +0000875/* High-Level API */
876/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000877int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000878{
Harald Welte52b1f982008-12-23 20:25:15 +0000879 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000880 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000881
882 /* Various consistency checks */
883 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100884 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000885 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200886 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
887 rc = -EINVAL;
888 goto err;
889 }
Harald Welte52b1f982008-12-23 20:25:15 +0000890 }
891 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100892 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000893 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200894 rc = -EINVAL;
895 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000896 }
Harald Welte702d8702008-12-26 20:25:35 +0000897#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200898 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000899 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000900 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100901 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000902 oh->length + sizeof(*oh), l2_len);
903 return -EINVAL;
904 }
Harald Welte702d8702008-12-26 20:25:35 +0000905 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100906 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 Welte702d8702008-12-26 20:25:35 +0000907#endif
Harald Weltead384642008-12-26 10:20:07 +0000908 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000909
910 switch (oh->mdisc) {
911 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000912 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000913 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000914 case ABIS_OM_MDISC_MANUF:
915 rc = abis_nm_rcvmsg_manuf(msg);
916 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000917 case ABIS_OM_MDISC_MMI:
918 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100919 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000920 oh->mdisc);
921 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000922 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100923 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000924 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200925 rc = -EINVAL;
926 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000927 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200928err:
Harald Weltead384642008-12-26 10:20:07 +0000929 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000930 return rc;
931}
932
933#if 0
934/* initialized all resources */
935struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
936{
937 struct abis_nm_h *nmh;
938
939 nmh = malloc(sizeof(*nmh));
940 if (!nmh)
941 return NULL;
942
943 nmh->cfg = cfg;
944
945 return nmh;
946}
947
948/* free all resources */
949void abis_nm_fini(struct abis_nm_h *nmh)
950{
951 free(nmh);
952}
953#endif
954
955/* Here we are trying to define a high-level API that can be used by
956 * the actual BSC implementation. However, the architecture is currently
957 * still under design. Ideally the calls to this API would be synchronous,
958 * while the underlying stack behind the APi runs in a traditional select
959 * based state machine.
960 */
961
Harald Welte4724f992009-01-18 18:01:49 +0000962/* 6.2 Software Load: */
963enum sw_state {
964 SW_STATE_NONE,
965 SW_STATE_WAIT_INITACK,
966 SW_STATE_WAIT_SEGACK,
967 SW_STATE_WAIT_ENDACK,
968 SW_STATE_WAIT_ACTACK,
969 SW_STATE_ERROR,
970};
Harald Welte52b1f982008-12-23 20:25:15 +0000971
Harald Welte52b1f982008-12-23 20:25:15 +0000972struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000973 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800974 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000975 gsm_cbfn *cbfn;
976 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000977 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000978
Harald Welte52b1f982008-12-23 20:25:15 +0000979 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200980 uint8_t obj_class;
981 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000982
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200983 uint8_t file_id[255];
984 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000985
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200986 uint8_t file_version[255];
987 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000988
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200989 uint8_t window_size;
990 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000991
992 int fd;
993 FILE *stream;
994 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000995 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000996};
997
Harald Welte4724f992009-01-18 18:01:49 +0000998static struct abis_nm_sw g_sw;
999
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001000static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1001{
1002 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1003 msgb_v_put(msg, NM_ATT_SW_DESCR);
1004 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1005 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1006 sw->file_version);
1007 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1008 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1009 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1010 sw->file_version);
1011 } else {
1012 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1013 }
1014}
1015
Harald Welte4724f992009-01-18 18:01:49 +00001016/* 6.2.1 / 8.3.1: Load Data Initiate */
1017static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001018{
Harald Welte4724f992009-01-18 18:01:49 +00001019 struct abis_om_hdr *oh;
1020 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001021 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001022
1023 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1024 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1025 sw->obj_instance[0], sw->obj_instance[1],
1026 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001027
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001028 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001029 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1030
1031 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001032}
1033
Harald Welte1602ade2009-01-29 21:12:39 +00001034static int is_last_line(FILE *stream)
1035{
1036 char next_seg_buf[256];
1037 long pos;
1038
1039 /* check if we're sending the last line */
1040 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +02001041
1042 /* Did ftell fail? Then we are at the end for sure */
1043 if (pos < 0)
1044 return 1;
1045
Harald Welte1602ade2009-01-29 21:12:39 +00001046 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +01001047 int rc = fseek(stream, pos, SEEK_SET);
1048 if (rc < 0)
1049 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001050 return 1;
1051 }
1052
1053 fseek(stream, pos, SEEK_SET);
1054 return 0;
1055}
1056
Harald Welte4724f992009-01-18 18:01:49 +00001057/* 6.2.2 / 8.3.2 Load Data Segment */
1058static int sw_load_segment(struct abis_nm_sw *sw)
1059{
1060 struct abis_om_hdr *oh;
1061 struct msgb *msg = nm_msgb_alloc();
1062 char seg_buf[256];
1063 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001064 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +02001065 int len;
Harald Welte4724f992009-01-18 18:01:49 +00001066
1067 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001068
1069 switch (sw->bts->type) {
1070 case GSM_BTS_TYPE_BS11:
1071 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1072 perror("fgets reading segment");
1073 return -EINVAL;
1074 }
1075 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001076
1077 /* check if we're sending the last line */
1078 sw->last_seg = is_last_line(sw->stream);
1079 if (sw->last_seg)
1080 seg_buf[1] = 0;
1081 else
1082 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001083
1084 len = strlen(line_buf) + 2;
1085 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001086 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001087 /* BS11 wants CR + LF in excess of the TLV length !?! */
1088 tlv[1] -= 2;
1089
1090 /* we only now know the exact length for the OM hdr */
1091 len = strlen(line_buf)+2;
1092 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001093 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001094 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001095 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1096 if (len < 0) {
1097 perror("read failed");
1098 return -EINVAL;
1099 }
1100
1101 if (len != IPACC_SEGMENT_SIZE)
1102 sw->last_seg = 1;
1103
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001104 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001105 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001106 len += 3;
1107 break;
1108 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001109 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001110 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001111 /* FIXME: Other BTS types */
1112 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001113 }
Harald Welte4724f992009-01-18 18:01:49 +00001114
Harald Welte4724f992009-01-18 18:01:49 +00001115 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1116 sw->obj_instance[0], sw->obj_instance[1],
1117 sw->obj_instance[2]);
1118
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001119 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001120}
1121
1122/* 6.2.4 / 8.3.4 Load Data End */
1123static int sw_load_end(struct abis_nm_sw *sw)
1124{
1125 struct abis_om_hdr *oh;
1126 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001127 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001128
1129 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1130 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1131 sw->obj_instance[0], sw->obj_instance[1],
1132 sw->obj_instance[2]);
1133
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001134 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001135 return abis_nm_sendmsg(sw->bts, msg);
1136}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001137
Harald Welte52b1f982008-12-23 20:25:15 +00001138/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001139static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001140{
Harald Welte4724f992009-01-18 18:01:49 +00001141 struct abis_om_hdr *oh;
1142 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001143 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001144
Harald Welte4724f992009-01-18 18:01:49 +00001145 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1146 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1147 sw->obj_instance[0], sw->obj_instance[1],
1148 sw->obj_instance[2]);
1149
1150 /* FIXME: this is BS11 specific format */
1151 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1152 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1153 sw->file_version);
1154
1155 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001156}
Harald Welte4724f992009-01-18 18:01:49 +00001157
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001158struct sdp_firmware {
1159 char magic[4];
1160 char more_magic[4];
1161 unsigned int header_length;
1162 unsigned int file_length;
1163} __attribute__ ((packed));
1164
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001165static int parse_sdp_header(struct abis_nm_sw *sw)
1166{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001167 struct sdp_firmware firmware_header;
1168 int rc;
1169 struct stat stat;
1170
1171 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1172 if (rc != sizeof(firmware_header)) {
1173 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1174 return -1;
1175 }
1176
1177 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1178 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1179 return -1;
1180 }
1181
1182 if (firmware_header.more_magic[0] != 0x10 ||
1183 firmware_header.more_magic[1] != 0x02 ||
1184 firmware_header.more_magic[2] != 0x00 ||
1185 firmware_header.more_magic[3] != 0x00) {
1186 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1187 return -1;
1188 }
1189
1190
1191 if (fstat(sw->fd, &stat) == -1) {
1192 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1193 return -1;
1194 }
1195
1196 if (ntohl(firmware_header.file_length) != stat.st_size) {
1197 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1198 return -1;
1199 }
1200
1201 /* go back to the start as we checked the whole filesize.. */
1202 lseek(sw->fd, 0l, SEEK_SET);
1203 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1204 "There might be checksums in the file that are not\n"
1205 "verified and incomplete firmware might be flashed.\n"
1206 "There is absolutely no WARRANTY that flashing will\n"
1207 "work.\n");
1208 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001209}
1210
Harald Welte4724f992009-01-18 18:01:49 +00001211static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1212{
1213 char file_id[12+1];
1214 char file_version[80+1];
1215 int rc;
1216
1217 sw->fd = open(fname, O_RDONLY);
1218 if (sw->fd < 0)
1219 return sw->fd;
1220
1221 switch (sw->bts->type) {
1222 case GSM_BTS_TYPE_BS11:
1223 sw->stream = fdopen(sw->fd, "r");
1224 if (!sw->stream) {
1225 perror("fdopen");
1226 return -1;
1227 }
1228 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001229 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001230 file_id, file_version);
1231 if (rc != 2) {
1232 perror("parsing header line of software file");
1233 return -1;
1234 }
1235 strcpy((char *)sw->file_id, file_id);
1236 sw->file_id_len = strlen(file_id);
1237 strcpy((char *)sw->file_version, file_version);
1238 sw->file_version_len = strlen(file_version);
1239 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001240 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001241 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001242 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001243 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001244 rc = parse_sdp_header(sw);
1245 if (rc < 0) {
1246 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1247 return -1;
1248 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001249
1250 strcpy((char *)sw->file_id, "id");
1251 sw->file_id_len = 3;
1252 strcpy((char *)sw->file_version, "version");
1253 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001254 break;
Harald Welte4724f992009-01-18 18:01:49 +00001255 default:
1256 /* We don't know how to treat them yet */
1257 close(sw->fd);
1258 return -EINVAL;
1259 }
1260
1261 return 0;
1262}
1263
1264static void sw_close_file(struct abis_nm_sw *sw)
1265{
1266 switch (sw->bts->type) {
1267 case GSM_BTS_TYPE_BS11:
1268 fclose(sw->stream);
1269 break;
1270 default:
1271 close(sw->fd);
1272 break;
1273 }
1274}
1275
1276/* Fill the window */
1277static int sw_fill_window(struct abis_nm_sw *sw)
1278{
1279 int rc;
1280
1281 while (sw->seg_in_window < sw->window_size) {
1282 rc = sw_load_segment(sw);
1283 if (rc < 0)
1284 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001285 if (sw->last_seg)
1286 break;
Harald Welte4724f992009-01-18 18:01:49 +00001287 }
1288 return 0;
1289}
1290
1291/* callback function from abis_nm_rcvmsg() handler */
1292static int abis_nm_rcvmsg_sw(struct msgb *mb)
1293{
1294 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001295 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001296 int rc = -1;
1297 struct abis_nm_sw *sw = &g_sw;
1298 enum sw_state old_state = sw->state;
1299
Harald Welte3ffd1372009-02-01 22:15:49 +00001300 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001301
1302 switch (sw->state) {
1303 case SW_STATE_WAIT_INITACK:
1304 switch (foh->msg_type) {
1305 case NM_MT_LOAD_INIT_ACK:
1306 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001307 if (sw->cbfn)
1308 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1309 NM_MT_LOAD_INIT_ACK, mb,
1310 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001311 rc = sw_fill_window(sw);
1312 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001313 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001314 break;
1315 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001316 if (sw->forced) {
1317 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1318 "Init NACK\n");
1319 if (sw->cbfn)
1320 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1321 NM_MT_LOAD_INIT_ACK, mb,
1322 sw->cb_data, NULL);
1323 rc = sw_fill_window(sw);
1324 sw->state = SW_STATE_WAIT_SEGACK;
1325 } else {
1326 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001327 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001328 if (sw->cbfn)
1329 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1330 NM_MT_LOAD_INIT_NACK, mb,
1331 sw->cb_data, NULL);
1332 sw->state = SW_STATE_ERROR;
1333 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001334 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001335 break;
1336 }
1337 break;
1338 case SW_STATE_WAIT_SEGACK:
1339 switch (foh->msg_type) {
1340 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001341 if (sw->cbfn)
1342 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1343 NM_MT_LOAD_SEG_ACK, mb,
1344 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001345 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001346 if (!sw->last_seg) {
1347 /* fill window with more segments */
1348 rc = sw_fill_window(sw);
1349 sw->state = SW_STATE_WAIT_SEGACK;
1350 } else {
1351 /* end the transfer */
1352 sw->state = SW_STATE_WAIT_ENDACK;
1353 rc = sw_load_end(sw);
1354 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001355 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001356 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001357 case NM_MT_LOAD_ABORT:
1358 if (sw->cbfn)
1359 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1360 NM_MT_LOAD_ABORT, mb,
1361 sw->cb_data, NULL);
1362 break;
Harald Welte4724f992009-01-18 18:01:49 +00001363 }
1364 break;
1365 case SW_STATE_WAIT_ENDACK:
1366 switch (foh->msg_type) {
1367 case NM_MT_LOAD_END_ACK:
1368 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001369 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1370 sw->bts->nr);
1371 sw->state = SW_STATE_NONE;
1372 if (sw->cbfn)
1373 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1374 NM_MT_LOAD_END_ACK, mb,
1375 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001376 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001377 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001378 break;
1379 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001380 if (sw->forced) {
1381 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1382 "End NACK\n");
1383 sw->state = SW_STATE_NONE;
1384 if (sw->cbfn)
1385 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1386 NM_MT_LOAD_END_ACK, mb,
1387 sw->cb_data, NULL);
1388 } else {
1389 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001390 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001391 sw->state = SW_STATE_ERROR;
1392 if (sw->cbfn)
1393 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1394 NM_MT_LOAD_END_NACK, mb,
1395 sw->cb_data, NULL);
1396 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001397 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001398 break;
1399 }
1400 case SW_STATE_WAIT_ACTACK:
1401 switch (foh->msg_type) {
1402 case NM_MT_ACTIVATE_SW_ACK:
1403 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001404 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001405 sw->state = SW_STATE_NONE;
1406 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001407 if (sw->cbfn)
1408 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1409 NM_MT_ACTIVATE_SW_ACK, mb,
1410 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001411 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001412 break;
1413 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001414 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001415 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001416 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001417 if (sw->cbfn)
1418 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1419 NM_MT_ACTIVATE_SW_NACK, mb,
1420 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001421 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001422 break;
1423 }
1424 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001425 switch (foh->msg_type) {
1426 case NM_MT_ACTIVATE_SW_ACK:
1427 rc = 0;
1428 break;
1429 }
1430 break;
Harald Welte4724f992009-01-18 18:01:49 +00001431 case SW_STATE_ERROR:
1432 break;
1433 }
1434
1435 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001436 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001437 foh->msg_type, old_state, sw->state);
1438
1439 return rc;
1440}
1441
1442/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001443int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001444 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001445 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001446{
1447 struct abis_nm_sw *sw = &g_sw;
1448 int rc;
1449
Harald Welte5e4d1b32009-02-01 13:36:56 +00001450 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1451 bts->nr, fname);
1452
Harald Welte4724f992009-01-18 18:01:49 +00001453 if (sw->state != SW_STATE_NONE)
1454 return -EBUSY;
1455
1456 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001457 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001458
1459 switch (bts->type) {
1460 case GSM_BTS_TYPE_BS11:
1461 sw->obj_class = NM_OC_SITE_MANAGER;
1462 sw->obj_instance[0] = 0xff;
1463 sw->obj_instance[1] = 0xff;
1464 sw->obj_instance[2] = 0xff;
1465 break;
1466 case GSM_BTS_TYPE_NANOBTS:
1467 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001468 sw->obj_instance[0] = sw->bts->nr;
1469 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001470 sw->obj_instance[2] = 0xff;
1471 break;
1472 case GSM_BTS_TYPE_UNKNOWN:
1473 default:
1474 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1475 return -1;
1476 break;
1477 }
Harald Welte4724f992009-01-18 18:01:49 +00001478 sw->window_size = win_size;
1479 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001480 sw->cbfn = cbfn;
1481 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001482 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001483
1484 rc = sw_open_file(sw, fname);
1485 if (rc < 0) {
1486 sw->state = SW_STATE_NONE;
1487 return rc;
1488 }
1489
1490 return sw_load_init(sw);
1491}
Harald Welte52b1f982008-12-23 20:25:15 +00001492
Harald Welte1602ade2009-01-29 21:12:39 +00001493int abis_nm_software_load_status(struct gsm_bts *bts)
1494{
1495 struct abis_nm_sw *sw = &g_sw;
1496 struct stat st;
1497 int rc, percent;
1498
1499 rc = fstat(sw->fd, &st);
1500 if (rc < 0) {
1501 perror("ERROR during stat");
1502 return rc;
1503 }
1504
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001505 if (sw->stream)
1506 percent = (ftell(sw->stream) * 100) / st.st_size;
1507 else
1508 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001509 return percent;
1510}
1511
Harald Welte5e4d1b32009-02-01 13:36:56 +00001512/* Activate the specified software into the BTS */
1513int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1514 gsm_cbfn *cbfn, void *cb_data)
1515{
1516 struct abis_nm_sw *sw = &g_sw;
1517 int rc;
1518
1519 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1520 bts->nr, fname);
1521
1522 if (sw->state != SW_STATE_NONE)
1523 return -EBUSY;
1524
1525 sw->bts = bts;
1526 sw->obj_class = NM_OC_SITE_MANAGER;
1527 sw->obj_instance[0] = 0xff;
1528 sw->obj_instance[1] = 0xff;
1529 sw->obj_instance[2] = 0xff;
1530 sw->state = SW_STATE_WAIT_ACTACK;
1531 sw->cbfn = cbfn;
1532 sw->cb_data = cb_data;
1533
1534 /* Open the file in order to fill some sw struct members */
1535 rc = sw_open_file(sw, fname);
1536 if (rc < 0) {
1537 sw->state = SW_STATE_NONE;
1538 return rc;
1539 }
1540 sw_close_file(sw);
1541
1542 return sw_activate(sw);
1543}
1544
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001545static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1546 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001547{
Harald Welteadaf08b2009-01-18 11:08:10 +00001548 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001549 ch->bts_port = bts_port;
1550 ch->timeslot = ts_nr;
1551 ch->subslot = subslot_nr;
1552}
1553
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001554int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1555 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1556 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001557{
1558 struct abis_om_hdr *oh;
1559 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001560 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001561 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001562
1563 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1564 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1565 bts->bts_nr, trx_nr, 0xff);
1566
Harald Welte8470bf22008-12-25 23:28:35 +00001567 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001568
1569 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1570 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1571
1572 return abis_nm_sendmsg(bts, msg);
1573}
1574
1575/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1576int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001577 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001578{
Harald Welte8470bf22008-12-25 23:28:35 +00001579 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001580 struct abis_om_hdr *oh;
1581 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001582 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001583
1584 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001585 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001586 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1587
1588 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1589 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1590
1591 return abis_nm_sendmsg(bts, msg);
1592}
1593
1594#if 0
1595int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1596 struct abis_nm_abis_channel *chan)
1597{
1598}
1599#endif
1600
1601int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001602 uint8_t e1_port, uint8_t e1_timeslot,
1603 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001604{
1605 struct gsm_bts *bts = ts->trx->bts;
1606 struct abis_om_hdr *oh;
1607 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001608 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001609
1610 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1611 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001612 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001613
1614 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1615 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1616
Harald Weltef325eb42009-02-19 17:07:39 +00001617 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1618 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001619 e1_port, e1_timeslot, e1_subslot);
1620
Harald Welte52b1f982008-12-23 20:25:15 +00001621 return abis_nm_sendmsg(bts, msg);
1622}
1623
1624#if 0
1625int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1626 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001627 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001628{
1629}
1630#endif
1631
Max1ebf23b2017-05-10 12:21:17 +02001632/* 3GPP TS 52.021 § 8.11.1 */
1633int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1634 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001635{
1636 struct abis_om_hdr *oh;
Maxe3dbd5d2017-06-09 17:15:45 +02001637 struct msgb *msg;
1638
1639 if (bts->type != GSM_BTS_TYPE_OSMOBTS) {
1640 LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n",
1641 bts->nr, btstype2str(bts->type));
1642 return -EINVAL;
1643 }
Harald Weltefe568f22012-08-14 19:15:57 +02001644
1645 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1646
Maxe3dbd5d2017-06-09 17:15:45 +02001647 msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001648 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1649 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1650 bts_nr, trx_nr, ts_nr);
1651 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1652
1653 return abis_nm_sendmsg(bts, msg);
1654}
1655
Harald Welte22af0db2009-02-14 15:41:08 +00001656/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001657int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001658{
1659 struct abis_om_hdr *oh;
1660 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001661 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001662
1663 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1664
1665 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001666 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001667 cur = msgb_put(msg, attr_len);
1668 memcpy(cur, attr, attr_len);
1669
1670 return abis_nm_sendmsg(bts, msg);
1671}
1672
1673/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001674int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001675{
1676 struct abis_om_hdr *oh;
1677 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001678 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001679
1680 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1681
1682 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1683 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001684 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001685 cur = msgb_put(msg, attr_len);
1686 memcpy(cur, attr, attr_len);
1687
1688 return abis_nm_sendmsg(trx->bts, msg);
1689}
1690
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001691int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1692{
1693 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1694 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1695}
1696
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001697static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1698 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001699{
1700 int i;
1701
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001702 *reason = "Reason unknown";
1703
Harald Welte39c7deb2009-08-09 21:49:48 +02001704 /* As it turns out, the BS-11 has some very peculiar restrictions
1705 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301706 switch (ts->trx->bts->type) {
1707 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001708 switch (chan_comb) {
1709 case NM_CHANC_TCHHalf:
1710 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001711 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001712 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001713 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001714 return -EINVAL;
1715 case NM_CHANC_SDCCH:
1716 /* only one SDCCH/8 per TRX */
1717 for (i = 0; i < TRX_NR_TS; i++) {
1718 if (i == ts->nr)
1719 continue;
1720 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001721 NM_CHANC_SDCCH) {
1722 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001723 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001724 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001725 }
1726 /* not allowed for TS0 of BCCH-TRX */
1727 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001728 ts->nr == 0) {
1729 *reason = "SDCCH/8 must be on TS0.";
1730 return -EINVAL;
1731 }
1732
Harald Welte39c7deb2009-08-09 21:49:48 +02001733 /* not on the same TRX that has a BCCH+SDCCH4
1734 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001735 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001736 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001737 ts->trx->ts[0].nm_chan_comb == 8)) {
1738 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1739 return -EINVAL;
1740 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001741 break;
1742 case NM_CHANC_mainBCCH:
1743 case NM_CHANC_BCCHComb:
1744 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001745 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1746 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001747 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001748 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001749 break;
1750 case NM_CHANC_BCCH:
1751 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001752 if (ts->trx != ts->trx->bts->c0) {
1753 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001754 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001755 }
1756 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1757 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001758 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001759 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001760 break;
1761 case 8: /* this is not like 08.58, but in fact
1762 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1763 /* FIXME: only one CBCH allowed per cell */
1764 break;
1765 }
Harald Welted6575f92009-12-02 02:45:23 +05301766 break;
1767 case GSM_BTS_TYPE_NANOBTS:
1768 switch (ts->nr) {
1769 case 0:
1770 if (ts->trx->nr == 0) {
1771 /* only on TRX0 */
1772 switch (chan_comb) {
1773 case NM_CHANC_BCCH:
1774 case NM_CHANC_mainBCCH:
1775 case NM_CHANC_BCCHComb:
1776 return 0;
1777 break;
1778 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001779 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301780 return -EINVAL;
1781 }
1782 } else {
1783 switch (chan_comb) {
1784 case NM_CHANC_TCHFull:
1785 case NM_CHANC_TCHHalf:
1786 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1787 return 0;
1788 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001789 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301790 return -EINVAL;
1791 }
1792 }
1793 break;
1794 case 1:
1795 if (ts->trx->nr == 0) {
1796 switch (chan_comb) {
1797 case NM_CHANC_SDCCH_CBCH:
1798 if (ts->trx->ts[0].nm_chan_comb ==
1799 NM_CHANC_mainBCCH)
1800 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001801 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301802 return -EINVAL;
1803 case NM_CHANC_SDCCH:
1804 case NM_CHANC_TCHFull:
1805 case NM_CHANC_TCHHalf:
1806 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1807 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001808 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301809 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001810 default:
1811 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1812 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301813 }
1814 } else {
1815 switch (chan_comb) {
1816 case NM_CHANC_SDCCH:
1817 case NM_CHANC_TCHFull:
1818 case NM_CHANC_TCHHalf:
1819 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1820 return 0;
1821 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001822 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301823 return -EINVAL;
1824 }
1825 }
1826 break;
1827 case 2:
1828 case 3:
1829 case 4:
1830 case 5:
1831 case 6:
1832 case 7:
1833 switch (chan_comb) {
1834 case NM_CHANC_TCHFull:
1835 case NM_CHANC_TCHHalf:
1836 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1837 return 0;
1838 case NM_CHANC_IPAC_PDCH:
1839 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001840 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301841 if (ts->trx->nr == 0)
1842 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001843 else {
1844 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301845 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001846 }
Harald Welted6575f92009-12-02 02:45:23 +05301847 }
1848 break;
1849 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001850 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301851 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001852 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001853 /* no known restrictions */
1854 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301855 default:
1856 /* unknown BTS type */
1857 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001858 }
1859 return 0;
1860}
1861
Harald Welte22af0db2009-02-14 15:41:08 +00001862/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001863int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001864{
1865 struct gsm_bts *bts = ts->trx->bts;
1866 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001867 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001868 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001869 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001870 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001871
1872 if (bts->type == GSM_BTS_TYPE_BS11)
1873 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001874
Harald Weltef325eb42009-02-19 17:07:39 +00001875 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001876 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001877 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001878 LOGP(DNM, LOGL_ERROR,
1879 "Invalid Channel Combination %d on %s. Reason: %s\n",
1880 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001881 return -EINVAL;
1882 }
1883 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001884
Harald Welte52b1f982008-12-23 20:25:15 +00001885 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001886 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001887 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001888 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001889 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001890 if (ts->hopping.enabled) {
1891 unsigned int i;
1892 uint8_t *len;
1893
Harald Welte6e0cd042009-09-12 13:05:33 +02001894 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1895 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001896
1897 /* build the ARFCN list */
1898 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1899 len = msgb_put(msg, 1);
1900 *len = 0;
1901 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1902 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1903 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001904 /* At least BS-11 wants a TLV16 here */
1905 if (bts->type == GSM_BTS_TYPE_BS11)
1906 *len += 1;
1907 else
1908 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001909 }
1910 }
Harald Weltee0590df2009-02-15 03:34:15 +00001911 }
Harald Welte1fe24122014-01-19 17:18:21 +01001912 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001913 if (bts->type == GSM_BTS_TYPE_BS11)
1914 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001915
1916 return abis_nm_sendmsg(bts, msg);
1917}
1918
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001919int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1920 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001921{
1922 struct abis_om_hdr *oh;
1923 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001924 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1925 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001926
1927 if (nack) {
1928 len += 2;
1929 msgtype = NM_MT_SW_ACT_REQ_NACK;
1930 }
Harald Welte34a99682009-02-13 02:41:40 +00001931
1932 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001933 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1934
Harald Welte34a99682009-02-13 02:41:40 +00001935 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001936 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001937 memcpy(ptr, attr, att_len);
1938 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001939 if (nack)
1940 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001941
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001942 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001943}
1944
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001945int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001946{
Harald Welte8470bf22008-12-25 23:28:35 +00001947 struct msgb *msg = nm_msgb_alloc();
1948 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001949 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001950
1951 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1952 fill_om_hdr(oh, len);
1953 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001954 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001955
1956 return abis_nm_sendmsg(bts, msg);
1957}
1958
1959/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001960static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001961{
1962 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001963 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001964
1965 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001966 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001967 0xff, 0xff, 0xff);
1968
1969 return abis_nm_sendmsg(bts, msg);
1970}
1971
Harald Welte34a99682009-02-13 02:41:40 +00001972/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001973int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
Harald Welte34a99682009-02-13 02:41:40 +00001974{
1975 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001976 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001977 struct msgb *msg = nm_msgb_alloc();
1978
1979 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001980 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001981
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001982 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001983 DEBUGPC(DNM, "Sending OPSTART\n");
1984
Harald Welte34a99682009-02-13 02:41:40 +00001985 return abis_nm_sendmsg(bts, msg);
1986}
1987
1988/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001989int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1990 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001991{
1992 struct abis_om_hdr *oh;
1993 struct msgb *msg = nm_msgb_alloc();
1994
1995 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1996 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1997 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1998
1999 return abis_nm_sendmsg(bts, msg);
2000}
2001
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002002int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
2003 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02002004{
2005 struct abis_om_hdr *oh;
2006 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002007 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02002008
2009 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2010 e1_port0, ts0, e1_port1, ts1);
2011
2012 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2013 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2014 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2015
2016 attr = msgb_put(msg, 3);
2017 attr[0] = NM_ATT_MDROP_LINK;
2018 attr[1] = e1_port0;
2019 attr[2] = ts0;
2020
2021 attr = msgb_put(msg, 3);
2022 attr[0] = NM_ATT_MDROP_NEXT;
2023 attr[1] = e1_port1;
2024 attr[2] = ts1;
2025
2026 return abis_nm_sendmsg(bts, msg);
2027}
Harald Welte34a99682009-02-13 02:41:40 +00002028
Harald Weltec7310382009-08-08 00:02:36 +02002029/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002030int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2031 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2032 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002033{
2034 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002035
Harald Welte15c61722011-05-22 22:45:37 +02002036 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002037
2038 if (!msg)
2039 msg = nm_msgb_alloc();
2040
2041 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2042 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2043 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2044 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002045 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002046
2047 return abis_nm_sendmsg(bts, msg);
2048}
2049
Harald Welte52b1f982008-12-23 20:25:15 +00002050int abis_nm_event_reports(struct gsm_bts *bts, int on)
2051{
2052 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002053 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002054 else
Harald Welte227d4072009-01-03 08:16:25 +00002055 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002056}
2057
Harald Welte47d88ae2009-01-04 12:02:08 +00002058/* Siemens (or BS-11) specific commands */
2059
Harald Welte3ffd1372009-02-01 22:15:49 +00002060int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2061{
2062 if (reconnect == 0)
2063 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2064 else
2065 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2066}
2067
Harald Welteb8427972009-02-05 19:27:17 +00002068int abis_nm_bs11_restart(struct gsm_bts *bts)
2069{
2070 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2071}
2072
2073
Harald Welte268bb402009-02-01 19:11:56 +00002074struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002075 uint16_t year;
2076 uint8_t month;
2077 uint8_t day;
2078 uint8_t hour;
2079 uint8_t min;
2080 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002081} __attribute__((packed));
2082
2083
2084void get_bs11_date_time(struct bs11_date_time *aet)
2085{
2086 time_t t;
2087 struct tm *tm;
2088
2089 t = time(NULL);
2090 tm = localtime(&t);
2091 aet->sec = tm->tm_sec;
2092 aet->min = tm->tm_min;
2093 aet->hour = tm->tm_hour;
2094 aet->day = tm->tm_mday;
2095 aet->month = tm->tm_mon;
2096 aet->year = htons(1900 + tm->tm_year);
2097}
2098
Harald Welte05188ee2009-01-18 11:39:08 +00002099int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002100{
Harald Welte4668fda2009-01-03 08:19:29 +00002101 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002102}
2103
Harald Welte05188ee2009-01-18 11:39:08 +00002104int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002105{
2106 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002107 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002108 else
Harald Welte4668fda2009-01-03 08:19:29 +00002109 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002110}
Harald Welte47d88ae2009-01-04 12:02:08 +00002111
Harald Welte05188ee2009-01-18 11:39:08 +00002112int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002113 enum abis_bs11_objtype type, uint8_t idx,
2114 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002115{
2116 struct abis_om_hdr *oh;
2117 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002118 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002119
2120 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002121 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002122 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002123 cur = msgb_put(msg, attr_len);
2124 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002125
2126 return abis_nm_sendmsg(bts, msg);
2127}
2128
Harald Welte78fc0d42009-02-19 02:50:57 +00002129int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002130 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002131{
2132 struct abis_om_hdr *oh;
2133 struct msgb *msg = nm_msgb_alloc();
2134
2135 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2136 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2137 NM_OC_BS11, type, 0, idx);
2138
2139 return abis_nm_sendmsg(bts, msg);
2140}
2141
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002142int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002143{
2144 struct abis_om_hdr *oh;
2145 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002146 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002147
2148 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002149 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002150 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2151 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002152
2153 return abis_nm_sendmsg(bts, msg);
2154}
2155
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002156int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002157{
2158 struct abis_om_hdr *oh;
2159 struct msgb *msg = nm_msgb_alloc();
2160
2161 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2162 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002163 idx, 0xff, 0xff);
2164
2165 return abis_nm_sendmsg(bts, msg);
2166}
2167
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002168int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002169{
2170 struct abis_om_hdr *oh;
2171 struct msgb *msg = nm_msgb_alloc();
2172
2173 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2174 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2175 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002176
2177 return abis_nm_sendmsg(bts, msg);
2178}
Harald Welte05188ee2009-01-18 11:39:08 +00002179
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002180static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002181int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2182{
2183 struct abis_om_hdr *oh;
2184 struct msgb *msg = nm_msgb_alloc();
2185
2186 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2187 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2188 0xff, 0xff, 0xff);
2189 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2190
2191 return abis_nm_sendmsg(bts, msg);
2192}
2193
Harald Welteb6c92ae2009-02-21 20:15:32 +00002194/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002195int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2196 uint8_t e1_timeslot, uint8_t e1_subslot,
2197 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002198{
2199 struct abis_om_hdr *oh;
2200 struct abis_nm_channel *ch;
2201 struct msgb *msg = nm_msgb_alloc();
2202
2203 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002204 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002205 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2206
2207 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2208 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002209 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002210
2211 return abis_nm_sendmsg(bts, msg);
2212}
2213
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002214int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002215{
2216 struct abis_om_hdr *oh;
2217 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002218
2219 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002220 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002221 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2222 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2223
2224 return abis_nm_sendmsg(trx->bts, msg);
2225}
2226
Harald Welte78fc0d42009-02-19 02:50:57 +00002227int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2228{
2229 struct abis_om_hdr *oh;
2230 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002231 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002232
2233 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2234 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2235 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2236 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2237
2238 return abis_nm_sendmsg(trx->bts, msg);
2239}
2240
Harald Welteaaf02d92009-04-29 13:25:57 +00002241int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2242{
2243 struct abis_om_hdr *oh;
2244 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002245 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002246
2247 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2248 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2249 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002250 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002251
2252 return abis_nm_sendmsg(bts, msg);
2253}
2254
Harald Welteef061952009-05-17 12:43:42 +00002255int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2256{
2257 struct abis_om_hdr *oh;
2258 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002259 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002260 NM_ATT_BS11_CCLK_TYPE };
2261
2262 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2263 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2264 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2265 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2266
2267 return abis_nm_sendmsg(bts, msg);
2268
2269}
Harald Welteaaf02d92009-04-29 13:25:57 +00002270
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002271//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002272
Harald Welte1bc09062009-01-18 14:17:52 +00002273int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002274{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002275 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2276}
2277
Daniel Willmann4b054c82010-01-07 00:46:26 +01002278int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2279{
2280 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2281}
2282
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002283int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002284{
Harald Welte05188ee2009-01-18 11:39:08 +00002285 struct abis_om_hdr *oh;
2286 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002287 struct bs11_date_time bdt;
2288
2289 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002290
2291 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002292 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002293 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002294 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002295 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002296 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002297 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002298 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002299 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002300 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002301 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002302 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002303 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002304 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002305 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002306 }
Harald Welte05188ee2009-01-18 11:39:08 +00002307
2308 return abis_nm_sendmsg(bts, msg);
2309}
Harald Welte1bc09062009-01-18 14:17:52 +00002310
2311int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2312{
2313 struct abis_om_hdr *oh;
2314 struct msgb *msg;
2315
2316 if (strlen(password) != 10)
2317 return -EINVAL;
2318
2319 msg = nm_msgb_alloc();
2320 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002321 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002322 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002323 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002324
2325 return abis_nm_sendmsg(bts, msg);
2326}
2327
Harald Weltee69f5fb2009-04-28 16:31:38 +00002328/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2329int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2330{
2331 struct abis_om_hdr *oh;
2332 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002333 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002334
2335 msg = nm_msgb_alloc();
2336 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2337 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2338 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002339
2340 if (locked)
2341 tlv_value = BS11_LI_PLL_LOCKED;
2342 else
2343 tlv_value = BS11_LI_PLL_STANDALONE;
2344
2345 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002346
2347 return abis_nm_sendmsg(bts, msg);
2348}
2349
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002350/* Set the calibration value of the PLL (work value/set value)
2351 * It depends on the login which one is changed */
2352int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2353{
2354 struct abis_om_hdr *oh;
2355 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002356 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002357
2358 msg = nm_msgb_alloc();
2359 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2360 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2361 BS11_OBJ_TRX1, 0x00, 0x00);
2362
2363 tlv_value[0] = value>>8;
2364 tlv_value[1] = value&0xff;
2365
2366 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2367
2368 return abis_nm_sendmsg(bts, msg);
2369}
2370
Harald Welte1bc09062009-01-18 14:17:52 +00002371int abis_nm_bs11_get_state(struct gsm_bts *bts)
2372{
2373 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2374}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002375
2376/* BS11 SWL */
2377
Neels Hofmeyrcc6240a2018-02-13 21:21:42 +01002378void *tall_fle_ctx = NULL;
Harald Welte2cf161b2009-06-20 22:36:41 +02002379
Harald Welte5e4d1b32009-02-01 13:36:56 +00002380struct abis_nm_bs11_sw {
2381 struct gsm_bts *bts;
2382 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002383 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002384 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002385 struct llist_head file_list;
2386 gsm_cbfn *user_cb; /* specified by the user */
2387};
2388static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2389
2390struct file_list_entry {
2391 struct llist_head list;
2392 char fname[PATH_MAX];
2393};
2394
2395struct file_list_entry *fl_dequeue(struct llist_head *queue)
2396{
2397 struct llist_head *lh;
2398
2399 if (llist_empty(queue))
2400 return NULL;
2401
2402 lh = queue->next;
2403 llist_del(lh);
2404
2405 return llist_entry(lh, struct file_list_entry, list);
2406}
2407
2408static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2409{
2410 char linebuf[255];
2411 struct llist_head *lh, *lh2;
2412 FILE *swl;
2413 int rc = 0;
2414
2415 swl = fopen(bs11_sw->swl_fname, "r");
2416 if (!swl)
2417 return -ENODEV;
2418
2419 /* zero the stale file list, if any */
2420 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2421 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002422 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002423 }
2424
2425 while (fgets(linebuf, sizeof(linebuf), swl)) {
2426 char file_id[12+1];
2427 char file_version[80+1];
2428 struct file_list_entry *fle;
2429 static char dir[PATH_MAX];
2430
2431 if (strlen(linebuf) < 4)
2432 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002433
Harald Welte5e4d1b32009-02-01 13:36:56 +00002434 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2435 if (rc < 0) {
2436 perror("ERR parsing SWL file");
2437 rc = -EINVAL;
2438 goto out;
2439 }
2440 if (rc < 2)
2441 continue;
2442
Harald Welte470ec292009-06-26 20:25:23 +02002443 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002444 if (!fle) {
2445 rc = -ENOMEM;
2446 goto out;
2447 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002448
2449 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002450 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002451 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2452 strcat(fle->fname, "/");
2453 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002454
2455 llist_add_tail(&fle->list, &bs11_sw->file_list);
2456 }
2457
2458out:
2459 fclose(swl);
2460 return rc;
2461}
2462
2463/* bs11 swload specific callback, passed to abis_nm core swload */
2464static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2465 struct msgb *msg, void *data, void *param)
2466{
2467 struct abis_nm_bs11_sw *bs11_sw = data;
2468 struct file_list_entry *fle;
2469 int rc = 0;
2470
Harald Welte5e4d1b32009-02-01 13:36:56 +00002471 switch (event) {
2472 case NM_MT_LOAD_END_ACK:
2473 fle = fl_dequeue(&bs11_sw->file_list);
2474 if (fle) {
2475 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002476 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002477 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002478 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002479 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002480 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002481 } else {
2482 /* activate the SWL */
2483 rc = abis_nm_software_activate(bs11_sw->bts,
2484 bs11_sw->swl_fname,
2485 bs11_swload_cbfn,
2486 bs11_sw);
2487 }
2488 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002489 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002490 case NM_MT_LOAD_END_NACK:
2491 case NM_MT_LOAD_INIT_ACK:
2492 case NM_MT_LOAD_INIT_NACK:
2493 case NM_MT_ACTIVATE_SW_NACK:
2494 case NM_MT_ACTIVATE_SW_ACK:
2495 default:
2496 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002497 if (bs11_sw->user_cb)
2498 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002499 break;
2500 }
2501
2502 return rc;
2503}
2504
2505/* Siemens provides a SWL file that is a mere listing of all the other
2506 * files that are part of a software release. We need to upload first
2507 * the list file, and then each file that is listed in the list file */
2508int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002509 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002510{
2511 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2512 struct file_list_entry *fle;
2513 int rc = 0;
2514
2515 INIT_LLIST_HEAD(&bs11_sw->file_list);
2516 bs11_sw->bts = bts;
2517 bs11_sw->win_size = win_size;
2518 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002519 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002520
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002521 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002522 rc = bs11_read_swl_file(bs11_sw);
2523 if (rc < 0)
2524 return rc;
2525
2526 /* dequeue next item in file list */
2527 fle = fl_dequeue(&bs11_sw->file_list);
2528 if (!fle)
2529 return -EINVAL;
2530
2531 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002532 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002533 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002534 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002535 return rc;
2536}
2537
Harald Welte5083b0b2009-02-02 19:20:52 +00002538#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002539static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002540 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2541 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2542 NM_ATT_BS11_LMT_USER_NAME,
2543
2544 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2545
2546 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2547
2548 NM_ATT_BS11_SW_LOAD_STORED };
2549
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002550static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002551 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2552 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2553 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2554 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002555#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002556
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002557static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002558 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2559 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002560 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002561
2562int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2563{
2564 struct abis_om_hdr *oh;
2565 struct msgb *msg = nm_msgb_alloc();
2566
2567 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2568 /* SiemensHW CCTRL object */
2569 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2570 0x03, 0x00, 0x00);
2571 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2572
2573 return abis_nm_sendmsg(bts, msg);
2574}
Harald Welte268bb402009-02-01 19:11:56 +00002575
2576int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2577{
2578 struct abis_om_hdr *oh;
2579 struct msgb *msg = nm_msgb_alloc();
2580 struct bs11_date_time aet;
2581
2582 get_bs11_date_time(&aet);
2583 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2584 /* SiemensHW CCTRL object */
2585 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2586 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002587 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002588
2589 return abis_nm_sendmsg(bts, msg);
2590}
Harald Welte5c1e4582009-02-15 11:57:29 +00002591
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002592int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002593{
2594 struct abis_om_hdr *oh;
2595 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002596 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002597
2598 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2599 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2600 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2601 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2602
2603 return abis_nm_sendmsg(bts, msg);
2604}
2605
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002606int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002607{
2608 struct abis_om_hdr *oh;
2609 struct msgb *msg = nm_msgb_alloc();
2610 struct bs11_date_time aet;
2611
2612 get_bs11_date_time(&aet);
2613 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2614 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2615 bport, 0xff, 0x02);
2616 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2617
2618 return abis_nm_sendmsg(bts, msg);
2619}
2620
Harald Welte5c1e4582009-02-15 11:57:29 +00002621/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002622static const char ipaccess_magic[] = "com.ipaccess";
2623
Harald Welte677c21f2009-02-17 13:22:23 +00002624
2625static int abis_nm_rx_ipacc(struct msgb *msg)
2626{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002627 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002628 struct abis_om_hdr *oh = msgb_l2(msg);
2629 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002630 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002631 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002632 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002633 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002634
2635 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002636 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002637 return -EINVAL;
2638 }
2639
Harald Welte193fefc2009-04-30 15:16:27 +00002640 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002641 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002642
Harald Welte15c61722011-05-22 22:45:37 +02002643 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002644
Harald Welte746d6092009-10-19 22:11:11 +02002645 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002646
Harald Welte677c21f2009-02-17 13:22:23 +00002647 switch (foh->msg_type) {
2648 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002649 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002650 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2651 memcpy(&addr,
2652 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2653
2654 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2655 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002656 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002657 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002658 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002659 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002660 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2661 DEBUGPC(DNM, "STREAM=0x%02x ",
2662 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002663 DEBUGPC(DNM, "\n");
Stefan Sperling73acbca2018-02-12 14:28:52 +01002664 osmo_timer_del(&sign_link->trx->rsl_connect_timeout);
Harald Welte677c21f2009-02-17 13:22:23 +00002665 break;
2666 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002667 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002668 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002669 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002670 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002671 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002672 LOGPC(DNM, LOGL_ERROR, "\n");
Stefan Sperling73acbca2018-02-12 14:28:52 +01002673 osmo_timer_del(&sign_link->trx->rsl_connect_timeout);
Harald Welte677c21f2009-02-17 13:22:23 +00002674 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002675 case NM_MT_IPACC_SET_NVATTR_ACK:
2676 DEBUGPC(DNM, "SET NVATTR ACK\n");
2677 /* FIXME: decode and show the actual attributes */
2678 break;
2679 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002680 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002681 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002682 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002683 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002684 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002685 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002686 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002687 case NM_MT_IPACC_GET_NVATTR_ACK:
2688 DEBUGPC(DNM, "GET NVATTR ACK\n");
2689 /* FIXME: decode and show the actual attributes */
2690 break;
2691 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002692 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002693 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002694 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002695 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002696 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002697 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002698 break;
Harald Welte15c44172009-10-08 20:15:24 +02002699 case NM_MT_IPACC_SET_ATTR_ACK:
2700 DEBUGPC(DNM, "SET ATTR ACK\n");
2701 break;
2702 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002703 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002704 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002705 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002706 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002707 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002708 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002709 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002710 default:
2711 DEBUGPC(DNM, "unknown\n");
2712 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002713 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002714
2715 /* signal handling */
2716 switch (foh->msg_type) {
2717 case NM_MT_IPACC_RSL_CONNECT_NACK:
2718 case NM_MT_IPACC_SET_NVATTR_NACK:
2719 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002720 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002721 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002722 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002723 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002724 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002725 signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002726 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002727 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002728 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002729 default:
2730 break;
2731 }
2732
Harald Welte677c21f2009-02-17 13:22:23 +00002733 return 0;
2734}
2735
Harald Welte193fefc2009-04-30 15:16:27 +00002736/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002737int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2738 uint8_t obj_class, uint8_t bts_nr,
2739 uint8_t trx_nr, uint8_t ts_nr,
2740 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002741{
2742 struct msgb *msg = nm_msgb_alloc();
2743 struct abis_om_hdr *oh;
2744 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002745 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002746
2747 /* construct the 12.21 OM header, observe the erroneous length */
2748 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2749 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2750 oh->mdisc = ABIS_OM_MDISC_MANUF;
2751
2752 /* add the ip.access magic */
2753 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2754 *data++ = sizeof(ipaccess_magic);
2755 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2756
2757 /* fill the 12.21 FOM header */
2758 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2759 foh->msg_type = msg_type;
2760 foh->obj_class = obj_class;
2761 foh->obj_inst.bts_nr = bts_nr;
2762 foh->obj_inst.trx_nr = trx_nr;
2763 foh->obj_inst.ts_nr = ts_nr;
2764
2765 if (attr && attr_len) {
2766 data = msgb_put(msg, attr_len);
2767 memcpy(data, attr, attr_len);
2768 }
2769
2770 return abis_nm_sendmsg(bts, msg);
2771}
Harald Welte677c21f2009-02-17 13:22:23 +00002772
Harald Welte193fefc2009-04-30 15:16:27 +00002773/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002774int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002775 int attr_len)
2776{
Harald Welte2ef156d2010-01-07 20:39:42 +01002777 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2778 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002779 attr_len);
2780}
2781
Stefan Sperling73acbca2018-02-12 14:28:52 +01002782static void rsl_connect_timeout(void *data)
2783{
2784 struct gsm_bts_trx *trx = data;
2785 struct ipacc_ack_signal_data signal;
2786
2787 LOGP(DRSL, LOGL_NOTICE, "(bts=%d,trx=%d) RSL connection request timed out\n", trx->bts->nr, trx->nr);
2788
2789 /* Fake an RSL CONECT NACK message from the BTS. */
2790 signal.trx = trx;
2791 signal.msg_type = NM_MT_IPACC_RSL_CONNECT_NACK;
2792 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
2793}
2794
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002795int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002796 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002797{
2798 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002799 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002800 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2801 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2802
2803 int attr_len = sizeof(attr);
Stefan Sperling73acbca2018-02-12 14:28:52 +01002804 int error;
2805
2806 osmo_timer_setup(&trx->rsl_connect_timeout, rsl_connect_timeout, trx);
Harald Welte746d6092009-10-19 22:11:11 +02002807
2808 ia.s_addr = htonl(ip);
2809 attr[1] = stream;
2810 attr[3] = port >> 8;
2811 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002812 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002813
2814 /* if ip == 0, we use the default IP */
2815 if (ip == 0)
2816 attr_len -= 5;
2817
2818 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002819 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002820
Stefan Sperling73acbca2018-02-12 14:28:52 +01002821 error = abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2822 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2823 trx->nr, 0xff, attr, attr_len);
2824 if (error == 0)
2825 osmo_timer_schedule(&trx->rsl_connect_timeout, 60, 0);
2826
2827 return error;
Harald Welte746d6092009-10-19 22:11:11 +02002828}
2829
Harald Welte193fefc2009-04-30 15:16:27 +00002830/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002831int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002832{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002833 struct abis_om_hdr *oh;
2834 struct msgb *msg = nm_msgb_alloc();
2835
2836 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2837 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2838 trx->bts->nr, trx->nr, 0xff);
2839
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002840 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002841}
Harald Weltedaef5212009-10-24 10:20:41 +02002842
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002843int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2844 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2845 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002846{
2847 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2848 obj_class, bts_nr, trx_nr, ts_nr,
2849 attr, attr_len);
2850}
Harald Welte0f255852009-11-12 14:48:42 +01002851
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002852void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002853{
Neels Hofmeyr4d358c02018-02-22 03:19:05 +01002854 struct gsm48_ra_id *_buf = (struct gsm48_ra_id*)buf;
2855 uint16_t ci = htons(bts->cell_identity);
2856 /* we simply reuse the GSM48 function and write the Cell ID over the position where the RAC
2857 * starts */
2858 gsm48_ra_id_by_bts(_buf, bts);
2859 memcpy(&_buf->rac, &ci, sizeof(ci));
Harald Welte97a282b2010-03-14 15:37:43 +08002860}
2861
Maxbe356ed2017-09-07 19:10:09 +02002862void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason)
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002863{
Maxbe356ed2017-09-07 19:10:09 +02002864 uint8_t new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2865
2866 LOGP(DNM, LOGL_NOTICE, "(bts=%d,trx=%d) Changing adm. state %s -> %s [%s]\n", trx->bts->nr, trx->nr,
2867 get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative),
2868 get_value_string(abis_nm_adm_state_names, new_state), reason);
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002869
Harald Welted64c0bc2011-05-30 12:07:53 +02002870 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002871 if (!trx->bts || !trx->bts->oml_link)
2872 return;
2873
2874 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2875 trx->bts->bts_nr, trx->nr, 0xff,
2876 new_state);
2877}
2878
Harald Welte92b1fe42010-03-25 11:45:30 +08002879static const struct value_string ipacc_testres_names[] = {
2880 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2881 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2882 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2883 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2884 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2885 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002886};
2887
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002888const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002889{
Harald Welte92b1fe42010-03-25 11:45:30 +08002890 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002891}
2892
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002893void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002894{
2895 cid->mcc = (buf[0] & 0xf) * 100;
2896 cid->mcc += (buf[0] >> 4) * 10;
2897 cid->mcc += (buf[1] & 0xf) * 1;
2898
2899 if (buf[1] >> 4 == 0xf) {
2900 cid->mnc = (buf[2] & 0xf) * 10;
2901 cid->mnc += (buf[2] >> 4) * 1;
2902 } else {
2903 cid->mnc = (buf[2] & 0xf) * 100;
2904 cid->mnc += (buf[2] >> 4) * 10;
2905 cid->mnc += (buf[1] >> 4) * 1;
2906 }
2907
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002908 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2909 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002910}
2911
Harald Welte0f255852009-11-12 14:48:42 +01002912/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002913int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002914{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002915 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002916 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002917
Harald Welteaf109b92010-07-22 18:14:36 +02002918 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002919
2920 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2921 return -EINVAL;
2922 cur++;
2923
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002924 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002925 cur += 2;
2926
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002927 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002928 cur += 2;
2929
2930 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2931 binf->freq_qual = *cur >> 2;
2932
Harald Welteaf109b92010-07-22 18:14:36 +02002933 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002934 binf->arfcn |= *cur++;
2935
2936 if (binf->info_type & IPAC_BINF_RXLEV)
2937 binf->rx_lev = *cur & 0x3f;
2938 cur++;
2939
2940 if (binf->info_type & IPAC_BINF_RXQUAL)
2941 binf->rx_qual = *cur & 0x7;
2942 cur++;
2943
2944 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002945 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002946 cur += 2;
2947
2948 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002949 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002950 cur += 2;
2951
2952 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002953 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002954 cur += 4;
2955
Harald Weltea780a3d2010-07-30 22:34:42 +02002956#if 0
2957 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002958 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002959#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002960 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002961 cur++;
2962
Harald Welteb40a38f2009-11-13 11:56:05 +01002963 ipac_parse_cgi(&binf->cgi, cur);
2964 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002965
2966 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2967 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2968 cur += sizeof(binf->ba_list_si2);
2969 }
2970
2971 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2972 memcpy(binf->ba_list_si2bis, cur,
2973 sizeof(binf->ba_list_si2bis));
2974 cur += sizeof(binf->ba_list_si2bis);
2975 }
2976
2977 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2978 memcpy(binf->ba_list_si2ter, cur,
2979 sizeof(binf->ba_list_si2ter));
2980 cur += sizeof(binf->ba_list_si2ter);
2981 }
2982
2983 return 0;
2984}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002985
2986void abis_nm_clear_queue(struct gsm_bts *bts)
2987{
2988 struct msgb *msg;
2989
2990 while (!llist_empty(&bts->abis_queue)) {
2991 msg = msgb_dequeue(&bts->abis_queue);
2992 msgb_free(msg);
2993 }
2994
2995 bts->abis_nm_pend = 0;
2996}