blob: ea94d3766fb5758a92bba8a211ecc7ac304b2a1a [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
Neels Hofmeyrbf709922018-05-03 16:11:28 +0200681static int abis_nm_rx_opstart_ack(struct msgb *mb)
682{
683 struct abis_om_fom_hdr *foh = msgb_l3(mb);
684 DEBUGPFOH(DNM, foh, "Opstart ACK\n");
685 osmo_signal_dispatch(SS_NM, S_NM_OPSTART_ACK, foh);
686 return 0;
687}
688
Maxaa954cd2017-11-29 12:18:02 +0100689bool all_trx_rsl_connected_unlocked(const struct gsm_bts *bts)
Max3d049d22017-10-09 17:12:53 +0200690{
691 const struct gsm_bts_trx *trx;
692
Maxaa954cd2017-11-29 12:18:02 +0100693 if (bts->mo.nm_state.administrative == NM_STATE_LOCKED)
694 return false;
695
Max115e2672017-11-29 13:21:58 +0100696 if (bts->gprs.mode != BTS_GPRS_NONE) {
697 if (bts->gprs.cell.mo.nm_state.administrative == NM_STATE_LOCKED)
698 return false;
699
700 if (bts->gprs.nse.mo.nm_state.administrative == NM_STATE_LOCKED)
701 return false;
702
703 if (bts->gprs.nsvc[0].mo.nm_state.administrative == NM_STATE_LOCKED &&
704 bts->gprs.nsvc[1].mo.nm_state.administrative == NM_STATE_LOCKED)
705 return false;
706 }
707
Max3d049d22017-10-09 17:12:53 +0200708 llist_for_each_entry(trx, &bts->trx_list, list) {
709 if (!trx->rsl_link)
710 return false;
Max115e2672017-11-29 13:21:58 +0100711
712 if (!trx_is_usable(trx))
713 return false;
714
Maxaa954cd2017-11-29 12:18:02 +0100715 if (trx->mo.nm_state.administrative == NM_STATE_LOCKED)
716 return false;
Max3d049d22017-10-09 17:12:53 +0200717 }
718
719 return true;
720}
721
Max3d049d22017-10-09 17:12:53 +0200722char *get_model_oml_status(const struct gsm_bts *bts)
723{
724 if (bts->model->oml_status)
725 return bts->model->oml_status(bts);
726
727 return "unknown";
728}
729
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200730void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100731{
732 int wait = 0;
733 struct msgb *msg;
734 /* the queue is empty */
735 while (!llist_empty(&bts->abis_queue)) {
736 msg = msgb_dequeue(&bts->abis_queue);
737 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200738 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100739
740 if (wait)
741 break;
742 }
743
744 bts->abis_nm_pend = wait;
745}
746
Harald Welte52b1f982008-12-23 20:25:15 +0000747/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000748static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000749{
Harald Welte6c96ba52009-05-01 13:03:40 +0000750 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000751 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200752 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200753 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100754 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
755 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100756 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000757
758 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000759 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100760 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000761
Harald Welte15c61722011-05-22 22:45:37 +0200762 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000763 return abis_nm_rcvmsg_sw(mb);
764
Harald Welte15c61722011-05-22 22:45:37 +0200765 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800766 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000767 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200768
Harald Weltefe00eda2018-03-17 10:30:33 +0100769 LOGPFOH(DNM, LOGL_NOTICE, foh, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000770
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100771 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000772 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200773 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200774 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000775 else
776 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200777
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800778 nack_data.msg = mb;
779 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100780 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200781 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100782 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200783 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000784 }
Harald Weltead384642008-12-26 10:20:07 +0000785#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000786 /* check if last message is to be acked */
787 if (is_ack_nack(nmh->last_msgtype)) {
788 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100789 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000790 /* we got our ACK, continue sending the next msg */
791 } else if (mt == MT_NACK(nmh->last_msgtype)) {
792 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100793 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000794 /* FIXME: somehow signal this to the caller */
795 } else {
796 /* really strange things happen */
797 return -EINVAL;
798 }
799 }
Harald Weltead384642008-12-26 10:20:07 +0000800#endif
801
Harald Welte97ed1e72009-02-06 13:38:02 +0000802 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000803 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100804 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000805 break;
Harald Welte34a99682009-02-13 02:41:40 +0000806 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100807 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000808 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000809 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100810 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000811 break;
Max689e7e52017-04-04 19:21:24 +0200812 case NM_MT_OPSTART_ACK:
Neels Hofmeyrbf709922018-05-03 16:11:28 +0200813 abis_nm_rx_opstart_ack(mb);
Max689e7e52017-04-04 19:21:24 +0200814 break;
815 case NM_MT_SET_CHAN_ATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100816 DEBUGPFOH(DNM, foh, "Set Channel Attributes ACK\n");
Max689e7e52017-04-04 19:21:24 +0200817 break;
818 case NM_MT_SET_RADIO_ATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100819 DEBUGPFOH(DNM, foh, "Set Radio Carrier Attributes ACK\n");
Max689e7e52017-04-04 19:21:24 +0200820 break;
Harald Welte1989c082009-08-06 17:58:31 +0200821 case NM_MT_CONN_MDROP_LINK_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100822 DEBUGPFOH(DNM, foh, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200823 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100824 case NM_MT_IPACC_RESTART_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100825 DEBUGPFOH(DNM, foh, "IPA Restart ACK\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200826 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100827 break;
828 case NM_MT_IPACC_RESTART_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100829 LOGPFOH(DNM, LOGL_NOTICE, foh, "IPA Restart NACK\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200830 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100831 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100832 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +0100833 DEBUGPFOH(DNM, foh, "Set BTS Attribute ACK\n");
Harald Weltefd355a32011-03-04 13:41:31 +0100834 break;
Maxdefb6c92017-05-15 10:29:54 +0200835 case NM_MT_GET_ATTR_RESP:
Max33e13572017-05-29 11:48:29 +0200836 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Maxdefb6c92017-05-15 10:29:54 +0200837 break;
Max689e7e52017-04-04 19:21:24 +0200838 default:
Harald Weltefe00eda2018-03-17 10:30:33 +0100839 LOGPFOH(DNM, LOGL_ERROR, foh, "Unhandled message %s\n",
840 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000841 }
842
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100843 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100844 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000845}
846
Harald Welte677c21f2009-02-17 13:22:23 +0000847static int abis_nm_rx_ipacc(struct msgb *mb);
848
849static int abis_nm_rcvmsg_manuf(struct msgb *mb)
850{
851 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200852 struct e1inp_sign_link *sign_link = mb->dst;
853 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000854
855 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100856 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100857 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000858 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200859 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000860 break;
861 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100862 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
863 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000864 rc = 0;
865 break;
866 }
867
868 return rc;
869}
870
Harald Welte52b1f982008-12-23 20:25:15 +0000871/* High-Level API */
872/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000873int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000874{
Harald Welte52b1f982008-12-23 20:25:15 +0000875 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000876 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000877
878 /* Various consistency checks */
879 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100880 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000881 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200882 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
883 rc = -EINVAL;
884 goto err;
885 }
Harald Welte52b1f982008-12-23 20:25:15 +0000886 }
887 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100888 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000889 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200890 rc = -EINVAL;
891 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000892 }
Harald Welte702d8702008-12-26 20:25:35 +0000893#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200894 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000895 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000896 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100897 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000898 oh->length + sizeof(*oh), l2_len);
899 return -EINVAL;
900 }
Harald Welte702d8702008-12-26 20:25:35 +0000901 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100902 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 +0000903#endif
Harald Weltead384642008-12-26 10:20:07 +0000904 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000905
906 switch (oh->mdisc) {
907 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000908 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000909 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000910 case ABIS_OM_MDISC_MANUF:
911 rc = abis_nm_rcvmsg_manuf(msg);
912 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000913 case ABIS_OM_MDISC_MMI:
914 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100915 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000916 oh->mdisc);
917 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000918 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100919 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000920 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200921 rc = -EINVAL;
922 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000923 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200924err:
Harald Weltead384642008-12-26 10:20:07 +0000925 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000926 return rc;
927}
928
929#if 0
930/* initialized all resources */
931struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
932{
933 struct abis_nm_h *nmh;
934
935 nmh = malloc(sizeof(*nmh));
936 if (!nmh)
937 return NULL;
938
939 nmh->cfg = cfg;
940
941 return nmh;
942}
943
944/* free all resources */
945void abis_nm_fini(struct abis_nm_h *nmh)
946{
947 free(nmh);
948}
949#endif
950
951/* Here we are trying to define a high-level API that can be used by
952 * the actual BSC implementation. However, the architecture is currently
953 * still under design. Ideally the calls to this API would be synchronous,
954 * while the underlying stack behind the APi runs in a traditional select
955 * based state machine.
956 */
957
Harald Welte4724f992009-01-18 18:01:49 +0000958/* 6.2 Software Load: */
959enum sw_state {
960 SW_STATE_NONE,
961 SW_STATE_WAIT_INITACK,
962 SW_STATE_WAIT_SEGACK,
963 SW_STATE_WAIT_ENDACK,
964 SW_STATE_WAIT_ACTACK,
965 SW_STATE_ERROR,
966};
Harald Welte52b1f982008-12-23 20:25:15 +0000967
Harald Welte52b1f982008-12-23 20:25:15 +0000968struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000969 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800970 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000971 gsm_cbfn *cbfn;
972 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000973 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000974
Harald Welte52b1f982008-12-23 20:25:15 +0000975 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200976 uint8_t obj_class;
977 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000978
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200979 uint8_t file_id[255];
980 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000981
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200982 uint8_t file_version[255];
983 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000984
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200985 uint8_t window_size;
986 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000987
988 int fd;
989 FILE *stream;
990 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000991 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000992};
993
Harald Welte4724f992009-01-18 18:01:49 +0000994static struct abis_nm_sw g_sw;
995
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100996static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
997{
998 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
999 msgb_v_put(msg, NM_ATT_SW_DESCR);
1000 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1001 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1002 sw->file_version);
1003 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1004 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1005 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1006 sw->file_version);
1007 } else {
1008 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1009 }
1010}
1011
Harald Welte4724f992009-01-18 18:01:49 +00001012/* 6.2.1 / 8.3.1: Load Data Initiate */
1013static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001014{
Harald Welte4724f992009-01-18 18:01:49 +00001015 struct abis_om_hdr *oh;
1016 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001017 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001018
1019 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1020 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1021 sw->obj_instance[0], sw->obj_instance[1],
1022 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001023
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001024 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001025 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1026
1027 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001028}
1029
Harald Welte1602ade2009-01-29 21:12:39 +00001030static int is_last_line(FILE *stream)
1031{
1032 char next_seg_buf[256];
1033 long pos;
1034
1035 /* check if we're sending the last line */
1036 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +02001037
1038 /* Did ftell fail? Then we are at the end for sure */
1039 if (pos < 0)
1040 return 1;
1041
Harald Welte1602ade2009-01-29 21:12:39 +00001042 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +01001043 int rc = fseek(stream, pos, SEEK_SET);
1044 if (rc < 0)
1045 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001046 return 1;
1047 }
1048
1049 fseek(stream, pos, SEEK_SET);
1050 return 0;
1051}
1052
Harald Welte4724f992009-01-18 18:01:49 +00001053/* 6.2.2 / 8.3.2 Load Data Segment */
1054static int sw_load_segment(struct abis_nm_sw *sw)
1055{
1056 struct abis_om_hdr *oh;
1057 struct msgb *msg = nm_msgb_alloc();
1058 char seg_buf[256];
1059 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001060 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +02001061 int len;
Harald Welte4724f992009-01-18 18:01:49 +00001062
1063 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001064
1065 switch (sw->bts->type) {
1066 case GSM_BTS_TYPE_BS11:
1067 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1068 perror("fgets reading segment");
1069 return -EINVAL;
1070 }
1071 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001072
1073 /* check if we're sending the last line */
1074 sw->last_seg = is_last_line(sw->stream);
1075 if (sw->last_seg)
1076 seg_buf[1] = 0;
1077 else
1078 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001079
1080 len = strlen(line_buf) + 2;
1081 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001082 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001083 /* BS11 wants CR + LF in excess of the TLV length !?! */
1084 tlv[1] -= 2;
1085
1086 /* we only now know the exact length for the OM hdr */
1087 len = strlen(line_buf)+2;
1088 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001089 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001090 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001091 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1092 if (len < 0) {
1093 perror("read failed");
1094 return -EINVAL;
1095 }
1096
1097 if (len != IPACC_SEGMENT_SIZE)
1098 sw->last_seg = 1;
1099
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001100 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001101 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001102 len += 3;
1103 break;
1104 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001105 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001106 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001107 /* FIXME: Other BTS types */
1108 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001109 }
Harald Welte4724f992009-01-18 18:01:49 +00001110
Harald Welte4724f992009-01-18 18:01:49 +00001111 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1112 sw->obj_instance[0], sw->obj_instance[1],
1113 sw->obj_instance[2]);
1114
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001115 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001116}
1117
1118/* 6.2.4 / 8.3.4 Load Data End */
1119static int sw_load_end(struct abis_nm_sw *sw)
1120{
1121 struct abis_om_hdr *oh;
1122 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001123 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001124
1125 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1126 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1127 sw->obj_instance[0], sw->obj_instance[1],
1128 sw->obj_instance[2]);
1129
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001130 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001131 return abis_nm_sendmsg(sw->bts, msg);
1132}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001133
Harald Welte52b1f982008-12-23 20:25:15 +00001134/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001135static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001136{
Harald Welte4724f992009-01-18 18:01:49 +00001137 struct abis_om_hdr *oh;
1138 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001139 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001140
Harald Welte4724f992009-01-18 18:01:49 +00001141 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1142 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1143 sw->obj_instance[0], sw->obj_instance[1],
1144 sw->obj_instance[2]);
1145
1146 /* FIXME: this is BS11 specific format */
1147 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1148 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1149 sw->file_version);
1150
1151 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001152}
Harald Welte4724f992009-01-18 18:01:49 +00001153
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001154struct sdp_firmware {
1155 char magic[4];
1156 char more_magic[4];
1157 unsigned int header_length;
1158 unsigned int file_length;
1159} __attribute__ ((packed));
1160
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001161static int parse_sdp_header(struct abis_nm_sw *sw)
1162{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001163 struct sdp_firmware firmware_header;
1164 int rc;
1165 struct stat stat;
1166
1167 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1168 if (rc != sizeof(firmware_header)) {
1169 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1170 return -1;
1171 }
1172
1173 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1174 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1175 return -1;
1176 }
1177
1178 if (firmware_header.more_magic[0] != 0x10 ||
1179 firmware_header.more_magic[1] != 0x02 ||
1180 firmware_header.more_magic[2] != 0x00 ||
1181 firmware_header.more_magic[3] != 0x00) {
1182 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1183 return -1;
1184 }
1185
1186
1187 if (fstat(sw->fd, &stat) == -1) {
1188 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1189 return -1;
1190 }
1191
1192 if (ntohl(firmware_header.file_length) != stat.st_size) {
1193 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1194 return -1;
1195 }
1196
1197 /* go back to the start as we checked the whole filesize.. */
1198 lseek(sw->fd, 0l, SEEK_SET);
1199 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1200 "There might be checksums in the file that are not\n"
1201 "verified and incomplete firmware might be flashed.\n"
1202 "There is absolutely no WARRANTY that flashing will\n"
1203 "work.\n");
1204 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001205}
1206
Harald Welte4724f992009-01-18 18:01:49 +00001207static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1208{
1209 char file_id[12+1];
1210 char file_version[80+1];
1211 int rc;
1212
1213 sw->fd = open(fname, O_RDONLY);
1214 if (sw->fd < 0)
1215 return sw->fd;
1216
1217 switch (sw->bts->type) {
1218 case GSM_BTS_TYPE_BS11:
1219 sw->stream = fdopen(sw->fd, "r");
1220 if (!sw->stream) {
1221 perror("fdopen");
1222 return -1;
1223 }
1224 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001225 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001226 file_id, file_version);
1227 if (rc != 2) {
1228 perror("parsing header line of software file");
1229 return -1;
1230 }
1231 strcpy((char *)sw->file_id, file_id);
1232 sw->file_id_len = strlen(file_id);
1233 strcpy((char *)sw->file_version, file_version);
1234 sw->file_version_len = strlen(file_version);
1235 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001236 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001237 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001238 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001239 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001240 rc = parse_sdp_header(sw);
1241 if (rc < 0) {
1242 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1243 return -1;
1244 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001245
1246 strcpy((char *)sw->file_id, "id");
1247 sw->file_id_len = 3;
1248 strcpy((char *)sw->file_version, "version");
1249 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001250 break;
Harald Welte4724f992009-01-18 18:01:49 +00001251 default:
1252 /* We don't know how to treat them yet */
1253 close(sw->fd);
1254 return -EINVAL;
1255 }
1256
1257 return 0;
1258}
1259
1260static void sw_close_file(struct abis_nm_sw *sw)
1261{
1262 switch (sw->bts->type) {
1263 case GSM_BTS_TYPE_BS11:
1264 fclose(sw->stream);
1265 break;
1266 default:
1267 close(sw->fd);
1268 break;
1269 }
1270}
1271
1272/* Fill the window */
1273static int sw_fill_window(struct abis_nm_sw *sw)
1274{
1275 int rc;
1276
1277 while (sw->seg_in_window < sw->window_size) {
1278 rc = sw_load_segment(sw);
1279 if (rc < 0)
1280 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001281 if (sw->last_seg)
1282 break;
Harald Welte4724f992009-01-18 18:01:49 +00001283 }
1284 return 0;
1285}
1286
1287/* callback function from abis_nm_rcvmsg() handler */
1288static int abis_nm_rcvmsg_sw(struct msgb *mb)
1289{
1290 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001291 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001292 int rc = -1;
1293 struct abis_nm_sw *sw = &g_sw;
1294 enum sw_state old_state = sw->state;
1295
Harald Welte3ffd1372009-02-01 22:15:49 +00001296 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001297
1298 switch (sw->state) {
1299 case SW_STATE_WAIT_INITACK:
1300 switch (foh->msg_type) {
1301 case NM_MT_LOAD_INIT_ACK:
1302 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001303 if (sw->cbfn)
1304 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1305 NM_MT_LOAD_INIT_ACK, mb,
1306 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001307 rc = sw_fill_window(sw);
1308 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001309 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001310 break;
1311 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001312 if (sw->forced) {
Harald Weltefe00eda2018-03-17 10:30:33 +01001313 DEBUGPFOH(DNM, foh, "FORCED: Ignoring Software Load Init NACK\n");
Harald Welte3ffd1372009-02-01 22:15:49 +00001314 if (sw->cbfn)
1315 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1316 NM_MT_LOAD_INIT_ACK, mb,
1317 sw->cb_data, NULL);
1318 rc = sw_fill_window(sw);
1319 sw->state = SW_STATE_WAIT_SEGACK;
1320 } else {
Harald Weltefe00eda2018-03-17 10:30:33 +01001321 LOGPFOH(DNM, LOGL_NOTICE, foh, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001322 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001323 if (sw->cbfn)
1324 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1325 NM_MT_LOAD_INIT_NACK, mb,
1326 sw->cb_data, NULL);
1327 sw->state = SW_STATE_ERROR;
1328 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001329 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001330 break;
1331 }
1332 break;
1333 case SW_STATE_WAIT_SEGACK:
1334 switch (foh->msg_type) {
1335 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001336 if (sw->cbfn)
1337 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1338 NM_MT_LOAD_SEG_ACK, mb,
1339 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001340 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001341 if (!sw->last_seg) {
1342 /* fill window with more segments */
1343 rc = sw_fill_window(sw);
1344 sw->state = SW_STATE_WAIT_SEGACK;
1345 } else {
1346 /* end the transfer */
1347 sw->state = SW_STATE_WAIT_ENDACK;
1348 rc = sw_load_end(sw);
1349 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001350 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001351 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001352 case NM_MT_LOAD_ABORT:
1353 if (sw->cbfn)
1354 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1355 NM_MT_LOAD_ABORT, mb,
1356 sw->cb_data, NULL);
1357 break;
Harald Welte4724f992009-01-18 18:01:49 +00001358 }
1359 break;
1360 case SW_STATE_WAIT_ENDACK:
1361 switch (foh->msg_type) {
1362 case NM_MT_LOAD_END_ACK:
1363 sw_close_file(sw);
Harald Weltefe00eda2018-03-17 10:30:33 +01001364 DEBUGPFOH(DNM, foh, "Software Load End (BTS %u)\n", sw->bts->nr);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001365 sw->state = SW_STATE_NONE;
1366 if (sw->cbfn)
1367 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1368 NM_MT_LOAD_END_ACK, mb,
1369 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001370 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001371 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001372 break;
1373 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001374 if (sw->forced) {
Harald Weltefe00eda2018-03-17 10:30:33 +01001375 DEBUGPFOH(DNM, foh, "FORCED: Ignoring Software Load End NACK\n");
Holger Freyther31338a12009-02-06 17:43:50 +00001376 sw->state = SW_STATE_NONE;
1377 if (sw->cbfn)
1378 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1379 NM_MT_LOAD_END_ACK, mb,
1380 sw->cb_data, NULL);
1381 } else {
Harald Weltefe00eda2018-03-17 10:30:33 +01001382 LOGPFOH(DNM, LOGL_NOTICE, foh, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001383 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001384 sw->state = SW_STATE_ERROR;
1385 if (sw->cbfn)
1386 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1387 NM_MT_LOAD_END_NACK, mb,
1388 sw->cb_data, NULL);
1389 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001390 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001391 break;
1392 }
1393 case SW_STATE_WAIT_ACTACK:
1394 switch (foh->msg_type) {
1395 case NM_MT_ACTIVATE_SW_ACK:
1396 /* we're done */
Harald Weltefe00eda2018-03-17 10:30:33 +01001397 LOGPFOH(DNM, LOGL_INFO, foh, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001398 sw->state = SW_STATE_NONE;
1399 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001400 if (sw->cbfn)
1401 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1402 NM_MT_ACTIVATE_SW_ACK, mb,
1403 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001404 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001405 break;
1406 case NM_MT_ACTIVATE_SW_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01001407 LOGPFOH(DNM, LOGL_ERROR, foh, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001408 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001409 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001410 if (sw->cbfn)
1411 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1412 NM_MT_ACTIVATE_SW_NACK, mb,
1413 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001414 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001415 break;
1416 }
1417 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001418 switch (foh->msg_type) {
1419 case NM_MT_ACTIVATE_SW_ACK:
1420 rc = 0;
1421 break;
1422 }
1423 break;
Harald Welte4724f992009-01-18 18:01:49 +00001424 case SW_STATE_ERROR:
1425 break;
1426 }
1427
1428 if (rc)
Harald Weltefe00eda2018-03-17 10:30:33 +01001429 LOGPFOH(DNM, LOGL_ERROR, foh, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001430 foh->msg_type, old_state, sw->state);
1431
1432 return rc;
1433}
1434
1435/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001436int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001437 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001438 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001439{
1440 struct abis_nm_sw *sw = &g_sw;
1441 int rc;
1442
Harald Weltefe00eda2018-03-17 10:30:33 +01001443 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n", bts->nr, fname);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001444
Harald Welte4724f992009-01-18 18:01:49 +00001445 if (sw->state != SW_STATE_NONE)
1446 return -EBUSY;
1447
1448 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001449 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001450
1451 switch (bts->type) {
1452 case GSM_BTS_TYPE_BS11:
1453 sw->obj_class = NM_OC_SITE_MANAGER;
1454 sw->obj_instance[0] = 0xff;
1455 sw->obj_instance[1] = 0xff;
1456 sw->obj_instance[2] = 0xff;
1457 break;
1458 case GSM_BTS_TYPE_NANOBTS:
1459 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001460 sw->obj_instance[0] = sw->bts->nr;
1461 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001462 sw->obj_instance[2] = 0xff;
1463 break;
1464 case GSM_BTS_TYPE_UNKNOWN:
1465 default:
1466 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1467 return -1;
1468 break;
1469 }
Harald Welte4724f992009-01-18 18:01:49 +00001470 sw->window_size = win_size;
1471 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001472 sw->cbfn = cbfn;
1473 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001474 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001475
1476 rc = sw_open_file(sw, fname);
1477 if (rc < 0) {
1478 sw->state = SW_STATE_NONE;
1479 return rc;
1480 }
1481
1482 return sw_load_init(sw);
1483}
Harald Welte52b1f982008-12-23 20:25:15 +00001484
Harald Welte1602ade2009-01-29 21:12:39 +00001485int abis_nm_software_load_status(struct gsm_bts *bts)
1486{
1487 struct abis_nm_sw *sw = &g_sw;
1488 struct stat st;
1489 int rc, percent;
1490
1491 rc = fstat(sw->fd, &st);
1492 if (rc < 0) {
1493 perror("ERROR during stat");
1494 return rc;
1495 }
1496
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001497 if (sw->stream)
1498 percent = (ftell(sw->stream) * 100) / st.st_size;
1499 else
1500 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001501 return percent;
1502}
1503
Harald Welte5e4d1b32009-02-01 13:36:56 +00001504/* Activate the specified software into the BTS */
1505int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1506 gsm_cbfn *cbfn, void *cb_data)
1507{
1508 struct abis_nm_sw *sw = &g_sw;
1509 int rc;
1510
Harald Weltefe00eda2018-03-17 10:30:33 +01001511 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n", bts->nr, fname);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001512
1513 if (sw->state != SW_STATE_NONE)
1514 return -EBUSY;
1515
1516 sw->bts = bts;
1517 sw->obj_class = NM_OC_SITE_MANAGER;
1518 sw->obj_instance[0] = 0xff;
1519 sw->obj_instance[1] = 0xff;
1520 sw->obj_instance[2] = 0xff;
1521 sw->state = SW_STATE_WAIT_ACTACK;
1522 sw->cbfn = cbfn;
1523 sw->cb_data = cb_data;
1524
1525 /* Open the file in order to fill some sw struct members */
1526 rc = sw_open_file(sw, fname);
1527 if (rc < 0) {
1528 sw->state = SW_STATE_NONE;
1529 return rc;
1530 }
1531 sw_close_file(sw);
1532
1533 return sw_activate(sw);
1534}
1535
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001536static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1537 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001538{
Harald Welteadaf08b2009-01-18 11:08:10 +00001539 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001540 ch->bts_port = bts_port;
1541 ch->timeslot = ts_nr;
1542 ch->subslot = subslot_nr;
1543}
1544
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001545int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1546 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1547 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001548{
1549 struct abis_om_hdr *oh;
1550 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001551 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001552 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001553
1554 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1555 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1556 bts->bts_nr, trx_nr, 0xff);
1557
Harald Welte8470bf22008-12-25 23:28:35 +00001558 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001559
1560 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1561 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1562
1563 return abis_nm_sendmsg(bts, msg);
1564}
1565
1566/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1567int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001568 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001569{
Harald Welte8470bf22008-12-25 23:28:35 +00001570 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001571 struct abis_om_hdr *oh;
1572 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001573 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001574
1575 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001576 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001577 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1578
1579 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1580 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1581
1582 return abis_nm_sendmsg(bts, msg);
1583}
1584
1585#if 0
1586int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1587 struct abis_nm_abis_channel *chan)
1588{
1589}
1590#endif
1591
1592int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001593 uint8_t e1_port, uint8_t e1_timeslot,
1594 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001595{
1596 struct gsm_bts *bts = ts->trx->bts;
1597 struct abis_om_hdr *oh;
1598 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001599 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001600
1601 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1602 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001603 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001604
1605 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1606 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1607
Harald Weltef325eb42009-02-19 17:07:39 +00001608 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1609 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001610 e1_port, e1_timeslot, e1_subslot);
1611
Harald Welte52b1f982008-12-23 20:25:15 +00001612 return abis_nm_sendmsg(bts, msg);
1613}
1614
1615#if 0
1616int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1617 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001618 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001619{
1620}
1621#endif
1622
Max1ebf23b2017-05-10 12:21:17 +02001623/* 3GPP TS 52.021 § 8.11.1 */
1624int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1625 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001626{
1627 struct abis_om_hdr *oh;
Maxe3dbd5d2017-06-09 17:15:45 +02001628 struct msgb *msg;
1629
1630 if (bts->type != GSM_BTS_TYPE_OSMOBTS) {
1631 LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n",
1632 bts->nr, btstype2str(bts->type));
1633 return -EINVAL;
1634 }
Harald Weltefe568f22012-08-14 19:15:57 +02001635
1636 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1637
Maxe3dbd5d2017-06-09 17:15:45 +02001638 msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001639 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1640 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1641 bts_nr, trx_nr, ts_nr);
1642 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1643
1644 return abis_nm_sendmsg(bts, msg);
1645}
1646
Harald Welte22af0db2009-02-14 15:41:08 +00001647/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001648int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001649{
1650 struct abis_om_hdr *oh;
1651 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001652 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001653
1654 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1655
1656 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001657 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 +00001658 cur = msgb_put(msg, attr_len);
1659 memcpy(cur, attr, attr_len);
1660
1661 return abis_nm_sendmsg(bts, msg);
1662}
1663
1664/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001665int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001666{
1667 struct abis_om_hdr *oh;
1668 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001669 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001670
1671 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1672
1673 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1674 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001675 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001676 cur = msgb_put(msg, attr_len);
1677 memcpy(cur, attr, attr_len);
1678
1679 return abis_nm_sendmsg(trx->bts, msg);
1680}
1681
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001682int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1683{
1684 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1685 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1686}
1687
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001688static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1689 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001690{
1691 int i;
1692
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001693 *reason = "Reason unknown";
1694
Harald Welte39c7deb2009-08-09 21:49:48 +02001695 /* As it turns out, the BS-11 has some very peculiar restrictions
1696 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301697 switch (ts->trx->bts->type) {
1698 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001699 switch (chan_comb) {
1700 case NM_CHANC_TCHHalf:
1701 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001702 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001703 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001704 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001705 return -EINVAL;
1706 case NM_CHANC_SDCCH:
1707 /* only one SDCCH/8 per TRX */
1708 for (i = 0; i < TRX_NR_TS; i++) {
1709 if (i == ts->nr)
1710 continue;
1711 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001712 NM_CHANC_SDCCH) {
1713 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001714 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001715 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001716 }
1717 /* not allowed for TS0 of BCCH-TRX */
1718 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001719 ts->nr == 0) {
1720 *reason = "SDCCH/8 must be on TS0.";
1721 return -EINVAL;
1722 }
1723
Harald Welte39c7deb2009-08-09 21:49:48 +02001724 /* not on the same TRX that has a BCCH+SDCCH4
1725 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001726 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001727 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001728 ts->trx->ts[0].nm_chan_comb == 8)) {
1729 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1730 return -EINVAL;
1731 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001732 break;
1733 case NM_CHANC_mainBCCH:
1734 case NM_CHANC_BCCHComb:
1735 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001736 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1737 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001738 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001739 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001740 break;
1741 case NM_CHANC_BCCH:
1742 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001743 if (ts->trx != ts->trx->bts->c0) {
1744 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001745 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001746 }
1747 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1748 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001749 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001750 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001751 break;
1752 case 8: /* this is not like 08.58, but in fact
1753 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1754 /* FIXME: only one CBCH allowed per cell */
1755 break;
1756 }
Harald Welted6575f92009-12-02 02:45:23 +05301757 break;
1758 case GSM_BTS_TYPE_NANOBTS:
1759 switch (ts->nr) {
1760 case 0:
1761 if (ts->trx->nr == 0) {
1762 /* only on TRX0 */
1763 switch (chan_comb) {
1764 case NM_CHANC_BCCH:
1765 case NM_CHANC_mainBCCH:
1766 case NM_CHANC_BCCHComb:
1767 return 0;
1768 break;
1769 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001770 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301771 return -EINVAL;
1772 }
1773 } else {
1774 switch (chan_comb) {
1775 case NM_CHANC_TCHFull:
1776 case NM_CHANC_TCHHalf:
1777 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1778 return 0;
1779 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001780 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301781 return -EINVAL;
1782 }
1783 }
1784 break;
1785 case 1:
1786 if (ts->trx->nr == 0) {
1787 switch (chan_comb) {
1788 case NM_CHANC_SDCCH_CBCH:
1789 if (ts->trx->ts[0].nm_chan_comb ==
1790 NM_CHANC_mainBCCH)
1791 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001792 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301793 return -EINVAL;
1794 case NM_CHANC_SDCCH:
1795 case NM_CHANC_TCHFull:
1796 case NM_CHANC_TCHHalf:
1797 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1798 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001799 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301800 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001801 default:
1802 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1803 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301804 }
1805 } else {
1806 switch (chan_comb) {
1807 case NM_CHANC_SDCCH:
1808 case NM_CHANC_TCHFull:
1809 case NM_CHANC_TCHHalf:
1810 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1811 return 0;
1812 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001813 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301814 return -EINVAL;
1815 }
1816 }
1817 break;
1818 case 2:
1819 case 3:
1820 case 4:
1821 case 5:
1822 case 6:
1823 case 7:
1824 switch (chan_comb) {
1825 case NM_CHANC_TCHFull:
1826 case NM_CHANC_TCHHalf:
1827 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1828 return 0;
1829 case NM_CHANC_IPAC_PDCH:
1830 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001831 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301832 if (ts->trx->nr == 0)
1833 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001834 else {
1835 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301836 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001837 }
Harald Welted6575f92009-12-02 02:45:23 +05301838 }
1839 break;
1840 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001841 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301842 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001843 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001844 /* no known restrictions */
1845 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301846 default:
1847 /* unknown BTS type */
1848 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001849 }
1850 return 0;
1851}
1852
Harald Welte22af0db2009-02-14 15:41:08 +00001853/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001854int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001855{
1856 struct gsm_bts *bts = ts->trx->bts;
1857 struct abis_om_hdr *oh;
Harald Weltefe00eda2018-03-17 10:30:33 +01001858 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001859 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001860 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001861 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001862 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001863
1864 if (bts->type == GSM_BTS_TYPE_BS11)
1865 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001866
Harald Weltefe00eda2018-03-17 10:30:33 +01001867 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1868 foh = fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR, NM_OC_CHANNEL, bts->bts_nr,
1869 ts->trx->nr, ts->nr);
1870
1871 DEBUGPFOH(DNM, foh, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001872 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001873 msgb_free(msg);
Harald Weltefe00eda2018-03-17 10:30:33 +01001874 LOGPFOH(DNM, LOGL_ERROR, foh, "Invalid Channel Combination %d on %s. Reason: %s\n",
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001875 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001876 return -EINVAL;
1877 }
1878 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001879
Harald Welte52b1f982008-12-23 20:25:15 +00001880 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001881 if (ts->hopping.enabled) {
1882 unsigned int i;
1883 uint8_t *len;
1884
Harald Welte6e0cd042009-09-12 13:05:33 +02001885 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1886 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001887
1888 /* build the ARFCN list */
1889 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1890 len = msgb_put(msg, 1);
1891 *len = 0;
1892 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1893 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1894 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001895 /* At least BS-11 wants a TLV16 here */
1896 if (bts->type == GSM_BTS_TYPE_BS11)
1897 *len += 1;
1898 else
1899 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001900 }
1901 }
Harald Weltee0590df2009-02-15 03:34:15 +00001902 }
Harald Welte1fe24122014-01-19 17:18:21 +01001903 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001904 if (bts->type == GSM_BTS_TYPE_BS11)
1905 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001906
Neels Hofmeyrbf709922018-05-03 16:11:28 +02001907 DEBUGPFOH(DNM, foh, "%s(): sending %s\n", __func__, msgb_hexdump(msg));
Harald Welte52b1f982008-12-23 20:25:15 +00001908 return abis_nm_sendmsg(bts, msg);
1909}
1910
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001911int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1912 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001913{
1914 struct abis_om_hdr *oh;
1915 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001916 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1917 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001918
1919 if (nack) {
1920 len += 2;
1921 msgtype = NM_MT_SW_ACT_REQ_NACK;
1922 }
Harald Welte34a99682009-02-13 02:41:40 +00001923
1924 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001925 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1926
Harald Welte34a99682009-02-13 02:41:40 +00001927 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001928 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001929 memcpy(ptr, attr, att_len);
1930 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001931 if (nack)
1932 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001933
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001934 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001935}
1936
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001937int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001938{
Harald Welte8470bf22008-12-25 23:28:35 +00001939 struct msgb *msg = nm_msgb_alloc();
1940 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001941 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001942
1943 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1944 fill_om_hdr(oh, len);
1945 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001946 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001947
1948 return abis_nm_sendmsg(bts, msg);
1949}
1950
1951/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001952static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001953{
1954 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001955 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001956
1957 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001958 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001959 0xff, 0xff, 0xff);
1960
1961 return abis_nm_sendmsg(bts, msg);
1962}
1963
Harald Welte34a99682009-02-13 02:41:40 +00001964/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001965int 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 +00001966{
1967 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001968 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001969 struct msgb *msg = nm_msgb_alloc();
1970
1971 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001972 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001973
Harald Weltefe00eda2018-03-17 10:30:33 +01001974 DEBUGPFOH(DNM, foh, "Sending OPSTART\n");
Harald Weltea8bd6d42009-10-20 09:56:18 +02001975
Harald Welte34a99682009-02-13 02:41:40 +00001976 return abis_nm_sendmsg(bts, msg);
1977}
1978
1979/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001980int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1981 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001982{
1983 struct abis_om_hdr *oh;
1984 struct msgb *msg = nm_msgb_alloc();
1985
1986 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1987 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1988 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1989
1990 return abis_nm_sendmsg(bts, msg);
1991}
1992
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001993int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1994 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001995{
1996 struct abis_om_hdr *oh;
1997 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001998 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001999
2000 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2001 e1_port0, ts0, e1_port1, ts1);
2002
2003 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2004 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2005 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2006
2007 attr = msgb_put(msg, 3);
2008 attr[0] = NM_ATT_MDROP_LINK;
2009 attr[1] = e1_port0;
2010 attr[2] = ts0;
2011
2012 attr = msgb_put(msg, 3);
2013 attr[0] = NM_ATT_MDROP_NEXT;
2014 attr[1] = e1_port1;
2015 attr[2] = ts1;
2016
2017 return abis_nm_sendmsg(bts, msg);
2018}
Harald Welte34a99682009-02-13 02:41:40 +00002019
Harald Weltec7310382009-08-08 00:02:36 +02002020/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002021int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2022 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2023 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002024{
2025 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002026
Harald Welte15c61722011-05-22 22:45:37 +02002027 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002028
2029 if (!msg)
2030 msg = nm_msgb_alloc();
2031
2032 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2033 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2034 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2035 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002036 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002037
2038 return abis_nm_sendmsg(bts, msg);
2039}
2040
Harald Welte52b1f982008-12-23 20:25:15 +00002041int abis_nm_event_reports(struct gsm_bts *bts, int on)
2042{
2043 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002044 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002045 else
Harald Welte227d4072009-01-03 08:16:25 +00002046 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002047}
2048
Harald Welte47d88ae2009-01-04 12:02:08 +00002049/* Siemens (or BS-11) specific commands */
2050
Harald Welte3ffd1372009-02-01 22:15:49 +00002051int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2052{
2053 if (reconnect == 0)
2054 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2055 else
2056 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2057}
2058
Harald Welteb8427972009-02-05 19:27:17 +00002059int abis_nm_bs11_restart(struct gsm_bts *bts)
2060{
2061 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2062}
2063
2064
Harald Welte268bb402009-02-01 19:11:56 +00002065struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002066 uint16_t year;
2067 uint8_t month;
2068 uint8_t day;
2069 uint8_t hour;
2070 uint8_t min;
2071 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002072} __attribute__((packed));
2073
2074
2075void get_bs11_date_time(struct bs11_date_time *aet)
2076{
2077 time_t t;
2078 struct tm *tm;
2079
2080 t = time(NULL);
2081 tm = localtime(&t);
2082 aet->sec = tm->tm_sec;
2083 aet->min = tm->tm_min;
2084 aet->hour = tm->tm_hour;
2085 aet->day = tm->tm_mday;
2086 aet->month = tm->tm_mon;
2087 aet->year = htons(1900 + tm->tm_year);
2088}
2089
Harald Welte05188ee2009-01-18 11:39:08 +00002090int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002091{
Harald Welte4668fda2009-01-03 08:19:29 +00002092 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002093}
2094
Harald Welte05188ee2009-01-18 11:39:08 +00002095int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002096{
2097 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002098 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002099 else
Harald Welte4668fda2009-01-03 08:19:29 +00002100 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002101}
Harald Welte47d88ae2009-01-04 12:02:08 +00002102
Harald Welte05188ee2009-01-18 11:39:08 +00002103int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002104 enum abis_bs11_objtype type, uint8_t idx,
2105 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002106{
2107 struct abis_om_hdr *oh;
2108 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002109 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002110
2111 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002112 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002113 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002114 cur = msgb_put(msg, attr_len);
2115 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002116
2117 return abis_nm_sendmsg(bts, msg);
2118}
2119
Harald Welte78fc0d42009-02-19 02:50:57 +00002120int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002121 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002122{
2123 struct abis_om_hdr *oh;
2124 struct msgb *msg = nm_msgb_alloc();
2125
2126 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2127 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2128 NM_OC_BS11, type, 0, idx);
2129
2130 return abis_nm_sendmsg(bts, msg);
2131}
2132
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002133int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002134{
2135 struct abis_om_hdr *oh;
2136 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002137 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002138
2139 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002140 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002141 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2142 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002143
2144 return abis_nm_sendmsg(bts, msg);
2145}
2146
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002147int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002148{
2149 struct abis_om_hdr *oh;
2150 struct msgb *msg = nm_msgb_alloc();
2151
2152 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2153 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002154 idx, 0xff, 0xff);
2155
2156 return abis_nm_sendmsg(bts, msg);
2157}
2158
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002159int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002160{
2161 struct abis_om_hdr *oh;
2162 struct msgb *msg = nm_msgb_alloc();
2163
2164 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2165 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2166 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002167
2168 return abis_nm_sendmsg(bts, msg);
2169}
Harald Welte05188ee2009-01-18 11:39:08 +00002170
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002171static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002172int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2173{
2174 struct abis_om_hdr *oh;
2175 struct msgb *msg = nm_msgb_alloc();
2176
2177 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2178 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2179 0xff, 0xff, 0xff);
2180 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2181
2182 return abis_nm_sendmsg(bts, msg);
2183}
2184
Harald Welteb6c92ae2009-02-21 20:15:32 +00002185/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002186int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2187 uint8_t e1_timeslot, uint8_t e1_subslot,
2188 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002189{
2190 struct abis_om_hdr *oh;
2191 struct abis_nm_channel *ch;
2192 struct msgb *msg = nm_msgb_alloc();
2193
2194 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002195 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002196 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2197
2198 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2199 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002200 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002201
2202 return abis_nm_sendmsg(bts, msg);
2203}
2204
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002205int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002206{
2207 struct abis_om_hdr *oh;
2208 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002209
2210 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002211 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002212 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2213 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2214
2215 return abis_nm_sendmsg(trx->bts, msg);
2216}
2217
Harald Welte78fc0d42009-02-19 02:50:57 +00002218int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2219{
2220 struct abis_om_hdr *oh;
2221 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002222 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002223
2224 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2225 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2226 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2227 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2228
2229 return abis_nm_sendmsg(trx->bts, msg);
2230}
2231
Harald Welteaaf02d92009-04-29 13:25:57 +00002232int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2233{
2234 struct abis_om_hdr *oh;
2235 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002236 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002237
2238 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2239 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2240 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002241 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002242
2243 return abis_nm_sendmsg(bts, msg);
2244}
2245
Harald Welteef061952009-05-17 12:43:42 +00002246int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2247{
2248 struct abis_om_hdr *oh;
2249 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002250 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002251 NM_ATT_BS11_CCLK_TYPE };
2252
2253 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2254 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2255 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2256 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2257
2258 return abis_nm_sendmsg(bts, msg);
2259
2260}
Harald Welteaaf02d92009-04-29 13:25:57 +00002261
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002262//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002263
Harald Welte1bc09062009-01-18 14:17:52 +00002264int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002265{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002266 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2267}
2268
Daniel Willmann4b054c82010-01-07 00:46:26 +01002269int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2270{
2271 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2272}
2273
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002274int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002275{
Harald Welte05188ee2009-01-18 11:39:08 +00002276 struct abis_om_hdr *oh;
2277 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002278 struct bs11_date_time bdt;
2279
2280 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002281
2282 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002283 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002284 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002285 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002286 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002287 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002288 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002289 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002290 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002291 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002292 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002293 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002294 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002295 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002296 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002297 }
Harald Welte05188ee2009-01-18 11:39:08 +00002298
2299 return abis_nm_sendmsg(bts, msg);
2300}
Harald Welte1bc09062009-01-18 14:17:52 +00002301
2302int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2303{
2304 struct abis_om_hdr *oh;
2305 struct msgb *msg;
2306
2307 if (strlen(password) != 10)
2308 return -EINVAL;
2309
2310 msg = nm_msgb_alloc();
2311 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002312 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002313 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002314 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002315
2316 return abis_nm_sendmsg(bts, msg);
2317}
2318
Harald Weltee69f5fb2009-04-28 16:31:38 +00002319/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2320int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2321{
2322 struct abis_om_hdr *oh;
2323 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002324 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002325
2326 msg = nm_msgb_alloc();
2327 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2328 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2329 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002330
2331 if (locked)
2332 tlv_value = BS11_LI_PLL_LOCKED;
2333 else
2334 tlv_value = BS11_LI_PLL_STANDALONE;
2335
2336 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002337
2338 return abis_nm_sendmsg(bts, msg);
2339}
2340
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002341/* Set the calibration value of the PLL (work value/set value)
2342 * It depends on the login which one is changed */
2343int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2344{
2345 struct abis_om_hdr *oh;
2346 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002347 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002348
2349 msg = nm_msgb_alloc();
2350 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2351 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2352 BS11_OBJ_TRX1, 0x00, 0x00);
2353
2354 tlv_value[0] = value>>8;
2355 tlv_value[1] = value&0xff;
2356
2357 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2358
2359 return abis_nm_sendmsg(bts, msg);
2360}
2361
Harald Welte1bc09062009-01-18 14:17:52 +00002362int abis_nm_bs11_get_state(struct gsm_bts *bts)
2363{
2364 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2365}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002366
2367/* BS11 SWL */
2368
Neels Hofmeyrcc6240a2018-02-13 21:21:42 +01002369void *tall_fle_ctx = NULL;
Harald Welte2cf161b2009-06-20 22:36:41 +02002370
Harald Welte5e4d1b32009-02-01 13:36:56 +00002371struct abis_nm_bs11_sw {
2372 struct gsm_bts *bts;
2373 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002374 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002375 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002376 struct llist_head file_list;
2377 gsm_cbfn *user_cb; /* specified by the user */
2378};
2379static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2380
2381struct file_list_entry {
2382 struct llist_head list;
2383 char fname[PATH_MAX];
2384};
2385
2386struct file_list_entry *fl_dequeue(struct llist_head *queue)
2387{
2388 struct llist_head *lh;
2389
2390 if (llist_empty(queue))
2391 return NULL;
2392
2393 lh = queue->next;
2394 llist_del(lh);
2395
2396 return llist_entry(lh, struct file_list_entry, list);
2397}
2398
2399static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2400{
2401 char linebuf[255];
2402 struct llist_head *lh, *lh2;
2403 FILE *swl;
2404 int rc = 0;
2405
2406 swl = fopen(bs11_sw->swl_fname, "r");
2407 if (!swl)
2408 return -ENODEV;
2409
2410 /* zero the stale file list, if any */
2411 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2412 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002413 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002414 }
2415
2416 while (fgets(linebuf, sizeof(linebuf), swl)) {
2417 char file_id[12+1];
2418 char file_version[80+1];
2419 struct file_list_entry *fle;
2420 static char dir[PATH_MAX];
2421
2422 if (strlen(linebuf) < 4)
2423 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002424
Harald Welte5e4d1b32009-02-01 13:36:56 +00002425 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2426 if (rc < 0) {
2427 perror("ERR parsing SWL file");
2428 rc = -EINVAL;
2429 goto out;
2430 }
2431 if (rc < 2)
2432 continue;
2433
Harald Welte470ec292009-06-26 20:25:23 +02002434 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002435 if (!fle) {
2436 rc = -ENOMEM;
2437 goto out;
2438 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002439
2440 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002441 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002442 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2443 strcat(fle->fname, "/");
2444 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002445
2446 llist_add_tail(&fle->list, &bs11_sw->file_list);
2447 }
2448
2449out:
2450 fclose(swl);
2451 return rc;
2452}
2453
2454/* bs11 swload specific callback, passed to abis_nm core swload */
2455static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2456 struct msgb *msg, void *data, void *param)
2457{
2458 struct abis_nm_bs11_sw *bs11_sw = data;
2459 struct file_list_entry *fle;
2460 int rc = 0;
2461
Harald Welte5e4d1b32009-02-01 13:36:56 +00002462 switch (event) {
2463 case NM_MT_LOAD_END_ACK:
2464 fle = fl_dequeue(&bs11_sw->file_list);
2465 if (fle) {
2466 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002467 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002468 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002469 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002470 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002471 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002472 } else {
2473 /* activate the SWL */
2474 rc = abis_nm_software_activate(bs11_sw->bts,
2475 bs11_sw->swl_fname,
2476 bs11_swload_cbfn,
2477 bs11_sw);
2478 }
2479 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002480 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002481 case NM_MT_LOAD_END_NACK:
2482 case NM_MT_LOAD_INIT_ACK:
2483 case NM_MT_LOAD_INIT_NACK:
2484 case NM_MT_ACTIVATE_SW_NACK:
2485 case NM_MT_ACTIVATE_SW_ACK:
2486 default:
2487 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002488 if (bs11_sw->user_cb)
2489 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002490 break;
2491 }
2492
2493 return rc;
2494}
2495
2496/* Siemens provides a SWL file that is a mere listing of all the other
2497 * files that are part of a software release. We need to upload first
2498 * the list file, and then each file that is listed in the list file */
2499int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002500 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002501{
2502 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2503 struct file_list_entry *fle;
2504 int rc = 0;
2505
2506 INIT_LLIST_HEAD(&bs11_sw->file_list);
2507 bs11_sw->bts = bts;
2508 bs11_sw->win_size = win_size;
2509 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002510 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002511
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002512 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002513 rc = bs11_read_swl_file(bs11_sw);
2514 if (rc < 0)
2515 return rc;
2516
2517 /* dequeue next item in file list */
2518 fle = fl_dequeue(&bs11_sw->file_list);
2519 if (!fle)
2520 return -EINVAL;
2521
2522 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002523 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002524 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002525 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002526 return rc;
2527}
2528
Harald Welte5083b0b2009-02-02 19:20:52 +00002529#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002530static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002531 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2532 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2533 NM_ATT_BS11_LMT_USER_NAME,
2534
2535 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2536
2537 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2538
2539 NM_ATT_BS11_SW_LOAD_STORED };
2540
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002541static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002542 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2543 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2544 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2545 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002546#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002547
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002548static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002549 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2550 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002551 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002552
2553int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2554{
2555 struct abis_om_hdr *oh;
2556 struct msgb *msg = nm_msgb_alloc();
2557
2558 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2559 /* SiemensHW CCTRL object */
2560 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2561 0x03, 0x00, 0x00);
2562 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2563
2564 return abis_nm_sendmsg(bts, msg);
2565}
Harald Welte268bb402009-02-01 19:11:56 +00002566
2567int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2568{
2569 struct abis_om_hdr *oh;
2570 struct msgb *msg = nm_msgb_alloc();
2571 struct bs11_date_time aet;
2572
2573 get_bs11_date_time(&aet);
2574 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2575 /* SiemensHW CCTRL object */
2576 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2577 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002578 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002579
2580 return abis_nm_sendmsg(bts, msg);
2581}
Harald Welte5c1e4582009-02-15 11:57:29 +00002582
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002583int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002584{
2585 struct abis_om_hdr *oh;
2586 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002587 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002588
2589 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2590 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2591 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2592 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2593
2594 return abis_nm_sendmsg(bts, msg);
2595}
2596
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002597int 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 +02002598{
2599 struct abis_om_hdr *oh;
2600 struct msgb *msg = nm_msgb_alloc();
2601 struct bs11_date_time aet;
2602
2603 get_bs11_date_time(&aet);
2604 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2605 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2606 bport, 0xff, 0x02);
2607 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2608
2609 return abis_nm_sendmsg(bts, msg);
2610}
2611
Harald Welte5c1e4582009-02-15 11:57:29 +00002612/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002613static const char ipaccess_magic[] = "com.ipaccess";
2614
Harald Welte677c21f2009-02-17 13:22:23 +00002615
2616static int abis_nm_rx_ipacc(struct msgb *msg)
2617{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002618 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002619 struct abis_om_hdr *oh = msgb_l2(msg);
2620 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002621 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002622 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002623 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002624 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002625
Harald Weltefe00eda2018-03-17 10:30:33 +01002626 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
2627
Harald Welte677c21f2009-02-17 13:22:23 +00002628 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Weltefe00eda2018-03-17 10:30:33 +01002629 LOGPFOH(DNM, LOGL_ERROR, foh, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002630 return -EINVAL;
2631 }
2632
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002633 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002634
Harald Weltefe00eda2018-03-17 10:30:33 +01002635 DEBUGPFOH(DNM, foh, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002636
Harald Welte677c21f2009-02-17 13:22:23 +00002637 switch (foh->msg_type) {
2638 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002639 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002640 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2641 memcpy(&addr,
2642 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2643
2644 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2645 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002646 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002647 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002648 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002649 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002650 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2651 DEBUGPC(DNM, "STREAM=0x%02x ",
2652 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002653 DEBUGPC(DNM, "\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;
2656 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002657 LOGPFOH(DNM, LOGL_ERROR, foh, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002658 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002659 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002660 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002661 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002662 LOGPC(DNM, LOGL_ERROR, "\n");
Stefan Sperling73acbca2018-02-12 14:28:52 +01002663 osmo_timer_del(&sign_link->trx->rsl_connect_timeout);
Harald Welte677c21f2009-02-17 13:22:23 +00002664 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002665 case NM_MT_IPACC_SET_NVATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002666 DEBUGPFOH(DNM, foh, "SET NVATTR ACK\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002667 /* FIXME: decode and show the actual attributes */
2668 break;
2669 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002670 LOGPFOH(DNM, LOGL_ERROR, foh, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002671 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002672 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002673 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002674 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002675 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002676 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002677 case NM_MT_IPACC_GET_NVATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002678 DEBUGPFOH(DNM, foh, "GET NVATTR ACK\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002679 /* FIXME: decode and show the actual attributes */
2680 break;
2681 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002682 LOGPFOH(DNM, LOGL_ERROR, foh, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002683 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002684 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002685 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002686 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002687 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002688 break;
Harald Welte15c44172009-10-08 20:15:24 +02002689 case NM_MT_IPACC_SET_ATTR_ACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002690 DEBUGPFOH(DNM, foh, "SET ATTR ACK\n");
Harald Welte15c44172009-10-08 20:15:24 +02002691 break;
2692 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Weltefe00eda2018-03-17 10:30:33 +01002693 LOGPFOH(DNM, LOGL_ERROR, foh, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002694 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002695 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002696 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002697 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002698 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002699 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002700 default:
2701 DEBUGPC(DNM, "unknown\n");
2702 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002703 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002704
2705 /* signal handling */
2706 switch (foh->msg_type) {
2707 case NM_MT_IPACC_RSL_CONNECT_NACK:
2708 case NM_MT_IPACC_SET_NVATTR_NACK:
2709 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002710 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 +01002711 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002712 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002713 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002714 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002715 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 +01002716 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002717 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002718 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002719 default:
2720 break;
2721 }
2722
Harald Welte677c21f2009-02-17 13:22:23 +00002723 return 0;
2724}
2725
Harald Welte193fefc2009-04-30 15:16:27 +00002726/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002727int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2728 uint8_t obj_class, uint8_t bts_nr,
2729 uint8_t trx_nr, uint8_t ts_nr,
2730 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002731{
2732 struct msgb *msg = nm_msgb_alloc();
2733 struct abis_om_hdr *oh;
2734 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002735 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002736
2737 /* construct the 12.21 OM header, observe the erroneous length */
2738 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2739 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2740 oh->mdisc = ABIS_OM_MDISC_MANUF;
2741
2742 /* add the ip.access magic */
2743 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2744 *data++ = sizeof(ipaccess_magic);
2745 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2746
2747 /* fill the 12.21 FOM header */
2748 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2749 foh->msg_type = msg_type;
2750 foh->obj_class = obj_class;
2751 foh->obj_inst.bts_nr = bts_nr;
2752 foh->obj_inst.trx_nr = trx_nr;
2753 foh->obj_inst.ts_nr = ts_nr;
2754
2755 if (attr && attr_len) {
2756 data = msgb_put(msg, attr_len);
2757 memcpy(data, attr, attr_len);
2758 }
2759
2760 return abis_nm_sendmsg(bts, msg);
2761}
Harald Welte677c21f2009-02-17 13:22:23 +00002762
Harald Welte193fefc2009-04-30 15:16:27 +00002763/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002764int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002765 int attr_len)
2766{
Harald Welte2ef156d2010-01-07 20:39:42 +01002767 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2768 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002769 attr_len);
2770}
2771
Stefan Sperling73acbca2018-02-12 14:28:52 +01002772static void rsl_connect_timeout(void *data)
2773{
2774 struct gsm_bts_trx *trx = data;
2775 struct ipacc_ack_signal_data signal;
2776
2777 LOGP(DRSL, LOGL_NOTICE, "(bts=%d,trx=%d) RSL connection request timed out\n", trx->bts->nr, trx->nr);
2778
2779 /* Fake an RSL CONECT NACK message from the BTS. */
2780 signal.trx = trx;
2781 signal.msg_type = NM_MT_IPACC_RSL_CONNECT_NACK;
2782 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
2783}
2784
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002785int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002786 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002787{
2788 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002789 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002790 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2791 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2792
2793 int attr_len = sizeof(attr);
Stefan Sperling73acbca2018-02-12 14:28:52 +01002794 int error;
2795
2796 osmo_timer_setup(&trx->rsl_connect_timeout, rsl_connect_timeout, trx);
Harald Welte746d6092009-10-19 22:11:11 +02002797
2798 ia.s_addr = htonl(ip);
2799 attr[1] = stream;
2800 attr[3] = port >> 8;
2801 attr[4] = port & 0xff;
Stefan Sperling5de80ca2018-05-22 12:17:20 +02002802 memcpy(attr + 6, &ia.s_addr, sizeof(uint32_t));
Harald Welte746d6092009-10-19 22:11:11 +02002803
2804 /* if ip == 0, we use the default IP */
2805 if (ip == 0)
2806 attr_len -= 5;
2807
Harald Weltefe00eda2018-03-17 10:30:33 +01002808 LOGP(DNM, LOGL_INFO, "IPA RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002809 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002810
Stefan Sperling73acbca2018-02-12 14:28:52 +01002811 error = abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2812 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2813 trx->nr, 0xff, attr, attr_len);
2814 if (error == 0)
2815 osmo_timer_schedule(&trx->rsl_connect_timeout, 60, 0);
2816
2817 return error;
Harald Welte746d6092009-10-19 22:11:11 +02002818}
2819
Harald Welte193fefc2009-04-30 15:16:27 +00002820/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002821int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002822{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002823 struct abis_om_hdr *oh;
2824 struct msgb *msg = nm_msgb_alloc();
2825
2826 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2827 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2828 trx->bts->nr, trx->nr, 0xff);
2829
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002830 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002831}
Harald Weltedaef5212009-10-24 10:20:41 +02002832
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002833int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2834 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2835 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002836{
2837 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2838 obj_class, bts_nr, trx_nr, ts_nr,
2839 attr, attr_len);
2840}
Harald Welte0f255852009-11-12 14:48:42 +01002841
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002842void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002843{
Neels Hofmeyr4d358c02018-02-22 03:19:05 +01002844 struct gsm48_ra_id *_buf = (struct gsm48_ra_id*)buf;
2845 uint16_t ci = htons(bts->cell_identity);
2846 /* we simply reuse the GSM48 function and write the Cell ID over the position where the RAC
2847 * starts */
2848 gsm48_ra_id_by_bts(_buf, bts);
2849 memcpy(&_buf->rac, &ci, sizeof(ci));
Harald Welte97a282b2010-03-14 15:37:43 +08002850}
2851
Maxbe356ed2017-09-07 19:10:09 +02002852void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason)
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002853{
Maxbe356ed2017-09-07 19:10:09 +02002854 uint8_t new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2855
Stefan Sperlingcda994e2018-04-12 09:18:36 +02002856
2857 if (!trx->bts || !trx->bts->oml_link) {
2858 /* Set initial state which will be sent when BTS connects. */
2859 trx->mo.nm_state.administrative = new_state;
2860 return;
2861 }
2862
2863 LOGP(DNM, LOGL_NOTICE, "(bts=%d,trx=%d) Requesting administrative state change %s -> %s [%s]\n",
2864 trx->bts->nr, trx->nr,
Maxbe356ed2017-09-07 19:10:09 +02002865 get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative),
2866 get_value_string(abis_nm_adm_state_names, new_state), reason);
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002867
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002868 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2869 trx->bts->bts_nr, trx->nr, 0xff,
2870 new_state);
2871}
2872
Harald Welte92b1fe42010-03-25 11:45:30 +08002873static const struct value_string ipacc_testres_names[] = {
2874 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2875 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2876 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2877 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2878 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2879 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002880};
2881
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002882const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002883{
Harald Welte92b1fe42010-03-25 11:45:30 +08002884 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002885}
2886
Neels Hofmeyrda5b09a2018-03-21 16:04:30 +01002887void ipac_parse_cgi(struct osmo_cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002888{
Neels Hofmeyrda5b09a2018-03-21 16:04:30 +01002889 osmo_plmn_from_bcd(buf, &cid->lai.plmn);
2890 cid->lai.lac = ntohs(*((uint16_t *)&buf[3]));
2891 cid->cell_identity = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002892}
2893
Harald Welte0f255852009-11-12 14:48:42 +01002894/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002895int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002896{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002897 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002898 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002899
Harald Welteaf109b92010-07-22 18:14:36 +02002900 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002901
2902 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2903 return -EINVAL;
2904 cur++;
2905
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002906 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002907 cur += 2;
2908
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002909 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002910 cur += 2;
2911
2912 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2913 binf->freq_qual = *cur >> 2;
2914
Harald Welteaf109b92010-07-22 18:14:36 +02002915 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002916 binf->arfcn |= *cur++;
2917
2918 if (binf->info_type & IPAC_BINF_RXLEV)
2919 binf->rx_lev = *cur & 0x3f;
2920 cur++;
2921
2922 if (binf->info_type & IPAC_BINF_RXQUAL)
2923 binf->rx_qual = *cur & 0x7;
2924 cur++;
2925
2926 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002927 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002928 cur += 2;
2929
2930 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002931 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002932 cur += 2;
2933
2934 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002935 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002936 cur += 4;
2937
Harald Weltea780a3d2010-07-30 22:34:42 +02002938#if 0
2939 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002940 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002941#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002942 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002943 cur++;
2944
Harald Welteb40a38f2009-11-13 11:56:05 +01002945 ipac_parse_cgi(&binf->cgi, cur);
2946 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002947
2948 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2949 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2950 cur += sizeof(binf->ba_list_si2);
2951 }
2952
2953 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2954 memcpy(binf->ba_list_si2bis, cur,
2955 sizeof(binf->ba_list_si2bis));
2956 cur += sizeof(binf->ba_list_si2bis);
2957 }
2958
2959 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2960 memcpy(binf->ba_list_si2ter, cur,
2961 sizeof(binf->ba_list_si2ter));
2962 cur += sizeof(binf->ba_list_si2ter);
2963 }
2964
2965 return 0;
2966}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002967
2968void abis_nm_clear_queue(struct gsm_bts *bts)
2969{
2970 struct msgb *msg;
2971
2972 while (!llist_empty(&bts->abis_queue)) {
2973 msg = msgb_dequeue(&bts->abis_queue);
2974 msgb_free(msg);
2975 }
2976
2977 bts->abis_nm_pend = 0;
2978}