blob: 295cefde2b200d9f75a3a2af06cf6a93032a0950 [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>
Harald Welte52b1f982008-12-23 20:25:15 +000049
Harald Welte8470bf22008-12-25 23:28:35 +000050#define OM_ALLOC_SIZE 1024
51#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010052#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000053
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020054int 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 +000055{
Harald Welte39315c42010-01-10 18:01:52 +010056 if (!bts->model)
57 return -EIO;
58 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000059}
Harald Weltee0590df2009-02-15 03:34:15 +000060
Harald Welte52b1f982008-12-23 20:25:15 +000061static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
62{
63 int i;
64
65 for (i = 0; i < size; i++) {
66 if (arr[i] == mt)
67 return 1;
68 }
69
70 return 0;
71}
72
Holger Freytherca362a62009-01-04 21:05:01 +000073#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000074/* is this msgtype the usual ACK/NACK type ? */
75static int is_ack_nack(enum abis_nm_msgtype mt)
76{
77 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
78}
Holger Freytherca362a62009-01-04 21:05:01 +000079#endif
Harald Welte52b1f982008-12-23 20:25:15 +000080
81/* is this msgtype a report ? */
82static int is_report(enum abis_nm_msgtype mt)
83{
Harald Welte15c61722011-05-22 22:45:37 +020084 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000085}
86
87#define MT_ACK(x) (x+1)
88#define MT_NACK(x) (x+2)
89
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020090static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000091{
92 oh->mdisc = ABIS_OM_MDISC_FOM;
93 oh->placement = ABIS_OM_PLACEMENT_ONLY;
94 oh->sequence = 0;
95 oh->length = len;
96}
97
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +020098static 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 +020099 uint8_t msg_type, uint8_t obj_class,
100 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000101{
102 struct abis_om_fom_hdr *foh =
103 (struct abis_om_fom_hdr *) oh->data;
104
Harald Welte702d8702008-12-26 20:25:35 +0000105 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000106 foh->msg_type = msg_type;
107 foh->obj_class = obj_class;
108 foh->obj_inst.bts_nr = bts_nr;
109 foh->obj_inst.trx_nr = trx_nr;
110 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200111 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000112}
113
Harald Welte8470bf22008-12-25 23:28:35 +0000114static struct msgb *nm_msgb_alloc(void)
115{
Harald Welte966636f2009-06-26 19:39:35 +0200116 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
117 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000118}
119
Harald Welte15eae8d2011-09-26 23:43:23 +0200120int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200121{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200122 msg->l2h = msg->data;
123
124 if (!msg->dst) {
125 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
126 return -EINVAL;
127 }
128
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200129 return abis_sendmsg(msg);
130}
131
Harald Welte52b1f982008-12-23 20:25:15 +0000132/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100133static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000134{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200135 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000136
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100137 /* queue OML messages */
138 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
139 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200140 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100141 } else {
142 msgb_enqueue(&bts->abis_queue, msg);
143 return 0;
144 }
145
146}
147
148int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
149{
150 OBSC_NM_W_ACK_CB(msg) = 1;
151 return abis_nm_queue_msg(bts, msg);
152}
153
154static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
155{
156 OBSC_NM_W_ACK_CB(msg) = 0;
157 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000158}
159
Harald Welte4724f992009-01-18 18:01:49 +0000160static int abis_nm_rcvmsg_sw(struct msgb *mb);
161
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100162int nm_is_running(struct gsm_nm_state *s) {
163 return (s->operational == NM_OPSTATE_ENABLED) && (
164 (s->availability == NM_AVSTATE_OK) ||
165 (s->availability == 0xff)
166 );
167}
168
Harald Weltee0590df2009-02-15 03:34:15 +0000169/* Update the administrative state of a given object in our in-memory data
170 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200171static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
172 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000173{
Harald Welteaeedeb42009-05-01 13:08:14 +0000174 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100175 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000176
Harald Welteaf9b8102011-03-06 21:20:38 +0100177 memset(&nsd, 0, sizeof(nsd));
178
Harald Welte978714d2011-06-06 18:31:20 +0200179 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100180 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100181 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200182 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000183 if (!nm_state)
184 return -1;
185
186 new_state = *nm_state;
187 new_state.administrative = adm_state;
188
Harald Weltef38ca9a2011-03-06 22:11:32 +0100189 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100190 nsd.obj_class = obj_class;
191 nsd.old_state = nm_state;
192 nsd.new_state = &new_state;
193 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200194 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000195
196 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000197
Harald Weltef338a032011-01-14 15:55:42 +0100198 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000199}
200
Harald Welte97ed1e72009-02-06 13:38:02 +0000201static int abis_nm_rx_statechg_rep(struct msgb *mb)
202{
Harald Weltee0590df2009-02-15 03:34:15 +0000203 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000204 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200205 struct e1inp_sign_link *sign_link = mb->dst;
206 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000207 struct tlv_parsed tp;
208 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000209
Harald Welte23897662009-05-01 14:52:51 +0000210 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000211
Harald Welte8b697c72009-06-05 19:18:45 +0000212 memset(&new_state, 0, sizeof(new_state));
213
Harald Welte978714d2011-06-06 18:31:20 +0200214 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000215 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100216 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000217 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000218 }
Harald Weltee0590df2009-02-15 03:34:15 +0000219
220 new_state = *nm_state;
221
Harald Welte39315c42010-01-10 18:01:52 +0100222 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000223 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
224 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200225 DEBUGPC(DNM, "OP_STATE=%s ",
226 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000227 }
228 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000229 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
230 new_state.availability = 0xff;
231 else
232 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200233 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
234 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000235 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100236 } else
237 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000238 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
239 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200240 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200241 get_value_string(abis_nm_adm_state_names,
242 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000243 }
244 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000245
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100246 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
247 new_state.operational != nm_state->operational ||
248 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000249 /* Update the operational state of a given object in our in-memory data
250 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100251 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200252 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100253 nsd.obj_class = foh->obj_class;
254 nsd.old_state = nm_state;
255 nsd.new_state = &new_state;
256 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100257 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200258 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100259 nm_state->operational = new_state.operational;
260 nm_state->availability = new_state.availability;
261 if (nm_state->administrative == 0)
262 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000263 }
264#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000265 if (op_state == 1) {
266 /* try to enable objects that are disabled */
267 abis_nm_opstart(bts, foh->obj_class,
268 foh->obj_inst.bts_nr,
269 foh->obj_inst.trx_nr,
270 foh->obj_inst.ts_nr);
271 }
Harald Weltee0590df2009-02-15 03:34:15 +0000272#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000273 return 0;
274}
275
Maxb1e6b372017-03-15 14:30:21 +0100276static inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type,
277 const char *severity, const uint8_t *p_val,
278 const char *text)
279{
280 enum abis_nm_pcause_type pcause = p_val[0];
281 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
282
283 LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr);
284 if (type)
285 LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type);
286 if (severity)
287 LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity);
288
289 LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
290 get_value_string(abis_nm_pcause_type_names, pcause));
291
292 if (pcause == NM_PCAUSE_T_MANUF)
293 LOGPC(DNM, LOGL_ERROR, "%s, ",
294 get_value_string(abis_mm_event_cause_names, cause));
295 else
296 LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
297
298 if (text) {
299 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text);
300 }
301
302 LOGPC(DNM, LOGL_ERROR, "\n");
303}
304
Maxa18001d2017-04-10 16:47:17 +0200305static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type,
Maxb1e6b372017-03-15 14:30:21 +0100306 const char *severity, const char *text)
307{
308 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
309
310 switch (cause) {
311 case OSMO_EVT_PCU_VERS:
Maxa18001d2017-04-10 16:47:17 +0200312 if (text) {
313 LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text);
314 osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version));
315 } else {
316 LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr);
317 bts->pcu_version[0] = '\0';
318 }
Maxb1e6b372017-03-15 14:30:21 +0100319 break;
320 default:
321 log_oml_fail_rep(bts, type, severity, p_val, text);
322 };
323}
324
Maxa18001d2017-04-10 16:47:17 +0200325static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts)
Harald Welte0db97b22009-05-01 17:22:47 +0000326{
327 struct abis_om_hdr *oh = msgb_l2(mb);
328 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200329 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000330 struct tlv_parsed tp;
Maxb1e6b372017-03-15 14:30:21 +0100331 int rc = 0;
332 const uint8_t *p_val = NULL;
333 char *p_text = NULL;
334 const char *e_type = NULL, *severity = NULL;
Harald Welte0db97b22009-05-01 17:22:47 +0000335
Maxb1e6b372017-03-15 14:30:21 +0100336 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
337 oh->length-sizeof(*foh));
Maxa5e36932017-01-11 11:51:28 +0100338
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100339 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
340 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
Maxb1e6b372017-03-15 14:30:21 +0100341 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val,
342 TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100343 }
Harald Welte0db97b22009-05-01 17:22:47 +0000344
Maxb1e6b372017-03-15 14:30:21 +0100345 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
346 e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
347 NM_ATT_EVENT_TYPE));
Harald Welte0db97b22009-05-01 17:22:47 +0000348
Maxb1e6b372017-03-15 14:30:21 +0100349 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
350 severity = abis_nm_severity_name(*TLVP_VAL(&tp,
351 NM_ATT_SEVERITY));
352
353 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
354 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
355
356 switch (p_val[0]) {
357 case NM_PCAUSE_T_MANUF:
358 handle_manufact_report(bts, p_val, e_type, severity,
359 p_text);
360 break;
361 default:
362 log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
363 };
364 } else {
365 LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without "
366 "Probable Cause?!\n", bts->nr);
367 rc = -EINVAL;
368 }
369
370 if (p_text)
371 talloc_free(p_text);
372
373 return rc;
Harald Welte0db97b22009-05-01 17:22:47 +0000374}
375
Maxb1e6b372017-03-15 14:30:21 +0100376static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
Harald Welte97ed1e72009-02-06 13:38:02 +0000377{
378 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200379 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000380
Harald Welte15c61722011-05-22 22:45:37 +0200381 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000382
Harald Welte97ed1e72009-02-06 13:38:02 +0000383 //nmh->cfg->report_cb(mb, foh);
384
385 switch (mt) {
386 case NM_MT_STATECHG_EVENT_REP:
387 return abis_nm_rx_statechg_rep(mb);
388 break;
Harald Welte34a99682009-02-13 02:41:40 +0000389 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000390 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200391 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000392 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000393 case NM_MT_FAILURE_EVENT_REP:
Maxb1e6b372017-03-15 14:30:21 +0100394 rx_fail_evt_rep(mb, bts);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200395 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000396 break;
Harald Weltec7310382009-08-08 00:02:36 +0200397 case NM_MT_TEST_REP:
398 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200399 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200400 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000401 default:
Harald Welte23897662009-05-01 14:52:51 +0000402 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000403 break;
404
Harald Welte97ed1e72009-02-06 13:38:02 +0000405 };
406
Harald Welte97ed1e72009-02-06 13:38:02 +0000407 return 0;
408}
409
Harald Welte34a99682009-02-13 02:41:40 +0000410/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200411static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
Maxfd2c1f92017-03-24 21:04:57 +0100412 uint8_t i2, const struct abis_nm_sw_desc *sw_desc)
Harald Welte34a99682009-02-13 02:41:40 +0000413{
414 struct abis_om_hdr *oh;
415 struct msgb *msg = nm_msgb_alloc();
Maxfd2c1f92017-03-24 21:04:57 +0100416 uint16_t len = abis_nm_sw_desc_len(sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000417
418 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
419 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
Maxfd2c1f92017-03-24 21:04:57 +0100420 abis_nm_put_sw_desc(msg, sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000421
422 return abis_nm_sendmsg(bts, msg);
423}
424
Maxfd2c1f92017-03-24 21:04:57 +0100425int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr,
426 const size_t size)
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100427{
428 int res = 0;
429 int i;
430
431 for (i = 1; i < size; ++i) {
Maxfd2c1f92017-03-24 21:04:57 +0100432 if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version,
433 OSMO_MIN(sw_descr[i].file_version_len,
434 sw_descr[res].file_version_len)) < 0) {
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100435 res = i;
436 }
437 }
438
439 return res;
440}
441
Max33e13572017-05-29 11:48:29 +0200442static 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 +0200443{
444 switch (id) {
445 case BTS_TYPE_VARIANT:
Max33e13572017-05-29 11:48:29 +0200446 LOGP(DNM, LOGL_NOTICE, "BTS%u reported variant: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200447 break;
448 case BTS_SUB_MODEL:
Max33e13572017-05-29 11:48:29 +0200449 LOGP(DNM, LOGL_NOTICE, "BTS%u reported submodel: %s\n", bts->nr, val);
Maxdefb6c92017-05-15 10:29:54 +0200450 break;
451 default:
452 return false;
453 }
454 return true;
455}
456
Max33e13572017-05-29 11:48:29 +0200457/* Parse Attribute Response Info - return pointer to the actual content */
458static inline uint8_t *parse_attr_resp_info_unreported(uint8_t bts_nr, uint8_t *ari, uint16_t ari_len, uint16_t *out_len)
459{
460 uint8_t num_unreported = ari[0], i;
461
462 DEBUGP(DNM, "BTS%u Get Attributes Response Info: %u bytes total with %u unreported attributes\n",
463 bts_nr, ari_len, num_unreported);
464
465 /* +1 because we have to account for number of unreported attributes, prefixing the list: */
466 for (i = 0; i < num_unreported; i++)
467 LOGP(DNM, LOGL_ERROR, "BTS%u Attribute %s is unreported\n",
468 bts_nr, get_value_string(abis_nm_att_names, ari[i + 1]));
469
470 /* the data starts right after the list of unreported attributes + space for length of that list */
471 *out_len = ari_len - (num_unreported + 2);
472
473 return ari + num_unreported + 1; /* we have to account for 1st byte with number of unreported attributes */
474}
475
Maxc51c1e72017-06-06 15:40:40 +0200476/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.30 Manufacturer Id */
477static inline uint8_t *parse_attr_resp_info_manuf_id(struct gsm_bts *bts, uint8_t *data, uint16_t *data_len)
478{
479 struct tlv_parsed tp;
480 uint16_t m_id_len = 0;
481 uint8_t adjust = 0, i;
482
483 abis_nm_tlv_parse(&tp, bts, data, *data_len);
484 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_ID, 2)) {
485 m_id_len = TLVP_LEN(&tp, NM_ATT_MANUF_ID);
486
Max5a44d252017-06-13 10:15:58 +0200487 /* log potential BTS feature vector overflow */
488 if (m_id_len > sizeof(bts->_features_data))
Maxc51c1e72017-06-06 15:40:40 +0200489 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: feature vector is truncated to %u bytes\n",
490 bts->nr, MAX_BTS_FEATURES/8);
Maxc51c1e72017-06-06 15:40:40 +0200491
Max5a44d252017-06-13 10:15:58 +0200492 /* check that max. expected BTS attribute is above given feature vector length */
493 if (m_id_len > OSMO_BYTES_FOR_BITS(_NUM_BTS_FEAT))
Maxc51c1e72017-06-06 15:40:40 +0200494 LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: reported unexpectedly long (%u bytes) "
495 "feature vector - most likely it was compiled against newer BSC headers. "
496 "Consider upgrading your BSC to later version.\n",
497 bts->nr, m_id_len);
498
Maxa60bb3d2017-06-12 13:45:03 +0200499 memcpy(bts->_features_data, TLVP_VAL(&tp, NM_ATT_MANUF_ID), sizeof(bts->_features_data));
Maxc51c1e72017-06-06 15:40:40 +0200500 adjust = m_id_len + 3; /* adjust for parsed TL16V struct */
501
502 for (i = 0; i < _NUM_BTS_FEAT; i++)
503 if (gsm_bts_has_feature(bts, i) != gsm_btsmodel_has_feature(bts->model, i))
504 LOGP(DNM, LOGL_NOTICE, "BTS%u feature '%s' reported via OML does not match statically "
505 "set feature: %u != %u. Please fix.\n", bts->nr,
506 get_value_string(gsm_bts_features_descs, i),
507 gsm_bts_has_feature(bts, i), gsm_btsmodel_has_feature(bts->model, i));
508 }
509
510 *data_len -= adjust;
511
512 return data + adjust;
513}
514
Max33e13572017-05-29 11:48:29 +0200515/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.28 Manufacturer Dependent State */
516static inline uint8_t *parse_attr_resp_info_manuf_state(const struct gsm_bts_trx *trx, uint8_t *data, uint16_t *data_len)
517{
518 struct tlv_parsed tp;
519 const uint8_t *power;
520 uint8_t adjust = 0;
521
522 if (!trx) /* this attribute does not make sense on BTS level, only on TRX level */
523 return data;
524
525 abis_nm_tlv_parse(&tp, trx->bts, data, *data_len);
526 if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_STATE, 1)) {
527 power = TLVP_VAL(&tp, NM_ATT_MANUF_STATE);
528 LOGP(DNM, LOGL_NOTICE, "%s Get Attributes Response: nominal power is %u\n", gsm_trx_name(trx), *power);
529 adjust = 2; /* adjust for parsed TV struct */
530 }
531
532 *data_len -= adjust;
533
534 return data + adjust;
535}
536
Maxdefb6c92017-05-15 10:29:54 +0200537/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */
Max33e13572017-05-29 11:48:29 +0200538static int abis_nm_rx_get_attr_resp(struct msgb *mb, const struct gsm_bts_trx *trx)
Maxdefb6c92017-05-15 10:29:54 +0200539{
540 struct abis_om_hdr *oh = msgb_l2(mb);
541 struct abis_om_fom_hdr *foh = msgb_l3(mb);
542 struct e1inp_sign_link *sign_link = mb->dst;
Max33e13572017-05-29 11:48:29 +0200543 struct gsm_bts *bts = trx ? trx->bts : sign_link->trx->bts;
Maxdefb6c92017-05-15 10:29:54 +0200544 struct tlv_parsed tp;
Max33e13572017-05-29 11:48:29 +0200545 uint8_t *data, i;
546 uint16_t data_len;
Maxdefb6c92017-05-15 10:29:54 +0200547 int rc;
548 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
549
550 abis_nm_debugp_foh(DNM, foh);
551
Max33e13572017-05-29 11:48:29 +0200552 DEBUGPC(DNM, "Get Attributes Response for BTS%u\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200553
Max33e13572017-05-29 11:48:29 +0200554 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
555 if (!TLVP_PRES_LEN(&tp, NM_ATT_GET_ARI, 1)) {
556 LOGP(DNM, LOGL_ERROR, "BTS%u: Get Attributes Response without Response Info?!\n", bts->nr);
Maxdefb6c92017-05-15 10:29:54 +0200557 return -EINVAL;
558 }
559
Max33e13572017-05-29 11:48:29 +0200560 data = parse_attr_resp_info_unreported(bts->nr, TLVP_VAL(&tp, NM_ATT_GET_ARI), TLVP_LEN(&tp, NM_ATT_GET_ARI),
561 &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200562
Max33e13572017-05-29 11:48:29 +0200563 data = parse_attr_resp_info_manuf_state(trx, data, &data_len);
Maxc51c1e72017-06-06 15:40:40 +0200564 data = parse_attr_resp_info_manuf_id(bts, data, &data_len);
Maxdefb6c92017-05-15 10:29:54 +0200565
Max33e13572017-05-29 11:48:29 +0200566 /* after parsing manufacturer-specific attributes there's list of replies in form of sw-conf structure: */
567 rc = abis_nm_get_sw_conf(data, data_len, &sw_descr[0], ARRAY_SIZE(sw_descr));
Maxdefb6c92017-05-15 10:29:54 +0200568 if (rc > 0) {
569 for (i = 0; i < rc; i++) {
Max33e13572017-05-29 11:48:29 +0200570 if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id),
571 sw_descr[i].file_version, sw_descr[i].file_version_len))
572 LOGP(DNM, LOGL_NOTICE, "BTS%u: ARI reported sw[%d/%d]: %s is %s\n",
573 bts->nr, i, rc, sw_descr[i].file_id, sw_descr[i].file_version);
Maxdefb6c92017-05-15 10:29:54 +0200574 }
575 } else
Max33e13572017-05-29 11:48:29 +0200576 LOGP(DNM, LOGL_ERROR, "BTS%u: failed to parse SW-Config part of Get Attribute Response Info: %s\n",
577 bts->nr, strerror(-rc));
Maxdefb6c92017-05-15 10:29:54 +0200578
579 return 0;
580}
581
Max1ebf23b2017-05-10 12:21:17 +0200582/* 3GPP TS 52.021 §6.2.5 */
Harald Welte34a99682009-02-13 02:41:40 +0000583static int abis_nm_rx_sw_act_req(struct msgb *mb)
584{
585 struct abis_om_hdr *oh = msgb_l2(mb);
586 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200587 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200588 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200589 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100590 int ret, sw_config_len, len;
Max1ebf23b2017-05-10 12:21:17 +0200591 struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
Harald Welte34a99682009-02-13 02:41:40 +0000592
Harald Welte15c61722011-05-22 22:45:37 +0200593 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200594
595 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000596
Harald Welte97a282b2010-03-14 15:37:43 +0800597 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000598
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200599 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000600 foh->obj_inst.bts_nr,
601 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800602 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000603 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100604 if (ret != 0) {
605 LOGP(DNM, LOGL_ERROR,
606 "Sending SW ActReq ACK failed: %d\n", ret);
607 return ret;
608 }
Harald Welte34a99682009-02-13 02:41:40 +0000609
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200610 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200611 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
612 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
613 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100614 LOGP(DNM, LOGL_ERROR,
615 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200616 return -EINVAL;
617 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200618 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200619 }
620
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100621 /* Parse up to two sw descriptions from the data */
Maxfd2c1f92017-03-24 21:04:57 +0100622 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
623 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100624 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100625 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100626 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100627 }
Mike Habena03f9772009-10-01 14:56:13 +0200628
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100629 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
630 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
631
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200632 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000633 foh->obj_inst.bts_nr,
634 foh->obj_inst.trx_nr,
635 foh->obj_inst.ts_nr,
Maxfd2c1f92017-03-24 21:04:57 +0100636 &sw_descr[ret]);
Harald Welte34a99682009-02-13 02:41:40 +0000637}
638
Harald Weltee0590df2009-02-15 03:34:15 +0000639/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
640static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
641{
642 struct abis_om_hdr *oh = msgb_l2(mb);
643 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200644 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000645 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200646 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000647
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200648 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000649 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
650 return -EINVAL;
651
652 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
653
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200654 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000655}
656
Harald Welteee670472009-02-22 21:58:49 +0000657static int abis_nm_rx_lmt_event(struct msgb *mb)
658{
659 struct abis_om_hdr *oh = msgb_l2(mb);
660 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200661 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000662 struct tlv_parsed tp;
663
664 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200665 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000666 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
667 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200668 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000669 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
670 }
671 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
672 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200673 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000674 DEBUGPC(DNM, "Level=%u ", level);
675 }
676 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
677 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
678 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
679 DEBUGPC(DNM, "Username=%s ", name);
680 }
681 DEBUGPC(DNM, "\n");
682 /* FIXME: parse LMT LOGON TIME */
683 return 0;
684}
685
Maxaa954cd2017-11-29 12:18:02 +0100686bool all_trx_rsl_connected_unlocked(const struct gsm_bts *bts)
Max3d049d22017-10-09 17:12:53 +0200687{
688 const struct gsm_bts_trx *trx;
689
Maxaa954cd2017-11-29 12:18:02 +0100690 if (bts->mo.nm_state.administrative == NM_STATE_LOCKED)
691 return false;
692
Max3d049d22017-10-09 17:12:53 +0200693 llist_for_each_entry(trx, &bts->trx_list, list) {
694 if (!trx->rsl_link)
695 return false;
Maxaa954cd2017-11-29 12:18:02 +0100696 if (trx->mo.nm_state.administrative == NM_STATE_LOCKED)
697 return false;
Max3d049d22017-10-09 17:12:53 +0200698 }
699
700 return true;
701}
702
Max3d049d22017-10-09 17:12:53 +0200703char *get_model_oml_status(const struct gsm_bts *bts)
704{
705 if (bts->model->oml_status)
706 return bts->model->oml_status(bts);
707
708 return "unknown";
709}
710
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200711void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100712{
713 int wait = 0;
714 struct msgb *msg;
715 /* the queue is empty */
716 while (!llist_empty(&bts->abis_queue)) {
717 msg = msgb_dequeue(&bts->abis_queue);
718 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200719 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100720
721 if (wait)
722 break;
723 }
724
725 bts->abis_nm_pend = wait;
726}
727
Harald Welte52b1f982008-12-23 20:25:15 +0000728/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000729static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000730{
Harald Welte6c96ba52009-05-01 13:03:40 +0000731 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000732 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200733 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200734 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100735 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
736 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100737 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000738
739 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000740 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100741 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000742
Harald Welte15c61722011-05-22 22:45:37 +0200743 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000744 return abis_nm_rcvmsg_sw(mb);
745
Harald Welte15c61722011-05-22 22:45:37 +0200746 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800747 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000748 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200749
Harald Welte15c61722011-05-22 22:45:37 +0200750 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200751
Harald Welte15c61722011-05-22 22:45:37 +0200752 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000753
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100754 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000755 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200756 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200757 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000758 else
759 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200760
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800761 nack_data.msg = mb;
762 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100763 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200764 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100765 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200766 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000767 }
Harald Weltead384642008-12-26 10:20:07 +0000768#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000769 /* check if last message is to be acked */
770 if (is_ack_nack(nmh->last_msgtype)) {
771 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100772 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000773 /* we got our ACK, continue sending the next msg */
774 } else if (mt == MT_NACK(nmh->last_msgtype)) {
775 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100776 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000777 /* FIXME: somehow signal this to the caller */
778 } else {
779 /* really strange things happen */
780 return -EINVAL;
781 }
782 }
Harald Weltead384642008-12-26 10:20:07 +0000783#endif
784
Harald Welte97ed1e72009-02-06 13:38:02 +0000785 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000786 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100787 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000788 break;
Harald Welte34a99682009-02-13 02:41:40 +0000789 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100790 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000791 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000792 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100793 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000794 break;
Max689e7e52017-04-04 19:21:24 +0200795 case NM_MT_OPSTART_ACK:
796 abis_nm_debugp_foh(DNM, foh);
797 DEBUGPC(DNM, "Opstart ACK\n");
798 break;
799 case NM_MT_SET_CHAN_ATTR_ACK:
800 abis_nm_debugp_foh(DNM, foh);
801 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
802 break;
803 case NM_MT_SET_RADIO_ATTR_ACK:
804 abis_nm_debugp_foh(DNM, foh);
805 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
806 break;
Harald Welte1989c082009-08-06 17:58:31 +0200807 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200808 abis_nm_debugp_foh(DNM, foh);
809 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200810 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100811 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200812 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100813 break;
814 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200815 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100816 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100817 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100818 break;
Maxdefb6c92017-05-15 10:29:54 +0200819 case NM_MT_GET_ATTR_RESP:
Max33e13572017-05-29 11:48:29 +0200820 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Maxdefb6c92017-05-15 10:29:54 +0200821 break;
Max689e7e52017-04-04 19:21:24 +0200822 default:
823 abis_nm_debugp_foh(DNM, foh);
824 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
825 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000826 }
827
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100828 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100829 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000830}
831
Harald Welte677c21f2009-02-17 13:22:23 +0000832static int abis_nm_rx_ipacc(struct msgb *mb);
833
834static int abis_nm_rcvmsg_manuf(struct msgb *mb)
835{
836 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200837 struct e1inp_sign_link *sign_link = mb->dst;
838 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000839
840 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100841 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100842 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000843 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200844 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000845 break;
846 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100847 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
848 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000849 rc = 0;
850 break;
851 }
852
853 return rc;
854}
855
Harald Welte52b1f982008-12-23 20:25:15 +0000856/* High-Level API */
857/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000858int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000859{
Harald Welte52b1f982008-12-23 20:25:15 +0000860 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000861 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000862
863 /* Various consistency checks */
864 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100865 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000866 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200867 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
868 rc = -EINVAL;
869 goto err;
870 }
Harald Welte52b1f982008-12-23 20:25:15 +0000871 }
872 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100873 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000874 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200875 rc = -EINVAL;
876 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000877 }
Harald Welte702d8702008-12-26 20:25:35 +0000878#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200879 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000880 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000881 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100882 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000883 oh->length + sizeof(*oh), l2_len);
884 return -EINVAL;
885 }
Harald Welte702d8702008-12-26 20:25:35 +0000886 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100887 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 +0000888#endif
Harald Weltead384642008-12-26 10:20:07 +0000889 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000890
891 switch (oh->mdisc) {
892 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000893 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000894 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000895 case ABIS_OM_MDISC_MANUF:
896 rc = abis_nm_rcvmsg_manuf(msg);
897 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000898 case ABIS_OM_MDISC_MMI:
899 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100900 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000901 oh->mdisc);
902 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000903 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100904 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000905 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200906 rc = -EINVAL;
907 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000908 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200909err:
Harald Weltead384642008-12-26 10:20:07 +0000910 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000911 return rc;
912}
913
914#if 0
915/* initialized all resources */
916struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
917{
918 struct abis_nm_h *nmh;
919
920 nmh = malloc(sizeof(*nmh));
921 if (!nmh)
922 return NULL;
923
924 nmh->cfg = cfg;
925
926 return nmh;
927}
928
929/* free all resources */
930void abis_nm_fini(struct abis_nm_h *nmh)
931{
932 free(nmh);
933}
934#endif
935
936/* Here we are trying to define a high-level API that can be used by
937 * the actual BSC implementation. However, the architecture is currently
938 * still under design. Ideally the calls to this API would be synchronous,
939 * while the underlying stack behind the APi runs in a traditional select
940 * based state machine.
941 */
942
Harald Welte4724f992009-01-18 18:01:49 +0000943/* 6.2 Software Load: */
944enum sw_state {
945 SW_STATE_NONE,
946 SW_STATE_WAIT_INITACK,
947 SW_STATE_WAIT_SEGACK,
948 SW_STATE_WAIT_ENDACK,
949 SW_STATE_WAIT_ACTACK,
950 SW_STATE_ERROR,
951};
Harald Welte52b1f982008-12-23 20:25:15 +0000952
Harald Welte52b1f982008-12-23 20:25:15 +0000953struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000954 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800955 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000956 gsm_cbfn *cbfn;
957 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000958 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000959
Harald Welte52b1f982008-12-23 20:25:15 +0000960 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200961 uint8_t obj_class;
962 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000963
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200964 uint8_t file_id[255];
965 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000966
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200967 uint8_t file_version[255];
968 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000969
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200970 uint8_t window_size;
971 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000972
973 int fd;
974 FILE *stream;
975 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000976 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000977};
978
Harald Welte4724f992009-01-18 18:01:49 +0000979static struct abis_nm_sw g_sw;
980
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100981static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
982{
983 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
984 msgb_v_put(msg, NM_ATT_SW_DESCR);
985 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
986 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
987 sw->file_version);
988 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
989 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
990 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
991 sw->file_version);
992 } else {
993 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
994 }
995}
996
Harald Welte4724f992009-01-18 18:01:49 +0000997/* 6.2.1 / 8.3.1: Load Data Initiate */
998static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000999{
Harald Welte4724f992009-01-18 18:01:49 +00001000 struct abis_om_hdr *oh;
1001 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001002 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001003
1004 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1005 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1006 sw->obj_instance[0], sw->obj_instance[1],
1007 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001008
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001009 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001010 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1011
1012 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001013}
1014
Harald Welte1602ade2009-01-29 21:12:39 +00001015static int is_last_line(FILE *stream)
1016{
1017 char next_seg_buf[256];
1018 long pos;
1019
1020 /* check if we're sending the last line */
1021 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +02001022
1023 /* Did ftell fail? Then we are at the end for sure */
1024 if (pos < 0)
1025 return 1;
1026
Harald Welte1602ade2009-01-29 21:12:39 +00001027 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +01001028 int rc = fseek(stream, pos, SEEK_SET);
1029 if (rc < 0)
1030 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001031 return 1;
1032 }
1033
1034 fseek(stream, pos, SEEK_SET);
1035 return 0;
1036}
1037
Harald Welte4724f992009-01-18 18:01:49 +00001038/* 6.2.2 / 8.3.2 Load Data Segment */
1039static int sw_load_segment(struct abis_nm_sw *sw)
1040{
1041 struct abis_om_hdr *oh;
1042 struct msgb *msg = nm_msgb_alloc();
1043 char seg_buf[256];
1044 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001045 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +02001046 int len;
Harald Welte4724f992009-01-18 18:01:49 +00001047
1048 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001049
1050 switch (sw->bts->type) {
1051 case GSM_BTS_TYPE_BS11:
1052 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1053 perror("fgets reading segment");
1054 return -EINVAL;
1055 }
1056 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001057
1058 /* check if we're sending the last line */
1059 sw->last_seg = is_last_line(sw->stream);
1060 if (sw->last_seg)
1061 seg_buf[1] = 0;
1062 else
1063 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001064
1065 len = strlen(line_buf) + 2;
1066 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001067 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001068 /* BS11 wants CR + LF in excess of the TLV length !?! */
1069 tlv[1] -= 2;
1070
1071 /* we only now know the exact length for the OM hdr */
1072 len = strlen(line_buf)+2;
1073 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001074 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001075 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001076 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1077 if (len < 0) {
1078 perror("read failed");
1079 return -EINVAL;
1080 }
1081
1082 if (len != IPACC_SEGMENT_SIZE)
1083 sw->last_seg = 1;
1084
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001085 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001086 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001087 len += 3;
1088 break;
1089 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001090 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001091 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001092 /* FIXME: Other BTS types */
1093 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001094 }
Harald Welte4724f992009-01-18 18:01:49 +00001095
Harald Welte4724f992009-01-18 18:01:49 +00001096 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1097 sw->obj_instance[0], sw->obj_instance[1],
1098 sw->obj_instance[2]);
1099
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001100 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001101}
1102
1103/* 6.2.4 / 8.3.4 Load Data End */
1104static int sw_load_end(struct abis_nm_sw *sw)
1105{
1106 struct abis_om_hdr *oh;
1107 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001108 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001109
1110 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1111 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1112 sw->obj_instance[0], sw->obj_instance[1],
1113 sw->obj_instance[2]);
1114
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001115 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001116 return abis_nm_sendmsg(sw->bts, msg);
1117}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001118
Harald Welte52b1f982008-12-23 20:25:15 +00001119/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001120static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001121{
Harald Welte4724f992009-01-18 18:01:49 +00001122 struct abis_om_hdr *oh;
1123 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001124 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001125
Harald Welte4724f992009-01-18 18:01:49 +00001126 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1127 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1128 sw->obj_instance[0], sw->obj_instance[1],
1129 sw->obj_instance[2]);
1130
1131 /* FIXME: this is BS11 specific format */
1132 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1133 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1134 sw->file_version);
1135
1136 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001137}
Harald Welte4724f992009-01-18 18:01:49 +00001138
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001139struct sdp_firmware {
1140 char magic[4];
1141 char more_magic[4];
1142 unsigned int header_length;
1143 unsigned int file_length;
1144} __attribute__ ((packed));
1145
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001146static int parse_sdp_header(struct abis_nm_sw *sw)
1147{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001148 struct sdp_firmware firmware_header;
1149 int rc;
1150 struct stat stat;
1151
1152 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1153 if (rc != sizeof(firmware_header)) {
1154 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1155 return -1;
1156 }
1157
1158 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1159 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1160 return -1;
1161 }
1162
1163 if (firmware_header.more_magic[0] != 0x10 ||
1164 firmware_header.more_magic[1] != 0x02 ||
1165 firmware_header.more_magic[2] != 0x00 ||
1166 firmware_header.more_magic[3] != 0x00) {
1167 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1168 return -1;
1169 }
1170
1171
1172 if (fstat(sw->fd, &stat) == -1) {
1173 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1174 return -1;
1175 }
1176
1177 if (ntohl(firmware_header.file_length) != stat.st_size) {
1178 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1179 return -1;
1180 }
1181
1182 /* go back to the start as we checked the whole filesize.. */
1183 lseek(sw->fd, 0l, SEEK_SET);
1184 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1185 "There might be checksums in the file that are not\n"
1186 "verified and incomplete firmware might be flashed.\n"
1187 "There is absolutely no WARRANTY that flashing will\n"
1188 "work.\n");
1189 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001190}
1191
Harald Welte4724f992009-01-18 18:01:49 +00001192static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1193{
1194 char file_id[12+1];
1195 char file_version[80+1];
1196 int rc;
1197
1198 sw->fd = open(fname, O_RDONLY);
1199 if (sw->fd < 0)
1200 return sw->fd;
1201
1202 switch (sw->bts->type) {
1203 case GSM_BTS_TYPE_BS11:
1204 sw->stream = fdopen(sw->fd, "r");
1205 if (!sw->stream) {
1206 perror("fdopen");
1207 return -1;
1208 }
1209 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001210 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001211 file_id, file_version);
1212 if (rc != 2) {
1213 perror("parsing header line of software file");
1214 return -1;
1215 }
1216 strcpy((char *)sw->file_id, file_id);
1217 sw->file_id_len = strlen(file_id);
1218 strcpy((char *)sw->file_version, file_version);
1219 sw->file_version_len = strlen(file_version);
1220 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001221 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001222 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001223 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001224 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001225 rc = parse_sdp_header(sw);
1226 if (rc < 0) {
1227 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1228 return -1;
1229 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001230
1231 strcpy((char *)sw->file_id, "id");
1232 sw->file_id_len = 3;
1233 strcpy((char *)sw->file_version, "version");
1234 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001235 break;
Harald Welte4724f992009-01-18 18:01:49 +00001236 default:
1237 /* We don't know how to treat them yet */
1238 close(sw->fd);
1239 return -EINVAL;
1240 }
1241
1242 return 0;
1243}
1244
1245static void sw_close_file(struct abis_nm_sw *sw)
1246{
1247 switch (sw->bts->type) {
1248 case GSM_BTS_TYPE_BS11:
1249 fclose(sw->stream);
1250 break;
1251 default:
1252 close(sw->fd);
1253 break;
1254 }
1255}
1256
1257/* Fill the window */
1258static int sw_fill_window(struct abis_nm_sw *sw)
1259{
1260 int rc;
1261
1262 while (sw->seg_in_window < sw->window_size) {
1263 rc = sw_load_segment(sw);
1264 if (rc < 0)
1265 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001266 if (sw->last_seg)
1267 break;
Harald Welte4724f992009-01-18 18:01:49 +00001268 }
1269 return 0;
1270}
1271
1272/* callback function from abis_nm_rcvmsg() handler */
1273static int abis_nm_rcvmsg_sw(struct msgb *mb)
1274{
1275 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001276 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001277 int rc = -1;
1278 struct abis_nm_sw *sw = &g_sw;
1279 enum sw_state old_state = sw->state;
1280
Harald Welte3ffd1372009-02-01 22:15:49 +00001281 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001282
1283 switch (sw->state) {
1284 case SW_STATE_WAIT_INITACK:
1285 switch (foh->msg_type) {
1286 case NM_MT_LOAD_INIT_ACK:
1287 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001288 if (sw->cbfn)
1289 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1290 NM_MT_LOAD_INIT_ACK, mb,
1291 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001292 rc = sw_fill_window(sw);
1293 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001294 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001295 break;
1296 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001297 if (sw->forced) {
1298 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1299 "Init NACK\n");
1300 if (sw->cbfn)
1301 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1302 NM_MT_LOAD_INIT_ACK, mb,
1303 sw->cb_data, NULL);
1304 rc = sw_fill_window(sw);
1305 sw->state = SW_STATE_WAIT_SEGACK;
1306 } else {
1307 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001308 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001309 if (sw->cbfn)
1310 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1311 NM_MT_LOAD_INIT_NACK, mb,
1312 sw->cb_data, NULL);
1313 sw->state = SW_STATE_ERROR;
1314 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001315 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001316 break;
1317 }
1318 break;
1319 case SW_STATE_WAIT_SEGACK:
1320 switch (foh->msg_type) {
1321 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001322 if (sw->cbfn)
1323 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1324 NM_MT_LOAD_SEG_ACK, mb,
1325 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001326 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001327 if (!sw->last_seg) {
1328 /* fill window with more segments */
1329 rc = sw_fill_window(sw);
1330 sw->state = SW_STATE_WAIT_SEGACK;
1331 } else {
1332 /* end the transfer */
1333 sw->state = SW_STATE_WAIT_ENDACK;
1334 rc = sw_load_end(sw);
1335 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001336 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001337 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001338 case NM_MT_LOAD_ABORT:
1339 if (sw->cbfn)
1340 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1341 NM_MT_LOAD_ABORT, mb,
1342 sw->cb_data, NULL);
1343 break;
Harald Welte4724f992009-01-18 18:01:49 +00001344 }
1345 break;
1346 case SW_STATE_WAIT_ENDACK:
1347 switch (foh->msg_type) {
1348 case NM_MT_LOAD_END_ACK:
1349 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001350 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1351 sw->bts->nr);
1352 sw->state = SW_STATE_NONE;
1353 if (sw->cbfn)
1354 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1355 NM_MT_LOAD_END_ACK, mb,
1356 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001357 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001358 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001359 break;
1360 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001361 if (sw->forced) {
1362 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1363 "End NACK\n");
1364 sw->state = SW_STATE_NONE;
1365 if (sw->cbfn)
1366 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1367 NM_MT_LOAD_END_ACK, mb,
1368 sw->cb_data, NULL);
1369 } else {
1370 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001371 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001372 sw->state = SW_STATE_ERROR;
1373 if (sw->cbfn)
1374 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1375 NM_MT_LOAD_END_NACK, mb,
1376 sw->cb_data, NULL);
1377 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001378 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001379 break;
1380 }
1381 case SW_STATE_WAIT_ACTACK:
1382 switch (foh->msg_type) {
1383 case NM_MT_ACTIVATE_SW_ACK:
1384 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001385 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001386 sw->state = SW_STATE_NONE;
1387 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001388 if (sw->cbfn)
1389 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1390 NM_MT_ACTIVATE_SW_ACK, mb,
1391 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001392 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001393 break;
1394 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001395 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001396 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001397 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001398 if (sw->cbfn)
1399 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1400 NM_MT_ACTIVATE_SW_NACK, mb,
1401 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001402 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001403 break;
1404 }
1405 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001406 switch (foh->msg_type) {
1407 case NM_MT_ACTIVATE_SW_ACK:
1408 rc = 0;
1409 break;
1410 }
1411 break;
Harald Welte4724f992009-01-18 18:01:49 +00001412 case SW_STATE_ERROR:
1413 break;
1414 }
1415
1416 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001417 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001418 foh->msg_type, old_state, sw->state);
1419
1420 return rc;
1421}
1422
1423/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001424int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001425 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001426 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001427{
1428 struct abis_nm_sw *sw = &g_sw;
1429 int rc;
1430
Harald Welte5e4d1b32009-02-01 13:36:56 +00001431 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1432 bts->nr, fname);
1433
Harald Welte4724f992009-01-18 18:01:49 +00001434 if (sw->state != SW_STATE_NONE)
1435 return -EBUSY;
1436
1437 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001438 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001439
1440 switch (bts->type) {
1441 case GSM_BTS_TYPE_BS11:
1442 sw->obj_class = NM_OC_SITE_MANAGER;
1443 sw->obj_instance[0] = 0xff;
1444 sw->obj_instance[1] = 0xff;
1445 sw->obj_instance[2] = 0xff;
1446 break;
1447 case GSM_BTS_TYPE_NANOBTS:
1448 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001449 sw->obj_instance[0] = sw->bts->nr;
1450 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001451 sw->obj_instance[2] = 0xff;
1452 break;
1453 case GSM_BTS_TYPE_UNKNOWN:
1454 default:
1455 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1456 return -1;
1457 break;
1458 }
Harald Welte4724f992009-01-18 18:01:49 +00001459 sw->window_size = win_size;
1460 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001461 sw->cbfn = cbfn;
1462 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001463 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001464
1465 rc = sw_open_file(sw, fname);
1466 if (rc < 0) {
1467 sw->state = SW_STATE_NONE;
1468 return rc;
1469 }
1470
1471 return sw_load_init(sw);
1472}
Harald Welte52b1f982008-12-23 20:25:15 +00001473
Harald Welte1602ade2009-01-29 21:12:39 +00001474int abis_nm_software_load_status(struct gsm_bts *bts)
1475{
1476 struct abis_nm_sw *sw = &g_sw;
1477 struct stat st;
1478 int rc, percent;
1479
1480 rc = fstat(sw->fd, &st);
1481 if (rc < 0) {
1482 perror("ERROR during stat");
1483 return rc;
1484 }
1485
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001486 if (sw->stream)
1487 percent = (ftell(sw->stream) * 100) / st.st_size;
1488 else
1489 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001490 return percent;
1491}
1492
Harald Welte5e4d1b32009-02-01 13:36:56 +00001493/* Activate the specified software into the BTS */
1494int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1495 gsm_cbfn *cbfn, void *cb_data)
1496{
1497 struct abis_nm_sw *sw = &g_sw;
1498 int rc;
1499
1500 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1501 bts->nr, fname);
1502
1503 if (sw->state != SW_STATE_NONE)
1504 return -EBUSY;
1505
1506 sw->bts = bts;
1507 sw->obj_class = NM_OC_SITE_MANAGER;
1508 sw->obj_instance[0] = 0xff;
1509 sw->obj_instance[1] = 0xff;
1510 sw->obj_instance[2] = 0xff;
1511 sw->state = SW_STATE_WAIT_ACTACK;
1512 sw->cbfn = cbfn;
1513 sw->cb_data = cb_data;
1514
1515 /* Open the file in order to fill some sw struct members */
1516 rc = sw_open_file(sw, fname);
1517 if (rc < 0) {
1518 sw->state = SW_STATE_NONE;
1519 return rc;
1520 }
1521 sw_close_file(sw);
1522
1523 return sw_activate(sw);
1524}
1525
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001526static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1527 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001528{
Harald Welteadaf08b2009-01-18 11:08:10 +00001529 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001530 ch->bts_port = bts_port;
1531 ch->timeslot = ts_nr;
1532 ch->subslot = subslot_nr;
1533}
1534
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001535int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1536 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1537 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001538{
1539 struct abis_om_hdr *oh;
1540 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001541 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001542 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001543
1544 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1545 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1546 bts->bts_nr, trx_nr, 0xff);
1547
Harald Welte8470bf22008-12-25 23:28:35 +00001548 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001549
1550 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1551 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1552
1553 return abis_nm_sendmsg(bts, msg);
1554}
1555
1556/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1557int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001558 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001559{
Harald Welte8470bf22008-12-25 23:28:35 +00001560 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001561 struct abis_om_hdr *oh;
1562 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001563 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001564
1565 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001566 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001567 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1568
1569 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1570 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1571
1572 return abis_nm_sendmsg(bts, msg);
1573}
1574
1575#if 0
1576int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1577 struct abis_nm_abis_channel *chan)
1578{
1579}
1580#endif
1581
1582int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001583 uint8_t e1_port, uint8_t e1_timeslot,
1584 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001585{
1586 struct gsm_bts *bts = ts->trx->bts;
1587 struct abis_om_hdr *oh;
1588 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001589 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001590
1591 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1592 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001593 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001594
1595 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1596 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1597
Harald Weltef325eb42009-02-19 17:07:39 +00001598 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1599 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001600 e1_port, e1_timeslot, e1_subslot);
1601
Harald Welte52b1f982008-12-23 20:25:15 +00001602 return abis_nm_sendmsg(bts, msg);
1603}
1604
1605#if 0
1606int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1607 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001608 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001609{
1610}
1611#endif
1612
Max1ebf23b2017-05-10 12:21:17 +02001613/* 3GPP TS 52.021 § 8.11.1 */
1614int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1615 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001616{
1617 struct abis_om_hdr *oh;
Maxe3dbd5d2017-06-09 17:15:45 +02001618 struct msgb *msg;
1619
1620 if (bts->type != GSM_BTS_TYPE_OSMOBTS) {
1621 LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n",
1622 bts->nr, btstype2str(bts->type));
1623 return -EINVAL;
1624 }
Harald Weltefe568f22012-08-14 19:15:57 +02001625
1626 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1627
Maxe3dbd5d2017-06-09 17:15:45 +02001628 msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001629 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1630 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1631 bts_nr, trx_nr, ts_nr);
1632 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1633
1634 return abis_nm_sendmsg(bts, msg);
1635}
1636
Harald Welte22af0db2009-02-14 15:41:08 +00001637/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001638int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001639{
1640 struct abis_om_hdr *oh;
1641 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001642 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001643
1644 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1645
1646 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001647 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 +00001648 cur = msgb_put(msg, attr_len);
1649 memcpy(cur, attr, attr_len);
1650
1651 return abis_nm_sendmsg(bts, msg);
1652}
1653
1654/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001655int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001656{
1657 struct abis_om_hdr *oh;
1658 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001659 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001660
1661 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1662
1663 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1664 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001665 trx->bts->bts_nr, trx->nr, 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(trx->bts, msg);
1670}
1671
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001672int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1673{
1674 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1675 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1676}
1677
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001678static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1679 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001680{
1681 int i;
1682
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001683 *reason = "Reason unknown";
1684
Harald Welte39c7deb2009-08-09 21:49:48 +02001685 /* As it turns out, the BS-11 has some very peculiar restrictions
1686 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301687 switch (ts->trx->bts->type) {
1688 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001689 switch (chan_comb) {
1690 case NM_CHANC_TCHHalf:
1691 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001692 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001693 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001694 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001695 return -EINVAL;
1696 case NM_CHANC_SDCCH:
1697 /* only one SDCCH/8 per TRX */
1698 for (i = 0; i < TRX_NR_TS; i++) {
1699 if (i == ts->nr)
1700 continue;
1701 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001702 NM_CHANC_SDCCH) {
1703 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001704 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001705 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001706 }
1707 /* not allowed for TS0 of BCCH-TRX */
1708 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001709 ts->nr == 0) {
1710 *reason = "SDCCH/8 must be on TS0.";
1711 return -EINVAL;
1712 }
1713
Harald Welte39c7deb2009-08-09 21:49:48 +02001714 /* not on the same TRX that has a BCCH+SDCCH4
1715 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001716 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001717 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001718 ts->trx->ts[0].nm_chan_comb == 8)) {
1719 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1720 return -EINVAL;
1721 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001722 break;
1723 case NM_CHANC_mainBCCH:
1724 case NM_CHANC_BCCHComb:
1725 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001726 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1727 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001728 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001729 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001730 break;
1731 case NM_CHANC_BCCH:
1732 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001733 if (ts->trx != ts->trx->bts->c0) {
1734 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001735 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001736 }
1737 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1738 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001739 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001740 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001741 break;
1742 case 8: /* this is not like 08.58, but in fact
1743 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1744 /* FIXME: only one CBCH allowed per cell */
1745 break;
1746 }
Harald Welted6575f92009-12-02 02:45:23 +05301747 break;
1748 case GSM_BTS_TYPE_NANOBTS:
1749 switch (ts->nr) {
1750 case 0:
1751 if (ts->trx->nr == 0) {
1752 /* only on TRX0 */
1753 switch (chan_comb) {
1754 case NM_CHANC_BCCH:
1755 case NM_CHANC_mainBCCH:
1756 case NM_CHANC_BCCHComb:
1757 return 0;
1758 break;
1759 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001760 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301761 return -EINVAL;
1762 }
1763 } else {
1764 switch (chan_comb) {
1765 case NM_CHANC_TCHFull:
1766 case NM_CHANC_TCHHalf:
1767 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1768 return 0;
1769 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001770 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301771 return -EINVAL;
1772 }
1773 }
1774 break;
1775 case 1:
1776 if (ts->trx->nr == 0) {
1777 switch (chan_comb) {
1778 case NM_CHANC_SDCCH_CBCH:
1779 if (ts->trx->ts[0].nm_chan_comb ==
1780 NM_CHANC_mainBCCH)
1781 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001782 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301783 return -EINVAL;
1784 case NM_CHANC_SDCCH:
1785 case NM_CHANC_TCHFull:
1786 case NM_CHANC_TCHHalf:
1787 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1788 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001789 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301790 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001791 default:
1792 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1793 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301794 }
1795 } else {
1796 switch (chan_comb) {
1797 case NM_CHANC_SDCCH:
1798 case NM_CHANC_TCHFull:
1799 case NM_CHANC_TCHHalf:
1800 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1801 return 0;
1802 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001803 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301804 return -EINVAL;
1805 }
1806 }
1807 break;
1808 case 2:
1809 case 3:
1810 case 4:
1811 case 5:
1812 case 6:
1813 case 7:
1814 switch (chan_comb) {
1815 case NM_CHANC_TCHFull:
1816 case NM_CHANC_TCHHalf:
1817 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1818 return 0;
1819 case NM_CHANC_IPAC_PDCH:
1820 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001821 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301822 if (ts->trx->nr == 0)
1823 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001824 else {
1825 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301826 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001827 }
Harald Welted6575f92009-12-02 02:45:23 +05301828 }
1829 break;
1830 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001831 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301832 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001833 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001834 /* no known restrictions */
1835 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301836 default:
1837 /* unknown BTS type */
1838 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001839 }
1840 return 0;
1841}
1842
Harald Welte22af0db2009-02-14 15:41:08 +00001843/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001844int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001845{
1846 struct gsm_bts *bts = ts->trx->bts;
1847 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001848 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001849 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001850 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001851 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001852
1853 if (bts->type == GSM_BTS_TYPE_BS11)
1854 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001855
Harald Weltef325eb42009-02-19 17:07:39 +00001856 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001857 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001858 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001859 LOGP(DNM, LOGL_ERROR,
1860 "Invalid Channel Combination %d on %s. Reason: %s\n",
1861 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001862 return -EINVAL;
1863 }
1864 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001865
Harald Welte52b1f982008-12-23 20:25:15 +00001866 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001867 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001868 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001869 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001870 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001871 if (ts->hopping.enabled) {
1872 unsigned int i;
1873 uint8_t *len;
1874
Harald Welte6e0cd042009-09-12 13:05:33 +02001875 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1876 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001877
1878 /* build the ARFCN list */
1879 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1880 len = msgb_put(msg, 1);
1881 *len = 0;
1882 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1883 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1884 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001885 /* At least BS-11 wants a TLV16 here */
1886 if (bts->type == GSM_BTS_TYPE_BS11)
1887 *len += 1;
1888 else
1889 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001890 }
1891 }
Harald Weltee0590df2009-02-15 03:34:15 +00001892 }
Harald Welte1fe24122014-01-19 17:18:21 +01001893 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001894 if (bts->type == GSM_BTS_TYPE_BS11)
1895 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001896
1897 return abis_nm_sendmsg(bts, msg);
1898}
1899
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001900int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1901 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001902{
1903 struct abis_om_hdr *oh;
1904 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001905 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1906 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001907
1908 if (nack) {
1909 len += 2;
1910 msgtype = NM_MT_SW_ACT_REQ_NACK;
1911 }
Harald Welte34a99682009-02-13 02:41:40 +00001912
1913 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001914 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1915
Harald Welte34a99682009-02-13 02:41:40 +00001916 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001917 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001918 memcpy(ptr, attr, att_len);
1919 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001920 if (nack)
1921 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001922
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001923 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001924}
1925
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001926int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001927{
Harald Welte8470bf22008-12-25 23:28:35 +00001928 struct msgb *msg = nm_msgb_alloc();
1929 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001930 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001931
1932 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1933 fill_om_hdr(oh, len);
1934 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001935 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001936
1937 return abis_nm_sendmsg(bts, msg);
1938}
1939
1940/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001941static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001942{
1943 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001944 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001945
1946 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001947 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001948 0xff, 0xff, 0xff);
1949
1950 return abis_nm_sendmsg(bts, msg);
1951}
1952
Harald Welte34a99682009-02-13 02:41:40 +00001953/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001954int 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 +00001955{
1956 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001957 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001958 struct msgb *msg = nm_msgb_alloc();
1959
1960 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001961 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001962
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001963 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001964 DEBUGPC(DNM, "Sending OPSTART\n");
1965
Harald Welte34a99682009-02-13 02:41:40 +00001966 return abis_nm_sendmsg(bts, msg);
1967}
1968
1969/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001970int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1971 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001972{
1973 struct abis_om_hdr *oh;
1974 struct msgb *msg = nm_msgb_alloc();
1975
1976 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1977 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1978 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1979
1980 return abis_nm_sendmsg(bts, msg);
1981}
1982
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001983int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1984 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001985{
1986 struct abis_om_hdr *oh;
1987 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001988 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001989
1990 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1991 e1_port0, ts0, e1_port1, ts1);
1992
1993 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1994 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1995 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1996
1997 attr = msgb_put(msg, 3);
1998 attr[0] = NM_ATT_MDROP_LINK;
1999 attr[1] = e1_port0;
2000 attr[2] = ts0;
2001
2002 attr = msgb_put(msg, 3);
2003 attr[0] = NM_ATT_MDROP_NEXT;
2004 attr[1] = e1_port1;
2005 attr[2] = ts1;
2006
2007 return abis_nm_sendmsg(bts, msg);
2008}
Harald Welte34a99682009-02-13 02:41:40 +00002009
Harald Weltec7310382009-08-08 00:02:36 +02002010/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002011int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2012 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2013 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002014{
2015 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002016
Harald Welte15c61722011-05-22 22:45:37 +02002017 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002018
2019 if (!msg)
2020 msg = nm_msgb_alloc();
2021
2022 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2023 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2024 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2025 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002026 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002027
2028 return abis_nm_sendmsg(bts, msg);
2029}
2030
Harald Welte52b1f982008-12-23 20:25:15 +00002031int abis_nm_event_reports(struct gsm_bts *bts, int on)
2032{
2033 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002034 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002035 else
Harald Welte227d4072009-01-03 08:16:25 +00002036 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002037}
2038
Harald Welte47d88ae2009-01-04 12:02:08 +00002039/* Siemens (or BS-11) specific commands */
2040
Harald Welte3ffd1372009-02-01 22:15:49 +00002041int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2042{
2043 if (reconnect == 0)
2044 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2045 else
2046 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2047}
2048
Harald Welteb8427972009-02-05 19:27:17 +00002049int abis_nm_bs11_restart(struct gsm_bts *bts)
2050{
2051 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2052}
2053
2054
Harald Welte268bb402009-02-01 19:11:56 +00002055struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002056 uint16_t year;
2057 uint8_t month;
2058 uint8_t day;
2059 uint8_t hour;
2060 uint8_t min;
2061 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002062} __attribute__((packed));
2063
2064
2065void get_bs11_date_time(struct bs11_date_time *aet)
2066{
2067 time_t t;
2068 struct tm *tm;
2069
2070 t = time(NULL);
2071 tm = localtime(&t);
2072 aet->sec = tm->tm_sec;
2073 aet->min = tm->tm_min;
2074 aet->hour = tm->tm_hour;
2075 aet->day = tm->tm_mday;
2076 aet->month = tm->tm_mon;
2077 aet->year = htons(1900 + tm->tm_year);
2078}
2079
Harald Welte05188ee2009-01-18 11:39:08 +00002080int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002081{
Harald Welte4668fda2009-01-03 08:19:29 +00002082 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002083}
2084
Harald Welte05188ee2009-01-18 11:39:08 +00002085int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002086{
2087 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002088 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002089 else
Harald Welte4668fda2009-01-03 08:19:29 +00002090 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002091}
Harald Welte47d88ae2009-01-04 12:02:08 +00002092
Harald Welte05188ee2009-01-18 11:39:08 +00002093int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002094 enum abis_bs11_objtype type, uint8_t idx,
2095 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002096{
2097 struct abis_om_hdr *oh;
2098 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002099 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002100
2101 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002102 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002103 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002104 cur = msgb_put(msg, attr_len);
2105 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002106
2107 return abis_nm_sendmsg(bts, msg);
2108}
2109
Harald Welte78fc0d42009-02-19 02:50:57 +00002110int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002111 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002112{
2113 struct abis_om_hdr *oh;
2114 struct msgb *msg = nm_msgb_alloc();
2115
2116 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2117 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2118 NM_OC_BS11, type, 0, idx);
2119
2120 return abis_nm_sendmsg(bts, msg);
2121}
2122
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002123int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002124{
2125 struct abis_om_hdr *oh;
2126 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002127 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002128
2129 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002130 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002131 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2132 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002133
2134 return abis_nm_sendmsg(bts, msg);
2135}
2136
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002137int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002138{
2139 struct abis_om_hdr *oh;
2140 struct msgb *msg = nm_msgb_alloc();
2141
2142 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2143 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002144 idx, 0xff, 0xff);
2145
2146 return abis_nm_sendmsg(bts, msg);
2147}
2148
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002149int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002150{
2151 struct abis_om_hdr *oh;
2152 struct msgb *msg = nm_msgb_alloc();
2153
2154 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2155 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2156 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002157
2158 return abis_nm_sendmsg(bts, msg);
2159}
Harald Welte05188ee2009-01-18 11:39:08 +00002160
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002161static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002162int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2163{
2164 struct abis_om_hdr *oh;
2165 struct msgb *msg = nm_msgb_alloc();
2166
2167 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2168 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2169 0xff, 0xff, 0xff);
2170 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2171
2172 return abis_nm_sendmsg(bts, msg);
2173}
2174
Harald Welteb6c92ae2009-02-21 20:15:32 +00002175/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002176int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2177 uint8_t e1_timeslot, uint8_t e1_subslot,
2178 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002179{
2180 struct abis_om_hdr *oh;
2181 struct abis_nm_channel *ch;
2182 struct msgb *msg = nm_msgb_alloc();
2183
2184 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002185 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002186 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2187
2188 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2189 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002190 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002191
2192 return abis_nm_sendmsg(bts, msg);
2193}
2194
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002195int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002196{
2197 struct abis_om_hdr *oh;
2198 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002199
2200 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002201 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002202 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2203 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2204
2205 return abis_nm_sendmsg(trx->bts, msg);
2206}
2207
Harald Welte78fc0d42009-02-19 02:50:57 +00002208int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2209{
2210 struct abis_om_hdr *oh;
2211 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002212 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002213
2214 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2215 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2216 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2217 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2218
2219 return abis_nm_sendmsg(trx->bts, msg);
2220}
2221
Harald Welteaaf02d92009-04-29 13:25:57 +00002222int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2223{
2224 struct abis_om_hdr *oh;
2225 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002226 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002227
2228 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2229 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2230 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002231 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002232
2233 return abis_nm_sendmsg(bts, msg);
2234}
2235
Harald Welteef061952009-05-17 12:43:42 +00002236int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2237{
2238 struct abis_om_hdr *oh;
2239 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002240 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002241 NM_ATT_BS11_CCLK_TYPE };
2242
2243 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2244 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2245 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2246 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2247
2248 return abis_nm_sendmsg(bts, msg);
2249
2250}
Harald Welteaaf02d92009-04-29 13:25:57 +00002251
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002252//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002253
Harald Welte1bc09062009-01-18 14:17:52 +00002254int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002255{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002256 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2257}
2258
Daniel Willmann4b054c82010-01-07 00:46:26 +01002259int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2260{
2261 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2262}
2263
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002264int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002265{
Harald Welte05188ee2009-01-18 11:39:08 +00002266 struct abis_om_hdr *oh;
2267 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002268 struct bs11_date_time bdt;
2269
2270 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002271
2272 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002273 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002274 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002275 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002276 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002277 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002278 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002279 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002280 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002281 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002282 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002283 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002284 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002285 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002286 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002287 }
Harald Welte05188ee2009-01-18 11:39:08 +00002288
2289 return abis_nm_sendmsg(bts, msg);
2290}
Harald Welte1bc09062009-01-18 14:17:52 +00002291
2292int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2293{
2294 struct abis_om_hdr *oh;
2295 struct msgb *msg;
2296
2297 if (strlen(password) != 10)
2298 return -EINVAL;
2299
2300 msg = nm_msgb_alloc();
2301 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002302 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002303 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002304 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002305
2306 return abis_nm_sendmsg(bts, msg);
2307}
2308
Harald Weltee69f5fb2009-04-28 16:31:38 +00002309/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2310int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2311{
2312 struct abis_om_hdr *oh;
2313 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002314 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002315
2316 msg = nm_msgb_alloc();
2317 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2318 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2319 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002320
2321 if (locked)
2322 tlv_value = BS11_LI_PLL_LOCKED;
2323 else
2324 tlv_value = BS11_LI_PLL_STANDALONE;
2325
2326 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002327
2328 return abis_nm_sendmsg(bts, msg);
2329}
2330
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002331/* Set the calibration value of the PLL (work value/set value)
2332 * It depends on the login which one is changed */
2333int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2334{
2335 struct abis_om_hdr *oh;
2336 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002337 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002338
2339 msg = nm_msgb_alloc();
2340 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2341 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2342 BS11_OBJ_TRX1, 0x00, 0x00);
2343
2344 tlv_value[0] = value>>8;
2345 tlv_value[1] = value&0xff;
2346
2347 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2348
2349 return abis_nm_sendmsg(bts, msg);
2350}
2351
Harald Welte1bc09062009-01-18 14:17:52 +00002352int abis_nm_bs11_get_state(struct gsm_bts *bts)
2353{
2354 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2355}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002356
2357/* BS11 SWL */
2358
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002359void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002360
Harald Welte5e4d1b32009-02-01 13:36:56 +00002361struct abis_nm_bs11_sw {
2362 struct gsm_bts *bts;
2363 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002364 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002365 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002366 struct llist_head file_list;
2367 gsm_cbfn *user_cb; /* specified by the user */
2368};
2369static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2370
2371struct file_list_entry {
2372 struct llist_head list;
2373 char fname[PATH_MAX];
2374};
2375
2376struct file_list_entry *fl_dequeue(struct llist_head *queue)
2377{
2378 struct llist_head *lh;
2379
2380 if (llist_empty(queue))
2381 return NULL;
2382
2383 lh = queue->next;
2384 llist_del(lh);
2385
2386 return llist_entry(lh, struct file_list_entry, list);
2387}
2388
2389static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2390{
2391 char linebuf[255];
2392 struct llist_head *lh, *lh2;
2393 FILE *swl;
2394 int rc = 0;
2395
2396 swl = fopen(bs11_sw->swl_fname, "r");
2397 if (!swl)
2398 return -ENODEV;
2399
2400 /* zero the stale file list, if any */
2401 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2402 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002403 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002404 }
2405
2406 while (fgets(linebuf, sizeof(linebuf), swl)) {
2407 char file_id[12+1];
2408 char file_version[80+1];
2409 struct file_list_entry *fle;
2410 static char dir[PATH_MAX];
2411
2412 if (strlen(linebuf) < 4)
2413 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002414
Harald Welte5e4d1b32009-02-01 13:36:56 +00002415 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2416 if (rc < 0) {
2417 perror("ERR parsing SWL file");
2418 rc = -EINVAL;
2419 goto out;
2420 }
2421 if (rc < 2)
2422 continue;
2423
Harald Welte470ec292009-06-26 20:25:23 +02002424 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002425 if (!fle) {
2426 rc = -ENOMEM;
2427 goto out;
2428 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002429
2430 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002431 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002432 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2433 strcat(fle->fname, "/");
2434 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002435
2436 llist_add_tail(&fle->list, &bs11_sw->file_list);
2437 }
2438
2439out:
2440 fclose(swl);
2441 return rc;
2442}
2443
2444/* bs11 swload specific callback, passed to abis_nm core swload */
2445static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2446 struct msgb *msg, void *data, void *param)
2447{
2448 struct abis_nm_bs11_sw *bs11_sw = data;
2449 struct file_list_entry *fle;
2450 int rc = 0;
2451
Harald Welte5e4d1b32009-02-01 13:36:56 +00002452 switch (event) {
2453 case NM_MT_LOAD_END_ACK:
2454 fle = fl_dequeue(&bs11_sw->file_list);
2455 if (fle) {
2456 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002457 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002458 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002459 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002460 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002461 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002462 } else {
2463 /* activate the SWL */
2464 rc = abis_nm_software_activate(bs11_sw->bts,
2465 bs11_sw->swl_fname,
2466 bs11_swload_cbfn,
2467 bs11_sw);
2468 }
2469 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002470 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002471 case NM_MT_LOAD_END_NACK:
2472 case NM_MT_LOAD_INIT_ACK:
2473 case NM_MT_LOAD_INIT_NACK:
2474 case NM_MT_ACTIVATE_SW_NACK:
2475 case NM_MT_ACTIVATE_SW_ACK:
2476 default:
2477 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002478 if (bs11_sw->user_cb)
2479 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002480 break;
2481 }
2482
2483 return rc;
2484}
2485
2486/* Siemens provides a SWL file that is a mere listing of all the other
2487 * files that are part of a software release. We need to upload first
2488 * the list file, and then each file that is listed in the list file */
2489int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002490 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002491{
2492 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2493 struct file_list_entry *fle;
2494 int rc = 0;
2495
2496 INIT_LLIST_HEAD(&bs11_sw->file_list);
2497 bs11_sw->bts = bts;
2498 bs11_sw->win_size = win_size;
2499 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002500 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002501
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002502 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002503 rc = bs11_read_swl_file(bs11_sw);
2504 if (rc < 0)
2505 return rc;
2506
2507 /* dequeue next item in file list */
2508 fle = fl_dequeue(&bs11_sw->file_list);
2509 if (!fle)
2510 return -EINVAL;
2511
2512 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002513 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002514 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002515 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002516 return rc;
2517}
2518
Harald Welte5083b0b2009-02-02 19:20:52 +00002519#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002520static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002521 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2522 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2523 NM_ATT_BS11_LMT_USER_NAME,
2524
2525 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2526
2527 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2528
2529 NM_ATT_BS11_SW_LOAD_STORED };
2530
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002531static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002532 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2533 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2534 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2535 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002536#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002537
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002538static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002539 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2540 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002541 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002542
2543int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2544{
2545 struct abis_om_hdr *oh;
2546 struct msgb *msg = nm_msgb_alloc();
2547
2548 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2549 /* SiemensHW CCTRL object */
2550 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2551 0x03, 0x00, 0x00);
2552 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2553
2554 return abis_nm_sendmsg(bts, msg);
2555}
Harald Welte268bb402009-02-01 19:11:56 +00002556
2557int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2558{
2559 struct abis_om_hdr *oh;
2560 struct msgb *msg = nm_msgb_alloc();
2561 struct bs11_date_time aet;
2562
2563 get_bs11_date_time(&aet);
2564 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2565 /* SiemensHW CCTRL object */
2566 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2567 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002568 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002569
2570 return abis_nm_sendmsg(bts, msg);
2571}
Harald Welte5c1e4582009-02-15 11:57:29 +00002572
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002573int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002574{
2575 struct abis_om_hdr *oh;
2576 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002577 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002578
2579 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2580 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2581 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2582 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2583
2584 return abis_nm_sendmsg(bts, msg);
2585}
2586
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002587int 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 +02002588{
2589 struct abis_om_hdr *oh;
2590 struct msgb *msg = nm_msgb_alloc();
2591 struct bs11_date_time aet;
2592
2593 get_bs11_date_time(&aet);
2594 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2595 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2596 bport, 0xff, 0x02);
2597 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2598
2599 return abis_nm_sendmsg(bts, msg);
2600}
2601
Harald Welte5c1e4582009-02-15 11:57:29 +00002602/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002603static const char ipaccess_magic[] = "com.ipaccess";
2604
Harald Welte677c21f2009-02-17 13:22:23 +00002605
2606static int abis_nm_rx_ipacc(struct msgb *msg)
2607{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002608 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002609 struct abis_om_hdr *oh = msgb_l2(msg);
2610 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002611 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002612 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002613 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002614 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002615
2616 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002617 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002618 return -EINVAL;
2619 }
2620
Harald Welte193fefc2009-04-30 15:16:27 +00002621 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002622 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002623
Harald Welte15c61722011-05-22 22:45:37 +02002624 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002625
Harald Welte746d6092009-10-19 22:11:11 +02002626 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002627
Harald Welte677c21f2009-02-17 13:22:23 +00002628 switch (foh->msg_type) {
2629 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002630 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002631 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2632 memcpy(&addr,
2633 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2634
2635 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2636 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002637 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002638 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002639 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002640 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002641 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2642 DEBUGPC(DNM, "STREAM=0x%02x ",
2643 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002644 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002645 break;
2646 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002647 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002648 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002649 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002650 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002651 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002652 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002653 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002654 case NM_MT_IPACC_SET_NVATTR_ACK:
2655 DEBUGPC(DNM, "SET NVATTR ACK\n");
2656 /* FIXME: decode and show the actual attributes */
2657 break;
2658 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002659 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002660 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002661 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002662 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002663 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002664 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002665 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002666 case NM_MT_IPACC_GET_NVATTR_ACK:
2667 DEBUGPC(DNM, "GET NVATTR ACK\n");
2668 /* FIXME: decode and show the actual attributes */
2669 break;
2670 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002671 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002672 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002673 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002674 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002675 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002676 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002677 break;
Harald Welte15c44172009-10-08 20:15:24 +02002678 case NM_MT_IPACC_SET_ATTR_ACK:
2679 DEBUGPC(DNM, "SET ATTR ACK\n");
2680 break;
2681 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002682 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002683 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002684 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002685 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002686 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002687 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002688 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002689 default:
2690 DEBUGPC(DNM, "unknown\n");
2691 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002692 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002693
2694 /* signal handling */
2695 switch (foh->msg_type) {
2696 case NM_MT_IPACC_RSL_CONNECT_NACK:
2697 case NM_MT_IPACC_SET_NVATTR_NACK:
2698 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002699 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 +01002700 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002701 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002702 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002703 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002704 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 +01002705 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002706 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002707 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002708 default:
2709 break;
2710 }
2711
Harald Welte677c21f2009-02-17 13:22:23 +00002712 return 0;
2713}
2714
Harald Welte193fefc2009-04-30 15:16:27 +00002715/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002716int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2717 uint8_t obj_class, uint8_t bts_nr,
2718 uint8_t trx_nr, uint8_t ts_nr,
2719 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002720{
2721 struct msgb *msg = nm_msgb_alloc();
2722 struct abis_om_hdr *oh;
2723 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002724 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002725
2726 /* construct the 12.21 OM header, observe the erroneous length */
2727 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2728 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2729 oh->mdisc = ABIS_OM_MDISC_MANUF;
2730
2731 /* add the ip.access magic */
2732 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2733 *data++ = sizeof(ipaccess_magic);
2734 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2735
2736 /* fill the 12.21 FOM header */
2737 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2738 foh->msg_type = msg_type;
2739 foh->obj_class = obj_class;
2740 foh->obj_inst.bts_nr = bts_nr;
2741 foh->obj_inst.trx_nr = trx_nr;
2742 foh->obj_inst.ts_nr = ts_nr;
2743
2744 if (attr && attr_len) {
2745 data = msgb_put(msg, attr_len);
2746 memcpy(data, attr, attr_len);
2747 }
2748
2749 return abis_nm_sendmsg(bts, msg);
2750}
Harald Welte677c21f2009-02-17 13:22:23 +00002751
Harald Welte193fefc2009-04-30 15:16:27 +00002752/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002753int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002754 int attr_len)
2755{
Harald Welte2ef156d2010-01-07 20:39:42 +01002756 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2757 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002758 attr_len);
2759}
2760
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002761int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002762 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002763{
2764 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002765 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002766 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2767 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2768
2769 int attr_len = sizeof(attr);
2770
2771 ia.s_addr = htonl(ip);
2772 attr[1] = stream;
2773 attr[3] = port >> 8;
2774 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002775 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002776
2777 /* if ip == 0, we use the default IP */
2778 if (ip == 0)
2779 attr_len -= 5;
2780
2781 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002782 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002783
2784 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2785 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2786 trx->nr, 0xff, attr, attr_len);
2787}
2788
Harald Welte193fefc2009-04-30 15:16:27 +00002789/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002790int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002791{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002792 struct abis_om_hdr *oh;
2793 struct msgb *msg = nm_msgb_alloc();
2794
2795 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2796 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2797 trx->bts->nr, trx->nr, 0xff);
2798
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002799 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002800}
Harald Weltedaef5212009-10-24 10:20:41 +02002801
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002802int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2803 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2804 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002805{
2806 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2807 obj_class, bts_nr, trx_nr, ts_nr,
2808 attr, attr_len);
2809}
Harald Welte0f255852009-11-12 14:48:42 +01002810
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002811void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002812{
2813 /* we simply reuse the GSM48 function and overwrite the RAC
2814 * with the Cell ID */
2815 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002816 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002817}
2818
Maxbe356ed2017-09-07 19:10:09 +02002819void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason)
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002820{
Maxbe356ed2017-09-07 19:10:09 +02002821 uint8_t new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2822
2823 LOGP(DNM, LOGL_NOTICE, "(bts=%d,trx=%d) Changing adm. state %s -> %s [%s]\n", trx->bts->nr, trx->nr,
2824 get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative),
2825 get_value_string(abis_nm_adm_state_names, new_state), reason);
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002826
Harald Welted64c0bc2011-05-30 12:07:53 +02002827 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002828 if (!trx->bts || !trx->bts->oml_link)
2829 return;
2830
2831 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2832 trx->bts->bts_nr, trx->nr, 0xff,
2833 new_state);
2834}
2835
Harald Welte92b1fe42010-03-25 11:45:30 +08002836static const struct value_string ipacc_testres_names[] = {
2837 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2838 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2839 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2840 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2841 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2842 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002843};
2844
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002845const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002846{
Harald Welte92b1fe42010-03-25 11:45:30 +08002847 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002848}
2849
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002850void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002851{
2852 cid->mcc = (buf[0] & 0xf) * 100;
2853 cid->mcc += (buf[0] >> 4) * 10;
2854 cid->mcc += (buf[1] & 0xf) * 1;
2855
2856 if (buf[1] >> 4 == 0xf) {
2857 cid->mnc = (buf[2] & 0xf) * 10;
2858 cid->mnc += (buf[2] >> 4) * 1;
2859 } else {
2860 cid->mnc = (buf[2] & 0xf) * 100;
2861 cid->mnc += (buf[2] >> 4) * 10;
2862 cid->mnc += (buf[1] >> 4) * 1;
2863 }
2864
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002865 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2866 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002867}
2868
Harald Welte0f255852009-11-12 14:48:42 +01002869/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002870int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002871{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002872 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002873 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002874
Harald Welteaf109b92010-07-22 18:14:36 +02002875 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002876
2877 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2878 return -EINVAL;
2879 cur++;
2880
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002881 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002882 cur += 2;
2883
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002884 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002885 cur += 2;
2886
2887 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2888 binf->freq_qual = *cur >> 2;
2889
Harald Welteaf109b92010-07-22 18:14:36 +02002890 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002891 binf->arfcn |= *cur++;
2892
2893 if (binf->info_type & IPAC_BINF_RXLEV)
2894 binf->rx_lev = *cur & 0x3f;
2895 cur++;
2896
2897 if (binf->info_type & IPAC_BINF_RXQUAL)
2898 binf->rx_qual = *cur & 0x7;
2899 cur++;
2900
2901 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002902 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002903 cur += 2;
2904
2905 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002906 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002907 cur += 2;
2908
2909 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002910 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002911 cur += 4;
2912
Harald Weltea780a3d2010-07-30 22:34:42 +02002913#if 0
2914 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002915 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002916#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002917 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002918 cur++;
2919
Harald Welteb40a38f2009-11-13 11:56:05 +01002920 ipac_parse_cgi(&binf->cgi, cur);
2921 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002922
2923 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2924 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2925 cur += sizeof(binf->ba_list_si2);
2926 }
2927
2928 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2929 memcpy(binf->ba_list_si2bis, cur,
2930 sizeof(binf->ba_list_si2bis));
2931 cur += sizeof(binf->ba_list_si2bis);
2932 }
2933
2934 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2935 memcpy(binf->ba_list_si2ter, cur,
2936 sizeof(binf->ba_list_si2ter));
2937 cur += sizeof(binf->ba_list_si2ter);
2938 }
2939
2940 return 0;
2941}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002942
2943void abis_nm_clear_queue(struct gsm_bts *bts)
2944{
2945 struct msgb *msg;
2946
2947 while (!llist_empty(&bts->abis_queue)) {
2948 msg = msgb_dequeue(&bts->abis_queue);
2949 msgb_free(msg);
2950 }
2951
2952 bts->abis_nm_pend = 0;
2953}