blob: 435d00453107b77e22175eeda4e9341d9303a847 [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Neels Hofmeyrc0164792017-09-04 15:15:32 +020037#include <osmocom/bsc/gsm_data.h>
38#include <osmocom/bsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
Maxa5e36932017-01-11 11:51:28 +010040#include <osmocom/gsm/protocol/gsm_12_21.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010041#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020042#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010043#include <osmocom/core/talloc.h>
Neels Hofmeyr93bafb62017-01-13 03:12:08 +010044#include <osmocom/core/utils.h>
Neels Hofmeyrc0164792017-09-04 15:15:32 +020045#include <osmocom/bsc/abis_nm.h>
46#include <osmocom/bsc/misdn.h>
47#include <osmocom/bsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020048#include <osmocom/abis/e1_input.h>
Max115e2672017-11-29 13:21:58 +010049#include <osmocom/bsc/chan_alloc.h>
Harald Welte52b1f982008-12-23 20:25:15 +000050
Harald Welte8470bf22008-12-25 23:28:35 +000051#define OM_ALLOC_SIZE 1024
52#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010053#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000054
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020055int 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 +000056{
Harald Welte39315c42010-01-10 18:01:52 +010057 if (!bts->model)
58 return -EIO;
59 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000060}
Harald Weltee0590df2009-02-15 03:34:15 +000061
Harald Welte52b1f982008-12-23 20:25:15 +000062static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
63{
64 int i;
65
66 for (i = 0; i < size; i++) {
67 if (arr[i] == mt)
68 return 1;
69 }
70
71 return 0;
72}
73
Holger Freytherca362a62009-01-04 21:05:01 +000074#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000075/* is this msgtype the usual ACK/NACK type ? */
76static int is_ack_nack(enum abis_nm_msgtype mt)
77{
78 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
79}
Holger Freytherca362a62009-01-04 21:05:01 +000080#endif
Harald Welte52b1f982008-12-23 20:25:15 +000081
82/* is this msgtype a report ? */
83static int is_report(enum abis_nm_msgtype mt)
84{
Harald Welte15c61722011-05-22 22:45:37 +020085 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000086}
87
88#define MT_ACK(x) (x+1)
89#define MT_NACK(x) (x+2)
90
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020091static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000092{
93 oh->mdisc = ABIS_OM_MDISC_FOM;
94 oh->placement = ABIS_OM_PLACEMENT_ONLY;
95 oh->sequence = 0;
96 oh->length = len;
97}
98
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +020099static 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 +0200100 uint8_t msg_type, uint8_t obj_class,
101 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000102{
103 struct abis_om_fom_hdr *foh =
104 (struct abis_om_fom_hdr *) oh->data;
105
Harald Welte702d8702008-12-26 20:25:35 +0000106 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000107 foh->msg_type = msg_type;
108 foh->obj_class = obj_class;
109 foh->obj_inst.bts_nr = bts_nr;
110 foh->obj_inst.trx_nr = trx_nr;
111 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200112 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000113}
114
Harald Welte8470bf22008-12-25 23:28:35 +0000115static struct msgb *nm_msgb_alloc(void)
116{
Harald Welte966636f2009-06-26 19:39:35 +0200117 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
118 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000119}
120
Harald Welte15eae8d2011-09-26 23:43:23 +0200121int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200122{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200123 msg->l2h = msg->data;
124
125 if (!msg->dst) {
126 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
127 return -EINVAL;
128 }
129
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200130 return abis_sendmsg(msg);
131}
132
Harald Welte52b1f982008-12-23 20:25:15 +0000133/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100134static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000135{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200136 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000137
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100138 /* queue OML messages */
139 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
140 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200141 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100142 } else {
143 msgb_enqueue(&bts->abis_queue, msg);
144 return 0;
145 }
146
147}
148
149int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
150{
151 OBSC_NM_W_ACK_CB(msg) = 1;
152 return abis_nm_queue_msg(bts, msg);
153}
154
155static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
156{
157 OBSC_NM_W_ACK_CB(msg) = 0;
158 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000159}
160
Harald Welte4724f992009-01-18 18:01:49 +0000161static int abis_nm_rcvmsg_sw(struct msgb *mb);
162
Maxd0ff6942017-11-29 12:45:34 +0100163bool nm_is_running(const struct gsm_nm_state *s) {
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100164 return (s->operational == NM_OPSTATE_ENABLED) && (
165 (s->availability == NM_AVSTATE_OK) ||
166 (s->availability == 0xff)
167 );
168}
169
Harald Weltee0590df2009-02-15 03:34:15 +0000170/* Update the administrative state of a given object in our in-memory data
171 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200172static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
173 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000174{
Harald Welteaeedeb42009-05-01 13:08:14 +0000175 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100176 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000177
Harald Welteaf9b8102011-03-06 21:20:38 +0100178 memset(&nsd, 0, sizeof(nsd));
179
Harald Welte978714d2011-06-06 18:31:20 +0200180 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100181 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100182 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200183 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000184 if (!nm_state)
185 return -1;
186
187 new_state = *nm_state;
188 new_state.administrative = adm_state;
189
Harald Weltef38ca9a2011-03-06 22:11:32 +0100190 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100191 nsd.obj_class = obj_class;
192 nsd.old_state = nm_state;
193 nsd.new_state = &new_state;
194 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200195 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000196
197 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000198
Harald Weltef338a032011-01-14 15:55:42 +0100199 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000200}
201
Harald Welte97ed1e72009-02-06 13:38:02 +0000202static int abis_nm_rx_statechg_rep(struct msgb *mb)
203{
Harald Weltee0590df2009-02-15 03:34:15 +0000204 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000205 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200206 struct e1inp_sign_link *sign_link = mb->dst;
207 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000208 struct tlv_parsed tp;
209 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000210
Harald Welte23897662009-05-01 14:52:51 +0000211 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000212
Harald Welte8b697c72009-06-05 19:18:45 +0000213 memset(&new_state, 0, sizeof(new_state));
214
Harald Welte978714d2011-06-06 18:31:20 +0200215 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000216 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100217 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000218 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000219 }
Harald Weltee0590df2009-02-15 03:34:15 +0000220
221 new_state = *nm_state;
222
Harald Welte39315c42010-01-10 18:01:52 +0100223 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000224 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
225 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200226 DEBUGPC(DNM, "OP_STATE=%s ",
227 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000228 }
229 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000230 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
231 new_state.availability = 0xff;
232 else
233 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200234 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
235 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000236 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100237 } else
238 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000239 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
240 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200241 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200242 get_value_string(abis_nm_adm_state_names,
243 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000244 }
245 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000246
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100247 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
248 new_state.operational != nm_state->operational ||
249 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000250 /* Update the operational state of a given object in our in-memory data
251 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100252 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200253 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100254 nsd.obj_class = foh->obj_class;
255 nsd.old_state = nm_state;
256 nsd.new_state = &new_state;
257 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100258 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200259 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100260 nm_state->operational = new_state.operational;
261 nm_state->availability = new_state.availability;
262 if (nm_state->administrative == 0)
263 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000264 }
265#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000266 if (op_state == 1) {
267 /* try to enable objects that are disabled */
268 abis_nm_opstart(bts, foh->obj_class,
269 foh->obj_inst.bts_nr,
270 foh->obj_inst.trx_nr,
271 foh->obj_inst.ts_nr);
272 }
Harald Weltee0590df2009-02-15 03:34:15 +0000273#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000274 return 0;
275}
276
Maxb1e6b372017-03-15 14:30:21 +0100277static inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type,
278 const char *severity, const uint8_t *p_val,
279 const char *text)
280{
281 enum abis_nm_pcause_type pcause = p_val[0];
282 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
283
284 LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr);
285 if (type)
286 LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type);
287 if (severity)
288 LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity);
289
290 LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
291 get_value_string(abis_nm_pcause_type_names, pcause));
292
293 if (pcause == NM_PCAUSE_T_MANUF)
294 LOGPC(DNM, LOGL_ERROR, "%s, ",
295 get_value_string(abis_mm_event_cause_names, cause));
296 else
297 LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
298
299 if (text) {
300 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text);
301 }
302
303 LOGPC(DNM, LOGL_ERROR, "\n");
304}
305
Maxa18001d2017-04-10 16:47:17 +0200306static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type,
Maxb1e6b372017-03-15 14:30:21 +0100307 const char *severity, const char *text)
308{
309 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
310
311 switch (cause) {
312 case OSMO_EVT_PCU_VERS:
Maxa18001d2017-04-10 16:47:17 +0200313 if (text) {
314 LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text);
315 osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version));
316 } else {
317 LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr);
318 bts->pcu_version[0] = '\0';
319 }
Maxb1e6b372017-03-15 14:30:21 +0100320 break;
321 default:
322 log_oml_fail_rep(bts, type, severity, p_val, text);
323 };
324}
325
Maxa18001d2017-04-10 16:47:17 +0200326static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts)
Harald Welte0db97b22009-05-01 17:22:47 +0000327{
328 struct abis_om_hdr *oh = msgb_l2(mb);
329 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200330 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000331 struct tlv_parsed tp;
Maxb1e6b372017-03-15 14:30:21 +0100332 int rc = 0;
333 const uint8_t *p_val = NULL;
334 char *p_text = NULL;
335 const char *e_type = NULL, *severity = NULL;
Harald Welte0db97b22009-05-01 17:22:47 +0000336
Maxb1e6b372017-03-15 14:30:21 +0100337 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
338 oh->length-sizeof(*foh));
Maxa5e36932017-01-11 11:51:28 +0100339
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100340 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
341 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
Maxb1e6b372017-03-15 14:30:21 +0100342 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val,
343 TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100344 }
Harald Welte0db97b22009-05-01 17:22:47 +0000345
Maxb1e6b372017-03-15 14:30:21 +0100346 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
347 e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
348 NM_ATT_EVENT_TYPE));
Harald Welte0db97b22009-05-01 17:22:47 +0000349
Maxb1e6b372017-03-15 14:30:21 +0100350 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
351 severity = abis_nm_severity_name(*TLVP_VAL(&tp,
352 NM_ATT_SEVERITY));
353
354 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
355 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
356
357 switch (p_val[0]) {
358 case NM_PCAUSE_T_MANUF:
359 handle_manufact_report(bts, p_val, e_type, severity,
360 p_text);
361 break;
362 default:
363 log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
364 };
365 } else {
366 LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without "
367 "Probable Cause?!\n", bts->nr);
368 rc = -EINVAL;
369 }
370
371 if (p_text)
372 talloc_free(p_text);
373
374 return rc;
Harald Welte0db97b22009-05-01 17:22:47 +0000375}
376
Maxb1e6b372017-03-15 14:30:21 +0100377static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
Harald Welte97ed1e72009-02-06 13:38:02 +0000378{
379 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200380 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000381
Harald Welte15c61722011-05-22 22:45:37 +0200382 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000383
Harald Welte97ed1e72009-02-06 13:38:02 +0000384 //nmh->cfg->report_cb(mb, foh);
385
386 switch (mt) {
387 case NM_MT_STATECHG_EVENT_REP:
388 return abis_nm_rx_statechg_rep(mb);
389 break;
Harald Welte34a99682009-02-13 02:41:40 +0000390 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000391 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200392 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000393 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000394 case NM_MT_FAILURE_EVENT_REP:
Maxb1e6b372017-03-15 14:30:21 +0100395 rx_fail_evt_rep(mb, bts);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200396 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000397 break;
Harald Weltec7310382009-08-08 00:02:36 +0200398 case NM_MT_TEST_REP:
399 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200400 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200401 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000402 default:
Harald Welte23897662009-05-01 14:52:51 +0000403 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000404 break;
405
Harald Welte97ed1e72009-02-06 13:38:02 +0000406 };
407
Harald Welte97ed1e72009-02-06 13:38:02 +0000408 return 0;
409}
410
Harald Welte34a99682009-02-13 02:41:40 +0000411/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200412static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
Maxfd2c1f92017-03-24 21:04:57 +0100413 uint8_t i2, const struct abis_nm_sw_desc *sw_desc)
Harald Welte34a99682009-02-13 02:41:40 +0000414{
415 struct abis_om_hdr *oh;
416 struct msgb *msg = nm_msgb_alloc();
Maxfd2c1f92017-03-24 21:04:57 +0100417 uint16_t len = abis_nm_sw_desc_len(sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000418
419 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
420 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
Maxfd2c1f92017-03-24 21:04:57 +0100421 abis_nm_put_sw_desc(msg, sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000422
423 return abis_nm_sendmsg(bts, msg);
424}
425
Maxfd2c1f92017-03-24 21:04:57 +0100426int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr,
427 const size_t size)
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100428{
429 int res = 0;
430 int i;
431
432 for (i = 1; i < size; ++i) {
Maxfd2c1f92017-03-24 21:04:57 +0100433 if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version,
434 OSMO_MIN(sw_descr[i].file_version_len,
435 sw_descr[res].file_version_len)) < 0) {
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100436 res = i;
437 }
438 }
439
440 return res;
441}
442
Max33e13572017-05-29 11:48:29 +0200443static 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 +0200444{
445 switch (id) {
446 case BTS_TYPE_VARIANT:
Max33e13572017-05-29 11:48:29 +0200447 LOGP(DNM, LOGL_NOTICE, "BTS%u reported variant: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200448 break;
449 case BTS_SUB_MODEL:
Max33e13572017-05-29 11:48:29 +0200450 LOGP(DNM, LOGL_NOTICE, "BTS%u reported submodel: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200451 break;
452 default:
453 return false;
454 }
455 return true;
456}
457
Max33e13572017-05-29 11:48:29 +0200458/* Parse Attribute Response Info - return pointer to the actual content */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100459static 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 +0200460{
461 uint8_t num_unreported = ari[0], i;
462
463 DEBUGP(DNM, "BTS%u Get Attributes Response Info: %u bytes total with %u unreported attributes\n",
464 bts_nr, ari_len, num_unreported);
465
466 /* +1 because we have to account for number of unreported attributes, prefixing the list: */
467 for (i = 0; i < num_unreported; i++)
468 LOGP(DNM, LOGL_ERROR, "BTS%u Attribute %s is unreported\n",
469 bts_nr, get_value_string(abis_nm_att_names, ari[i + 1]));
470
471 /* the data starts right after the list of unreported attributes + space for length of that list */
472 *out_len = ari_len - (num_unreported + 2);
473
474 return ari + num_unreported + 1; /* we have to account for 1st byte with number of unreported attributes */
475}
476
Maxc51c1e72017-06-06 15:40:40 +0200477/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.30 Manufacturer Id */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100478static 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 +0200479{
480 struct tlv_parsed tp;
481 uint16_t m_id_len = 0;
482 uint8_t adjust = 0, i;
483
484 abis_nm_tlv_parse(&tp, bts, data, *data_len);
485 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_ID, 2)) {
486 m_id_len = TLVP_LEN(&tp, NM_ATT_MANUF_ID);
487
Max5a44d252017-06-13 10:15:58 +0200488 /* log potential BTS feature vector overflow */
489 if (m_id_len > sizeof(bts->_features_data))
Maxc51c1e72017-06-06 15:40:40 +0200490 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: feature vector is truncated to %u bytes\n",
491 bts->nr, MAX_BTS_FEATURES/8);
Maxc51c1e72017-06-06 15:40:40 +0200492
Max5a44d252017-06-13 10:15:58 +0200493 /* check that max. expected BTS attribute is above given feature vector length */
494 if (m_id_len > OSMO_BYTES_FOR_BITS(_NUM_BTS_FEAT))
Maxc51c1e72017-06-06 15:40:40 +0200495 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: reported unexpectedly long (%u bytes) "
496 "feature vector - most likely it was compiled against newer BSC headers. "
497 "Consider upgrading your BSC to later version.\n",
498 bts->nr, m_id_len);
499
Maxa60bb3d2017-06-12 13:45:03 +0200500 memcpy(bts->_features_data, TLVP_VAL(&tp, NM_ATT_MANUF_ID), sizeof(bts->_features_data));
Maxc51c1e72017-06-06 15:40:40 +0200501 adjust = m_id_len + 3; /* adjust for parsed TL16V struct */
502
503 for (i = 0; i < _NUM_BTS_FEAT; i++)
504 if (gsm_bts_has_feature(bts, i) != gsm_btsmodel_has_feature(bts->model, i))
505 LOGP(DNM, LOGL_NOTICE, "BTS%u feature '%s' reported via OML does not match statically "
506 "set feature: %u != %u. Please fix.\n", bts->nr,
507 get_value_string(gsm_bts_features_descs, i),
508 gsm_bts_has_feature(bts, i), gsm_btsmodel_has_feature(bts->model, i));
509 }
510
511 *data_len -= adjust;
512
513 return data + adjust;
514}
515
Max33e13572017-05-29 11:48:29 +0200516/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.28 Manufacturer Dependent State */
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100517static 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 +0200518{
519 struct tlv_parsed tp;
520 const uint8_t *power;
521 uint8_t adjust = 0;
522
523 if (!trx) /* this attribute does not make sense on BTS level, only on TRX level */
524 return data;
525
526 abis_nm_tlv_parse(&tp, trx->bts, data, *data_len);
527 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_STATE, 1)) {
528 power = TLVP_VAL(&tp, NM_ATT_MANUF_STATE);
529 LOGP(DNM, LOGL_NOTICE, "%s Get Attributes Response: nominal power is %u\n", gsm_trx_name(trx), *power);
530 adjust = 2; /* adjust for parsed TV struct */
531 }
532
533 *data_len -= adjust;
534
535 return data + adjust;
536}
537
Maxdefb6c92017-05-15 10:29:54 +0200538/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */
Max33e13572017-05-29 11:48:29 +0200539static int abis_nm_rx_get_attr_resp(struct msgb *mb, const struct gsm_bts_trx *trx)
Maxdefb6c92017-05-15 10:29:54 +0200540{
541 struct abis_om_hdr *oh = msgb_l2(mb);
542 struct abis_om_fom_hdr *foh = msgb_l3(mb);
543 struct e1inp_sign_link *sign_link = mb->dst;
Max33e13572017-05-29 11:48:29 +0200544 struct gsm_bts *bts = trx ? trx->bts : sign_link->trx->bts;
Maxdefb6c92017-05-15 10:29:54 +0200545 struct tlv_parsed tp;
Neels Hofmeyr27cd0fe2017-11-27 22:22:23 +0100546 const uint8_t *data;
547 int i;
Max33e13572017-05-29 11:48:29 +0200548 uint16_t data_len;
Maxdefb6c92017-05-15 10:29:54 +0200549 int rc;
550 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
551
552 abis_nm_debugp_foh(DNM, foh);
553
Max33e13572017-05-29 11:48:29 +0200554 DEBUGPC(DNM, "Get Attributes Response for BTS%u\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200555
Max33e13572017-05-29 11:48:29 +0200556 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
557 if (!TLVP_PRES_LEN(&tp, NM_ATT_GET_ARI, 1)) {
558 LOGP(DNM, LOGL_ERROR, "BTS%u: Get Attributes Response without Response Info?!\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200559 return -EINVAL;
560 }
561
Max33e13572017-05-29 11:48:29 +0200562 data = parse_attr_resp_info_unreported(bts->nr, TLVP_VAL(&tp, NM_ATT_GET_ARI), TLVP_LEN(&tp, NM_ATT_GET_ARI),
563 &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200564
Max33e13572017-05-29 11:48:29 +0200565 data = parse_attr_resp_info_manuf_state(trx, data, &data_len);
Maxc51c1e72017-06-06 15:40:40 +0200566 data = parse_attr_resp_info_manuf_id(bts, data, &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200567
Max33e13572017-05-29 11:48:29 +0200568 /* after parsing manufacturer-specific attributes there's list of replies in form of sw-conf structure: */
569 rc = abis_nm_get_sw_conf(data, data_len, &sw_descr[0], ARRAY_SIZE(sw_descr));
Maxdefb6c92017-05-15 10:29:54 +0200570 if (rc > 0) {
571 for (i = 0; i < rc; i++) {
Max33e13572017-05-29 11:48:29 +0200572 if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id),
573 sw_descr[i].file_version, sw_descr[i].file_version_len))
574 LOGP(DNM, LOGL_NOTICE, "BTS%u: ARI reported sw[%d/%d]: %s is %s\n",
575 bts->nr, i, rc, sw_descr[i].file_id, sw_descr[i].file_version);
Maxdefb6c92017-05-15 10:29:54 +0200576 }
577 } else
Max33e13572017-05-29 11:48:29 +0200578 LOGP(DNM, LOGL_ERROR, "BTS%u: failed to parse SW-Config part of Get Attribute Response Info: %s\n",
579 bts->nr, strerror(-rc));
Maxdefb6c92017-05-15 10:29:54 +0200580
581 return 0;
582}
583
Max1ebf23b2017-05-10 12:21:17 +0200584/* 3GPP TS 52.021 §6.2.5 */
Harald Welte34a99682009-02-13 02:41:40 +0000585static int abis_nm_rx_sw_act_req(struct msgb *mb)
586{
587 struct abis_om_hdr *oh = msgb_l2(mb);
588 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200589 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200590 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200591 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100592 int ret, sw_config_len, len;
Max1ebf23b2017-05-10 12:21:17 +0200593 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
Harald Welte34a99682009-02-13 02:41:40 +0000594
Harald Welte15c61722011-05-22 22:45:37 +0200595 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200596
597 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000598
Harald Welte97a282b2010-03-14 15:37:43 +0800599 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000600
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200601 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000602 foh->obj_inst.bts_nr,
603 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800604 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000605 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100606 if (ret != 0) {
607 LOGP(DNM, LOGL_ERROR,
608 "Sending SW ActReq ACK failed: %d\n", ret);
609 return ret;
610 }
Harald Welte34a99682009-02-13 02:41:40 +0000611
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200612 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200613 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
614 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
615 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100616 LOGP(DNM, LOGL_ERROR,
617 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200618 return -EINVAL;
619 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200620 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200621 }
622
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100623 /* Parse up to two sw descriptions from the data */
Maxfd2c1f92017-03-24 21:04:57 +0100624 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
625 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100626 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100627 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100628 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100629 }
Mike Habena03f9772009-10-01 14:56:13 +0200630
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100631 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
632 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
633
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200634 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000635 foh->obj_inst.bts_nr,
636 foh->obj_inst.trx_nr,
637 foh->obj_inst.ts_nr,
Maxfd2c1f92017-03-24 21:04:57 +0100638 &sw_descr[ret]);
Harald Welte34a99682009-02-13 02:41:40 +0000639}
640
Harald Weltee0590df2009-02-15 03:34:15 +0000641/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
642static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
643{
644 struct abis_om_hdr *oh = msgb_l2(mb);
645 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200646 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000647 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200648 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000649
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200650 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000651 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
652 return -EINVAL;
653
654 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
655
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200656 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000657}
658
Harald Welteee670472009-02-22 21:58:49 +0000659static int abis_nm_rx_lmt_event(struct msgb *mb)
660{
661 struct abis_om_hdr *oh = msgb_l2(mb);
662 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200663 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000664 struct tlv_parsed tp;
665
666 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200667 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000668 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
669 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200670 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000671 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
672 }
673 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
674 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200675 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000676 DEBUGPC(DNM, "Level=%u ", level);
677 }
678 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
679 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
680 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
681 DEBUGPC(DNM, "Username=%s ", name);
682 }
683 DEBUGPC(DNM, "\n");
684 /* FIXME: parse LMT LOGON TIME */
685 return 0;
686}
687
Maxaa954cd2017-11-29 12:18:02 +0100688bool all_trx_rsl_connected_unlocked(const struct gsm_bts *bts)
Max3d049d22017-10-09 17:12:53 +0200689{
690 const struct gsm_bts_trx *trx;
691
Maxaa954cd2017-11-29 12:18:02 +0100692 if (bts->mo.nm_state.administrative == NM_STATE_LOCKED)
693 return false;
694
Max115e2672017-11-29 13:21:58 +0100695 if (bts->gprs.mode != BTS_GPRS_NONE) {
696 if (bts->gprs.cell.mo.nm_state.administrative == NM_STATE_LOCKED)
697 return false;
698
699 if (bts->gprs.nse.mo.nm_state.administrative == NM_STATE_LOCKED)
700 return false;
701
702 if (bts->gprs.nsvc[0].mo.nm_state.administrative == NM_STATE_LOCKED &&
703 bts->gprs.nsvc[1].mo.nm_state.administrative == NM_STATE_LOCKED)
704 return false;
705 }
706
Max3d049d22017-10-09 17:12:53 +0200707 llist_for_each_entry(trx, &bts->trx_list, list) {
708 if (!trx->rsl_link)
709 return false;
Max115e2672017-11-29 13:21:58 +0100710
711 if (!trx_is_usable(trx))
712 return false;
713
Maxaa954cd2017-11-29 12:18:02 +0100714 if (trx->mo.nm_state.administrative == NM_STATE_LOCKED)
715 return false;
Max3d049d22017-10-09 17:12:53 +0200716 }
717
718 return true;
719}
720
Max3d049d22017-10-09 17:12:53 +0200721char *get_model_oml_status(const struct gsm_bts *bts)
722{
723 if (bts->model->oml_status)
724 return bts->model->oml_status(bts);
725
726 return "unknown";
727}
728
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200729void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100730{
731 int wait = 0;
732 struct msgb *msg;
733 /* the queue is empty */
734 while (!llist_empty(&bts->abis_queue)) {
735 msg = msgb_dequeue(&bts->abis_queue);
736 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200737 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100738
739 if (wait)
740 break;
741 }
742
743 bts->abis_nm_pend = wait;
744}
745
Harald Welte52b1f982008-12-23 20:25:15 +0000746/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000747static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000748{
Harald Welte6c96ba52009-05-01 13:03:40 +0000749 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000750 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200751 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200752 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100753 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
754 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100755 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000756
757 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000758 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100759 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000760
Harald Welte15c61722011-05-22 22:45:37 +0200761 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000762 return abis_nm_rcvmsg_sw(mb);
763
Harald Welte15c61722011-05-22 22:45:37 +0200764 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800765 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000766 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200767
Harald Welte15c61722011-05-22 22:45:37 +0200768 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200769
Harald Welte15c61722011-05-22 22:45:37 +0200770 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000771
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100772 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000773 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200774 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200775 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000776 else
777 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200778
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800779 nack_data.msg = mb;
780 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100781 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200782 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100783 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200784 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000785 }
Harald Weltead384642008-12-26 10:20:07 +0000786#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000787 /* check if last message is to be acked */
788 if (is_ack_nack(nmh->last_msgtype)) {
789 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100790 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000791 /* we got our ACK, continue sending the next msg */
792 } else if (mt == MT_NACK(nmh->last_msgtype)) {
793 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100794 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000795 /* FIXME: somehow signal this to the caller */
796 } else {
797 /* really strange things happen */
798 return -EINVAL;
799 }
800 }
Harald Weltead384642008-12-26 10:20:07 +0000801#endif
802
Harald Welte97ed1e72009-02-06 13:38:02 +0000803 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000804 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100805 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000806 break;
Harald Welte34a99682009-02-13 02:41:40 +0000807 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100808 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000809 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000810 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100811 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000812 break;
Max689e7e52017-04-04 19:21:24 +0200813 case NM_MT_OPSTART_ACK:
814 abis_nm_debugp_foh(DNM, foh);
815 DEBUGPC(DNM, "Opstart ACK\n");
816 break;
817 case NM_MT_SET_CHAN_ATTR_ACK:
818 abis_nm_debugp_foh(DNM, foh);
819 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
820 break;
821 case NM_MT_SET_RADIO_ATTR_ACK:
822 abis_nm_debugp_foh(DNM, foh);
823 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
824 break;
Harald Welte1989c082009-08-06 17:58:31 +0200825 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200826 abis_nm_debugp_foh(DNM, foh);
827 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200828 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100829 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200830 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100831 break;
832 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200833 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100834 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100835 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100836 break;
Maxdefb6c92017-05-15 10:29:54 +0200837 case NM_MT_GET_ATTR_RESP:
Max33e13572017-05-29 11:48:29 +0200838 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Maxdefb6c92017-05-15 10:29:54 +0200839 break;
Max689e7e52017-04-04 19:21:24 +0200840 default:
841 abis_nm_debugp_foh(DNM, foh);
842 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
843 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000844 }
845
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100846 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100847 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000848}
849
Harald Welte677c21f2009-02-17 13:22:23 +0000850static int abis_nm_rx_ipacc(struct msgb *mb);
851
852static int abis_nm_rcvmsg_manuf(struct msgb *mb)
853{
854 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200855 struct e1inp_sign_link *sign_link = mb->dst;
856 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000857
858 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100859 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100860 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000861 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200862 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000863 break;
864 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100865 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
866 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000867 rc = 0;
868 break;
869 }
870
871 return rc;
872}
873
Harald Welte52b1f982008-12-23 20:25:15 +0000874/* High-Level API */
875/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000876int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000877{
Harald Welte52b1f982008-12-23 20:25:15 +0000878 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000879 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000880
881 /* Various consistency checks */
882 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100883 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000884 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200885 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
886 rc = -EINVAL;
887 goto err;
888 }
Harald Welte52b1f982008-12-23 20:25:15 +0000889 }
890 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100891 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000892 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200893 rc = -EINVAL;
894 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000895 }
Harald Welte702d8702008-12-26 20:25:35 +0000896#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200897 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000898 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000899 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100900 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000901 oh->length + sizeof(*oh), l2_len);
902 return -EINVAL;
903 }
Harald Welte702d8702008-12-26 20:25:35 +0000904 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100905 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 +0000906#endif
Harald Weltead384642008-12-26 10:20:07 +0000907 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000908
909 switch (oh->mdisc) {
910 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000911 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000912 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000913 case ABIS_OM_MDISC_MANUF:
914 rc = abis_nm_rcvmsg_manuf(msg);
915 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000916 case ABIS_OM_MDISC_MMI:
917 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100918 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000919 oh->mdisc);
920 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000921 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100922 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000923 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200924 rc = -EINVAL;
925 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000926 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200927err:
Harald Weltead384642008-12-26 10:20:07 +0000928 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000929 return rc;
930}
931
932#if 0
933/* initialized all resources */
934struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
935{
936 struct abis_nm_h *nmh;
937
938 nmh = malloc(sizeof(*nmh));
939 if (!nmh)
940 return NULL;
941
942 nmh->cfg = cfg;
943
944 return nmh;
945}
946
947/* free all resources */
948void abis_nm_fini(struct abis_nm_h *nmh)
949{
950 free(nmh);
951}
952#endif
953
954/* Here we are trying to define a high-level API that can be used by
955 * the actual BSC implementation. However, the architecture is currently
956 * still under design. Ideally the calls to this API would be synchronous,
957 * while the underlying stack behind the APi runs in a traditional select
958 * based state machine.
959 */
960
Harald Welte4724f992009-01-18 18:01:49 +0000961/* 6.2 Software Load: */
962enum sw_state {
963 SW_STATE_NONE,
964 SW_STATE_WAIT_INITACK,
965 SW_STATE_WAIT_SEGACK,
966 SW_STATE_WAIT_ENDACK,
967 SW_STATE_WAIT_ACTACK,
968 SW_STATE_ERROR,
969};
Harald Welte52b1f982008-12-23 20:25:15 +0000970
Harald Welte52b1f982008-12-23 20:25:15 +0000971struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000972 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800973 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000974 gsm_cbfn *cbfn;
975 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000976 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000977
Harald Welte52b1f982008-12-23 20:25:15 +0000978 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200979 uint8_t obj_class;
980 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000981
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200982 uint8_t file_id[255];
983 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000984
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200985 uint8_t file_version[255];
986 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000987
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200988 uint8_t window_size;
989 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000990
991 int fd;
992 FILE *stream;
993 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000994 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000995};
996
Harald Welte4724f992009-01-18 18:01:49 +0000997static struct abis_nm_sw g_sw;
998
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100999static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
1000{
1001 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
1002 msgb_v_put(msg, NM_ATT_SW_DESCR);
1003 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1004 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1005 sw->file_version);
1006 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
1007 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1008 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1009 sw->file_version);
1010 } else {
1011 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
1012 }
1013}
1014
Harald Welte4724f992009-01-18 18:01:49 +00001015/* 6.2.1 / 8.3.1: Load Data Initiate */
1016static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001017{
Harald Welte4724f992009-01-18 18:01:49 +00001018 struct abis_om_hdr *oh;
1019 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001020 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001021
1022 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1023 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1024 sw->obj_instance[0], sw->obj_instance[1],
1025 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001026
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001027 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001028 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1029
1030 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001031}
1032
Harald Welte1602ade2009-01-29 21:12:39 +00001033static int is_last_line(FILE *stream)
1034{
1035 char next_seg_buf[256];
1036 long pos;
1037
1038 /* check if we're sending the last line */
1039 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +02001040
1041 /* Did ftell fail? Then we are at the end for sure */
1042 if (pos < 0)
1043 return 1;
1044
Harald Welte1602ade2009-01-29 21:12:39 +00001045 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +01001046 int rc = fseek(stream, pos, SEEK_SET);
1047 if (rc < 0)
1048 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001049 return 1;
1050 }
1051
1052 fseek(stream, pos, SEEK_SET);
1053 return 0;
1054}
1055
Harald Welte4724f992009-01-18 18:01:49 +00001056/* 6.2.2 / 8.3.2 Load Data Segment */
1057static int sw_load_segment(struct abis_nm_sw *sw)
1058{
1059 struct abis_om_hdr *oh;
1060 struct msgb *msg = nm_msgb_alloc();
1061 char seg_buf[256];
1062 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001063 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +02001064 int len;
Harald Welte4724f992009-01-18 18:01:49 +00001065
1066 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001067
1068 switch (sw->bts->type) {
1069 case GSM_BTS_TYPE_BS11:
1070 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1071 perror("fgets reading segment");
1072 return -EINVAL;
1073 }
1074 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001075
1076 /* check if we're sending the last line */
1077 sw->last_seg = is_last_line(sw->stream);
1078 if (sw->last_seg)
1079 seg_buf[1] = 0;
1080 else
1081 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001082
1083 len = strlen(line_buf) + 2;
1084 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001085 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001086 /* BS11 wants CR + LF in excess of the TLV length !?! */
1087 tlv[1] -= 2;
1088
1089 /* we only now know the exact length for the OM hdr */
1090 len = strlen(line_buf)+2;
1091 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001092 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001093 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001094 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1095 if (len < 0) {
1096 perror("read failed");
1097 return -EINVAL;
1098 }
1099
1100 if (len != IPACC_SEGMENT_SIZE)
1101 sw->last_seg = 1;
1102
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001103 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001104 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001105 len += 3;
1106 break;
1107 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001108 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001109 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001110 /* FIXME: Other BTS types */
1111 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001112 }
Harald Welte4724f992009-01-18 18:01:49 +00001113
Harald Welte4724f992009-01-18 18:01:49 +00001114 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1115 sw->obj_instance[0], sw->obj_instance[1],
1116 sw->obj_instance[2]);
1117
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001118 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001119}
1120
1121/* 6.2.4 / 8.3.4 Load Data End */
1122static int sw_load_end(struct abis_nm_sw *sw)
1123{
1124 struct abis_om_hdr *oh;
1125 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001126 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001127
1128 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1129 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1130 sw->obj_instance[0], sw->obj_instance[1],
1131 sw->obj_instance[2]);
1132
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001133 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001134 return abis_nm_sendmsg(sw->bts, msg);
1135}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001136
Harald Welte52b1f982008-12-23 20:25:15 +00001137/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001138static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001139{
Harald Welte4724f992009-01-18 18:01:49 +00001140 struct abis_om_hdr *oh;
1141 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001142 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001143
Harald Welte4724f992009-01-18 18:01:49 +00001144 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1145 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1146 sw->obj_instance[0], sw->obj_instance[1],
1147 sw->obj_instance[2]);
1148
1149 /* FIXME: this is BS11 specific format */
1150 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1151 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1152 sw->file_version);
1153
1154 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001155}
Harald Welte4724f992009-01-18 18:01:49 +00001156
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001157struct sdp_firmware {
1158 char magic[4];
1159 char more_magic[4];
1160 unsigned int header_length;
1161 unsigned int file_length;
1162} __attribute__ ((packed));
1163
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001164static int parse_sdp_header(struct abis_nm_sw *sw)
1165{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001166 struct sdp_firmware firmware_header;
1167 int rc;
1168 struct stat stat;
1169
1170 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1171 if (rc != sizeof(firmware_header)) {
1172 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1173 return -1;
1174 }
1175
1176 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1177 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1178 return -1;
1179 }
1180
1181 if (firmware_header.more_magic[0] != 0x10 ||
1182 firmware_header.more_magic[1] != 0x02 ||
1183 firmware_header.more_magic[2] != 0x00 ||
1184 firmware_header.more_magic[3] != 0x00) {
1185 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1186 return -1;
1187 }
1188
1189
1190 if (fstat(sw->fd, &stat) == -1) {
1191 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1192 return -1;
1193 }
1194
1195 if (ntohl(firmware_header.file_length) != stat.st_size) {
1196 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1197 return -1;
1198 }
1199
1200 /* go back to the start as we checked the whole filesize.. */
1201 lseek(sw->fd, 0l, SEEK_SET);
1202 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1203 "There might be checksums in the file that are not\n"
1204 "verified and incomplete firmware might be flashed.\n"
1205 "There is absolutely no WARRANTY that flashing will\n"
1206 "work.\n");
1207 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001208}
1209
Harald Welte4724f992009-01-18 18:01:49 +00001210static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1211{
1212 char file_id[12+1];
1213 char file_version[80+1];
1214 int rc;
1215
1216 sw->fd = open(fname, O_RDONLY);
1217 if (sw->fd < 0)
1218 return sw->fd;
1219
1220 switch (sw->bts->type) {
1221 case GSM_BTS_TYPE_BS11:
1222 sw->stream = fdopen(sw->fd, "r");
1223 if (!sw->stream) {
1224 perror("fdopen");
1225 return -1;
1226 }
1227 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001228 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001229 file_id, file_version);
1230 if (rc != 2) {
1231 perror("parsing header line of software file");
1232 return -1;
1233 }
1234 strcpy((char *)sw->file_id, file_id);
1235 sw->file_id_len = strlen(file_id);
1236 strcpy((char *)sw->file_version, file_version);
1237 sw->file_version_len = strlen(file_version);
1238 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001239 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001240 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001241 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001242 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001243 rc = parse_sdp_header(sw);
1244 if (rc < 0) {
1245 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1246 return -1;
1247 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001248
1249 strcpy((char *)sw->file_id, "id");
1250 sw->file_id_len = 3;
1251 strcpy((char *)sw->file_version, "version");
1252 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001253 break;
Harald Welte4724f992009-01-18 18:01:49 +00001254 default:
1255 /* We don't know how to treat them yet */
1256 close(sw->fd);
1257 return -EINVAL;
1258 }
1259
1260 return 0;
1261}
1262
1263static void sw_close_file(struct abis_nm_sw *sw)
1264{
1265 switch (sw->bts->type) {
1266 case GSM_BTS_TYPE_BS11:
1267 fclose(sw->stream);
1268 break;
1269 default:
1270 close(sw->fd);
1271 break;
1272 }
1273}
1274
1275/* Fill the window */
1276static int sw_fill_window(struct abis_nm_sw *sw)
1277{
1278 int rc;
1279
1280 while (sw->seg_in_window < sw->window_size) {
1281 rc = sw_load_segment(sw);
1282 if (rc < 0)
1283 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001284 if (sw->last_seg)
1285 break;
Harald Welte4724f992009-01-18 18:01:49 +00001286 }
1287 return 0;
1288}
1289
1290/* callback function from abis_nm_rcvmsg() handler */
1291static int abis_nm_rcvmsg_sw(struct msgb *mb)
1292{
1293 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001294 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001295 int rc = -1;
1296 struct abis_nm_sw *sw = &g_sw;
1297 enum sw_state old_state = sw->state;
1298
Harald Welte3ffd1372009-02-01 22:15:49 +00001299 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001300
1301 switch (sw->state) {
1302 case SW_STATE_WAIT_INITACK:
1303 switch (foh->msg_type) {
1304 case NM_MT_LOAD_INIT_ACK:
1305 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001306 if (sw->cbfn)
1307 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1308 NM_MT_LOAD_INIT_ACK, mb,
1309 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001310 rc = sw_fill_window(sw);
1311 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001312 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001313 break;
1314 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001315 if (sw->forced) {
1316 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1317 "Init NACK\n");
1318 if (sw->cbfn)
1319 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1320 NM_MT_LOAD_INIT_ACK, mb,
1321 sw->cb_data, NULL);
1322 rc = sw_fill_window(sw);
1323 sw->state = SW_STATE_WAIT_SEGACK;
1324 } else {
1325 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001326 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001327 if (sw->cbfn)
1328 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1329 NM_MT_LOAD_INIT_NACK, mb,
1330 sw->cb_data, NULL);
1331 sw->state = SW_STATE_ERROR;
1332 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001333 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001334 break;
1335 }
1336 break;
1337 case SW_STATE_WAIT_SEGACK:
1338 switch (foh->msg_type) {
1339 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001340 if (sw->cbfn)
1341 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1342 NM_MT_LOAD_SEG_ACK, mb,
1343 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001344 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001345 if (!sw->last_seg) {
1346 /* fill window with more segments */
1347 rc = sw_fill_window(sw);
1348 sw->state = SW_STATE_WAIT_SEGACK;
1349 } else {
1350 /* end the transfer */
1351 sw->state = SW_STATE_WAIT_ENDACK;
1352 rc = sw_load_end(sw);
1353 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001354 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001355 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001356 case NM_MT_LOAD_ABORT:
1357 if (sw->cbfn)
1358 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1359 NM_MT_LOAD_ABORT, mb,
1360 sw->cb_data, NULL);
1361 break;
Harald Welte4724f992009-01-18 18:01:49 +00001362 }
1363 break;
1364 case SW_STATE_WAIT_ENDACK:
1365 switch (foh->msg_type) {
1366 case NM_MT_LOAD_END_ACK:
1367 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001368 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1369 sw->bts->nr);
1370 sw->state = SW_STATE_NONE;
1371 if (sw->cbfn)
1372 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1373 NM_MT_LOAD_END_ACK, mb,
1374 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001375 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001376 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001377 break;
1378 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001379 if (sw->forced) {
1380 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1381 "End NACK\n");
1382 sw->state = SW_STATE_NONE;
1383 if (sw->cbfn)
1384 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1385 NM_MT_LOAD_END_ACK, mb,
1386 sw->cb_data, NULL);
1387 } else {
1388 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001389 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001390 sw->state = SW_STATE_ERROR;
1391 if (sw->cbfn)
1392 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1393 NM_MT_LOAD_END_NACK, mb,
1394 sw->cb_data, NULL);
1395 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001396 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001397 break;
1398 }
1399 case SW_STATE_WAIT_ACTACK:
1400 switch (foh->msg_type) {
1401 case NM_MT_ACTIVATE_SW_ACK:
1402 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001403 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001404 sw->state = SW_STATE_NONE;
1405 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001406 if (sw->cbfn)
1407 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1408 NM_MT_ACTIVATE_SW_ACK, mb,
1409 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001410 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001411 break;
1412 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001413 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001414 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001415 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001416 if (sw->cbfn)
1417 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1418 NM_MT_ACTIVATE_SW_NACK, mb,
1419 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001420 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001421 break;
1422 }
1423 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001424 switch (foh->msg_type) {
1425 case NM_MT_ACTIVATE_SW_ACK:
1426 rc = 0;
1427 break;
1428 }
1429 break;
Harald Welte4724f992009-01-18 18:01:49 +00001430 case SW_STATE_ERROR:
1431 break;
1432 }
1433
1434 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001435 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001436 foh->msg_type, old_state, sw->state);
1437
1438 return rc;
1439}
1440
1441/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001442int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001443 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001444 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001445{
1446 struct abis_nm_sw *sw = &g_sw;
1447 int rc;
1448
Harald Welte5e4d1b32009-02-01 13:36:56 +00001449 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1450 bts->nr, fname);
1451
Harald Welte4724f992009-01-18 18:01:49 +00001452 if (sw->state != SW_STATE_NONE)
1453 return -EBUSY;
1454
1455 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001456 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001457
1458 switch (bts->type) {
1459 case GSM_BTS_TYPE_BS11:
1460 sw->obj_class = NM_OC_SITE_MANAGER;
1461 sw->obj_instance[0] = 0xff;
1462 sw->obj_instance[1] = 0xff;
1463 sw->obj_instance[2] = 0xff;
1464 break;
1465 case GSM_BTS_TYPE_NANOBTS:
1466 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001467 sw->obj_instance[0] = sw->bts->nr;
1468 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001469 sw->obj_instance[2] = 0xff;
1470 break;
1471 case GSM_BTS_TYPE_UNKNOWN:
1472 default:
1473 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1474 return -1;
1475 break;
1476 }
Harald Welte4724f992009-01-18 18:01:49 +00001477 sw->window_size = win_size;
1478 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001479 sw->cbfn = cbfn;
1480 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001481 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001482
1483 rc = sw_open_file(sw, fname);
1484 if (rc < 0) {
1485 sw->state = SW_STATE_NONE;
1486 return rc;
1487 }
1488
1489 return sw_load_init(sw);
1490}
Harald Welte52b1f982008-12-23 20:25:15 +00001491
Harald Welte1602ade2009-01-29 21:12:39 +00001492int abis_nm_software_load_status(struct gsm_bts *bts)
1493{
1494 struct abis_nm_sw *sw = &g_sw;
1495 struct stat st;
1496 int rc, percent;
1497
1498 rc = fstat(sw->fd, &st);
1499 if (rc < 0) {
1500 perror("ERROR during stat");
1501 return rc;
1502 }
1503
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001504 if (sw->stream)
1505 percent = (ftell(sw->stream) * 100) / st.st_size;
1506 else
1507 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001508 return percent;
1509}
1510
Harald Welte5e4d1b32009-02-01 13:36:56 +00001511/* Activate the specified software into the BTS */
1512int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1513 gsm_cbfn *cbfn, void *cb_data)
1514{
1515 struct abis_nm_sw *sw = &g_sw;
1516 int rc;
1517
1518 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1519 bts->nr, fname);
1520
1521 if (sw->state != SW_STATE_NONE)
1522 return -EBUSY;
1523
1524 sw->bts = bts;
1525 sw->obj_class = NM_OC_SITE_MANAGER;
1526 sw->obj_instance[0] = 0xff;
1527 sw->obj_instance[1] = 0xff;
1528 sw->obj_instance[2] = 0xff;
1529 sw->state = SW_STATE_WAIT_ACTACK;
1530 sw->cbfn = cbfn;
1531 sw->cb_data = cb_data;
1532
1533 /* Open the file in order to fill some sw struct members */
1534 rc = sw_open_file(sw, fname);
1535 if (rc < 0) {
1536 sw->state = SW_STATE_NONE;
1537 return rc;
1538 }
1539 sw_close_file(sw);
1540
1541 return sw_activate(sw);
1542}
1543
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001544static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1545 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001546{
Harald Welteadaf08b2009-01-18 11:08:10 +00001547 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001548 ch->bts_port = bts_port;
1549 ch->timeslot = ts_nr;
1550 ch->subslot = subslot_nr;
1551}
1552
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001553int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1554 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1555 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001556{
1557 struct abis_om_hdr *oh;
1558 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001559 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001560 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001561
1562 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1563 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1564 bts->bts_nr, trx_nr, 0xff);
1565
Harald Welte8470bf22008-12-25 23:28:35 +00001566 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001567
1568 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1569 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1570
1571 return abis_nm_sendmsg(bts, msg);
1572}
1573
1574/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1575int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001576 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001577{
Harald Welte8470bf22008-12-25 23:28:35 +00001578 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001579 struct abis_om_hdr *oh;
1580 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001581 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001582
1583 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001584 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001585 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1586
1587 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1588 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1589
1590 return abis_nm_sendmsg(bts, msg);
1591}
1592
1593#if 0
1594int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1595 struct abis_nm_abis_channel *chan)
1596{
1597}
1598#endif
1599
1600int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001601 uint8_t e1_port, uint8_t e1_timeslot,
1602 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001603{
1604 struct gsm_bts *bts = ts->trx->bts;
1605 struct abis_om_hdr *oh;
1606 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001607 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001608
1609 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1610 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001611 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001612
1613 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1614 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1615
Harald Weltef325eb42009-02-19 17:07:39 +00001616 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1617 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001618 e1_port, e1_timeslot, e1_subslot);
1619
Harald Welte52b1f982008-12-23 20:25:15 +00001620 return abis_nm_sendmsg(bts, msg);
1621}
1622
1623#if 0
1624int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1625 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001626 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001627{
1628}
1629#endif
1630
Max1ebf23b2017-05-10 12:21:17 +02001631/* 3GPP TS 52.021 § 8.11.1 */
1632int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1633 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001634{
1635 struct abis_om_hdr *oh;
Maxe3dbd5d2017-06-09 17:15:45 +02001636 struct msgb *msg;
1637
1638 if (bts->type != GSM_BTS_TYPE_OSMOBTS) {
1639 LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n",
1640 bts->nr, btstype2str(bts->type));
1641 return -EINVAL;
1642 }
Harald Weltefe568f22012-08-14 19:15:57 +02001643
1644 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1645
Maxe3dbd5d2017-06-09 17:15:45 +02001646 msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001647 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1648 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1649 bts_nr, trx_nr, ts_nr);
1650 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1651
1652 return abis_nm_sendmsg(bts, msg);
1653}
1654
Harald Welte22af0db2009-02-14 15:41:08 +00001655/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001656int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001657{
1658 struct abis_om_hdr *oh;
1659 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001660 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001661
1662 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1663
1664 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001665 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 +00001666 cur = msgb_put(msg, attr_len);
1667 memcpy(cur, attr, attr_len);
1668
1669 return abis_nm_sendmsg(bts, msg);
1670}
1671
1672/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001673int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001674{
1675 struct abis_om_hdr *oh;
1676 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001677 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001678
1679 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1680
1681 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1682 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001683 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001684 cur = msgb_put(msg, attr_len);
1685 memcpy(cur, attr, attr_len);
1686
1687 return abis_nm_sendmsg(trx->bts, msg);
1688}
1689
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001690int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1691{
1692 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1693 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1694}
1695
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001696static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1697 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001698{
1699 int i;
1700
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001701 *reason = "Reason unknown";
1702
Harald Welte39c7deb2009-08-09 21:49:48 +02001703 /* As it turns out, the BS-11 has some very peculiar restrictions
1704 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301705 switch (ts->trx->bts->type) {
1706 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001707 switch (chan_comb) {
1708 case NM_CHANC_TCHHalf:
1709 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001710 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001711 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001712 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001713 return -EINVAL;
1714 case NM_CHANC_SDCCH:
1715 /* only one SDCCH/8 per TRX */
1716 for (i = 0; i < TRX_NR_TS; i++) {
1717 if (i == ts->nr)
1718 continue;
1719 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001720 NM_CHANC_SDCCH) {
1721 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001722 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001723 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001724 }
1725 /* not allowed for TS0 of BCCH-TRX */
1726 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001727 ts->nr == 0) {
1728 *reason = "SDCCH/8 must be on TS0.";
1729 return -EINVAL;
1730 }
1731
Harald Welte39c7deb2009-08-09 21:49:48 +02001732 /* not on the same TRX that has a BCCH+SDCCH4
1733 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001734 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001735 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001736 ts->trx->ts[0].nm_chan_comb == 8)) {
1737 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1738 return -EINVAL;
1739 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001740 break;
1741 case NM_CHANC_mainBCCH:
1742 case NM_CHANC_BCCHComb:
1743 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001744 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1745 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001746 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001747 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001748 break;
1749 case NM_CHANC_BCCH:
1750 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001751 if (ts->trx != ts->trx->bts->c0) {
1752 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001753 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001754 }
1755 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1756 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001757 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001758 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001759 break;
1760 case 8: /* this is not like 08.58, but in fact
1761 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1762 /* FIXME: only one CBCH allowed per cell */
1763 break;
1764 }
Harald Welted6575f92009-12-02 02:45:23 +05301765 break;
1766 case GSM_BTS_TYPE_NANOBTS:
1767 switch (ts->nr) {
1768 case 0:
1769 if (ts->trx->nr == 0) {
1770 /* only on TRX0 */
1771 switch (chan_comb) {
1772 case NM_CHANC_BCCH:
1773 case NM_CHANC_mainBCCH:
1774 case NM_CHANC_BCCHComb:
1775 return 0;
1776 break;
1777 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001778 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301779 return -EINVAL;
1780 }
1781 } else {
1782 switch (chan_comb) {
1783 case NM_CHANC_TCHFull:
1784 case NM_CHANC_TCHHalf:
1785 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1786 return 0;
1787 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001788 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301789 return -EINVAL;
1790 }
1791 }
1792 break;
1793 case 1:
1794 if (ts->trx->nr == 0) {
1795 switch (chan_comb) {
1796 case NM_CHANC_SDCCH_CBCH:
1797 if (ts->trx->ts[0].nm_chan_comb ==
1798 NM_CHANC_mainBCCH)
1799 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001800 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301801 return -EINVAL;
1802 case NM_CHANC_SDCCH:
1803 case NM_CHANC_TCHFull:
1804 case NM_CHANC_TCHHalf:
1805 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1806 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001807 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301808 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001809 default:
1810 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1811 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301812 }
1813 } else {
1814 switch (chan_comb) {
1815 case NM_CHANC_SDCCH:
1816 case NM_CHANC_TCHFull:
1817 case NM_CHANC_TCHHalf:
1818 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1819 return 0;
1820 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001821 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301822 return -EINVAL;
1823 }
1824 }
1825 break;
1826 case 2:
1827 case 3:
1828 case 4:
1829 case 5:
1830 case 6:
1831 case 7:
1832 switch (chan_comb) {
1833 case NM_CHANC_TCHFull:
1834 case NM_CHANC_TCHHalf:
1835 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1836 return 0;
1837 case NM_CHANC_IPAC_PDCH:
1838 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001839 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301840 if (ts->trx->nr == 0)
1841 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001842 else {
1843 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301844 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001845 }
Harald Welted6575f92009-12-02 02:45:23 +05301846 }
1847 break;
1848 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001849 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301850 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001851 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001852 /* no known restrictions */
1853 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301854 default:
1855 /* unknown BTS type */
1856 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001857 }
1858 return 0;
1859}
1860
Harald Welte22af0db2009-02-14 15:41:08 +00001861/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001862int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001863{
1864 struct gsm_bts *bts = ts->trx->bts;
1865 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001866 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001867 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001868 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001869 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001870
1871 if (bts->type == GSM_BTS_TYPE_BS11)
1872 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001873
Harald Weltef325eb42009-02-19 17:07:39 +00001874 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001875 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001876 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001877 LOGP(DNM, LOGL_ERROR,
1878 "Invalid Channel Combination %d on %s. Reason: %s\n",
1879 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001880 return -EINVAL;
1881 }
1882 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001883
Harald Welte52b1f982008-12-23 20:25:15 +00001884 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001885 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001886 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001887 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001888 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001889 if (ts->hopping.enabled) {
1890 unsigned int i;
1891 uint8_t *len;
1892
Harald Welte6e0cd042009-09-12 13:05:33 +02001893 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1894 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001895
1896 /* build the ARFCN list */
1897 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1898 len = msgb_put(msg, 1);
1899 *len = 0;
1900 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1901 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1902 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001903 /* At least BS-11 wants a TLV16 here */
1904 if (bts->type == GSM_BTS_TYPE_BS11)
1905 *len += 1;
1906 else
1907 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001908 }
1909 }
Harald Weltee0590df2009-02-15 03:34:15 +00001910 }
Harald Welte1fe24122014-01-19 17:18:21 +01001911 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001912 if (bts->type == GSM_BTS_TYPE_BS11)
1913 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001914
1915 return abis_nm_sendmsg(bts, msg);
1916}
1917
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001918int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1919 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001920{
1921 struct abis_om_hdr *oh;
1922 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001923 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1924 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001925
1926 if (nack) {
1927 len += 2;
1928 msgtype = NM_MT_SW_ACT_REQ_NACK;
1929 }
Harald Welte34a99682009-02-13 02:41:40 +00001930
1931 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001932 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1933
Harald Welte34a99682009-02-13 02:41:40 +00001934 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001935 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001936 memcpy(ptr, attr, att_len);
1937 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001938 if (nack)
1939 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001940
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001941 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001942}
1943
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001944int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001945{
Harald Welte8470bf22008-12-25 23:28:35 +00001946 struct msgb *msg = nm_msgb_alloc();
1947 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001948 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001949
1950 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1951 fill_om_hdr(oh, len);
1952 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001953 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001954
1955 return abis_nm_sendmsg(bts, msg);
1956}
1957
1958/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001959static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001960{
1961 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001962 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001963
1964 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001965 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001966 0xff, 0xff, 0xff);
1967
1968 return abis_nm_sendmsg(bts, msg);
1969}
1970
Harald Welte34a99682009-02-13 02:41:40 +00001971/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001972int 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 +00001973{
1974 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001975 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001976 struct msgb *msg = nm_msgb_alloc();
1977
1978 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001979 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001980
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001981 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001982 DEBUGPC(DNM, "Sending OPSTART\n");
1983
Harald Welte34a99682009-02-13 02:41:40 +00001984 return abis_nm_sendmsg(bts, msg);
1985}
1986
1987/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001988int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1989 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001990{
1991 struct abis_om_hdr *oh;
1992 struct msgb *msg = nm_msgb_alloc();
1993
1994 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1995 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1996 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1997
1998 return abis_nm_sendmsg(bts, msg);
1999}
2000
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002001int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
2002 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02002003{
2004 struct abis_om_hdr *oh;
2005 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002006 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02002007
2008 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
2009 e1_port0, ts0, e1_port1, ts1);
2010
2011 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2012 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
2013 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
2014
2015 attr = msgb_put(msg, 3);
2016 attr[0] = NM_ATT_MDROP_LINK;
2017 attr[1] = e1_port0;
2018 attr[2] = ts0;
2019
2020 attr = msgb_put(msg, 3);
2021 attr[0] = NM_ATT_MDROP_NEXT;
2022 attr[1] = e1_port1;
2023 attr[2] = ts1;
2024
2025 return abis_nm_sendmsg(bts, msg);
2026}
Harald Welte34a99682009-02-13 02:41:40 +00002027
Harald Weltec7310382009-08-08 00:02:36 +02002028/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002029int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2030 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2031 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002032{
2033 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002034
Harald Welte15c61722011-05-22 22:45:37 +02002035 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002036
2037 if (!msg)
2038 msg = nm_msgb_alloc();
2039
2040 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2041 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2042 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2043 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002044 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002045
2046 return abis_nm_sendmsg(bts, msg);
2047}
2048
Harald Welte52b1f982008-12-23 20:25:15 +00002049int abis_nm_event_reports(struct gsm_bts *bts, int on)
2050{
2051 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002052 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002053 else
Harald Welte227d4072009-01-03 08:16:25 +00002054 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002055}
2056
Harald Welte47d88ae2009-01-04 12:02:08 +00002057/* Siemens (or BS-11) specific commands */
2058
Harald Welte3ffd1372009-02-01 22:15:49 +00002059int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2060{
2061 if (reconnect == 0)
2062 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2063 else
2064 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2065}
2066
Harald Welteb8427972009-02-05 19:27:17 +00002067int abis_nm_bs11_restart(struct gsm_bts *bts)
2068{
2069 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2070}
2071
2072
Harald Welte268bb402009-02-01 19:11:56 +00002073struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002074 uint16_t year;
2075 uint8_t month;
2076 uint8_t day;
2077 uint8_t hour;
2078 uint8_t min;
2079 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002080} __attribute__((packed));
2081
2082
2083void get_bs11_date_time(struct bs11_date_time *aet)
2084{
2085 time_t t;
2086 struct tm *tm;
2087
2088 t = time(NULL);
2089 tm = localtime(&t);
2090 aet->sec = tm->tm_sec;
2091 aet->min = tm->tm_min;
2092 aet->hour = tm->tm_hour;
2093 aet->day = tm->tm_mday;
2094 aet->month = tm->tm_mon;
2095 aet->year = htons(1900 + tm->tm_year);
2096}
2097
Harald Welte05188ee2009-01-18 11:39:08 +00002098int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002099{
Harald Welte4668fda2009-01-03 08:19:29 +00002100 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002101}
2102
Harald Welte05188ee2009-01-18 11:39:08 +00002103int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002104{
2105 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002106 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002107 else
Harald Welte4668fda2009-01-03 08:19:29 +00002108 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002109}
Harald Welte47d88ae2009-01-04 12:02:08 +00002110
Harald Welte05188ee2009-01-18 11:39:08 +00002111int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002112 enum abis_bs11_objtype type, uint8_t idx,
2113 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002114{
2115 struct abis_om_hdr *oh;
2116 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002117 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002118
2119 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002120 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002121 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002122 cur = msgb_put(msg, attr_len);
2123 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002124
2125 return abis_nm_sendmsg(bts, msg);
2126}
2127
Harald Welte78fc0d42009-02-19 02:50:57 +00002128int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002129 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002130{
2131 struct abis_om_hdr *oh;
2132 struct msgb *msg = nm_msgb_alloc();
2133
2134 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2135 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2136 NM_OC_BS11, type, 0, idx);
2137
2138 return abis_nm_sendmsg(bts, msg);
2139}
2140
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002141int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002142{
2143 struct abis_om_hdr *oh;
2144 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002145 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002146
2147 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002148 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002149 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2150 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002151
2152 return abis_nm_sendmsg(bts, msg);
2153}
2154
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002155int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002156{
2157 struct abis_om_hdr *oh;
2158 struct msgb *msg = nm_msgb_alloc();
2159
2160 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2161 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002162 idx, 0xff, 0xff);
2163
2164 return abis_nm_sendmsg(bts, msg);
2165}
2166
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002167int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002168{
2169 struct abis_om_hdr *oh;
2170 struct msgb *msg = nm_msgb_alloc();
2171
2172 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2173 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2174 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002175
2176 return abis_nm_sendmsg(bts, msg);
2177}
Harald Welte05188ee2009-01-18 11:39:08 +00002178
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002179static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002180int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2181{
2182 struct abis_om_hdr *oh;
2183 struct msgb *msg = nm_msgb_alloc();
2184
2185 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2186 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2187 0xff, 0xff, 0xff);
2188 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2189
2190 return abis_nm_sendmsg(bts, msg);
2191}
2192
Harald Welteb6c92ae2009-02-21 20:15:32 +00002193/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002194int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2195 uint8_t e1_timeslot, uint8_t e1_subslot,
2196 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002197{
2198 struct abis_om_hdr *oh;
2199 struct abis_nm_channel *ch;
2200 struct msgb *msg = nm_msgb_alloc();
2201
2202 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002203 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002204 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2205
2206 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2207 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002208 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002209
2210 return abis_nm_sendmsg(bts, msg);
2211}
2212
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002213int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002214{
2215 struct abis_om_hdr *oh;
2216 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002217
2218 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002219 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002220 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2221 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2222
2223 return abis_nm_sendmsg(trx->bts, msg);
2224}
2225
Harald Welte78fc0d42009-02-19 02:50:57 +00002226int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2227{
2228 struct abis_om_hdr *oh;
2229 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002230 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002231
2232 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2233 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2234 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2235 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2236
2237 return abis_nm_sendmsg(trx->bts, msg);
2238}
2239
Harald Welteaaf02d92009-04-29 13:25:57 +00002240int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2241{
2242 struct abis_om_hdr *oh;
2243 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002244 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002245
2246 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2247 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2248 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002249 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002250
2251 return abis_nm_sendmsg(bts, msg);
2252}
2253
Harald Welteef061952009-05-17 12:43:42 +00002254int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2255{
2256 struct abis_om_hdr *oh;
2257 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002258 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002259 NM_ATT_BS11_CCLK_TYPE };
2260
2261 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2262 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2263 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2264 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2265
2266 return abis_nm_sendmsg(bts, msg);
2267
2268}
Harald Welteaaf02d92009-04-29 13:25:57 +00002269
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002270//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002271
Harald Welte1bc09062009-01-18 14:17:52 +00002272int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002273{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002274 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2275}
2276
Daniel Willmann4b054c82010-01-07 00:46:26 +01002277int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2278{
2279 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2280}
2281
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002282int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002283{
Harald Welte05188ee2009-01-18 11:39:08 +00002284 struct abis_om_hdr *oh;
2285 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002286 struct bs11_date_time bdt;
2287
2288 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002289
2290 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002291 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002292 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002293 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002294 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002295 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002296 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002297 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002298 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002299 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002300 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002301 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002302 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002303 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002304 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002305 }
Harald Welte05188ee2009-01-18 11:39:08 +00002306
2307 return abis_nm_sendmsg(bts, msg);
2308}
Harald Welte1bc09062009-01-18 14:17:52 +00002309
2310int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2311{
2312 struct abis_om_hdr *oh;
2313 struct msgb *msg;
2314
2315 if (strlen(password) != 10)
2316 return -EINVAL;
2317
2318 msg = nm_msgb_alloc();
2319 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002320 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002321 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002322 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002323
2324 return abis_nm_sendmsg(bts, msg);
2325}
2326
Harald Weltee69f5fb2009-04-28 16:31:38 +00002327/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2328int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2329{
2330 struct abis_om_hdr *oh;
2331 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002332 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002333
2334 msg = nm_msgb_alloc();
2335 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2336 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2337 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002338
2339 if (locked)
2340 tlv_value = BS11_LI_PLL_LOCKED;
2341 else
2342 tlv_value = BS11_LI_PLL_STANDALONE;
2343
2344 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002345
2346 return abis_nm_sendmsg(bts, msg);
2347}
2348
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002349/* Set the calibration value of the PLL (work value/set value)
2350 * It depends on the login which one is changed */
2351int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2352{
2353 struct abis_om_hdr *oh;
2354 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002355 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002356
2357 msg = nm_msgb_alloc();
2358 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2359 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2360 BS11_OBJ_TRX1, 0x00, 0x00);
2361
2362 tlv_value[0] = value>>8;
2363 tlv_value[1] = value&0xff;
2364
2365 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2366
2367 return abis_nm_sendmsg(bts, msg);
2368}
2369
Harald Welte1bc09062009-01-18 14:17:52 +00002370int abis_nm_bs11_get_state(struct gsm_bts *bts)
2371{
2372 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2373}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002374
2375/* BS11 SWL */
2376
Neels Hofmeyrcc6240a2018-02-13 21:21:42 +01002377void *tall_fle_ctx = NULL;
Harald Welte2cf161b2009-06-20 22:36:41 +02002378
Harald Welte5e4d1b32009-02-01 13:36:56 +00002379struct abis_nm_bs11_sw {
2380 struct gsm_bts *bts;
2381 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002382 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002383 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002384 struct llist_head file_list;
2385 gsm_cbfn *user_cb; /* specified by the user */
2386};
2387static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2388
2389struct file_list_entry {
2390 struct llist_head list;
2391 char fname[PATH_MAX];
2392};
2393
2394struct file_list_entry *fl_dequeue(struct llist_head *queue)
2395{
2396 struct llist_head *lh;
2397
2398 if (llist_empty(queue))
2399 return NULL;
2400
2401 lh = queue->next;
2402 llist_del(lh);
2403
2404 return llist_entry(lh, struct file_list_entry, list);
2405}
2406
2407static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2408{
2409 char linebuf[255];
2410 struct llist_head *lh, *lh2;
2411 FILE *swl;
2412 int rc = 0;
2413
2414 swl = fopen(bs11_sw->swl_fname, "r");
2415 if (!swl)
2416 return -ENODEV;
2417
2418 /* zero the stale file list, if any */
2419 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2420 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002421 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002422 }
2423
2424 while (fgets(linebuf, sizeof(linebuf), swl)) {
2425 char file_id[12+1];
2426 char file_version[80+1];
2427 struct file_list_entry *fle;
2428 static char dir[PATH_MAX];
2429
2430 if (strlen(linebuf) < 4)
2431 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002432
Harald Welte5e4d1b32009-02-01 13:36:56 +00002433 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2434 if (rc < 0) {
2435 perror("ERR parsing SWL file");
2436 rc = -EINVAL;
2437 goto out;
2438 }
2439 if (rc < 2)
2440 continue;
2441
Harald Welte470ec292009-06-26 20:25:23 +02002442 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002443 if (!fle) {
2444 rc = -ENOMEM;
2445 goto out;
2446 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002447
2448 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002449 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002450 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2451 strcat(fle->fname, "/");
2452 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002453
2454 llist_add_tail(&fle->list, &bs11_sw->file_list);
2455 }
2456
2457out:
2458 fclose(swl);
2459 return rc;
2460}
2461
2462/* bs11 swload specific callback, passed to abis_nm core swload */
2463static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2464 struct msgb *msg, void *data, void *param)
2465{
2466 struct abis_nm_bs11_sw *bs11_sw = data;
2467 struct file_list_entry *fle;
2468 int rc = 0;
2469
Harald Welte5e4d1b32009-02-01 13:36:56 +00002470 switch (event) {
2471 case NM_MT_LOAD_END_ACK:
2472 fle = fl_dequeue(&bs11_sw->file_list);
2473 if (fle) {
2474 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002475 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002476 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002477 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002478 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002479 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002480 } else {
2481 /* activate the SWL */
2482 rc = abis_nm_software_activate(bs11_sw->bts,
2483 bs11_sw->swl_fname,
2484 bs11_swload_cbfn,
2485 bs11_sw);
2486 }
2487 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002488 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002489 case NM_MT_LOAD_END_NACK:
2490 case NM_MT_LOAD_INIT_ACK:
2491 case NM_MT_LOAD_INIT_NACK:
2492 case NM_MT_ACTIVATE_SW_NACK:
2493 case NM_MT_ACTIVATE_SW_ACK:
2494 default:
2495 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002496 if (bs11_sw->user_cb)
2497 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002498 break;
2499 }
2500
2501 return rc;
2502}
2503
2504/* Siemens provides a SWL file that is a mere listing of all the other
2505 * files that are part of a software release. We need to upload first
2506 * the list file, and then each file that is listed in the list file */
2507int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002508 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002509{
2510 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2511 struct file_list_entry *fle;
2512 int rc = 0;
2513
2514 INIT_LLIST_HEAD(&bs11_sw->file_list);
2515 bs11_sw->bts = bts;
2516 bs11_sw->win_size = win_size;
2517 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002518 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002519
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002520 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002521 rc = bs11_read_swl_file(bs11_sw);
2522 if (rc < 0)
2523 return rc;
2524
2525 /* dequeue next item in file list */
2526 fle = fl_dequeue(&bs11_sw->file_list);
2527 if (!fle)
2528 return -EINVAL;
2529
2530 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002531 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002532 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002533 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002534 return rc;
2535}
2536
Harald Welte5083b0b2009-02-02 19:20:52 +00002537#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002538static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002539 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2540 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2541 NM_ATT_BS11_LMT_USER_NAME,
2542
2543 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2544
2545 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2546
2547 NM_ATT_BS11_SW_LOAD_STORED };
2548
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002549static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002550 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2551 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2552 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2553 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002554#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002555
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002556static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002557 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2558 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002559 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002560
2561int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2562{
2563 struct abis_om_hdr *oh;
2564 struct msgb *msg = nm_msgb_alloc();
2565
2566 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2567 /* SiemensHW CCTRL object */
2568 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2569 0x03, 0x00, 0x00);
2570 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2571
2572 return abis_nm_sendmsg(bts, msg);
2573}
Harald Welte268bb402009-02-01 19:11:56 +00002574
2575int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2576{
2577 struct abis_om_hdr *oh;
2578 struct msgb *msg = nm_msgb_alloc();
2579 struct bs11_date_time aet;
2580
2581 get_bs11_date_time(&aet);
2582 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2583 /* SiemensHW CCTRL object */
2584 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2585 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002586 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002587
2588 return abis_nm_sendmsg(bts, msg);
2589}
Harald Welte5c1e4582009-02-15 11:57:29 +00002590
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002591int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002592{
2593 struct abis_om_hdr *oh;
2594 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002595 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002596
2597 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2598 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2599 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2600 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2601
2602 return abis_nm_sendmsg(bts, msg);
2603}
2604
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002605int 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 +02002606{
2607 struct abis_om_hdr *oh;
2608 struct msgb *msg = nm_msgb_alloc();
2609 struct bs11_date_time aet;
2610
2611 get_bs11_date_time(&aet);
2612 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2613 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2614 bport, 0xff, 0x02);
2615 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2616
2617 return abis_nm_sendmsg(bts, msg);
2618}
2619
Harald Welte5c1e4582009-02-15 11:57:29 +00002620/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002621static const char ipaccess_magic[] = "com.ipaccess";
2622
Harald Welte677c21f2009-02-17 13:22:23 +00002623
2624static int abis_nm_rx_ipacc(struct msgb *msg)
2625{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002626 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002627 struct abis_om_hdr *oh = msgb_l2(msg);
2628 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002629 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002630 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002631 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002632 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002633
2634 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002635 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002636 return -EINVAL;
2637 }
2638
Harald Welte193fefc2009-04-30 15:16:27 +00002639 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002640 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002641
Harald Welte15c61722011-05-22 22:45:37 +02002642 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002643
Harald Welte746d6092009-10-19 22:11:11 +02002644 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002645
Harald Welte677c21f2009-02-17 13:22:23 +00002646 switch (foh->msg_type) {
2647 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002648 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002649 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2650 memcpy(&addr,
2651 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2652
2653 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2654 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002655 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002656 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002657 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002658 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002659 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2660 DEBUGPC(DNM, "STREAM=0x%02x ",
2661 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002662 DEBUGPC(DNM, "\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;
2665 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002666 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002667 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002668 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002669 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002670 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002671 LOGPC(DNM, LOGL_ERROR, "\n");
Stefan Sperling73acbca2018-02-12 14:28:52 +01002672 osmo_timer_del(&sign_link->trx->rsl_connect_timeout);
Harald Welte677c21f2009-02-17 13:22:23 +00002673 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002674 case NM_MT_IPACC_SET_NVATTR_ACK:
2675 DEBUGPC(DNM, "SET NVATTR ACK\n");
2676 /* FIXME: decode and show the actual attributes */
2677 break;
2678 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002679 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002680 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002681 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002682 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002683 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002684 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002685 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002686 case NM_MT_IPACC_GET_NVATTR_ACK:
2687 DEBUGPC(DNM, "GET NVATTR ACK\n");
2688 /* FIXME: decode and show the actual attributes */
2689 break;
2690 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002691 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002692 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002693 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002694 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002695 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002696 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002697 break;
Harald Welte15c44172009-10-08 20:15:24 +02002698 case NM_MT_IPACC_SET_ATTR_ACK:
2699 DEBUGPC(DNM, "SET ATTR ACK\n");
2700 break;
2701 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002702 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002703 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002704 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002705 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002706 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002707 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002708 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002709 default:
2710 DEBUGPC(DNM, "unknown\n");
2711 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002712 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002713
2714 /* signal handling */
2715 switch (foh->msg_type) {
2716 case NM_MT_IPACC_RSL_CONNECT_NACK:
2717 case NM_MT_IPACC_SET_NVATTR_NACK:
2718 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002719 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 +01002720 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002721 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002722 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002723 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002724 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 +01002725 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002726 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002727 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002728 default:
2729 break;
2730 }
2731
Harald Welte677c21f2009-02-17 13:22:23 +00002732 return 0;
2733}
2734
Harald Welte193fefc2009-04-30 15:16:27 +00002735/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002736int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2737 uint8_t obj_class, uint8_t bts_nr,
2738 uint8_t trx_nr, uint8_t ts_nr,
2739 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002740{
2741 struct msgb *msg = nm_msgb_alloc();
2742 struct abis_om_hdr *oh;
2743 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002744 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002745
2746 /* construct the 12.21 OM header, observe the erroneous length */
2747 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2748 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2749 oh->mdisc = ABIS_OM_MDISC_MANUF;
2750
2751 /* add the ip.access magic */
2752 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2753 *data++ = sizeof(ipaccess_magic);
2754 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2755
2756 /* fill the 12.21 FOM header */
2757 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2758 foh->msg_type = msg_type;
2759 foh->obj_class = obj_class;
2760 foh->obj_inst.bts_nr = bts_nr;
2761 foh->obj_inst.trx_nr = trx_nr;
2762 foh->obj_inst.ts_nr = ts_nr;
2763
2764 if (attr && attr_len) {
2765 data = msgb_put(msg, attr_len);
2766 memcpy(data, attr, attr_len);
2767 }
2768
2769 return abis_nm_sendmsg(bts, msg);
2770}
Harald Welte677c21f2009-02-17 13:22:23 +00002771
Harald Welte193fefc2009-04-30 15:16:27 +00002772/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002773int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002774 int attr_len)
2775{
Harald Welte2ef156d2010-01-07 20:39:42 +01002776 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2777 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002778 attr_len);
2779}
2780
Stefan Sperling73acbca2018-02-12 14:28:52 +01002781static void rsl_connect_timeout(void *data)
2782{
2783 struct gsm_bts_trx *trx = data;
2784 struct ipacc_ack_signal_data signal;
2785
2786 LOGP(DRSL, LOGL_NOTICE, "(bts=%d,trx=%d) RSL connection request timed out\n", trx->bts->nr, trx->nr);
2787
2788 /* Fake an RSL CONECT NACK message from the BTS. */
2789 signal.trx = trx;
2790 signal.msg_type = NM_MT_IPACC_RSL_CONNECT_NACK;
2791 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
2792}
2793
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002794int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002795 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002796{
2797 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002798 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002799 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2800 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2801
2802 int attr_len = sizeof(attr);
Stefan Sperling73acbca2018-02-12 14:28:52 +01002803 int error;
2804
2805 osmo_timer_setup(&trx->rsl_connect_timeout, rsl_connect_timeout, trx);
Harald Welte746d6092009-10-19 22:11:11 +02002806
2807 ia.s_addr = htonl(ip);
2808 attr[1] = stream;
2809 attr[3] = port >> 8;
2810 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002811 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002812
2813 /* if ip == 0, we use the default IP */
2814 if (ip == 0)
2815 attr_len -= 5;
2816
2817 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002818 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002819
Stefan Sperling73acbca2018-02-12 14:28:52 +01002820 error = abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2821 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2822 trx->nr, 0xff, attr, attr_len);
2823 if (error == 0)
2824 osmo_timer_schedule(&trx->rsl_connect_timeout, 60, 0);
2825
2826 return error;
Harald Welte746d6092009-10-19 22:11:11 +02002827}
2828
Harald Welte193fefc2009-04-30 15:16:27 +00002829/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002830int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002831{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002832 struct abis_om_hdr *oh;
2833 struct msgb *msg = nm_msgb_alloc();
2834
2835 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2836 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2837 trx->bts->nr, trx->nr, 0xff);
2838
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002839 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002840}
Harald Weltedaef5212009-10-24 10:20:41 +02002841
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002842int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2843 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2844 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002845{
2846 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2847 obj_class, bts_nr, trx_nr, ts_nr,
2848 attr, attr_len);
2849}
Harald Welte0f255852009-11-12 14:48:42 +01002850
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002851void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002852{
Neels Hofmeyr4d358c02018-02-22 03:19:05 +01002853 struct gsm48_ra_id *_buf = (struct gsm48_ra_id*)buf;
2854 uint16_t ci = htons(bts->cell_identity);
2855 /* we simply reuse the GSM48 function and write the Cell ID over the position where the RAC
2856 * starts */
2857 gsm48_ra_id_by_bts(_buf, bts);
2858 memcpy(&_buf->rac, &ci, sizeof(ci));
Harald Welte97a282b2010-03-14 15:37:43 +08002859}
2860
Maxbe356ed2017-09-07 19:10:09 +02002861void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason)
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002862{
Maxbe356ed2017-09-07 19:10:09 +02002863 uint8_t new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2864
2865 LOGP(DNM, LOGL_NOTICE, "(bts=%d,trx=%d) Changing adm. state %s -> %s [%s]\n", trx->bts->nr, trx->nr,
2866 get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative),
2867 get_value_string(abis_nm_adm_state_names, new_state), reason);
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002868
Harald Welted64c0bc2011-05-30 12:07:53 +02002869 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002870 if (!trx->bts || !trx->bts->oml_link)
2871 return;
2872
2873 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2874 trx->bts->bts_nr, trx->nr, 0xff,
2875 new_state);
2876}
2877
Harald Welte92b1fe42010-03-25 11:45:30 +08002878static const struct value_string ipacc_testres_names[] = {
2879 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2880 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2881 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2882 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2883 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2884 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002885};
2886
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002887const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002888{
Harald Welte92b1fe42010-03-25 11:45:30 +08002889 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002890}
2891
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002892void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002893{
2894 cid->mcc = (buf[0] & 0xf) * 100;
2895 cid->mcc += (buf[0] >> 4) * 10;
2896 cid->mcc += (buf[1] & 0xf) * 1;
2897
2898 if (buf[1] >> 4 == 0xf) {
2899 cid->mnc = (buf[2] & 0xf) * 10;
2900 cid->mnc += (buf[2] >> 4) * 1;
2901 } else {
2902 cid->mnc = (buf[2] & 0xf) * 100;
2903 cid->mnc += (buf[2] >> 4) * 10;
2904 cid->mnc += (buf[1] >> 4) * 1;
2905 }
2906
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002907 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2908 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002909}
2910
Harald Welte0f255852009-11-12 14:48:42 +01002911/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002912int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002913{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002914 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002915 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002916
Harald Welteaf109b92010-07-22 18:14:36 +02002917 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002918
2919 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2920 return -EINVAL;
2921 cur++;
2922
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002923 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002924 cur += 2;
2925
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002926 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002927 cur += 2;
2928
2929 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2930 binf->freq_qual = *cur >> 2;
2931
Harald Welteaf109b92010-07-22 18:14:36 +02002932 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002933 binf->arfcn |= *cur++;
2934
2935 if (binf->info_type & IPAC_BINF_RXLEV)
2936 binf->rx_lev = *cur & 0x3f;
2937 cur++;
2938
2939 if (binf->info_type & IPAC_BINF_RXQUAL)
2940 binf->rx_qual = *cur & 0x7;
2941 cur++;
2942
2943 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002944 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002945 cur += 2;
2946
2947 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002948 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002949 cur += 2;
2950
2951 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002952 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002953 cur += 4;
2954
Harald Weltea780a3d2010-07-30 22:34:42 +02002955#if 0
2956 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002957 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002958#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002959 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002960 cur++;
2961
Harald Welteb40a38f2009-11-13 11:56:05 +01002962 ipac_parse_cgi(&binf->cgi, cur);
2963 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002964
2965 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2966 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2967 cur += sizeof(binf->ba_list_si2);
2968 }
2969
2970 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2971 memcpy(binf->ba_list_si2bis, cur,
2972 sizeof(binf->ba_list_si2bis));
2973 cur += sizeof(binf->ba_list_si2bis);
2974 }
2975
2976 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2977 memcpy(binf->ba_list_si2ter, cur,
2978 sizeof(binf->ba_list_si2ter));
2979 cur += sizeof(binf->ba_list_si2ter);
2980 }
2981
2982 return 0;
2983}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002984
2985void abis_nm_clear_queue(struct gsm_bts *bts)
2986{
2987 struct msgb *msg;
2988
2989 while (!llist_empty(&bts->abis_queue)) {
2990 msg = msgb_dequeue(&bts->abis_queue);
2991 msgb_free(msg);
2992 }
2993
2994 bts->abis_nm_pend = 0;
2995}