blob: 2ee2e24fa299f481e12b5cfe2c8ff3393a77f56a [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 Weltefe00eda2018-03-17 10:30:33 +01004/* (C) 2008-2018 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
Harald Weltefe00eda2018-03-17 10:30:33 +010056#define LOGPFOH(ss, lvl, foh, fmt, args ...) LOGP(ss, lvl, "%s: " fmt, abis_nm_dump_foh(foh), ## args)
57#define DEBUGPFOH(ss, foh, fmt, args ...) LOGPFOH(ss, LOGL_DEBUG, foh, fmt, ## args)
58
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020059int 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 +000060{
Harald Welte39315c42010-01-10 18:01:52 +010061 if (!bts->model)
62 return -EIO;
63 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000064}
Harald Weltee0590df2009-02-15 03:34:15 +000065
Harald Welte52b1f982008-12-23 20:25:15 +000066static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
67{
68 int i;
69
70 for (i = 0; i < size; i++) {
71 if (arr[i] == mt)
72 return 1;
73 }
74
75 return 0;
76}
77
Holger Freytherca362a62009-01-04 21:05:01 +000078#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000079/* is this msgtype the usual ACK/NACK type ? */
80static int is_ack_nack(enum abis_nm_msgtype mt)
81{
82 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
83}
Holger Freytherca362a62009-01-04 21:05:01 +000084#endif
Harald Welte52b1f982008-12-23 20:25:15 +000085
86/* is this msgtype a report ? */
87static int is_report(enum abis_nm_msgtype mt)
88{
Harald Welte15c61722011-05-22 22:45:37 +020089 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000090}
91
92#define MT_ACK(x) (x+1)
93#define MT_NACK(x) (x+2)
94
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020095static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000096{
97 oh->mdisc = ABIS_OM_MDISC_FOM;
98 oh->placement = ABIS_OM_PLACEMENT_ONLY;
99 oh->sequence = 0;
100 oh->length = len;
101}
102
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200103static 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 +0200104 uint8_t msg_type, uint8_t obj_class,
105 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000106{
107 struct abis_om_fom_hdr *foh =
108 (struct abis_om_fom_hdr *) oh->data;
109
Harald Welte702d8702008-12-26 20:25:35 +0000110 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000111 foh->msg_type = msg_type;
112 foh->obj_class = obj_class;
113 foh->obj_inst.bts_nr = bts_nr;
114 foh->obj_inst.trx_nr = trx_nr;
115 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200116 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000117}
118
Harald Welte8470bf22008-12-25 23:28:35 +0000119static struct msgb *nm_msgb_alloc(void)
120{
Harald Welte966636f2009-06-26 19:39:35 +0200121 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
122 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000123}
124
Harald Welte15eae8d2011-09-26 23:43:23 +0200125int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200126{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200127 msg->l2h = msg->data;
128
129 if (!msg->dst) {
130 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
131 return -EINVAL;
132 }
133
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200134 return abis_sendmsg(msg);
135}
136
Harald Welte52b1f982008-12-23 20:25:15 +0000137/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100138static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000139{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200140 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000141
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100142 /* queue OML messages */
143 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
144 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200145 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100146 } else {
147 msgb_enqueue(&bts->abis_queue, msg);
148 return 0;
149 }
150
151}
152
153int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
154{
155 OBSC_NM_W_ACK_CB(msg) = 1;
156 return abis_nm_queue_msg(bts, msg);
157}
158
159static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
160{
161 OBSC_NM_W_ACK_CB(msg) = 0;
162 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000163}
164
Harald Welte4724f992009-01-18 18:01:49 +0000165static int abis_nm_rcvmsg_sw(struct msgb *mb);
166
Maxd0ff6942017-11-29 12:45:34 +0100167bool nm_is_running(const struct gsm_nm_state *s) {
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100168 return (s->operational == NM_OPSTATE_ENABLED) && (
169 (s->availability == NM_AVSTATE_OK) ||
170 (s->availability == 0xff)
171 );
172}
173
Harald Weltee0590df2009-02-15 03:34:15 +0000174/* Update the administrative state of a given object in our in-memory data
175 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200176static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
177 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000178{
Harald Welteaeedeb42009-05-01 13:08:14 +0000179 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100180 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000181
Harald Welteaf9b8102011-03-06 21:20:38 +0100182 memset(&nsd, 0, sizeof(nsd));
183
Harald Welte978714d2011-06-06 18:31:20 +0200184 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100185 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100186 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200187 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000188 if (!nm_state)
189 return -1;
190
191 new_state = *nm_state;
192 new_state.administrative = adm_state;
193
Harald Weltef38ca9a2011-03-06 22:11:32 +0100194 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100195 nsd.obj_class = obj_class;
196 nsd.old_state = nm_state;
197 nsd.new_state = &new_state;
198 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200199 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000200
201 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000202
Harald Weltef338a032011-01-14 15:55:42 +0100203 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000204}
205
Harald Welte97ed1e72009-02-06 13:38:02 +0000206static int abis_nm_rx_statechg_rep(struct msgb *mb)
207{
Harald Weltee0590df2009-02-15 03:34:15 +0000208 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000209 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200210 struct e1inp_sign_link *sign_link = mb->dst;
211 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000212 struct tlv_parsed tp;
213 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000214
Harald Welte8b697c72009-06-05 19:18:45 +0000215 memset(&new_state, 0, sizeof(new_state));
216
Harald Welte978714d2011-06-06 18:31:20 +0200217 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000218 if (!nm_state) {
Harald Weltefe00eda2018-03-17 10:30:33 +0100219 LOGPFOH(DNM, LOGL_ERROR, foh, "unknown managed object\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000220 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000221 }
Harald Weltee0590df2009-02-15 03:34:15 +0000222
223 new_state = *nm_state;
Harald Weltefe00eda2018-03-17 10:30:33 +0100224
225 DEBUGPFOH(DNM, foh, "STATE CHG: ");
Harald Welte39315c42010-01-10 18:01:52 +0100226 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000227 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
228 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200229 DEBUGPC(DNM, "OP_STATE=%s ",
230 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000231 }
232 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000233 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
234 new_state.availability = 0xff;
235 else
236 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200237 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
238 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000239 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100240 } else
241 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000242 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
243 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200244 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200245 get_value_string(abis_nm_adm_state_names,
246 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000247 }
248 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000249
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100250 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
251 new_state.operational != nm_state->operational ||
252 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000253 /* Update the operational state of a given object in our in-memory data
254 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100255 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200256 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100257 nsd.obj_class = foh->obj_class;
258 nsd.old_state = nm_state;
259 nsd.new_state = &new_state;
260 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100261 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200262 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100263 nm_state->operational = new_state.operational;
264 nm_state->availability = new_state.availability;
265 if (nm_state->administrative == 0)
266 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000267 }
268#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000269 if (op_state == 1) {
270 /* try to enable objects that are disabled */
271 abis_nm_opstart(bts, foh->obj_class,
272 foh->obj_inst.bts_nr,
273 foh->obj_inst.trx_nr,
274 foh->obj_inst.ts_nr);
275 }
Harald Weltee0590df2009-02-15 03:34:15 +0000276#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000277 return 0;
278}
279
Maxb1e6b372017-03-15 14:30:21 +0100280static inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type,
281 const char *severity, const uint8_t *p_val,
282 const char *text)
283{
284 enum abis_nm_pcause_type pcause = p_val[0];
285 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
286
287 LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr);
288 if (type)
289 LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type);
290 if (severity)
291 LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity);
292
293 LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
294 get_value_string(abis_nm_pcause_type_names, pcause));
295
296 if (pcause == NM_PCAUSE_T_MANUF)
297 LOGPC(DNM, LOGL_ERROR, "%s, ",
298 get_value_string(abis_mm_event_cause_names, cause));
299 else
300 LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
301
302 if (text) {
303 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text);
304 }
305
306 LOGPC(DNM, LOGL_ERROR, "\n");
307}
308
Maxa18001d2017-04-10 16:47:17 +0200309static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type,
Maxb1e6b372017-03-15 14:30:21 +0100310 const char *severity, const char *text)
311{
312 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
313
314 switch (cause) {
315 case OSMO_EVT_PCU_VERS:
Maxa18001d2017-04-10 16:47:17 +0200316 if (text) {
317 LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text);
318 osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version));
319 } else {
320 LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr);
321 bts->pcu_version[0] = '\0';
322 }
Maxb1e6b372017-03-15 14:30:21 +0100323 break;
324 default:
325 log_oml_fail_rep(bts, type, severity, p_val, text);
326 };
327}
328
Maxa18001d2017-04-10 16:47:17 +0200329static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts)
Harald Welte0db97b22009-05-01 17:22:47 +0000330{
331 struct abis_om_hdr *oh = msgb_l2(mb);
332 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200333 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000334 struct tlv_parsed tp;
Maxb1e6b372017-03-15 14:30:21 +0100335 int rc = 0;
336 const uint8_t *p_val = NULL;
337 char *p_text = NULL;
338 const char *e_type = NULL, *severity = NULL;
Harald Welte0db97b22009-05-01 17:22:47 +0000339
Maxb1e6b372017-03-15 14:30:21 +0100340 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
341 oh->length-sizeof(*foh));
Maxa5e36932017-01-11 11:51:28 +0100342
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100343 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
344 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
Maxb1e6b372017-03-15 14:30:21 +0100345 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val,
346 TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100347 }
Harald Welte0db97b22009-05-01 17:22:47 +0000348
Maxb1e6b372017-03-15 14:30:21 +0100349 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
350 e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
351 NM_ATT_EVENT_TYPE));
Harald Welte0db97b22009-05-01 17:22:47 +0000352
Maxb1e6b372017-03-15 14:30:21 +0100353 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
354 severity = abis_nm_severity_name(*TLVP_VAL(&tp,
355 NM_ATT_SEVERITY));
356
357 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
358 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
359
360 switch (p_val[0]) {
361 case NM_PCAUSE_T_MANUF:
362 handle_manufact_report(bts, p_val, e_type, severity,
363 p_text);
364 break;
365 default:
366 log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
367 };
368 } else {
Harald Weltefe00eda2018-03-17 10:30:33 +0100369 LOGPFOH(DNM, LOGL_ERROR, foh, "BTS%u: Failure Event Report without "
370 "Probable Cause?!\n", bts->nr);
Maxb1e6b372017-03-15 14:30:21 +0100371 rc = -EINVAL;
372 }
373
374 if (p_text)
375 talloc_free(p_text);
376
377 return rc;
Harald Welte0db97b22009-05-01 17:22:47 +0000378}
379
Maxb1e6b372017-03-15 14:30:21 +0100380static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
Harald Welte97ed1e72009-02-06 13:38:02 +0000381{
382 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200383 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000384
Harald Welte97ed1e72009-02-06 13:38:02 +0000385 switch (mt) {
386 case NM_MT_STATECHG_EVENT_REP:
387 return abis_nm_rx_statechg_rep(mb);
388 break;
Harald Welte34a99682009-02-13 02:41:40 +0000389 case NM_MT_SW_ACTIVATED_REP:
Harald Weltefe00eda2018-03-17 10:30:33 +0100390 DEBUGPFOH(DNM, foh, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200391 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000392 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000393 case NM_MT_FAILURE_EVENT_REP:
Maxb1e6b372017-03-15 14:30:21 +0100394 rx_fail_evt_rep(mb, bts);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200395 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000396 break;
Harald Weltec7310382009-08-08 00:02:36 +0200397 case NM_MT_TEST_REP:
Harald Weltefe00eda2018-03-17 10:30:33 +0100398 DEBUGPFOH(DNM, foh, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200399 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200400 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000401 default:
Harald Weltefe00eda2018-03-17 10:30:33 +0100402 LOGPFOH(DNM, LOGL_NOTICE, foh, "unknown NM report MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000403 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000404 };
405
Harald Welte97ed1e72009-02-06 13:38:02 +0000406 return 0;
407}
408
Harald Welte34a99682009-02-13 02:41:40 +0000409/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200410static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
Maxfd2c1f92017-03-24 21:04:57 +0100411 uint8_t i2, const struct abis_nm_sw_desc *sw_desc)
Harald Welte34a99682009-02-13 02:41:40 +0000412{
413 struct abis_om_hdr *oh;
414 struct msgb *msg = nm_msgb_alloc();
Maxfd2c1f92017-03-24 21:04:57 +0100415 uint16_t len = abis_nm_sw_desc_len(sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000416
417 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
418 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
Maxfd2c1f92017-03-24 21:04:57 +0100419 abis_nm_put_sw_desc(msg, sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000420
421 return abis_nm_sendmsg(bts, msg);
422}
423
Maxfd2c1f92017-03-24 21:04:57 +0100424int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr,
425 const size_t size)
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100426{
427 int res = 0;
428 int i;
429
430 for (i = 1; i < size; ++i) {
Maxfd2c1f92017-03-24 21:04:57 +0100431 if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version,
432 OSMO_MIN(sw_descr[i].file_version_len,
433 sw_descr[res].file_version_len)) < 0) {
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100434 res = i;
435 }
436 }
437
438 return res;
439}
440
Max33e13572017-05-29 11:48:29 +0200441static 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 +0200442{
443 switch (id) {
444 case BTS_TYPE_VARIANT:
Max33e13572017-05-29 11:48:29 +0200445 LOGP(DNM, LOGL_NOTICE, "BTS%u reported variant: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200446 break;
447 case BTS_SUB_MODEL:
Max33e13572017-05-29 11:48:29 +0200448 LOGP(DNM, LOGL_NOTICE, "BTS%u reported submodel: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200449 break;
450 default:
451 return false;
452 }
453 return true;
454}
455
Max33e13572017-05-29 11:48:29 +0200456/* Parse Attribute Response Info - return pointer to the actual content */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100457static 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 +0200458{
459 uint8_t num_unreported = ari[0], i;
460
461 DEBUGP(DNM, "BTS%u Get Attributes Response Info: %u bytes total with %u unreported attributes\n",
462 bts_nr, ari_len, num_unreported);
463
464 /* +1 because we have to account for number of unreported attributes, prefixing the list: */
465 for (i = 0; i < num_unreported; i++)
466 LOGP(DNM, LOGL_ERROR, "BTS%u Attribute %s is unreported\n",
467 bts_nr, get_value_string(abis_nm_att_names, ari[i + 1]));
468
469 /* the data starts right after the list of unreported attributes + space for length of that list */
470 *out_len = ari_len - (num_unreported + 2);
471
472 return ari + num_unreported + 1; /* we have to account for 1st byte with number of unreported attributes */
473}
474
Maxc51c1e72017-06-06 15:40:40 +0200475/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.30 Manufacturer Id */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100476static 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 +0200477{
478 struct tlv_parsed tp;
479 uint16_t m_id_len = 0;
480 uint8_t adjust = 0, i;
481
482 abis_nm_tlv_parse(&tp, bts, data, *data_len);
483 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_ID, 2)) {
484 m_id_len = TLVP_LEN(&tp, NM_ATT_MANUF_ID);
485
Max5a44d252017-06-13 10:15:58 +0200486 /* log potential BTS feature vector overflow */
487 if (m_id_len > sizeof(bts->_features_data))
Maxc51c1e72017-06-06 15:40:40 +0200488 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: feature vector is truncated to %u bytes\n",
489 bts->nr, MAX_BTS_FEATURES/8);
Maxc51c1e72017-06-06 15:40:40 +0200490
Max5a44d252017-06-13 10:15:58 +0200491 /* check that max. expected BTS attribute is above given feature vector length */
492 if (m_id_len > OSMO_BYTES_FOR_BITS(_NUM_BTS_FEAT))
Maxc51c1e72017-06-06 15:40:40 +0200493 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: reported unexpectedly long (%u bytes) "
494 "feature vector - most likely it was compiled against newer BSC headers. "
495 "Consider upgrading your BSC to later version.\n",
496 bts->nr, m_id_len);
497
Maxa60bb3d2017-06-12 13:45:03 +0200498 memcpy(bts->_features_data, TLVP_VAL(&tp, NM_ATT_MANUF_ID), sizeof(bts->_features_data));
Maxc51c1e72017-06-06 15:40:40 +0200499 adjust = m_id_len + 3; /* adjust for parsed TL16V struct */
500
501 for (i = 0; i < _NUM_BTS_FEAT; i++)
Philipp Maier8c498fc2018-02-21 13:24:36 +0100502 if (osmo_bts_has_feature(&bts->features, i) != osmo_bts_has_feature(&bts->model->features, i))
Maxc51c1e72017-06-06 15:40:40 +0200503 LOGP(DNM, LOGL_NOTICE, "BTS%u feature '%s' reported via OML does not match statically "
504 "set feature: %u != %u. Please fix.\n", bts->nr,
Philipp Maier8c498fc2018-02-21 13:24:36 +0100505 get_value_string(osmo_bts_features_descs, i),
506 osmo_bts_has_feature(&bts->features, i), osmo_bts_has_feature(&bts->model->features, i));
Maxc51c1e72017-06-06 15:40:40 +0200507 }
508
509 *data_len -= adjust;
510
511 return data + adjust;
512}
513
Max33e13572017-05-29 11:48:29 +0200514/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.28 Manufacturer Dependent State */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100515static 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 +0200516{
517 struct tlv_parsed tp;
518 const uint8_t *power;
519 uint8_t adjust = 0;
520
521 if (!trx) /* this attribute does not make sense on BTS level, only on TRX level */
522 return data;
523
524 abis_nm_tlv_parse(&tp, trx->bts, data, *data_len);
525 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_STATE, 1)) {
526 power = TLVP_VAL(&tp, NM_ATT_MANUF_STATE);
527 LOGP(DNM, LOGL_NOTICE, "%s Get Attributes Response: nominal power is %u\n", gsm_trx_name(trx), *power);
528 adjust = 2; /* adjust for parsed TV struct */
529 }
530
531 *data_len -= adjust;
532
533 return data + adjust;
534}
535
Maxdefb6c92017-05-15 10:29:54 +0200536/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */
Max33e13572017-05-29 11:48:29 +0200537static int abis_nm_rx_get_attr_resp(struct msgb *mb, const struct gsm_bts_trx *trx)
Maxdefb6c92017-05-15 10:29:54 +0200538{
539 struct abis_om_hdr *oh = msgb_l2(mb);
540 struct abis_om_fom_hdr *foh = msgb_l3(mb);
541 struct e1inp_sign_link *sign_link = mb->dst;
Max33e13572017-05-29 11:48:29 +0200542 struct gsm_bts *bts = trx ? trx->bts : sign_link->trx->bts;
Maxdefb6c92017-05-15 10:29:54 +0200543 struct tlv_parsed tp;
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100544 const uint8_t *data;
545 int i;
Max33e13572017-05-29 11:48:29 +0200546 uint16_t data_len;
Maxdefb6c92017-05-15 10:29:54 +0200547 int rc;
548 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
549
Harald Weltefe00eda2018-03-17 10:30:33 +0100550 DEBUGPFOH(DNM, foh, "Get Attributes Response for BTS%u\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200551
Max33e13572017-05-29 11:48:29 +0200552 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
553 if (!TLVP_PRES_LEN(&tp, NM_ATT_GET_ARI, 1)) {
Harald Weltefe00eda2018-03-17 10:30:33 +0100554 LOGPFOH(DNM, LOGL_ERROR, foh, "BTS%u: Get Attr Response without Response Info?!\n",
555 bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200556 return -EINVAL;
557 }
558
Max33e13572017-05-29 11:48:29 +0200559 data = parse_attr_resp_info_unreported(bts->nr, TLVP_VAL(&tp, NM_ATT_GET_ARI), TLVP_LEN(&tp, NM_ATT_GET_ARI),
560 &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200561
Max33e13572017-05-29 11:48:29 +0200562 data = parse_attr_resp_info_manuf_state(trx, data, &data_len);
Maxc51c1e72017-06-06 15:40:40 +0200563 data = parse_attr_resp_info_manuf_id(bts, data, &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200564
Max33e13572017-05-29 11:48:29 +0200565 /* after parsing manufacturer-specific attributes there's list of replies in form of sw-conf structure: */
566 rc = abis_nm_get_sw_conf(data, data_len, &sw_descr[0], ARRAY_SIZE(sw_descr));
Maxdefb6c92017-05-15 10:29:54 +0200567 if (rc > 0) {
568 for (i = 0; i < rc; i++) {
Max33e13572017-05-29 11:48:29 +0200569 if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id),
570 sw_descr[i].file_version, sw_descr[i].file_version_len))
Harald Weltefe00eda2018-03-17 10:30:33 +0100571 LOGPFOH(DNM, LOGL_NOTICE, foh, "BTS%u: ARI reported sw[%d/%d]: %s "
572 "is %s\n", bts->nr, i, rc, sw_descr[i].file_id,
573 sw_descr[i].file_version);
Maxdefb6c92017-05-15 10:29:54 +0200574 }
Harald Weltefe00eda2018-03-17 10:30:33 +0100575 } else {
576 LOGPFOH(DNM, LOGL_ERROR, foh, "BTS%u: failed to parse SW-Config part of "
577 "Get Attribute Response Info: %s\n", bts->nr, strerror(-rc));
578 }
Maxdefb6c92017-05-15 10:29:54 +0200579
580 return 0;
581}
582
Max1ebf23b2017-05-10 12:21:17 +0200583/* 3GPP TS 52.021 §6.2.5 */
Harald Welte34a99682009-02-13 02:41:40 +0000584static int abis_nm_rx_sw_act_req(struct msgb *mb)
585{
586 struct abis_om_hdr *oh = msgb_l2(mb);
587 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200588 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200589 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200590 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100591 int ret, sw_config_len, len;
Max1ebf23b2017-05-10 12:21:17 +0200592 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
Harald Welte34a99682009-02-13 02:41:40 +0000593
Harald Weltefe00eda2018-03-17 10:30:33 +0100594 DEBUGPFOH(DNM, foh, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000595
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200596 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000597 foh->obj_inst.bts_nr,
598 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800599 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000600 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100601 if (ret != 0) {
Harald Weltefe00eda2018-03-17 10:30:33 +0100602 LOGPFOH(DNM, LOGL_ERROR, foh, "Sending SW ActReq ACK failed: %d\n", ret);
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100603 return ret;
604 }
Harald Welte34a99682009-02-13 02:41:40 +0000605
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200606 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200607 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
608 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
609 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Harald Weltefe00eda2018-03-17 10:30:33 +0100610 LOGPFOH(DNM, LOGL_ERROR, foh, "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200611 return -EINVAL;
612 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200613 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200614 }
615
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100616 /* Parse up to two sw descriptions from the data */
Maxfd2c1f92017-03-24 21:04:57 +0100617 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
618 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100619 if (len <= 0) {
Harald Weltefe00eda2018-03-17 10:30:33 +0100620 LOGPFOH(DNM, LOGL_ERROR, foh, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100621 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100622 }
Mike Habena03f9772009-10-01 14:56:13 +0200623
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100624 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
Harald Weltefe00eda2018-03-17 10:30:33 +0100625 DEBUGPFOH(DNM, foh, "Selected sw description %d of %d\n", ret, len);
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100626
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200627 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000628 foh->obj_inst.bts_nr,
629 foh->obj_inst.trx_nr,
630 foh->obj_inst.ts_nr,
Maxfd2c1f92017-03-24 21:04:57 +0100631 &sw_descr[ret]);
Harald Welte34a99682009-02-13 02:41:40 +0000632}
633
Harald Weltee0590df2009-02-15 03:34:15 +0000634/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
635static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
636{
637 struct abis_om_hdr *oh = msgb_l2(mb);
638 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200639 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000640 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200641 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000642
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200643 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000644 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
645 return -EINVAL;
646
647 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
648
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200649 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000650}
651
Harald Welteee670472009-02-22 21:58:49 +0000652static int abis_nm_rx_lmt_event(struct msgb *mb)
653{
654 struct abis_om_hdr *oh = msgb_l2(mb);
655 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200656 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000657 struct tlv_parsed tp;
658
Harald Weltefe00eda2018-03-17 10:30:33 +0100659 DEBUGPFOH(DNM, foh, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200660 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000661 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
662 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200663 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000664 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
665 }
666 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
667 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200668 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000669 DEBUGPC(DNM, "Level=%u ", level);
670 }
671 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
672 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
673 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
674 DEBUGPC(DNM, "Username=%s ", name);
675 }
676 DEBUGPC(DNM, "\n");
677 /* FIXME: parse LMT LOGON TIME */
678 return 0;
679}
680
Maxaa954cd2017-11-29 12:18:02 +0100681bool all_trx_rsl_connected_unlocked(const struct gsm_bts *bts)
Max3d049d22017-10-09 17:12:53 +0200682{
683 const struct gsm_bts_trx *trx;
684
Maxaa954cd2017-11-29 12:18:02 +0100685 if (bts->mo.nm_state.administrative == NM_STATE_LOCKED)
686 return false;
687
Max115e2672017-11-29 13:21:58 +0100688 if (bts->gprs.mode != BTS_GPRS_NONE) {
689 if (bts->gprs.cell.mo.nm_state.administrative == NM_STATE_LOCKED)
690 return false;
691
692 if (bts->gprs.nse.mo.nm_state.administrative == NM_STATE_LOCKED)
693 return false;
694
695 if (bts->gprs.nsvc[0].mo.nm_state.administrative == NM_STATE_LOCKED &&
696 bts->gprs.nsvc[1].mo.nm_state.administrative == NM_STATE_LOCKED)
697 return false;
698 }
699
Max3d049d22017-10-09 17:12:53 +0200700 llist_for_each_entry(trx, &bts->trx_list, list) {
701 if (!trx->rsl_link)
702 return false;
Max115e2672017-11-29 13:21:58 +0100703
704 if (!trx_is_usable(trx))
705 return false;
706
Maxaa954cd2017-11-29 12:18:02 +0100707 if (trx->mo.nm_state.administrative == NM_STATE_LOCKED)
708 return false;
Max3d049d22017-10-09 17:12:53 +0200709 }
710
711 return true;
712}
713
Max3d049d22017-10-09 17:12:53 +0200714char *get_model_oml_status(const struct gsm_bts *bts)
715{
716 if (bts->model->oml_status)
717 return bts->model->oml_status(bts);
718
719 return "unknown";
720}
721
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200722void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100723{
724 int wait = 0;
725 struct msgb *msg;
726 /* the queue is empty */
727 while (!llist_empty(&bts->abis_queue)) {
728 msg = msgb_dequeue(&bts->abis_queue);
729 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200730 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100731
732 if (wait)
733 break;
734 }
735
736 bts->abis_nm_pend = wait;
737}
738
Harald Welte52b1f982008-12-23 20:25:15 +0000739/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000740static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000741{
Harald Welte6c96ba52009-05-01 13:03:40 +0000742 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000743 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200744 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200745 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100746 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
747 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100748 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000749
750 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000751 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100752 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000753
Harald Welte15c61722011-05-22 22:45:37 +0200754 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000755 return abis_nm_rcvmsg_sw(mb);
756
Harald Welte15c61722011-05-22 22:45:37 +0200757 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800758 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000759 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200760
Harald Weltefe00eda2018-03-17 10:30:33 +0100761 LOGPFOH(DNM, LOGL_NOTICE, foh, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000762
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100763 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000764 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200765 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200766 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000767 else
768 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200769
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800770 nack_data.msg = mb;
771 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100772 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200773 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100774 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200775 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000776 }
Harald Weltead384642008-12-26 10:20:07 +0000777#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000778 /* check if last message is to be acked */
779 if (is_ack_nack(nmh->last_msgtype)) {
780 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100781 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000782 /* we got our ACK, continue sending the next msg */
783 } else if (mt == MT_NACK(nmh->last_msgtype)) {
784 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100785 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000786 /* FIXME: somehow signal this to the caller */
787 } else {
788 /* really strange things happen */
789 return -EINVAL;
790 }
791 }
Harald Weltead384642008-12-26 10:20:07 +0000792#endif
793
Harald Welte97ed1e72009-02-06 13:38:02 +0000794 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000795 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100796 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000797 break;
Harald Welte34a99682009-02-13 02:41:40 +0000798 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100799 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000800 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000801 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100802 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000803 break;
Max689e7e52017-04-04 19:21:24 +0200804 case NM_MT_OPSTART_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100805 DEBUGPFOH(DNM, foh, "Opstart ACK\n");
Max689e7e52017-04-04 19:21:24 +0200806 break;
807 case NM_MT_SET_CHAN_ATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100808 DEBUGPFOH(DNM, foh, "Set Channel Attributes ACK\n");
Max689e7e52017-04-04 19:21:24 +0200809 break;
810 case NM_MT_SET_RADIO_ATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100811 DEBUGPFOH(DNM, foh, "Set Radio Carrier Attributes ACK\n");
Max689e7e52017-04-04 19:21:24 +0200812 break;
Harald Welte1989c082009-08-06 17:58:31 +0200813 case NM_MT_CONN_MDROP_LINK_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100814 DEBUGPFOH(DNM, foh, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200815 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100816 case NM_MT_IPACC_RESTART_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100817 DEBUGPFOH(DNM, foh, "IPA Restart ACK\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200818 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100819 break;
820 case NM_MT_IPACC_RESTART_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100821 LOGPFOH(DNM, LOGL_NOTICE, foh, "IPA Restart NACK\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200822 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100823 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100824 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100825 DEBUGPFOH(DNM, foh, "Set BTS Attribute ACK\n");
Harald Weltefd355a32011-03-04 13:41:31 +0100826 break;
Maxdefb6c92017-05-15 10:29:54 +0200827 case NM_MT_GET_ATTR_RESP:
Max33e13572017-05-29 11:48:29 +0200828 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Maxdefb6c92017-05-15 10:29:54 +0200829 break;
Max689e7e52017-04-04 19:21:24 +0200830 default:
Harald Weltefe00eda2018-03-17 10:30:33 +0100831 LOGPFOH(DNM, LOGL_ERROR, foh, "Unhandled message %s\n",
832 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000833 }
834
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100835 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100836 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000837}
838
Harald Welte677c21f2009-02-17 13:22:23 +0000839static int abis_nm_rx_ipacc(struct msgb *mb);
840
841static int abis_nm_rcvmsg_manuf(struct msgb *mb)
842{
843 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200844 struct e1inp_sign_link *sign_link = mb->dst;
845 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000846
847 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100848 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100849 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000850 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200851 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000852 break;
853 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100854 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
855 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000856 rc = 0;
857 break;
858 }
859
860 return rc;
861}
862
Harald Welte52b1f982008-12-23 20:25:15 +0000863/* High-Level API */
864/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000865int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000866{
Harald Welte52b1f982008-12-23 20:25:15 +0000867 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000868 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000869
870 /* Various consistency checks */
871 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100872 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000873 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200874 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
875 rc = -EINVAL;
876 goto err;
877 }
Harald Welte52b1f982008-12-23 20:25:15 +0000878 }
879 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100880 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000881 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200882 rc = -EINVAL;
883 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000884 }
Harald Welte702d8702008-12-26 20:25:35 +0000885#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200886 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000887 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000888 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100889 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000890 oh->length + sizeof(*oh), l2_len);
891 return -EINVAL;
892 }
Harald Welte702d8702008-12-26 20:25:35 +0000893 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100894 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 +0000895#endif
Harald Weltead384642008-12-26 10:20:07 +0000896 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000897
898 switch (oh->mdisc) {
899 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000900 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000901 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000902 case ABIS_OM_MDISC_MANUF:
903 rc = abis_nm_rcvmsg_manuf(msg);
904 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000905 case ABIS_OM_MDISC_MMI:
906 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100907 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000908 oh->mdisc);
909 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000910 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100911 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000912 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200913 rc = -EINVAL;
914 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000915 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200916err:
Harald Weltead384642008-12-26 10:20:07 +0000917 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000918 return rc;
919}
920
921#if 0
922/* initialized all resources */
923struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
924{
925 struct abis_nm_h *nmh;
926
927 nmh = malloc(sizeof(*nmh));
928 if (!nmh)
929 return NULL;
930
931 nmh->cfg = cfg;
932
933 return nmh;
934}
935
936/* free all resources */
937void abis_nm_fini(struct abis_nm_h *nmh)
938{
939 free(nmh);
940}
941#endif
942
943/* Here we are trying to define a high-level API that can be used by
944 * the actual BSC implementation. However, the architecture is currently
945 * still under design. Ideally the calls to this API would be synchronous,
946 * while the underlying stack behind the APi runs in a traditional select
947 * based state machine.
948 */
949
Harald Welte4724f992009-01-18 18:01:49 +0000950/* 6.2 Software Load: */
951enum sw_state {
952 SW_STATE_NONE,
953 SW_STATE_WAIT_INITACK,
954 SW_STATE_WAIT_SEGACK,
955 SW_STATE_WAIT_ENDACK,
956 SW_STATE_WAIT_ACTACK,
957 SW_STATE_ERROR,
958};
Harald Welte52b1f982008-12-23 20:25:15 +0000959
Harald Welte52b1f982008-12-23 20:25:15 +0000960struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000961 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800962 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000963 gsm_cbfn *cbfn;
964 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000965 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000966
Harald Welte52b1f982008-12-23 20:25:15 +0000967 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200968 uint8_t obj_class;
969 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000970
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200971 uint8_t file_id[255];
972 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000973
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200974 uint8_t file_version[255];
975 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000976
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200977 uint8_t window_size;
978 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000979
980 int fd;
981 FILE *stream;
982 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000983 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000984};
985
Harald Welte4724f992009-01-18 18:01:49 +0000986static struct abis_nm_sw g_sw;
987
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100988static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
989{
990 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
991 msgb_v_put(msg, NM_ATT_SW_DESCR);
992 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
993 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
994 sw->file_version);
995 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
996 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
997 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
998 sw->file_version);
999 } else {
1000 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1001 }
1002}
1003
Harald Welte4724f992009-01-18 18:01:49 +00001004/* 6.2.1 / 8.3.1: Load Data Initiate */
1005static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001006{
Harald Welte4724f992009-01-18 18:01:49 +00001007 struct abis_om_hdr *oh;
1008 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001009 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001010
1011 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1012 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1013 sw->obj_instance[0], sw->obj_instance[1],
1014 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001015
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001016 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001017 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1018
1019 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001020}
1021
Harald Welte1602ade2009-01-29 21:12:39 +00001022static int is_last_line(FILE *stream)
1023{
1024 char next_seg_buf[256];
1025 long pos;
1026
1027 /* check if we're sending the last line */
1028 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +02001029
1030 /* Did ftell fail? Then we are at the end for sure */
1031 if (pos < 0)
1032 return 1;
1033
Harald Welte1602ade2009-01-29 21:12:39 +00001034 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +01001035 int rc = fseek(stream, pos, SEEK_SET);
1036 if (rc < 0)
1037 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001038 return 1;
1039 }
1040
1041 fseek(stream, pos, SEEK_SET);
1042 return 0;
1043}
1044
Harald Welte4724f992009-01-18 18:01:49 +00001045/* 6.2.2 / 8.3.2 Load Data Segment */
1046static int sw_load_segment(struct abis_nm_sw *sw)
1047{
1048 struct abis_om_hdr *oh;
1049 struct msgb *msg = nm_msgb_alloc();
1050 char seg_buf[256];
1051 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001052 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +02001053 int len;
Harald Welte4724f992009-01-18 18:01:49 +00001054
1055 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001056
1057 switch (sw->bts->type) {
1058 case GSM_BTS_TYPE_BS11:
1059 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1060 perror("fgets reading segment");
1061 return -EINVAL;
1062 }
1063 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001064
1065 /* check if we're sending the last line */
1066 sw->last_seg = is_last_line(sw->stream);
1067 if (sw->last_seg)
1068 seg_buf[1] = 0;
1069 else
1070 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001071
1072 len = strlen(line_buf) + 2;
1073 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001074 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001075 /* BS11 wants CR + LF in excess of the TLV length !?! */
1076 tlv[1] -= 2;
1077
1078 /* we only now know the exact length for the OM hdr */
1079 len = strlen(line_buf)+2;
1080 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001081 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001082 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001083 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1084 if (len < 0) {
1085 perror("read failed");
1086 return -EINVAL;
1087 }
1088
1089 if (len != IPACC_SEGMENT_SIZE)
1090 sw->last_seg = 1;
1091
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001092 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001093 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001094 len += 3;
1095 break;
1096 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001097 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001098 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001099 /* FIXME: Other BTS types */
1100 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001101 }
Harald Welte4724f992009-01-18 18:01:49 +00001102
Harald Welte4724f992009-01-18 18:01:49 +00001103 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1104 sw->obj_instance[0], sw->obj_instance[1],
1105 sw->obj_instance[2]);
1106
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001107 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001108}
1109
1110/* 6.2.4 / 8.3.4 Load Data End */
1111static int sw_load_end(struct abis_nm_sw *sw)
1112{
1113 struct abis_om_hdr *oh;
1114 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001115 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001116
1117 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1118 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1119 sw->obj_instance[0], sw->obj_instance[1],
1120 sw->obj_instance[2]);
1121
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001122 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001123 return abis_nm_sendmsg(sw->bts, msg);
1124}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001125
Harald Welte52b1f982008-12-23 20:25:15 +00001126/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001127static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001128{
Harald Welte4724f992009-01-18 18:01:49 +00001129 struct abis_om_hdr *oh;
1130 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001131 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001132
Harald Welte4724f992009-01-18 18:01:49 +00001133 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1134 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1135 sw->obj_instance[0], sw->obj_instance[1],
1136 sw->obj_instance[2]);
1137
1138 /* FIXME: this is BS11 specific format */
1139 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1140 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1141 sw->file_version);
1142
1143 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001144}
Harald Welte4724f992009-01-18 18:01:49 +00001145
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001146struct sdp_firmware {
1147 char magic[4];
1148 char more_magic[4];
1149 unsigned int header_length;
1150 unsigned int file_length;
1151} __attribute__ ((packed));
1152
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001153static int parse_sdp_header(struct abis_nm_sw *sw)
1154{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001155 struct sdp_firmware firmware_header;
1156 int rc;
1157 struct stat stat;
1158
1159 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1160 if (rc != sizeof(firmware_header)) {
1161 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1162 return -1;
1163 }
1164
1165 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1166 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1167 return -1;
1168 }
1169
1170 if (firmware_header.more_magic[0] != 0x10 ||
1171 firmware_header.more_magic[1] != 0x02 ||
1172 firmware_header.more_magic[2] != 0x00 ||
1173 firmware_header.more_magic[3] != 0x00) {
1174 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1175 return -1;
1176 }
1177
1178
1179 if (fstat(sw->fd, &stat) == -1) {
1180 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1181 return -1;
1182 }
1183
1184 if (ntohl(firmware_header.file_length) != stat.st_size) {
1185 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1186 return -1;
1187 }
1188
1189 /* go back to the start as we checked the whole filesize.. */
1190 lseek(sw->fd, 0l, SEEK_SET);
1191 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1192 "There might be checksums in the file that are not\n"
1193 "verified and incomplete firmware might be flashed.\n"
1194 "There is absolutely no WARRANTY that flashing will\n"
1195 "work.\n");
1196 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001197}
1198
Harald Welte4724f992009-01-18 18:01:49 +00001199static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1200{
1201 char file_id[12+1];
1202 char file_version[80+1];
1203 int rc;
1204
1205 sw->fd = open(fname, O_RDONLY);
1206 if (sw->fd < 0)
1207 return sw->fd;
1208
1209 switch (sw->bts->type) {
1210 case GSM_BTS_TYPE_BS11:
1211 sw->stream = fdopen(sw->fd, "r");
1212 if (!sw->stream) {
1213 perror("fdopen");
1214 return -1;
1215 }
1216 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001217 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001218 file_id, file_version);
1219 if (rc != 2) {
1220 perror("parsing header line of software file");
1221 return -1;
1222 }
1223 strcpy((char *)sw->file_id, file_id);
1224 sw->file_id_len = strlen(file_id);
1225 strcpy((char *)sw->file_version, file_version);
1226 sw->file_version_len = strlen(file_version);
1227 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001228 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001229 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001230 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001231 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001232 rc = parse_sdp_header(sw);
1233 if (rc < 0) {
1234 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1235 return -1;
1236 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001237
1238 strcpy((char *)sw->file_id, "id");
1239 sw->file_id_len = 3;
1240 strcpy((char *)sw->file_version, "version");
1241 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001242 break;
Harald Welte4724f992009-01-18 18:01:49 +00001243 default:
1244 /* We don't know how to treat them yet */
1245 close(sw->fd);
1246 return -EINVAL;
1247 }
1248
1249 return 0;
1250}
1251
1252static void sw_close_file(struct abis_nm_sw *sw)
1253{
1254 switch (sw->bts->type) {
1255 case GSM_BTS_TYPE_BS11:
1256 fclose(sw->stream);
1257 break;
1258 default:
1259 close(sw->fd);
1260 break;
1261 }
1262}
1263
1264/* Fill the window */
1265static int sw_fill_window(struct abis_nm_sw *sw)
1266{
1267 int rc;
1268
1269 while (sw->seg_in_window < sw->window_size) {
1270 rc = sw_load_segment(sw);
1271 if (rc < 0)
1272 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001273 if (sw->last_seg)
1274 break;
Harald Welte4724f992009-01-18 18:01:49 +00001275 }
1276 return 0;
1277}
1278
1279/* callback function from abis_nm_rcvmsg() handler */
1280static int abis_nm_rcvmsg_sw(struct msgb *mb)
1281{
1282 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001283 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001284 int rc = -1;
1285 struct abis_nm_sw *sw = &g_sw;
1286 enum sw_state old_state = sw->state;
1287
Harald Welte3ffd1372009-02-01 22:15:49 +00001288 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001289
1290 switch (sw->state) {
1291 case SW_STATE_WAIT_INITACK:
1292 switch (foh->msg_type) {
1293 case NM_MT_LOAD_INIT_ACK:
1294 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001295 if (sw->cbfn)
1296 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1297 NM_MT_LOAD_INIT_ACK, mb,
1298 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001299 rc = sw_fill_window(sw);
1300 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001301 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001302 break;
1303 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001304 if (sw->forced) {
Harald Weltefe00eda2018-03-17 10:30:33 +01001305 DEBUGPFOH(DNM, foh, "FORCED: Ignoring Software Load Init NACK\n");
Harald Welte3ffd1372009-02-01 22:15:49 +00001306 if (sw->cbfn)
1307 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1308 NM_MT_LOAD_INIT_ACK, mb,
1309 sw->cb_data, NULL);
1310 rc = sw_fill_window(sw);
1311 sw->state = SW_STATE_WAIT_SEGACK;
1312 } else {
Harald Weltefe00eda2018-03-17 10:30:33 +01001313 LOGPFOH(DNM, LOGL_NOTICE, foh, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001314 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001315 if (sw->cbfn)
1316 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1317 NM_MT_LOAD_INIT_NACK, mb,
1318 sw->cb_data, NULL);
1319 sw->state = SW_STATE_ERROR;
1320 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001321 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001322 break;
1323 }
1324 break;
1325 case SW_STATE_WAIT_SEGACK:
1326 switch (foh->msg_type) {
1327 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001328 if (sw->cbfn)
1329 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1330 NM_MT_LOAD_SEG_ACK, mb,
1331 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001332 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001333 if (!sw->last_seg) {
1334 /* fill window with more segments */
1335 rc = sw_fill_window(sw);
1336 sw->state = SW_STATE_WAIT_SEGACK;
1337 } else {
1338 /* end the transfer */
1339 sw->state = SW_STATE_WAIT_ENDACK;
1340 rc = sw_load_end(sw);
1341 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001342 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001343 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001344 case NM_MT_LOAD_ABORT:
1345 if (sw->cbfn)
1346 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1347 NM_MT_LOAD_ABORT, mb,
1348 sw->cb_data, NULL);
1349 break;
Harald Welte4724f992009-01-18 18:01:49 +00001350 }
1351 break;
1352 case SW_STATE_WAIT_ENDACK:
1353 switch (foh->msg_type) {
1354 case NM_MT_LOAD_END_ACK:
1355 sw_close_file(sw);
Harald Weltefe00eda2018-03-17 10:30:33 +01001356 DEBUGPFOH(DNM, foh, "Software Load End (BTS %u)\n", sw->bts->nr);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001357 sw->state = SW_STATE_NONE;
1358 if (sw->cbfn)
1359 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1360 NM_MT_LOAD_END_ACK, mb,
1361 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001362 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001363 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001364 break;
1365 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001366 if (sw->forced) {
Harald Weltefe00eda2018-03-17 10:30:33 +01001367 DEBUGPFOH(DNM, foh, "FORCED: Ignoring Software Load End NACK\n");
Holger Freyther31338a12009-02-06 17:43:50 +00001368 sw->state = SW_STATE_NONE;
1369 if (sw->cbfn)
1370 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1371 NM_MT_LOAD_END_ACK, mb,
1372 sw->cb_data, NULL);
1373 } else {
Harald Weltefe00eda2018-03-17 10:30:33 +01001374 LOGPFOH(DNM, LOGL_NOTICE, foh, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001375 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001376 sw->state = SW_STATE_ERROR;
1377 if (sw->cbfn)
1378 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1379 NM_MT_LOAD_END_NACK, mb,
1380 sw->cb_data, NULL);
1381 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001382 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001383 break;
1384 }
1385 case SW_STATE_WAIT_ACTACK:
1386 switch (foh->msg_type) {
1387 case NM_MT_ACTIVATE_SW_ACK:
1388 /* we're done */
Harald Weltefe00eda2018-03-17 10:30:33 +01001389 LOGPFOH(DNM, LOGL_INFO, foh, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001390 sw->state = SW_STATE_NONE;
1391 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001392 if (sw->cbfn)
1393 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1394 NM_MT_ACTIVATE_SW_ACK, mb,
1395 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001396 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001397 break;
1398 case NM_MT_ACTIVATE_SW_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01001399 LOGPFOH(DNM, LOGL_ERROR, foh, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001400 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001401 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001402 if (sw->cbfn)
1403 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1404 NM_MT_ACTIVATE_SW_NACK, mb,
1405 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001406 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001407 break;
1408 }
1409 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001410 switch (foh->msg_type) {
1411 case NM_MT_ACTIVATE_SW_ACK:
1412 rc = 0;
1413 break;
1414 }
1415 break;
Harald Welte4724f992009-01-18 18:01:49 +00001416 case SW_STATE_ERROR:
1417 break;
1418 }
1419
1420 if (rc)
Harald Weltefe00eda2018-03-17 10:30:33 +01001421 LOGPFOH(DNM, LOGL_ERROR, foh, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001422 foh->msg_type, old_state, sw->state);
1423
1424 return rc;
1425}
1426
1427/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001428int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001429 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001430 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001431{
1432 struct abis_nm_sw *sw = &g_sw;
1433 int rc;
1434
Harald Weltefe00eda2018-03-17 10:30:33 +01001435 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n", bts->nr, fname);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001436
Harald Welte4724f992009-01-18 18:01:49 +00001437 if (sw->state != SW_STATE_NONE)
1438 return -EBUSY;
1439
1440 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001441 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001442
1443 switch (bts->type) {
1444 case GSM_BTS_TYPE_BS11:
1445 sw->obj_class = NM_OC_SITE_MANAGER;
1446 sw->obj_instance[0] = 0xff;
1447 sw->obj_instance[1] = 0xff;
1448 sw->obj_instance[2] = 0xff;
1449 break;
1450 case GSM_BTS_TYPE_NANOBTS:
1451 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001452 sw->obj_instance[0] = sw->bts->nr;
1453 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001454 sw->obj_instance[2] = 0xff;
1455 break;
1456 case GSM_BTS_TYPE_UNKNOWN:
1457 default:
1458 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1459 return -1;
1460 break;
1461 }
Harald Welte4724f992009-01-18 18:01:49 +00001462 sw->window_size = win_size;
1463 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001464 sw->cbfn = cbfn;
1465 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001466 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001467
1468 rc = sw_open_file(sw, fname);
1469 if (rc < 0) {
1470 sw->state = SW_STATE_NONE;
1471 return rc;
1472 }
1473
1474 return sw_load_init(sw);
1475}
Harald Welte52b1f982008-12-23 20:25:15 +00001476
Harald Welte1602ade2009-01-29 21:12:39 +00001477int abis_nm_software_load_status(struct gsm_bts *bts)
1478{
1479 struct abis_nm_sw *sw = &g_sw;
1480 struct stat st;
1481 int rc, percent;
1482
1483 rc = fstat(sw->fd, &st);
1484 if (rc < 0) {
1485 perror("ERROR during stat");
1486 return rc;
1487 }
1488
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001489 if (sw->stream)
1490 percent = (ftell(sw->stream) * 100) / st.st_size;
1491 else
1492 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001493 return percent;
1494}
1495
Harald Welte5e4d1b32009-02-01 13:36:56 +00001496/* Activate the specified software into the BTS */
1497int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1498 gsm_cbfn *cbfn, void *cb_data)
1499{
1500 struct abis_nm_sw *sw = &g_sw;
1501 int rc;
1502
Harald Weltefe00eda2018-03-17 10:30:33 +01001503 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n", bts->nr, fname);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001504
1505 if (sw->state != SW_STATE_NONE)
1506 return -EBUSY;
1507
1508 sw->bts = bts;
1509 sw->obj_class = NM_OC_SITE_MANAGER;
1510 sw->obj_instance[0] = 0xff;
1511 sw->obj_instance[1] = 0xff;
1512 sw->obj_instance[2] = 0xff;
1513 sw->state = SW_STATE_WAIT_ACTACK;
1514 sw->cbfn = cbfn;
1515 sw->cb_data = cb_data;
1516
1517 /* Open the file in order to fill some sw struct members */
1518 rc = sw_open_file(sw, fname);
1519 if (rc < 0) {
1520 sw->state = SW_STATE_NONE;
1521 return rc;
1522 }
1523 sw_close_file(sw);
1524
1525 return sw_activate(sw);
1526}
1527
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001528static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1529 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001530{
Harald Welteadaf08b2009-01-18 11:08:10 +00001531 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001532 ch->bts_port = bts_port;
1533 ch->timeslot = ts_nr;
1534 ch->subslot = subslot_nr;
1535}
1536
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001537int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1538 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1539 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001540{
1541 struct abis_om_hdr *oh;
1542 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001543 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001544 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001545
1546 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1547 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1548 bts->bts_nr, trx_nr, 0xff);
1549
Harald Welte8470bf22008-12-25 23:28:35 +00001550 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001551
1552 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1553 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1554
1555 return abis_nm_sendmsg(bts, msg);
1556}
1557
1558/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1559int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001560 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001561{
Harald Welte8470bf22008-12-25 23:28:35 +00001562 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001563 struct abis_om_hdr *oh;
1564 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001565 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001566
1567 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001568 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001569 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1570
1571 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1572 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1573
1574 return abis_nm_sendmsg(bts, msg);
1575}
1576
1577#if 0
1578int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1579 struct abis_nm_abis_channel *chan)
1580{
1581}
1582#endif
1583
1584int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001585 uint8_t e1_port, uint8_t e1_timeslot,
1586 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001587{
1588 struct gsm_bts *bts = ts->trx->bts;
1589 struct abis_om_hdr *oh;
1590 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001591 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001592
1593 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1594 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001595 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001596
1597 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1598 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1599
Harald Weltef325eb42009-02-19 17:07:39 +00001600 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1601 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001602 e1_port, e1_timeslot, e1_subslot);
1603
Harald Welte52b1f982008-12-23 20:25:15 +00001604 return abis_nm_sendmsg(bts, msg);
1605}
1606
1607#if 0
1608int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1609 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001610 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001611{
1612}
1613#endif
1614
Max1ebf23b2017-05-10 12:21:17 +02001615/* 3GPP TS 52.021 § 8.11.1 */
1616int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1617 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001618{
1619 struct abis_om_hdr *oh;
Maxe3dbd5d2017-06-09 17:15:45 +02001620 struct msgb *msg;
1621
1622 if (bts->type != GSM_BTS_TYPE_OSMOBTS) {
1623 LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n",
1624 bts->nr, btstype2str(bts->type));
1625 return -EINVAL;
1626 }
Harald Weltefe568f22012-08-14 19:15:57 +02001627
1628 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1629
Maxe3dbd5d2017-06-09 17:15:45 +02001630 msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001631 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1632 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1633 bts_nr, trx_nr, ts_nr);
1634 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1635
1636 return abis_nm_sendmsg(bts, msg);
1637}
1638
Harald Welte22af0db2009-02-14 15:41:08 +00001639/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001640int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001641{
1642 struct abis_om_hdr *oh;
1643 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001644 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001645
1646 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1647
1648 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001649 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 +00001650 cur = msgb_put(msg, attr_len);
1651 memcpy(cur, attr, attr_len);
1652
1653 return abis_nm_sendmsg(bts, msg);
1654}
1655
1656/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001657int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, 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 TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1664
1665 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1666 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001667 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001668 cur = msgb_put(msg, attr_len);
1669 memcpy(cur, attr, attr_len);
1670
1671 return abis_nm_sendmsg(trx->bts, msg);
1672}
1673
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001674int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1675{
1676 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1677 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1678}
1679
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001680static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1681 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001682{
1683 int i;
1684
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001685 *reason = "Reason unknown";
1686
Harald Welte39c7deb2009-08-09 21:49:48 +02001687 /* As it turns out, the BS-11 has some very peculiar restrictions
1688 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301689 switch (ts->trx->bts->type) {
1690 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001691 switch (chan_comb) {
1692 case NM_CHANC_TCHHalf:
1693 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001694 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001695 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001696 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001697 return -EINVAL;
1698 case NM_CHANC_SDCCH:
1699 /* only one SDCCH/8 per TRX */
1700 for (i = 0; i < TRX_NR_TS; i++) {
1701 if (i == ts->nr)
1702 continue;
1703 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001704 NM_CHANC_SDCCH) {
1705 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001706 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001707 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001708 }
1709 /* not allowed for TS0 of BCCH-TRX */
1710 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001711 ts->nr == 0) {
1712 *reason = "SDCCH/8 must be on TS0.";
1713 return -EINVAL;
1714 }
1715
Harald Welte39c7deb2009-08-09 21:49:48 +02001716 /* not on the same TRX that has a BCCH+SDCCH4
1717 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001718 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001719 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001720 ts->trx->ts[0].nm_chan_comb == 8)) {
1721 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1722 return -EINVAL;
1723 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001724 break;
1725 case NM_CHANC_mainBCCH:
1726 case NM_CHANC_BCCHComb:
1727 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001728 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1729 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001730 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001731 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001732 break;
1733 case NM_CHANC_BCCH:
1734 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001735 if (ts->trx != ts->trx->bts->c0) {
1736 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001737 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001738 }
1739 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1740 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001741 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001742 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001743 break;
1744 case 8: /* this is not like 08.58, but in fact
1745 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1746 /* FIXME: only one CBCH allowed per cell */
1747 break;
1748 }
Harald Welted6575f92009-12-02 02:45:23 +05301749 break;
1750 case GSM_BTS_TYPE_NANOBTS:
1751 switch (ts->nr) {
1752 case 0:
1753 if (ts->trx->nr == 0) {
1754 /* only on TRX0 */
1755 switch (chan_comb) {
1756 case NM_CHANC_BCCH:
1757 case NM_CHANC_mainBCCH:
1758 case NM_CHANC_BCCHComb:
1759 return 0;
1760 break;
1761 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001762 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301763 return -EINVAL;
1764 }
1765 } else {
1766 switch (chan_comb) {
1767 case NM_CHANC_TCHFull:
1768 case NM_CHANC_TCHHalf:
1769 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1770 return 0;
1771 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001772 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301773 return -EINVAL;
1774 }
1775 }
1776 break;
1777 case 1:
1778 if (ts->trx->nr == 0) {
1779 switch (chan_comb) {
1780 case NM_CHANC_SDCCH_CBCH:
1781 if (ts->trx->ts[0].nm_chan_comb ==
1782 NM_CHANC_mainBCCH)
1783 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001784 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301785 return -EINVAL;
1786 case NM_CHANC_SDCCH:
1787 case NM_CHANC_TCHFull:
1788 case NM_CHANC_TCHHalf:
1789 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1790 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001791 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301792 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001793 default:
1794 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1795 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301796 }
1797 } else {
1798 switch (chan_comb) {
1799 case NM_CHANC_SDCCH:
1800 case NM_CHANC_TCHFull:
1801 case NM_CHANC_TCHHalf:
1802 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1803 return 0;
1804 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001805 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301806 return -EINVAL;
1807 }
1808 }
1809 break;
1810 case 2:
1811 case 3:
1812 case 4:
1813 case 5:
1814 case 6:
1815 case 7:
1816 switch (chan_comb) {
1817 case NM_CHANC_TCHFull:
1818 case NM_CHANC_TCHHalf:
1819 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1820 return 0;
1821 case NM_CHANC_IPAC_PDCH:
1822 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001823 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301824 if (ts->trx->nr == 0)
1825 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001826 else {
1827 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301828 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001829 }
Harald Welted6575f92009-12-02 02:45:23 +05301830 }
1831 break;
1832 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001833 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301834 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001835 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001836 /* no known restrictions */
1837 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301838 default:
1839 /* unknown BTS type */
1840 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001841 }
1842 return 0;
1843}
1844
Harald Welte22af0db2009-02-14 15:41:08 +00001845/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001846int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001847{
1848 struct gsm_bts *bts = ts->trx->bts;
1849 struct abis_om_hdr *oh;
Harald Weltefe00eda2018-03-17 10:30:33 +01001850 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001851 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001852 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001853 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001854 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001855
1856 if (bts->type == GSM_BTS_TYPE_BS11)
1857 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001858
Harald Weltefe00eda2018-03-17 10:30:33 +01001859 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1860 foh = fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR, NM_OC_CHANNEL, bts->bts_nr,
1861 ts->trx->nr, ts->nr);
1862
1863 DEBUGPFOH(DNM, foh, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001864 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001865 msgb_free(msg);
Harald Weltefe00eda2018-03-17 10:30:33 +01001866 LOGPFOH(DNM, LOGL_ERROR, foh, "Invalid Channel Combination %d on %s. Reason: %s\n",
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001867 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001868 return -EINVAL;
1869 }
1870 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001871
Harald Welte52b1f982008-12-23 20:25:15 +00001872 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001873 if (ts->hopping.enabled) {
1874 unsigned int i;
1875 uint8_t *len;
1876
Harald Welte6e0cd042009-09-12 13:05:33 +02001877 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1878 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001879
1880 /* build the ARFCN list */
1881 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1882 len = msgb_put(msg, 1);
1883 *len = 0;
1884 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1885 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1886 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001887 /* At least BS-11 wants a TLV16 here */
1888 if (bts->type == GSM_BTS_TYPE_BS11)
1889 *len += 1;
1890 else
1891 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001892 }
1893 }
Harald Weltee0590df2009-02-15 03:34:15 +00001894 }
Harald Welte1fe24122014-01-19 17:18:21 +01001895 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001896 if (bts->type == GSM_BTS_TYPE_BS11)
1897 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001898
1899 return abis_nm_sendmsg(bts, msg);
1900}
1901
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001902int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1903 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001904{
1905 struct abis_om_hdr *oh;
1906 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001907 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1908 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001909
1910 if (nack) {
1911 len += 2;
1912 msgtype = NM_MT_SW_ACT_REQ_NACK;
1913 }
Harald Welte34a99682009-02-13 02:41:40 +00001914
1915 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001916 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1917
Harald Welte34a99682009-02-13 02:41:40 +00001918 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001919 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001920 memcpy(ptr, attr, att_len);
1921 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001922 if (nack)
1923 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001924
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001925 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001926}
1927
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001928int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001929{
Harald Welte8470bf22008-12-25 23:28:35 +00001930 struct msgb *msg = nm_msgb_alloc();
1931 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001932 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001933
1934 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1935 fill_om_hdr(oh, len);
1936 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001937 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001938
1939 return abis_nm_sendmsg(bts, msg);
1940}
1941
1942/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001943static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001944{
1945 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001946 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001947
1948 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001949 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001950 0xff, 0xff, 0xff);
1951
1952 return abis_nm_sendmsg(bts, msg);
1953}
1954
Harald Welte34a99682009-02-13 02:41:40 +00001955/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001956int 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 +00001957{
1958 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001959 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001960 struct msgb *msg = nm_msgb_alloc();
1961
1962 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001963 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001964
Harald Weltefe00eda2018-03-17 10:30:33 +01001965 DEBUGPFOH(DNM, foh, "Sending OPSTART\n");
Harald Weltea8bd6d42009-10-20 09:56:18 +02001966
Harald Welte34a99682009-02-13 02:41:40 +00001967 return abis_nm_sendmsg(bts, msg);
1968}
1969
1970/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001971int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1972 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001973{
1974 struct abis_om_hdr *oh;
1975 struct msgb *msg = nm_msgb_alloc();
1976
1977 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1978 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1979 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1980
1981 return abis_nm_sendmsg(bts, msg);
1982}
1983
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001984int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1985 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001986{
1987 struct abis_om_hdr *oh;
1988 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001989 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001990
1991 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1992 e1_port0, ts0, e1_port1, ts1);
1993
1994 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1995 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1996 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1997
1998 attr = msgb_put(msg, 3);
1999 attr[0] = NM_ATT_MDROP_LINK;
2000 attr[1] = e1_port0;
2001 attr[2] = ts0;
2002
2003 attr = msgb_put(msg, 3);
2004 attr[0] = NM_ATT_MDROP_NEXT;
2005 attr[1] = e1_port1;
2006 attr[2] = ts1;
2007
2008 return abis_nm_sendmsg(bts, msg);
2009}
Harald Welte34a99682009-02-13 02:41:40 +00002010
Harald Weltec7310382009-08-08 00:02:36 +02002011/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002012int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2013 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2014 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002015{
2016 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002017
Harald Welte15c61722011-05-22 22:45:37 +02002018 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002019
2020 if (!msg)
2021 msg = nm_msgb_alloc();
2022
2023 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2024 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2025 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2026 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002027 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002028
2029 return abis_nm_sendmsg(bts, msg);
2030}
2031
Harald Welte52b1f982008-12-23 20:25:15 +00002032int abis_nm_event_reports(struct gsm_bts *bts, int on)
2033{
2034 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002035 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002036 else
Harald Welte227d4072009-01-03 08:16:25 +00002037 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002038}
2039
Harald Welte47d88ae2009-01-04 12:02:08 +00002040/* Siemens (or BS-11) specific commands */
2041
Harald Welte3ffd1372009-02-01 22:15:49 +00002042int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2043{
2044 if (reconnect == 0)
2045 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2046 else
2047 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2048}
2049
Harald Welteb8427972009-02-05 19:27:17 +00002050int abis_nm_bs11_restart(struct gsm_bts *bts)
2051{
2052 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2053}
2054
2055
Harald Welte268bb402009-02-01 19:11:56 +00002056struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002057 uint16_t year;
2058 uint8_t month;
2059 uint8_t day;
2060 uint8_t hour;
2061 uint8_t min;
2062 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002063} __attribute__((packed));
2064
2065
2066void get_bs11_date_time(struct bs11_date_time *aet)
2067{
2068 time_t t;
2069 struct tm *tm;
2070
2071 t = time(NULL);
2072 tm = localtime(&t);
2073 aet->sec = tm->tm_sec;
2074 aet->min = tm->tm_min;
2075 aet->hour = tm->tm_hour;
2076 aet->day = tm->tm_mday;
2077 aet->month = tm->tm_mon;
2078 aet->year = htons(1900 + tm->tm_year);
2079}
2080
Harald Welte05188ee2009-01-18 11:39:08 +00002081int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002082{
Harald Welte4668fda2009-01-03 08:19:29 +00002083 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002084}
2085
Harald Welte05188ee2009-01-18 11:39:08 +00002086int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002087{
2088 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002089 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002090 else
Harald Welte4668fda2009-01-03 08:19:29 +00002091 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002092}
Harald Welte47d88ae2009-01-04 12:02:08 +00002093
Harald Welte05188ee2009-01-18 11:39:08 +00002094int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002095 enum abis_bs11_objtype type, uint8_t idx,
2096 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002097{
2098 struct abis_om_hdr *oh;
2099 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002100 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002101
2102 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002103 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002104 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002105 cur = msgb_put(msg, attr_len);
2106 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002107
2108 return abis_nm_sendmsg(bts, msg);
2109}
2110
Harald Welte78fc0d42009-02-19 02:50:57 +00002111int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002112 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002113{
2114 struct abis_om_hdr *oh;
2115 struct msgb *msg = nm_msgb_alloc();
2116
2117 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2118 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2119 NM_OC_BS11, type, 0, idx);
2120
2121 return abis_nm_sendmsg(bts, msg);
2122}
2123
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002124int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002125{
2126 struct abis_om_hdr *oh;
2127 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002128 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002129
2130 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002131 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002132 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2133 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002134
2135 return abis_nm_sendmsg(bts, msg);
2136}
2137
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002138int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002139{
2140 struct abis_om_hdr *oh;
2141 struct msgb *msg = nm_msgb_alloc();
2142
2143 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2144 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002145 idx, 0xff, 0xff);
2146
2147 return abis_nm_sendmsg(bts, msg);
2148}
2149
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002150int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002151{
2152 struct abis_om_hdr *oh;
2153 struct msgb *msg = nm_msgb_alloc();
2154
2155 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2156 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2157 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002158
2159 return abis_nm_sendmsg(bts, msg);
2160}
Harald Welte05188ee2009-01-18 11:39:08 +00002161
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002162static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002163int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2164{
2165 struct abis_om_hdr *oh;
2166 struct msgb *msg = nm_msgb_alloc();
2167
2168 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2169 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2170 0xff, 0xff, 0xff);
2171 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2172
2173 return abis_nm_sendmsg(bts, msg);
2174}
2175
Harald Welteb6c92ae2009-02-21 20:15:32 +00002176/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002177int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2178 uint8_t e1_timeslot, uint8_t e1_subslot,
2179 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002180{
2181 struct abis_om_hdr *oh;
2182 struct abis_nm_channel *ch;
2183 struct msgb *msg = nm_msgb_alloc();
2184
2185 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002186 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002187 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2188
2189 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2190 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002191 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002192
2193 return abis_nm_sendmsg(bts, msg);
2194}
2195
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002196int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002197{
2198 struct abis_om_hdr *oh;
2199 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002200
2201 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002202 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002203 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2204 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2205
2206 return abis_nm_sendmsg(trx->bts, msg);
2207}
2208
Harald Welte78fc0d42009-02-19 02:50:57 +00002209int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2210{
2211 struct abis_om_hdr *oh;
2212 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002213 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002214
2215 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2216 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2217 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2218 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2219
2220 return abis_nm_sendmsg(trx->bts, msg);
2221}
2222
Harald Welteaaf02d92009-04-29 13:25:57 +00002223int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2224{
2225 struct abis_om_hdr *oh;
2226 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002227 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002228
2229 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2230 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2231 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002232 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002233
2234 return abis_nm_sendmsg(bts, msg);
2235}
2236
Harald Welteef061952009-05-17 12:43:42 +00002237int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2238{
2239 struct abis_om_hdr *oh;
2240 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002241 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002242 NM_ATT_BS11_CCLK_TYPE };
2243
2244 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2245 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2246 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2247 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2248
2249 return abis_nm_sendmsg(bts, msg);
2250
2251}
Harald Welteaaf02d92009-04-29 13:25:57 +00002252
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002253//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002254
Harald Welte1bc09062009-01-18 14:17:52 +00002255int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002256{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002257 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2258}
2259
Daniel Willmann4b054c82010-01-07 00:46:26 +01002260int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2261{
2262 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2263}
2264
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002265int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002266{
Harald Welte05188ee2009-01-18 11:39:08 +00002267 struct abis_om_hdr *oh;
2268 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002269 struct bs11_date_time bdt;
2270
2271 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002272
2273 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002274 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002275 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002276 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002277 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002278 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002279 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002280 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002281 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002282 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002283 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002284 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002285 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002286 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002287 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002288 }
Harald Welte05188ee2009-01-18 11:39:08 +00002289
2290 return abis_nm_sendmsg(bts, msg);
2291}
Harald Welte1bc09062009-01-18 14:17:52 +00002292
2293int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2294{
2295 struct abis_om_hdr *oh;
2296 struct msgb *msg;
2297
2298 if (strlen(password) != 10)
2299 return -EINVAL;
2300
2301 msg = nm_msgb_alloc();
2302 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002303 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002304 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002305 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002306
2307 return abis_nm_sendmsg(bts, msg);
2308}
2309
Harald Weltee69f5fb2009-04-28 16:31:38 +00002310/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2311int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2312{
2313 struct abis_om_hdr *oh;
2314 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002315 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002316
2317 msg = nm_msgb_alloc();
2318 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2319 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2320 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002321
2322 if (locked)
2323 tlv_value = BS11_LI_PLL_LOCKED;
2324 else
2325 tlv_value = BS11_LI_PLL_STANDALONE;
2326
2327 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002328
2329 return abis_nm_sendmsg(bts, msg);
2330}
2331
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002332/* Set the calibration value of the PLL (work value/set value)
2333 * It depends on the login which one is changed */
2334int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2335{
2336 struct abis_om_hdr *oh;
2337 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002338 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002339
2340 msg = nm_msgb_alloc();
2341 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2342 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2343 BS11_OBJ_TRX1, 0x00, 0x00);
2344
2345 tlv_value[0] = value>>8;
2346 tlv_value[1] = value&0xff;
2347
2348 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2349
2350 return abis_nm_sendmsg(bts, msg);
2351}
2352
Harald Welte1bc09062009-01-18 14:17:52 +00002353int abis_nm_bs11_get_state(struct gsm_bts *bts)
2354{
2355 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2356}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002357
2358/* BS11 SWL */
2359
Neels Hofmeyrcc6240a2018-02-13 21:21:42 +01002360void *tall_fle_ctx = NULL;
Harald Welte2cf161b2009-06-20 22:36:41 +02002361
Harald Welte5e4d1b32009-02-01 13:36:56 +00002362struct abis_nm_bs11_sw {
2363 struct gsm_bts *bts;
2364 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002365 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002366 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002367 struct llist_head file_list;
2368 gsm_cbfn *user_cb; /* specified by the user */
2369};
2370static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2371
2372struct file_list_entry {
2373 struct llist_head list;
2374 char fname[PATH_MAX];
2375};
2376
2377struct file_list_entry *fl_dequeue(struct llist_head *queue)
2378{
2379 struct llist_head *lh;
2380
2381 if (llist_empty(queue))
2382 return NULL;
2383
2384 lh = queue->next;
2385 llist_del(lh);
2386
2387 return llist_entry(lh, struct file_list_entry, list);
2388}
2389
2390static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2391{
2392 char linebuf[255];
2393 struct llist_head *lh, *lh2;
2394 FILE *swl;
2395 int rc = 0;
2396
2397 swl = fopen(bs11_sw->swl_fname, "r");
2398 if (!swl)
2399 return -ENODEV;
2400
2401 /* zero the stale file list, if any */
2402 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2403 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002404 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002405 }
2406
2407 while (fgets(linebuf, sizeof(linebuf), swl)) {
2408 char file_id[12+1];
2409 char file_version[80+1];
2410 struct file_list_entry *fle;
2411 static char dir[PATH_MAX];
2412
2413 if (strlen(linebuf) < 4)
2414 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002415
Harald Welte5e4d1b32009-02-01 13:36:56 +00002416 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2417 if (rc < 0) {
2418 perror("ERR parsing SWL file");
2419 rc = -EINVAL;
2420 goto out;
2421 }
2422 if (rc < 2)
2423 continue;
2424
Harald Welte470ec292009-06-26 20:25:23 +02002425 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002426 if (!fle) {
2427 rc = -ENOMEM;
2428 goto out;
2429 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002430
2431 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002432 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002433 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2434 strcat(fle->fname, "/");
2435 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002436
2437 llist_add_tail(&fle->list, &bs11_sw->file_list);
2438 }
2439
2440out:
2441 fclose(swl);
2442 return rc;
2443}
2444
2445/* bs11 swload specific callback, passed to abis_nm core swload */
2446static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2447 struct msgb *msg, void *data, void *param)
2448{
2449 struct abis_nm_bs11_sw *bs11_sw = data;
2450 struct file_list_entry *fle;
2451 int rc = 0;
2452
Harald Welte5e4d1b32009-02-01 13:36:56 +00002453 switch (event) {
2454 case NM_MT_LOAD_END_ACK:
2455 fle = fl_dequeue(&bs11_sw->file_list);
2456 if (fle) {
2457 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002458 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002459 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002460 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002461 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002462 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002463 } else {
2464 /* activate the SWL */
2465 rc = abis_nm_software_activate(bs11_sw->bts,
2466 bs11_sw->swl_fname,
2467 bs11_swload_cbfn,
2468 bs11_sw);
2469 }
2470 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002471 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002472 case NM_MT_LOAD_END_NACK:
2473 case NM_MT_LOAD_INIT_ACK:
2474 case NM_MT_LOAD_INIT_NACK:
2475 case NM_MT_ACTIVATE_SW_NACK:
2476 case NM_MT_ACTIVATE_SW_ACK:
2477 default:
2478 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002479 if (bs11_sw->user_cb)
2480 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002481 break;
2482 }
2483
2484 return rc;
2485}
2486
2487/* Siemens provides a SWL file that is a mere listing of all the other
2488 * files that are part of a software release. We need to upload first
2489 * the list file, and then each file that is listed in the list file */
2490int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002491 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002492{
2493 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2494 struct file_list_entry *fle;
2495 int rc = 0;
2496
2497 INIT_LLIST_HEAD(&bs11_sw->file_list);
2498 bs11_sw->bts = bts;
2499 bs11_sw->win_size = win_size;
2500 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002501 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002502
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002503 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002504 rc = bs11_read_swl_file(bs11_sw);
2505 if (rc < 0)
2506 return rc;
2507
2508 /* dequeue next item in file list */
2509 fle = fl_dequeue(&bs11_sw->file_list);
2510 if (!fle)
2511 return -EINVAL;
2512
2513 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002514 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002515 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002516 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002517 return rc;
2518}
2519
Harald Welte5083b0b2009-02-02 19:20:52 +00002520#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002521static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002522 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2523 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2524 NM_ATT_BS11_LMT_USER_NAME,
2525
2526 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2527
2528 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2529
2530 NM_ATT_BS11_SW_LOAD_STORED };
2531
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002532static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002533 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2534 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2535 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2536 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002537#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002538
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002539static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002540 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2541 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002542 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002543
2544int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2545{
2546 struct abis_om_hdr *oh;
2547 struct msgb *msg = nm_msgb_alloc();
2548
2549 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2550 /* SiemensHW CCTRL object */
2551 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2552 0x03, 0x00, 0x00);
2553 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2554
2555 return abis_nm_sendmsg(bts, msg);
2556}
Harald Welte268bb402009-02-01 19:11:56 +00002557
2558int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2559{
2560 struct abis_om_hdr *oh;
2561 struct msgb *msg = nm_msgb_alloc();
2562 struct bs11_date_time aet;
2563
2564 get_bs11_date_time(&aet);
2565 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2566 /* SiemensHW CCTRL object */
2567 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2568 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002569 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002570
2571 return abis_nm_sendmsg(bts, msg);
2572}
Harald Welte5c1e4582009-02-15 11:57:29 +00002573
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002574int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002575{
2576 struct abis_om_hdr *oh;
2577 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002578 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002579
2580 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2581 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2582 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2583 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2584
2585 return abis_nm_sendmsg(bts, msg);
2586}
2587
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002588int 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 +02002589{
2590 struct abis_om_hdr *oh;
2591 struct msgb *msg = nm_msgb_alloc();
2592 struct bs11_date_time aet;
2593
2594 get_bs11_date_time(&aet);
2595 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2596 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2597 bport, 0xff, 0x02);
2598 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2599
2600 return abis_nm_sendmsg(bts, msg);
2601}
2602
Harald Welte5c1e4582009-02-15 11:57:29 +00002603/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002604static const char ipaccess_magic[] = "com.ipaccess";
2605
Harald Welte677c21f2009-02-17 13:22:23 +00002606
2607static int abis_nm_rx_ipacc(struct msgb *msg)
2608{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002609 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002610 struct abis_om_hdr *oh = msgb_l2(msg);
2611 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002612 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002613 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002614 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002615 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002616
Harald Weltefe00eda2018-03-17 10:30:33 +01002617 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
2618
Harald Welte677c21f2009-02-17 13:22:23 +00002619 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltefe00eda2018-03-17 10:30:33 +01002620 LOGPFOH(DNM, LOGL_ERROR, foh, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002621 return -EINVAL;
2622 }
2623
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002624 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002625
Harald Weltefe00eda2018-03-17 10:30:33 +01002626 DEBUGPFOH(DNM, foh, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002627
Harald Welte677c21f2009-02-17 13:22:23 +00002628 switch (foh->msg_type) {
2629 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002630 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002631 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2632 memcpy(&addr,
2633 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2634
2635 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2636 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002637 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002638 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002639 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002640 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002641 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2642 DEBUGPC(DNM, "STREAM=0x%02x ",
2643 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002644 DEBUGPC(DNM, "\n");
Stefan Sperling73acbca2018-02-12 14:28:52 +01002645 osmo_timer_del(&sign_link->trx->rsl_connect_timeout);
Harald Welte677c21f2009-02-17 13:22:23 +00002646 break;
2647 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002648 LOGPFOH(DNM, LOGL_ERROR, foh, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002649 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002650 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002651 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002652 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002653 LOGPC(DNM, LOGL_ERROR, "\n");
Stefan Sperling73acbca2018-02-12 14:28:52 +01002654 osmo_timer_del(&sign_link->trx->rsl_connect_timeout);
Harald Welte677c21f2009-02-17 13:22:23 +00002655 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002656 case NM_MT_IPACC_SET_NVATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002657 DEBUGPFOH(DNM, foh, "SET NVATTR ACK\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002658 /* FIXME: decode and show the actual attributes */
2659 break;
2660 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002661 LOGPFOH(DNM, LOGL_ERROR, foh, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002662 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002663 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002664 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002665 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002666 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002667 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002668 case NM_MT_IPACC_GET_NVATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002669 DEBUGPFOH(DNM, foh, "GET NVATTR ACK\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002670 /* FIXME: decode and show the actual attributes */
2671 break;
2672 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002673 LOGPFOH(DNM, LOGL_ERROR, foh, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002674 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002675 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002676 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002677 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002678 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002679 break;
Harald Welte15c44172009-10-08 20:15:24 +02002680 case NM_MT_IPACC_SET_ATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002681 DEBUGPFOH(DNM, foh, "SET ATTR ACK\n");
Harald Welte15c44172009-10-08 20:15:24 +02002682 break;
2683 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002684 LOGPFOH(DNM, LOGL_ERROR, foh, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002685 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002686 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002687 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002688 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002689 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002690 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002691 default:
2692 DEBUGPC(DNM, "unknown\n");
2693 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002694 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002695
2696 /* signal handling */
2697 switch (foh->msg_type) {
2698 case NM_MT_IPACC_RSL_CONNECT_NACK:
2699 case NM_MT_IPACC_SET_NVATTR_NACK:
2700 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002701 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 +01002702 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002703 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002704 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002705 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002706 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 +01002707 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002708 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002709 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002710 default:
2711 break;
2712 }
2713
Harald Welte677c21f2009-02-17 13:22:23 +00002714 return 0;
2715}
2716
Harald Welte193fefc2009-04-30 15:16:27 +00002717/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002718int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2719 uint8_t obj_class, uint8_t bts_nr,
2720 uint8_t trx_nr, uint8_t ts_nr,
2721 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002722{
2723 struct msgb *msg = nm_msgb_alloc();
2724 struct abis_om_hdr *oh;
2725 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002726 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002727
2728 /* construct the 12.21 OM header, observe the erroneous length */
2729 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2730 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2731 oh->mdisc = ABIS_OM_MDISC_MANUF;
2732
2733 /* add the ip.access magic */
2734 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2735 *data++ = sizeof(ipaccess_magic);
2736 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2737
2738 /* fill the 12.21 FOM header */
2739 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2740 foh->msg_type = msg_type;
2741 foh->obj_class = obj_class;
2742 foh->obj_inst.bts_nr = bts_nr;
2743 foh->obj_inst.trx_nr = trx_nr;
2744 foh->obj_inst.ts_nr = ts_nr;
2745
2746 if (attr && attr_len) {
2747 data = msgb_put(msg, attr_len);
2748 memcpy(data, attr, attr_len);
2749 }
2750
2751 return abis_nm_sendmsg(bts, msg);
2752}
Harald Welte677c21f2009-02-17 13:22:23 +00002753
Harald Welte193fefc2009-04-30 15:16:27 +00002754/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002755int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002756 int attr_len)
2757{
Harald Welte2ef156d2010-01-07 20:39:42 +01002758 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2759 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002760 attr_len);
2761}
2762
Stefan Sperling73acbca2018-02-12 14:28:52 +01002763static void rsl_connect_timeout(void *data)
2764{
2765 struct gsm_bts_trx *trx = data;
2766 struct ipacc_ack_signal_data signal;
2767
2768 LOGP(DRSL, LOGL_NOTICE, "(bts=%d,trx=%d) RSL connection request timed out\n", trx->bts->nr, trx->nr);
2769
2770 /* Fake an RSL CONECT NACK message from the BTS. */
2771 signal.trx = trx;
2772 signal.msg_type = NM_MT_IPACC_RSL_CONNECT_NACK;
2773 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
2774}
2775
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002776int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002777 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002778{
2779 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002780 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002781 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2782 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2783
2784 int attr_len = sizeof(attr);
Stefan Sperling73acbca2018-02-12 14:28:52 +01002785 int error;
2786
2787 osmo_timer_setup(&trx->rsl_connect_timeout, rsl_connect_timeout, trx);
Harald Welte746d6092009-10-19 22:11:11 +02002788
2789 ia.s_addr = htonl(ip);
2790 attr[1] = stream;
2791 attr[3] = port >> 8;
2792 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002793 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002794
2795 /* if ip == 0, we use the default IP */
2796 if (ip == 0)
2797 attr_len -= 5;
2798
Harald Weltefe00eda2018-03-17 10:30:33 +01002799 LOGP(DNM, LOGL_INFO, "IPA RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002800 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002801
Stefan Sperling73acbca2018-02-12 14:28:52 +01002802 error = abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2803 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2804 trx->nr, 0xff, attr, attr_len);
2805 if (error == 0)
2806 osmo_timer_schedule(&trx->rsl_connect_timeout, 60, 0);
2807
2808 return error;
Harald Welte746d6092009-10-19 22:11:11 +02002809}
2810
Harald Welte193fefc2009-04-30 15:16:27 +00002811/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002812int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002813{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002814 struct abis_om_hdr *oh;
2815 struct msgb *msg = nm_msgb_alloc();
2816
2817 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2818 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2819 trx->bts->nr, trx->nr, 0xff);
2820
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002821 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002822}
Harald Weltedaef5212009-10-24 10:20:41 +02002823
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002824int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2825 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2826 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002827{
2828 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2829 obj_class, bts_nr, trx_nr, ts_nr,
2830 attr, attr_len);
2831}
Harald Welte0f255852009-11-12 14:48:42 +01002832
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002833void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002834{
Neels Hofmeyr4d358c02018-02-22 03:19:05 +01002835 struct gsm48_ra_id *_buf = (struct gsm48_ra_id*)buf;
2836 uint16_t ci = htons(bts->cell_identity);
2837 /* we simply reuse the GSM48 function and write the Cell ID over the position where the RAC
2838 * starts */
2839 gsm48_ra_id_by_bts(_buf, bts);
2840 memcpy(&_buf->rac, &ci, sizeof(ci));
Harald Welte97a282b2010-03-14 15:37:43 +08002841}
2842
Maxbe356ed2017-09-07 19:10:09 +02002843void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason)
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002844{
Maxbe356ed2017-09-07 19:10:09 +02002845 uint8_t new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2846
2847 LOGP(DNM, LOGL_NOTICE, "(bts=%d,trx=%d) Changing adm. state %s -> %s [%s]\n", trx->bts->nr, trx->nr,
2848 get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative),
2849 get_value_string(abis_nm_adm_state_names, new_state), reason);
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002850
Harald Welted64c0bc2011-05-30 12:07:53 +02002851 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002852 if (!trx->bts || !trx->bts->oml_link)
2853 return;
2854
2855 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2856 trx->bts->bts_nr, trx->nr, 0xff,
2857 new_state);
2858}
2859
Harald Welte92b1fe42010-03-25 11:45:30 +08002860static const struct value_string ipacc_testres_names[] = {
2861 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2862 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2863 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2864 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2865 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2866 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002867};
2868
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002869const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002870{
Harald Welte92b1fe42010-03-25 11:45:30 +08002871 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002872}
2873
Neels Hofmeyrda5b09a2018-03-21 16:04:30 +01002874void ipac_parse_cgi(struct osmo_cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002875{
Neels Hofmeyrda5b09a2018-03-21 16:04:30 +01002876 osmo_plmn_from_bcd(buf, &cid->lai.plmn);
2877 cid->lai.lac = ntohs(*((uint16_t *)&buf[3]));
2878 cid->cell_identity = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002879}
2880
Harald Welte0f255852009-11-12 14:48:42 +01002881/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002882int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002883{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002884 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002885 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002886
Harald Welteaf109b92010-07-22 18:14:36 +02002887 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002888
2889 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2890 return -EINVAL;
2891 cur++;
2892
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002893 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002894 cur += 2;
2895
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002896 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002897 cur += 2;
2898
2899 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2900 binf->freq_qual = *cur >> 2;
2901
Harald Welteaf109b92010-07-22 18:14:36 +02002902 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002903 binf->arfcn |= *cur++;
2904
2905 if (binf->info_type & IPAC_BINF_RXLEV)
2906 binf->rx_lev = *cur & 0x3f;
2907 cur++;
2908
2909 if (binf->info_type & IPAC_BINF_RXQUAL)
2910 binf->rx_qual = *cur & 0x7;
2911 cur++;
2912
2913 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002914 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002915 cur += 2;
2916
2917 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002918 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002919 cur += 2;
2920
2921 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002922 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002923 cur += 4;
2924
Harald Weltea780a3d2010-07-30 22:34:42 +02002925#if 0
2926 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002927 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002928#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002929 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002930 cur++;
2931
Harald Welteb40a38f2009-11-13 11:56:05 +01002932 ipac_parse_cgi(&binf->cgi, cur);
2933 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002934
2935 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2936 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2937 cur += sizeof(binf->ba_list_si2);
2938 }
2939
2940 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2941 memcpy(binf->ba_list_si2bis, cur,
2942 sizeof(binf->ba_list_si2bis));
2943 cur += sizeof(binf->ba_list_si2bis);
2944 }
2945
2946 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2947 memcpy(binf->ba_list_si2ter, cur,
2948 sizeof(binf->ba_list_si2ter));
2949 cur += sizeof(binf->ba_list_si2ter);
2950 }
2951
2952 return 0;
2953}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002954
2955void abis_nm_clear_queue(struct gsm_bts *bts)
2956{
2957 struct msgb *msg;
2958
2959 while (!llist_empty(&bts->abis_queue)) {
2960 msg = msgb_dequeue(&bts->abis_queue);
2961 msgb_free(msg);
2962 }
2963
2964 bts->abis_nm_pend = 0;
2965}