blob: f0dfe9e79098e81580cde57e17d9881b75a68993 [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
Max3d049d22017-10-09 17:12:53 +0200686static inline bool all_trx_rsl_connected(const struct gsm_bts *bts)
687{
688 const struct gsm_bts_trx *trx;
689
690 llist_for_each_entry(trx, &bts->trx_list, list) {
691 if (!trx->rsl_link)
692 return false;
693 }
694
695 return true;
696}
697
698char *get_oml_status(const struct gsm_bts *bts)
699{
700 if (bts->oml_link)
701 return all_trx_rsl_connected(bts) ? "connected" : "degraded";
702
703 return "disconnected";
704}
705
706char *get_model_oml_status(const struct gsm_bts *bts)
707{
708 if (bts->model->oml_status)
709 return bts->model->oml_status(bts);
710
711 return "unknown";
712}
713
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200714void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100715{
716 int wait = 0;
717 struct msgb *msg;
718 /* the queue is empty */
719 while (!llist_empty(&bts->abis_queue)) {
720 msg = msgb_dequeue(&bts->abis_queue);
721 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200722 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100723
724 if (wait)
725 break;
726 }
727
728 bts->abis_nm_pend = wait;
729}
730
Harald Welte52b1f982008-12-23 20:25:15 +0000731/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000732static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000733{
Harald Welte6c96ba52009-05-01 13:03:40 +0000734 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000735 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200736 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200737 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100738 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
739 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100740 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000741
742 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000743 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100744 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000745
Harald Welte15c61722011-05-22 22:45:37 +0200746 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000747 return abis_nm_rcvmsg_sw(mb);
748
Harald Welte15c61722011-05-22 22:45:37 +0200749 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800750 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000751 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200752
Harald Welte15c61722011-05-22 22:45:37 +0200753 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200754
Harald Welte15c61722011-05-22 22:45:37 +0200755 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000756
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100757 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000758 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200759 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200760 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000761 else
762 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200763
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800764 nack_data.msg = mb;
765 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100766 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200767 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100768 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200769 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000770 }
Harald Weltead384642008-12-26 10:20:07 +0000771#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000772 /* check if last message is to be acked */
773 if (is_ack_nack(nmh->last_msgtype)) {
774 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100775 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000776 /* we got our ACK, continue sending the next msg */
777 } else if (mt == MT_NACK(nmh->last_msgtype)) {
778 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100779 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000780 /* FIXME: somehow signal this to the caller */
781 } else {
782 /* really strange things happen */
783 return -EINVAL;
784 }
785 }
Harald Weltead384642008-12-26 10:20:07 +0000786#endif
787
Harald Welte97ed1e72009-02-06 13:38:02 +0000788 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000789 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100790 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000791 break;
Harald Welte34a99682009-02-13 02:41:40 +0000792 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100793 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000794 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000795 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100796 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000797 break;
Max689e7e52017-04-04 19:21:24 +0200798 case NM_MT_OPSTART_ACK:
799 abis_nm_debugp_foh(DNM, foh);
800 DEBUGPC(DNM, "Opstart ACK\n");
801 break;
802 case NM_MT_SET_CHAN_ATTR_ACK:
803 abis_nm_debugp_foh(DNM, foh);
804 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
805 break;
806 case NM_MT_SET_RADIO_ATTR_ACK:
807 abis_nm_debugp_foh(DNM, foh);
808 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
809 break;
Harald Welte1989c082009-08-06 17:58:31 +0200810 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200811 abis_nm_debugp_foh(DNM, foh);
812 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200813 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100814 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200815 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100816 break;
817 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200818 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100819 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100820 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100821 break;
Maxdefb6c92017-05-15 10:29:54 +0200822 case NM_MT_GET_ATTR_RESP:
Max33e13572017-05-29 11:48:29 +0200823 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Maxdefb6c92017-05-15 10:29:54 +0200824 break;
Max689e7e52017-04-04 19:21:24 +0200825 default:
826 abis_nm_debugp_foh(DNM, foh);
827 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
828 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000829 }
830
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100831 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100832 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000833}
834
Harald Welte677c21f2009-02-17 13:22:23 +0000835static int abis_nm_rx_ipacc(struct msgb *mb);
836
837static int abis_nm_rcvmsg_manuf(struct msgb *mb)
838{
839 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200840 struct e1inp_sign_link *sign_link = mb->dst;
841 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000842
843 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100844 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100845 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000846 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200847 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000848 break;
849 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100850 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
851 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000852 rc = 0;
853 break;
854 }
855
856 return rc;
857}
858
Harald Welte52b1f982008-12-23 20:25:15 +0000859/* High-Level API */
860/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000861int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000862{
Harald Welte52b1f982008-12-23 20:25:15 +0000863 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000864 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000865
866 /* Various consistency checks */
867 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100868 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000869 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200870 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
871 rc = -EINVAL;
872 goto err;
873 }
Harald Welte52b1f982008-12-23 20:25:15 +0000874 }
875 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100876 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000877 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200878 rc = -EINVAL;
879 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000880 }
Harald Welte702d8702008-12-26 20:25:35 +0000881#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200882 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000883 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000884 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100885 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000886 oh->length + sizeof(*oh), l2_len);
887 return -EINVAL;
888 }
Harald Welte702d8702008-12-26 20:25:35 +0000889 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100890 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 +0000891#endif
Harald Weltead384642008-12-26 10:20:07 +0000892 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000893
894 switch (oh->mdisc) {
895 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000896 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000897 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000898 case ABIS_OM_MDISC_MANUF:
899 rc = abis_nm_rcvmsg_manuf(msg);
900 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000901 case ABIS_OM_MDISC_MMI:
902 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100903 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000904 oh->mdisc);
905 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000906 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100907 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000908 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200909 rc = -EINVAL;
910 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000911 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200912err:
Harald Weltead384642008-12-26 10:20:07 +0000913 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000914 return rc;
915}
916
917#if 0
918/* initialized all resources */
919struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
920{
921 struct abis_nm_h *nmh;
922
923 nmh = malloc(sizeof(*nmh));
924 if (!nmh)
925 return NULL;
926
927 nmh->cfg = cfg;
928
929 return nmh;
930}
931
932/* free all resources */
933void abis_nm_fini(struct abis_nm_h *nmh)
934{
935 free(nmh);
936}
937#endif
938
939/* Here we are trying to define a high-level API that can be used by
940 * the actual BSC implementation. However, the architecture is currently
941 * still under design. Ideally the calls to this API would be synchronous,
942 * while the underlying stack behind the APi runs in a traditional select
943 * based state machine.
944 */
945
Harald Welte4724f992009-01-18 18:01:49 +0000946/* 6.2 Software Load: */
947enum sw_state {
948 SW_STATE_NONE,
949 SW_STATE_WAIT_INITACK,
950 SW_STATE_WAIT_SEGACK,
951 SW_STATE_WAIT_ENDACK,
952 SW_STATE_WAIT_ACTACK,
953 SW_STATE_ERROR,
954};
Harald Welte52b1f982008-12-23 20:25:15 +0000955
Harald Welte52b1f982008-12-23 20:25:15 +0000956struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000957 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800958 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000959 gsm_cbfn *cbfn;
960 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000961 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000962
Harald Welte52b1f982008-12-23 20:25:15 +0000963 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200964 uint8_t obj_class;
965 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000966
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200967 uint8_t file_id[255];
968 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000969
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200970 uint8_t file_version[255];
971 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000972
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200973 uint8_t window_size;
974 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000975
976 int fd;
977 FILE *stream;
978 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000979 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000980};
981
Harald Welte4724f992009-01-18 18:01:49 +0000982static struct abis_nm_sw g_sw;
983
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100984static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
985{
986 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
987 msgb_v_put(msg, NM_ATT_SW_DESCR);
988 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
989 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
990 sw->file_version);
991 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
992 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
993 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
994 sw->file_version);
995 } else {
996 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
997 }
998}
999
Harald Welte4724f992009-01-18 18:01:49 +00001000/* 6.2.1 / 8.3.1: Load Data Initiate */
1001static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001002{
Harald Welte4724f992009-01-18 18:01:49 +00001003 struct abis_om_hdr *oh;
1004 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001005 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001006
1007 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1008 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
1009 sw->obj_instance[0], sw->obj_instance[1],
1010 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001011
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001012 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001013 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
1014
1015 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001016}
1017
Harald Welte1602ade2009-01-29 21:12:39 +00001018static int is_last_line(FILE *stream)
1019{
1020 char next_seg_buf[256];
1021 long pos;
1022
1023 /* check if we're sending the last line */
1024 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +02001025
1026 /* Did ftell fail? Then we are at the end for sure */
1027 if (pos < 0)
1028 return 1;
1029
Harald Welte1602ade2009-01-29 21:12:39 +00001030 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +01001031 int rc = fseek(stream, pos, SEEK_SET);
1032 if (rc < 0)
1033 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001034 return 1;
1035 }
1036
1037 fseek(stream, pos, SEEK_SET);
1038 return 0;
1039}
1040
Harald Welte4724f992009-01-18 18:01:49 +00001041/* 6.2.2 / 8.3.2 Load Data Segment */
1042static int sw_load_segment(struct abis_nm_sw *sw)
1043{
1044 struct abis_om_hdr *oh;
1045 struct msgb *msg = nm_msgb_alloc();
1046 char seg_buf[256];
1047 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001048 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +02001049 int len;
Harald Welte4724f992009-01-18 18:01:49 +00001050
1051 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001052
1053 switch (sw->bts->type) {
1054 case GSM_BTS_TYPE_BS11:
1055 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1056 perror("fgets reading segment");
1057 return -EINVAL;
1058 }
1059 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001060
1061 /* check if we're sending the last line */
1062 sw->last_seg = is_last_line(sw->stream);
1063 if (sw->last_seg)
1064 seg_buf[1] = 0;
1065 else
1066 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001067
1068 len = strlen(line_buf) + 2;
1069 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001070 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001071 /* BS11 wants CR + LF in excess of the TLV length !?! */
1072 tlv[1] -= 2;
1073
1074 /* we only now know the exact length for the OM hdr */
1075 len = strlen(line_buf)+2;
1076 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001077 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001078 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001079 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1080 if (len < 0) {
1081 perror("read failed");
1082 return -EINVAL;
1083 }
1084
1085 if (len != IPACC_SEGMENT_SIZE)
1086 sw->last_seg = 1;
1087
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001088 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001089 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001090 len += 3;
1091 break;
1092 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001093 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001094 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001095 /* FIXME: Other BTS types */
1096 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001097 }
Harald Welte4724f992009-01-18 18:01:49 +00001098
Harald Welte4724f992009-01-18 18:01:49 +00001099 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1100 sw->obj_instance[0], sw->obj_instance[1],
1101 sw->obj_instance[2]);
1102
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001103 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001104}
1105
1106/* 6.2.4 / 8.3.4 Load Data End */
1107static int sw_load_end(struct abis_nm_sw *sw)
1108{
1109 struct abis_om_hdr *oh;
1110 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001111 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001112
1113 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1114 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1115 sw->obj_instance[0], sw->obj_instance[1],
1116 sw->obj_instance[2]);
1117
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001118 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001119 return abis_nm_sendmsg(sw->bts, msg);
1120}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001121
Harald Welte52b1f982008-12-23 20:25:15 +00001122/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001123static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001124{
Harald Welte4724f992009-01-18 18:01:49 +00001125 struct abis_om_hdr *oh;
1126 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001127 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001128
Harald Welte4724f992009-01-18 18:01:49 +00001129 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1130 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1131 sw->obj_instance[0], sw->obj_instance[1],
1132 sw->obj_instance[2]);
1133
1134 /* FIXME: this is BS11 specific format */
1135 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1136 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1137 sw->file_version);
1138
1139 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001140}
Harald Welte4724f992009-01-18 18:01:49 +00001141
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001142struct sdp_firmware {
1143 char magic[4];
1144 char more_magic[4];
1145 unsigned int header_length;
1146 unsigned int file_length;
1147} __attribute__ ((packed));
1148
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001149static int parse_sdp_header(struct abis_nm_sw *sw)
1150{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001151 struct sdp_firmware firmware_header;
1152 int rc;
1153 struct stat stat;
1154
1155 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1156 if (rc != sizeof(firmware_header)) {
1157 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1158 return -1;
1159 }
1160
1161 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1162 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1163 return -1;
1164 }
1165
1166 if (firmware_header.more_magic[0] != 0x10 ||
1167 firmware_header.more_magic[1] != 0x02 ||
1168 firmware_header.more_magic[2] != 0x00 ||
1169 firmware_header.more_magic[3] != 0x00) {
1170 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1171 return -1;
1172 }
1173
1174
1175 if (fstat(sw->fd, &stat) == -1) {
1176 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1177 return -1;
1178 }
1179
1180 if (ntohl(firmware_header.file_length) != stat.st_size) {
1181 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1182 return -1;
1183 }
1184
1185 /* go back to the start as we checked the whole filesize.. */
1186 lseek(sw->fd, 0l, SEEK_SET);
1187 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1188 "There might be checksums in the file that are not\n"
1189 "verified and incomplete firmware might be flashed.\n"
1190 "There is absolutely no WARRANTY that flashing will\n"
1191 "work.\n");
1192 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001193}
1194
Harald Welte4724f992009-01-18 18:01:49 +00001195static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1196{
1197 char file_id[12+1];
1198 char file_version[80+1];
1199 int rc;
1200
1201 sw->fd = open(fname, O_RDONLY);
1202 if (sw->fd < 0)
1203 return sw->fd;
1204
1205 switch (sw->bts->type) {
1206 case GSM_BTS_TYPE_BS11:
1207 sw->stream = fdopen(sw->fd, "r");
1208 if (!sw->stream) {
1209 perror("fdopen");
1210 return -1;
1211 }
1212 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001213 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001214 file_id, file_version);
1215 if (rc != 2) {
1216 perror("parsing header line of software file");
1217 return -1;
1218 }
1219 strcpy((char *)sw->file_id, file_id);
1220 sw->file_id_len = strlen(file_id);
1221 strcpy((char *)sw->file_version, file_version);
1222 sw->file_version_len = strlen(file_version);
1223 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001224 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001225 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001226 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001227 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001228 rc = parse_sdp_header(sw);
1229 if (rc < 0) {
1230 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1231 return -1;
1232 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001233
1234 strcpy((char *)sw->file_id, "id");
1235 sw->file_id_len = 3;
1236 strcpy((char *)sw->file_version, "version");
1237 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001238 break;
Harald Welte4724f992009-01-18 18:01:49 +00001239 default:
1240 /* We don't know how to treat them yet */
1241 close(sw->fd);
1242 return -EINVAL;
1243 }
1244
1245 return 0;
1246}
1247
1248static void sw_close_file(struct abis_nm_sw *sw)
1249{
1250 switch (sw->bts->type) {
1251 case GSM_BTS_TYPE_BS11:
1252 fclose(sw->stream);
1253 break;
1254 default:
1255 close(sw->fd);
1256 break;
1257 }
1258}
1259
1260/* Fill the window */
1261static int sw_fill_window(struct abis_nm_sw *sw)
1262{
1263 int rc;
1264
1265 while (sw->seg_in_window < sw->window_size) {
1266 rc = sw_load_segment(sw);
1267 if (rc < 0)
1268 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001269 if (sw->last_seg)
1270 break;
Harald Welte4724f992009-01-18 18:01:49 +00001271 }
1272 return 0;
1273}
1274
1275/* callback function from abis_nm_rcvmsg() handler */
1276static int abis_nm_rcvmsg_sw(struct msgb *mb)
1277{
1278 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001279 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001280 int rc = -1;
1281 struct abis_nm_sw *sw = &g_sw;
1282 enum sw_state old_state = sw->state;
1283
Harald Welte3ffd1372009-02-01 22:15:49 +00001284 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001285
1286 switch (sw->state) {
1287 case SW_STATE_WAIT_INITACK:
1288 switch (foh->msg_type) {
1289 case NM_MT_LOAD_INIT_ACK:
1290 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001291 if (sw->cbfn)
1292 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1293 NM_MT_LOAD_INIT_ACK, mb,
1294 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001295 rc = sw_fill_window(sw);
1296 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001297 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001298 break;
1299 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001300 if (sw->forced) {
1301 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1302 "Init NACK\n");
1303 if (sw->cbfn)
1304 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1305 NM_MT_LOAD_INIT_ACK, mb,
1306 sw->cb_data, NULL);
1307 rc = sw_fill_window(sw);
1308 sw->state = SW_STATE_WAIT_SEGACK;
1309 } else {
1310 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001311 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001312 if (sw->cbfn)
1313 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1314 NM_MT_LOAD_INIT_NACK, mb,
1315 sw->cb_data, NULL);
1316 sw->state = SW_STATE_ERROR;
1317 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001318 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001319 break;
1320 }
1321 break;
1322 case SW_STATE_WAIT_SEGACK:
1323 switch (foh->msg_type) {
1324 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001325 if (sw->cbfn)
1326 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1327 NM_MT_LOAD_SEG_ACK, mb,
1328 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001329 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001330 if (!sw->last_seg) {
1331 /* fill window with more segments */
1332 rc = sw_fill_window(sw);
1333 sw->state = SW_STATE_WAIT_SEGACK;
1334 } else {
1335 /* end the transfer */
1336 sw->state = SW_STATE_WAIT_ENDACK;
1337 rc = sw_load_end(sw);
1338 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001339 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001340 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001341 case NM_MT_LOAD_ABORT:
1342 if (sw->cbfn)
1343 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1344 NM_MT_LOAD_ABORT, mb,
1345 sw->cb_data, NULL);
1346 break;
Harald Welte4724f992009-01-18 18:01:49 +00001347 }
1348 break;
1349 case SW_STATE_WAIT_ENDACK:
1350 switch (foh->msg_type) {
1351 case NM_MT_LOAD_END_ACK:
1352 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001353 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1354 sw->bts->nr);
1355 sw->state = SW_STATE_NONE;
1356 if (sw->cbfn)
1357 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1358 NM_MT_LOAD_END_ACK, mb,
1359 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001360 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001361 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001362 break;
1363 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001364 if (sw->forced) {
1365 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1366 "End NACK\n");
1367 sw->state = SW_STATE_NONE;
1368 if (sw->cbfn)
1369 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1370 NM_MT_LOAD_END_ACK, mb,
1371 sw->cb_data, NULL);
1372 } else {
1373 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001374 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001375 sw->state = SW_STATE_ERROR;
1376 if (sw->cbfn)
1377 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1378 NM_MT_LOAD_END_NACK, mb,
1379 sw->cb_data, NULL);
1380 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001381 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001382 break;
1383 }
1384 case SW_STATE_WAIT_ACTACK:
1385 switch (foh->msg_type) {
1386 case NM_MT_ACTIVATE_SW_ACK:
1387 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001388 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001389 sw->state = SW_STATE_NONE;
1390 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001391 if (sw->cbfn)
1392 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1393 NM_MT_ACTIVATE_SW_ACK, mb,
1394 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001395 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001396 break;
1397 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001398 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001399 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001400 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001401 if (sw->cbfn)
1402 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1403 NM_MT_ACTIVATE_SW_NACK, mb,
1404 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001405 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001406 break;
1407 }
1408 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001409 switch (foh->msg_type) {
1410 case NM_MT_ACTIVATE_SW_ACK:
1411 rc = 0;
1412 break;
1413 }
1414 break;
Harald Welte4724f992009-01-18 18:01:49 +00001415 case SW_STATE_ERROR:
1416 break;
1417 }
1418
1419 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001420 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001421 foh->msg_type, old_state, sw->state);
1422
1423 return rc;
1424}
1425
1426/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001427int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001428 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001429 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001430{
1431 struct abis_nm_sw *sw = &g_sw;
1432 int rc;
1433
Harald Welte5e4d1b32009-02-01 13:36:56 +00001434 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1435 bts->nr, fname);
1436
Harald Welte4724f992009-01-18 18:01:49 +00001437 if (sw->state != SW_STATE_NONE)
1438 return -EBUSY;
1439
1440 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001441 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001442
1443 switch (bts->type) {
1444 case GSM_BTS_TYPE_BS11:
1445 sw->obj_class = NM_OC_SITE_MANAGER;
1446 sw->obj_instance[0] = 0xff;
1447 sw->obj_instance[1] = 0xff;
1448 sw->obj_instance[2] = 0xff;
1449 break;
1450 case GSM_BTS_TYPE_NANOBTS:
1451 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001452 sw->obj_instance[0] = sw->bts->nr;
1453 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001454 sw->obj_instance[2] = 0xff;
1455 break;
1456 case GSM_BTS_TYPE_UNKNOWN:
1457 default:
1458 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1459 return -1;
1460 break;
1461 }
Harald Welte4724f992009-01-18 18:01:49 +00001462 sw->window_size = win_size;
1463 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001464 sw->cbfn = cbfn;
1465 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001466 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001467
1468 rc = sw_open_file(sw, fname);
1469 if (rc < 0) {
1470 sw->state = SW_STATE_NONE;
1471 return rc;
1472 }
1473
1474 return sw_load_init(sw);
1475}
Harald Welte52b1f982008-12-23 20:25:15 +00001476
Harald Welte1602ade2009-01-29 21:12:39 +00001477int abis_nm_software_load_status(struct gsm_bts *bts)
1478{
1479 struct abis_nm_sw *sw = &g_sw;
1480 struct stat st;
1481 int rc, percent;
1482
1483 rc = fstat(sw->fd, &st);
1484 if (rc < 0) {
1485 perror("ERROR during stat");
1486 return rc;
1487 }
1488
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001489 if (sw->stream)
1490 percent = (ftell(sw->stream) * 100) / st.st_size;
1491 else
1492 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001493 return percent;
1494}
1495
Harald Welte5e4d1b32009-02-01 13:36:56 +00001496/* Activate the specified software into the BTS */
1497int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1498 gsm_cbfn *cbfn, void *cb_data)
1499{
1500 struct abis_nm_sw *sw = &g_sw;
1501 int rc;
1502
1503 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1504 bts->nr, fname);
1505
1506 if (sw->state != SW_STATE_NONE)
1507 return -EBUSY;
1508
1509 sw->bts = bts;
1510 sw->obj_class = NM_OC_SITE_MANAGER;
1511 sw->obj_instance[0] = 0xff;
1512 sw->obj_instance[1] = 0xff;
1513 sw->obj_instance[2] = 0xff;
1514 sw->state = SW_STATE_WAIT_ACTACK;
1515 sw->cbfn = cbfn;
1516 sw->cb_data = cb_data;
1517
1518 /* Open the file in order to fill some sw struct members */
1519 rc = sw_open_file(sw, fname);
1520 if (rc < 0) {
1521 sw->state = SW_STATE_NONE;
1522 return rc;
1523 }
1524 sw_close_file(sw);
1525
1526 return sw_activate(sw);
1527}
1528
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001529static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1530 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001531{
Harald Welteadaf08b2009-01-18 11:08:10 +00001532 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001533 ch->bts_port = bts_port;
1534 ch->timeslot = ts_nr;
1535 ch->subslot = subslot_nr;
1536}
1537
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001538int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1539 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1540 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001541{
1542 struct abis_om_hdr *oh;
1543 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001544 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001545 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001546
1547 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1548 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1549 bts->bts_nr, trx_nr, 0xff);
1550
Harald Welte8470bf22008-12-25 23:28:35 +00001551 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001552
1553 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1554 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1555
1556 return abis_nm_sendmsg(bts, msg);
1557}
1558
1559/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1560int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001561 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001562{
Harald Welte8470bf22008-12-25 23:28:35 +00001563 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001564 struct abis_om_hdr *oh;
1565 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001566 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001567
1568 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001569 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001570 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1571
1572 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1573 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1574
1575 return abis_nm_sendmsg(bts, msg);
1576}
1577
1578#if 0
1579int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1580 struct abis_nm_abis_channel *chan)
1581{
1582}
1583#endif
1584
1585int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001586 uint8_t e1_port, uint8_t e1_timeslot,
1587 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001588{
1589 struct gsm_bts *bts = ts->trx->bts;
1590 struct abis_om_hdr *oh;
1591 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001592 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001593
1594 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1595 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001596 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001597
1598 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1599 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1600
Harald Weltef325eb42009-02-19 17:07:39 +00001601 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1602 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001603 e1_port, e1_timeslot, e1_subslot);
1604
Harald Welte52b1f982008-12-23 20:25:15 +00001605 return abis_nm_sendmsg(bts, msg);
1606}
1607
1608#if 0
1609int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1610 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001611 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001612{
1613}
1614#endif
1615
Max1ebf23b2017-05-10 12:21:17 +02001616/* 3GPP TS 52.021 § 8.11.1 */
1617int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1618 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001619{
1620 struct abis_om_hdr *oh;
Maxe3dbd5d2017-06-09 17:15:45 +02001621 struct msgb *msg;
1622
1623 if (bts->type != GSM_BTS_TYPE_OSMOBTS) {
1624 LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n",
1625 bts->nr, btstype2str(bts->type));
1626 return -EINVAL;
1627 }
Harald Weltefe568f22012-08-14 19:15:57 +02001628
1629 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1630
Maxe3dbd5d2017-06-09 17:15:45 +02001631 msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001632 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1633 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1634 bts_nr, trx_nr, ts_nr);
1635 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1636
1637 return abis_nm_sendmsg(bts, msg);
1638}
1639
Harald Welte22af0db2009-02-14 15:41:08 +00001640/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001641int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001642{
1643 struct abis_om_hdr *oh;
1644 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001645 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001646
1647 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1648
1649 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001650 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 +00001651 cur = msgb_put(msg, attr_len);
1652 memcpy(cur, attr, attr_len);
1653
1654 return abis_nm_sendmsg(bts, msg);
1655}
1656
1657/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001658int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001659{
1660 struct abis_om_hdr *oh;
1661 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001662 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001663
1664 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1665
1666 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1667 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001668 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001669 cur = msgb_put(msg, attr_len);
1670 memcpy(cur, attr, attr_len);
1671
1672 return abis_nm_sendmsg(trx->bts, msg);
1673}
1674
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001675int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1676{
1677 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1678 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1679}
1680
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001681static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1682 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001683{
1684 int i;
1685
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001686 *reason = "Reason unknown";
1687
Harald Welte39c7deb2009-08-09 21:49:48 +02001688 /* As it turns out, the BS-11 has some very peculiar restrictions
1689 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301690 switch (ts->trx->bts->type) {
1691 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001692 switch (chan_comb) {
1693 case NM_CHANC_TCHHalf:
1694 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001695 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001696 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001697 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001698 return -EINVAL;
1699 case NM_CHANC_SDCCH:
1700 /* only one SDCCH/8 per TRX */
1701 for (i = 0; i < TRX_NR_TS; i++) {
1702 if (i == ts->nr)
1703 continue;
1704 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001705 NM_CHANC_SDCCH) {
1706 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001707 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001708 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001709 }
1710 /* not allowed for TS0 of BCCH-TRX */
1711 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001712 ts->nr == 0) {
1713 *reason = "SDCCH/8 must be on TS0.";
1714 return -EINVAL;
1715 }
1716
Harald Welte39c7deb2009-08-09 21:49:48 +02001717 /* not on the same TRX that has a BCCH+SDCCH4
1718 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001719 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001720 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001721 ts->trx->ts[0].nm_chan_comb == 8)) {
1722 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1723 return -EINVAL;
1724 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001725 break;
1726 case NM_CHANC_mainBCCH:
1727 case NM_CHANC_BCCHComb:
1728 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001729 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1730 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001731 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001732 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001733 break;
1734 case NM_CHANC_BCCH:
1735 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001736 if (ts->trx != ts->trx->bts->c0) {
1737 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001738 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001739 }
1740 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1741 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001742 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001743 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001744 break;
1745 case 8: /* this is not like 08.58, but in fact
1746 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1747 /* FIXME: only one CBCH allowed per cell */
1748 break;
1749 }
Harald Welted6575f92009-12-02 02:45:23 +05301750 break;
1751 case GSM_BTS_TYPE_NANOBTS:
1752 switch (ts->nr) {
1753 case 0:
1754 if (ts->trx->nr == 0) {
1755 /* only on TRX0 */
1756 switch (chan_comb) {
1757 case NM_CHANC_BCCH:
1758 case NM_CHANC_mainBCCH:
1759 case NM_CHANC_BCCHComb:
1760 return 0;
1761 break;
1762 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001763 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301764 return -EINVAL;
1765 }
1766 } else {
1767 switch (chan_comb) {
1768 case NM_CHANC_TCHFull:
1769 case NM_CHANC_TCHHalf:
1770 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1771 return 0;
1772 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001773 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301774 return -EINVAL;
1775 }
1776 }
1777 break;
1778 case 1:
1779 if (ts->trx->nr == 0) {
1780 switch (chan_comb) {
1781 case NM_CHANC_SDCCH_CBCH:
1782 if (ts->trx->ts[0].nm_chan_comb ==
1783 NM_CHANC_mainBCCH)
1784 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001785 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301786 return -EINVAL;
1787 case NM_CHANC_SDCCH:
1788 case NM_CHANC_TCHFull:
1789 case NM_CHANC_TCHHalf:
1790 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1791 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001792 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301793 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001794 default:
1795 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1796 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301797 }
1798 } else {
1799 switch (chan_comb) {
1800 case NM_CHANC_SDCCH:
1801 case NM_CHANC_TCHFull:
1802 case NM_CHANC_TCHHalf:
1803 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1804 return 0;
1805 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001806 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301807 return -EINVAL;
1808 }
1809 }
1810 break;
1811 case 2:
1812 case 3:
1813 case 4:
1814 case 5:
1815 case 6:
1816 case 7:
1817 switch (chan_comb) {
1818 case NM_CHANC_TCHFull:
1819 case NM_CHANC_TCHHalf:
1820 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1821 return 0;
1822 case NM_CHANC_IPAC_PDCH:
1823 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001824 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301825 if (ts->trx->nr == 0)
1826 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001827 else {
1828 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301829 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001830 }
Harald Welted6575f92009-12-02 02:45:23 +05301831 }
1832 break;
1833 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001834 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301835 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001836 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001837 /* no known restrictions */
1838 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301839 default:
1840 /* unknown BTS type */
1841 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001842 }
1843 return 0;
1844}
1845
Harald Welte22af0db2009-02-14 15:41:08 +00001846/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001847int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001848{
1849 struct gsm_bts *bts = ts->trx->bts;
1850 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001851 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001852 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001853 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001854 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001855
1856 if (bts->type == GSM_BTS_TYPE_BS11)
1857 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001858
Harald Weltef325eb42009-02-19 17:07:39 +00001859 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001860 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001861 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001862 LOGP(DNM, LOGL_ERROR,
1863 "Invalid Channel Combination %d on %s. Reason: %s\n",
1864 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001865 return -EINVAL;
1866 }
1867 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001868
Harald Welte52b1f982008-12-23 20:25:15 +00001869 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001870 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001871 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001872 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001873 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001874 if (ts->hopping.enabled) {
1875 unsigned int i;
1876 uint8_t *len;
1877
Harald Welte6e0cd042009-09-12 13:05:33 +02001878 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1879 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001880
1881 /* build the ARFCN list */
1882 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1883 len = msgb_put(msg, 1);
1884 *len = 0;
1885 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1886 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1887 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001888 /* At least BS-11 wants a TLV16 here */
1889 if (bts->type == GSM_BTS_TYPE_BS11)
1890 *len += 1;
1891 else
1892 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001893 }
1894 }
Harald Weltee0590df2009-02-15 03:34:15 +00001895 }
Harald Welte1fe24122014-01-19 17:18:21 +01001896 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001897 if (bts->type == GSM_BTS_TYPE_BS11)
1898 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001899
1900 return abis_nm_sendmsg(bts, msg);
1901}
1902
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001903int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1904 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001905{
1906 struct abis_om_hdr *oh;
1907 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001908 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1909 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001910
1911 if (nack) {
1912 len += 2;
1913 msgtype = NM_MT_SW_ACT_REQ_NACK;
1914 }
Harald Welte34a99682009-02-13 02:41:40 +00001915
1916 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001917 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1918
Harald Welte34a99682009-02-13 02:41:40 +00001919 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001920 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001921 memcpy(ptr, attr, att_len);
1922 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001923 if (nack)
1924 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001925
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001926 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001927}
1928
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001929int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001930{
Harald Welte8470bf22008-12-25 23:28:35 +00001931 struct msgb *msg = nm_msgb_alloc();
1932 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001933 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001934
1935 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1936 fill_om_hdr(oh, len);
1937 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001938 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001939
1940 return abis_nm_sendmsg(bts, msg);
1941}
1942
1943/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001944static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001945{
1946 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001947 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001948
1949 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001950 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001951 0xff, 0xff, 0xff);
1952
1953 return abis_nm_sendmsg(bts, msg);
1954}
1955
Harald Welte34a99682009-02-13 02:41:40 +00001956/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001957int 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 +00001958{
1959 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001960 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001961 struct msgb *msg = nm_msgb_alloc();
1962
1963 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001964 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001965
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001966 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001967 DEBUGPC(DNM, "Sending OPSTART\n");
1968
Harald Welte34a99682009-02-13 02:41:40 +00001969 return abis_nm_sendmsg(bts, msg);
1970}
1971
1972/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001973int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1974 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001975{
1976 struct abis_om_hdr *oh;
1977 struct msgb *msg = nm_msgb_alloc();
1978
1979 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1980 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1981 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1982
1983 return abis_nm_sendmsg(bts, msg);
1984}
1985
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001986int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1987 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001988{
1989 struct abis_om_hdr *oh;
1990 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001991 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001992
1993 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1994 e1_port0, ts0, e1_port1, ts1);
1995
1996 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1997 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1998 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1999
2000 attr = msgb_put(msg, 3);
2001 attr[0] = NM_ATT_MDROP_LINK;
2002 attr[1] = e1_port0;
2003 attr[2] = ts0;
2004
2005 attr = msgb_put(msg, 3);
2006 attr[0] = NM_ATT_MDROP_NEXT;
2007 attr[1] = e1_port1;
2008 attr[2] = ts1;
2009
2010 return abis_nm_sendmsg(bts, msg);
2011}
Harald Welte34a99682009-02-13 02:41:40 +00002012
Harald Weltec7310382009-08-08 00:02:36 +02002013/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002014int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
2015 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2016 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02002017{
2018 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02002019
Harald Welte15c61722011-05-22 22:45:37 +02002020 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01002021
2022 if (!msg)
2023 msg = nm_msgb_alloc();
2024
2025 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
2026 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
2027 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2028 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002029 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002030
2031 return abis_nm_sendmsg(bts, msg);
2032}
2033
Harald Welte52b1f982008-12-23 20:25:15 +00002034int abis_nm_event_reports(struct gsm_bts *bts, int on)
2035{
2036 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002037 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002038 else
Harald Welte227d4072009-01-03 08:16:25 +00002039 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002040}
2041
Harald Welte47d88ae2009-01-04 12:02:08 +00002042/* Siemens (or BS-11) specific commands */
2043
Harald Welte3ffd1372009-02-01 22:15:49 +00002044int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2045{
2046 if (reconnect == 0)
2047 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2048 else
2049 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2050}
2051
Harald Welteb8427972009-02-05 19:27:17 +00002052int abis_nm_bs11_restart(struct gsm_bts *bts)
2053{
2054 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2055}
2056
2057
Harald Welte268bb402009-02-01 19:11:56 +00002058struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002059 uint16_t year;
2060 uint8_t month;
2061 uint8_t day;
2062 uint8_t hour;
2063 uint8_t min;
2064 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002065} __attribute__((packed));
2066
2067
2068void get_bs11_date_time(struct bs11_date_time *aet)
2069{
2070 time_t t;
2071 struct tm *tm;
2072
2073 t = time(NULL);
2074 tm = localtime(&t);
2075 aet->sec = tm->tm_sec;
2076 aet->min = tm->tm_min;
2077 aet->hour = tm->tm_hour;
2078 aet->day = tm->tm_mday;
2079 aet->month = tm->tm_mon;
2080 aet->year = htons(1900 + tm->tm_year);
2081}
2082
Harald Welte05188ee2009-01-18 11:39:08 +00002083int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002084{
Harald Welte4668fda2009-01-03 08:19:29 +00002085 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002086}
2087
Harald Welte05188ee2009-01-18 11:39:08 +00002088int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002089{
2090 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002091 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002092 else
Harald Welte4668fda2009-01-03 08:19:29 +00002093 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002094}
Harald Welte47d88ae2009-01-04 12:02:08 +00002095
Harald Welte05188ee2009-01-18 11:39:08 +00002096int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002097 enum abis_bs11_objtype type, uint8_t idx,
2098 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002099{
2100 struct abis_om_hdr *oh;
2101 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002102 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002103
2104 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002105 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002106 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002107 cur = msgb_put(msg, attr_len);
2108 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002109
2110 return abis_nm_sendmsg(bts, msg);
2111}
2112
Harald Welte78fc0d42009-02-19 02:50:57 +00002113int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002114 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002115{
2116 struct abis_om_hdr *oh;
2117 struct msgb *msg = nm_msgb_alloc();
2118
2119 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2120 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2121 NM_OC_BS11, type, 0, idx);
2122
2123 return abis_nm_sendmsg(bts, msg);
2124}
2125
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002126int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002127{
2128 struct abis_om_hdr *oh;
2129 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002130 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002131
2132 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002133 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002134 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2135 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002136
2137 return abis_nm_sendmsg(bts, msg);
2138}
2139
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002140int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002141{
2142 struct abis_om_hdr *oh;
2143 struct msgb *msg = nm_msgb_alloc();
2144
2145 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2146 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002147 idx, 0xff, 0xff);
2148
2149 return abis_nm_sendmsg(bts, msg);
2150}
2151
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002152int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002153{
2154 struct abis_om_hdr *oh;
2155 struct msgb *msg = nm_msgb_alloc();
2156
2157 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2158 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2159 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002160
2161 return abis_nm_sendmsg(bts, msg);
2162}
Harald Welte05188ee2009-01-18 11:39:08 +00002163
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002164static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002165int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2166{
2167 struct abis_om_hdr *oh;
2168 struct msgb *msg = nm_msgb_alloc();
2169
2170 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2171 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2172 0xff, 0xff, 0xff);
2173 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2174
2175 return abis_nm_sendmsg(bts, msg);
2176}
2177
Harald Welteb6c92ae2009-02-21 20:15:32 +00002178/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002179int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2180 uint8_t e1_timeslot, uint8_t e1_subslot,
2181 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002182{
2183 struct abis_om_hdr *oh;
2184 struct abis_nm_channel *ch;
2185 struct msgb *msg = nm_msgb_alloc();
2186
2187 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002188 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002189 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2190
2191 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2192 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002193 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002194
2195 return abis_nm_sendmsg(bts, msg);
2196}
2197
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002198int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002199{
2200 struct abis_om_hdr *oh;
2201 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002202
2203 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002204 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002205 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2206 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2207
2208 return abis_nm_sendmsg(trx->bts, msg);
2209}
2210
Harald Welte78fc0d42009-02-19 02:50:57 +00002211int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2212{
2213 struct abis_om_hdr *oh;
2214 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002215 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002216
2217 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2218 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2219 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2220 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2221
2222 return abis_nm_sendmsg(trx->bts, msg);
2223}
2224
Harald Welteaaf02d92009-04-29 13:25:57 +00002225int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2226{
2227 struct abis_om_hdr *oh;
2228 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002229 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002230
2231 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2232 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2233 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002234 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002235
2236 return abis_nm_sendmsg(bts, msg);
2237}
2238
Harald Welteef061952009-05-17 12:43:42 +00002239int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2240{
2241 struct abis_om_hdr *oh;
2242 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002243 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002244 NM_ATT_BS11_CCLK_TYPE };
2245
2246 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2247 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2248 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2249 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2250
2251 return abis_nm_sendmsg(bts, msg);
2252
2253}
Harald Welteaaf02d92009-04-29 13:25:57 +00002254
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002255//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002256
Harald Welte1bc09062009-01-18 14:17:52 +00002257int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002258{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002259 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2260}
2261
Daniel Willmann4b054c82010-01-07 00:46:26 +01002262int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2263{
2264 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2265}
2266
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002267int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002268{
Harald Welte05188ee2009-01-18 11:39:08 +00002269 struct abis_om_hdr *oh;
2270 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002271 struct bs11_date_time bdt;
2272
2273 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002274
2275 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002276 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002277 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002278 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002279 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002280 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002281 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002282 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002283 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002284 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002285 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002286 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002287 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002288 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002289 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002290 }
Harald Welte05188ee2009-01-18 11:39:08 +00002291
2292 return abis_nm_sendmsg(bts, msg);
2293}
Harald Welte1bc09062009-01-18 14:17:52 +00002294
2295int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2296{
2297 struct abis_om_hdr *oh;
2298 struct msgb *msg;
2299
2300 if (strlen(password) != 10)
2301 return -EINVAL;
2302
2303 msg = nm_msgb_alloc();
2304 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002305 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002306 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002307 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002308
2309 return abis_nm_sendmsg(bts, msg);
2310}
2311
Harald Weltee69f5fb2009-04-28 16:31:38 +00002312/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2313int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2314{
2315 struct abis_om_hdr *oh;
2316 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002317 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002318
2319 msg = nm_msgb_alloc();
2320 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2321 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2322 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002323
2324 if (locked)
2325 tlv_value = BS11_LI_PLL_LOCKED;
2326 else
2327 tlv_value = BS11_LI_PLL_STANDALONE;
2328
2329 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002330
2331 return abis_nm_sendmsg(bts, msg);
2332}
2333
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002334/* Set the calibration value of the PLL (work value/set value)
2335 * It depends on the login which one is changed */
2336int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2337{
2338 struct abis_om_hdr *oh;
2339 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002340 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002341
2342 msg = nm_msgb_alloc();
2343 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2344 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2345 BS11_OBJ_TRX1, 0x00, 0x00);
2346
2347 tlv_value[0] = value>>8;
2348 tlv_value[1] = value&0xff;
2349
2350 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2351
2352 return abis_nm_sendmsg(bts, msg);
2353}
2354
Harald Welte1bc09062009-01-18 14:17:52 +00002355int abis_nm_bs11_get_state(struct gsm_bts *bts)
2356{
2357 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2358}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002359
2360/* BS11 SWL */
2361
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002362void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002363
Harald Welte5e4d1b32009-02-01 13:36:56 +00002364struct abis_nm_bs11_sw {
2365 struct gsm_bts *bts;
2366 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002367 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002368 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002369 struct llist_head file_list;
2370 gsm_cbfn *user_cb; /* specified by the user */
2371};
2372static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2373
2374struct file_list_entry {
2375 struct llist_head list;
2376 char fname[PATH_MAX];
2377};
2378
2379struct file_list_entry *fl_dequeue(struct llist_head *queue)
2380{
2381 struct llist_head *lh;
2382
2383 if (llist_empty(queue))
2384 return NULL;
2385
2386 lh = queue->next;
2387 llist_del(lh);
2388
2389 return llist_entry(lh, struct file_list_entry, list);
2390}
2391
2392static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2393{
2394 char linebuf[255];
2395 struct llist_head *lh, *lh2;
2396 FILE *swl;
2397 int rc = 0;
2398
2399 swl = fopen(bs11_sw->swl_fname, "r");
2400 if (!swl)
2401 return -ENODEV;
2402
2403 /* zero the stale file list, if any */
2404 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2405 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002406 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002407 }
2408
2409 while (fgets(linebuf, sizeof(linebuf), swl)) {
2410 char file_id[12+1];
2411 char file_version[80+1];
2412 struct file_list_entry *fle;
2413 static char dir[PATH_MAX];
2414
2415 if (strlen(linebuf) < 4)
2416 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002417
Harald Welte5e4d1b32009-02-01 13:36:56 +00002418 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2419 if (rc < 0) {
2420 perror("ERR parsing SWL file");
2421 rc = -EINVAL;
2422 goto out;
2423 }
2424 if (rc < 2)
2425 continue;
2426
Harald Welte470ec292009-06-26 20:25:23 +02002427 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002428 if (!fle) {
2429 rc = -ENOMEM;
2430 goto out;
2431 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002432
2433 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002434 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002435 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2436 strcat(fle->fname, "/");
2437 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002438
2439 llist_add_tail(&fle->list, &bs11_sw->file_list);
2440 }
2441
2442out:
2443 fclose(swl);
2444 return rc;
2445}
2446
2447/* bs11 swload specific callback, passed to abis_nm core swload */
2448static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2449 struct msgb *msg, void *data, void *param)
2450{
2451 struct abis_nm_bs11_sw *bs11_sw = data;
2452 struct file_list_entry *fle;
2453 int rc = 0;
2454
Harald Welte5e4d1b32009-02-01 13:36:56 +00002455 switch (event) {
2456 case NM_MT_LOAD_END_ACK:
2457 fle = fl_dequeue(&bs11_sw->file_list);
2458 if (fle) {
2459 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002460 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002461 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002462 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002463 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002464 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002465 } else {
2466 /* activate the SWL */
2467 rc = abis_nm_software_activate(bs11_sw->bts,
2468 bs11_sw->swl_fname,
2469 bs11_swload_cbfn,
2470 bs11_sw);
2471 }
2472 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002473 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002474 case NM_MT_LOAD_END_NACK:
2475 case NM_MT_LOAD_INIT_ACK:
2476 case NM_MT_LOAD_INIT_NACK:
2477 case NM_MT_ACTIVATE_SW_NACK:
2478 case NM_MT_ACTIVATE_SW_ACK:
2479 default:
2480 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002481 if (bs11_sw->user_cb)
2482 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002483 break;
2484 }
2485
2486 return rc;
2487}
2488
2489/* Siemens provides a SWL file that is a mere listing of all the other
2490 * files that are part of a software release. We need to upload first
2491 * the list file, and then each file that is listed in the list file */
2492int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002493 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002494{
2495 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2496 struct file_list_entry *fle;
2497 int rc = 0;
2498
2499 INIT_LLIST_HEAD(&bs11_sw->file_list);
2500 bs11_sw->bts = bts;
2501 bs11_sw->win_size = win_size;
2502 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002503 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002504
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002505 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002506 rc = bs11_read_swl_file(bs11_sw);
2507 if (rc < 0)
2508 return rc;
2509
2510 /* dequeue next item in file list */
2511 fle = fl_dequeue(&bs11_sw->file_list);
2512 if (!fle)
2513 return -EINVAL;
2514
2515 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002516 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002517 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002518 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002519 return rc;
2520}
2521
Harald Welte5083b0b2009-02-02 19:20:52 +00002522#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002523static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002524 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2525 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2526 NM_ATT_BS11_LMT_USER_NAME,
2527
2528 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2529
2530 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2531
2532 NM_ATT_BS11_SW_LOAD_STORED };
2533
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002534static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002535 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2536 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2537 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2538 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002539#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002540
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002541static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002542 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2543 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002544 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002545
2546int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2547{
2548 struct abis_om_hdr *oh;
2549 struct msgb *msg = nm_msgb_alloc();
2550
2551 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2552 /* SiemensHW CCTRL object */
2553 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2554 0x03, 0x00, 0x00);
2555 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2556
2557 return abis_nm_sendmsg(bts, msg);
2558}
Harald Welte268bb402009-02-01 19:11:56 +00002559
2560int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2561{
2562 struct abis_om_hdr *oh;
2563 struct msgb *msg = nm_msgb_alloc();
2564 struct bs11_date_time aet;
2565
2566 get_bs11_date_time(&aet);
2567 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2568 /* SiemensHW CCTRL object */
2569 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2570 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002571 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002572
2573 return abis_nm_sendmsg(bts, msg);
2574}
Harald Welte5c1e4582009-02-15 11:57:29 +00002575
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002576int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002577{
2578 struct abis_om_hdr *oh;
2579 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002580 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002581
2582 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2583 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2584 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2585 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2586
2587 return abis_nm_sendmsg(bts, msg);
2588}
2589
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002590int 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 +02002591{
2592 struct abis_om_hdr *oh;
2593 struct msgb *msg = nm_msgb_alloc();
2594 struct bs11_date_time aet;
2595
2596 get_bs11_date_time(&aet);
2597 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2598 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2599 bport, 0xff, 0x02);
2600 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2601
2602 return abis_nm_sendmsg(bts, msg);
2603}
2604
Harald Welte5c1e4582009-02-15 11:57:29 +00002605/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002606static const char ipaccess_magic[] = "com.ipaccess";
2607
Harald Welte677c21f2009-02-17 13:22:23 +00002608
2609static int abis_nm_rx_ipacc(struct msgb *msg)
2610{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002611 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002612 struct abis_om_hdr *oh = msgb_l2(msg);
2613 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002614 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002615 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002616 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002617 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002618
2619 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002620 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002621 return -EINVAL;
2622 }
2623
Harald Welte193fefc2009-04-30 15:16:27 +00002624 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002625 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002626
Harald Welte15c61722011-05-22 22:45:37 +02002627 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002628
Harald Welte746d6092009-10-19 22:11:11 +02002629 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002630
Harald Welte677c21f2009-02-17 13:22:23 +00002631 switch (foh->msg_type) {
2632 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002633 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002634 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2635 memcpy(&addr,
2636 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2637
2638 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2639 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002640 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002641 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002642 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002643 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002644 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2645 DEBUGPC(DNM, "STREAM=0x%02x ",
2646 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002647 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002648 break;
2649 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002650 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002651 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002652 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002653 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002654 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002655 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002656 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002657 case NM_MT_IPACC_SET_NVATTR_ACK:
2658 DEBUGPC(DNM, "SET NVATTR ACK\n");
2659 /* FIXME: decode and show the actual attributes */
2660 break;
2661 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002662 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002663 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002664 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002665 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002666 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002667 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002668 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002669 case NM_MT_IPACC_GET_NVATTR_ACK:
2670 DEBUGPC(DNM, "GET NVATTR ACK\n");
2671 /* FIXME: decode and show the actual attributes */
2672 break;
2673 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002674 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002675 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002676 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002677 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002678 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002679 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002680 break;
Harald Welte15c44172009-10-08 20:15:24 +02002681 case NM_MT_IPACC_SET_ATTR_ACK:
2682 DEBUGPC(DNM, "SET ATTR ACK\n");
2683 break;
2684 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002685 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002686 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002687 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002688 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002689 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002690 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002691 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002692 default:
2693 DEBUGPC(DNM, "unknown\n");
2694 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002695 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002696
2697 /* signal handling */
2698 switch (foh->msg_type) {
2699 case NM_MT_IPACC_RSL_CONNECT_NACK:
2700 case NM_MT_IPACC_SET_NVATTR_NACK:
2701 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002702 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 +01002703 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002704 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002705 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002706 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002707 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 +01002708 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002709 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002710 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002711 default:
2712 break;
2713 }
2714
Harald Welte677c21f2009-02-17 13:22:23 +00002715 return 0;
2716}
2717
Harald Welte193fefc2009-04-30 15:16:27 +00002718/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002719int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2720 uint8_t obj_class, uint8_t bts_nr,
2721 uint8_t trx_nr, uint8_t ts_nr,
2722 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002723{
2724 struct msgb *msg = nm_msgb_alloc();
2725 struct abis_om_hdr *oh;
2726 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002727 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002728
2729 /* construct the 12.21 OM header, observe the erroneous length */
2730 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2731 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2732 oh->mdisc = ABIS_OM_MDISC_MANUF;
2733
2734 /* add the ip.access magic */
2735 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2736 *data++ = sizeof(ipaccess_magic);
2737 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2738
2739 /* fill the 12.21 FOM header */
2740 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2741 foh->msg_type = msg_type;
2742 foh->obj_class = obj_class;
2743 foh->obj_inst.bts_nr = bts_nr;
2744 foh->obj_inst.trx_nr = trx_nr;
2745 foh->obj_inst.ts_nr = ts_nr;
2746
2747 if (attr && attr_len) {
2748 data = msgb_put(msg, attr_len);
2749 memcpy(data, attr, attr_len);
2750 }
2751
2752 return abis_nm_sendmsg(bts, msg);
2753}
Harald Welte677c21f2009-02-17 13:22:23 +00002754
Harald Welte193fefc2009-04-30 15:16:27 +00002755/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002756int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002757 int attr_len)
2758{
Harald Welte2ef156d2010-01-07 20:39:42 +01002759 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2760 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002761 attr_len);
2762}
2763
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002764int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002765 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002766{
2767 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002768 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002769 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2770 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2771
2772 int attr_len = sizeof(attr);
2773
2774 ia.s_addr = htonl(ip);
2775 attr[1] = stream;
2776 attr[3] = port >> 8;
2777 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002778 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002779
2780 /* if ip == 0, we use the default IP */
2781 if (ip == 0)
2782 attr_len -= 5;
2783
2784 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002785 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002786
2787 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2788 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2789 trx->nr, 0xff, attr, attr_len);
2790}
2791
Harald Welte193fefc2009-04-30 15:16:27 +00002792/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002793int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002794{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002795 struct abis_om_hdr *oh;
2796 struct msgb *msg = nm_msgb_alloc();
2797
2798 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2799 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2800 trx->bts->nr, trx->nr, 0xff);
2801
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002802 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002803}
Harald Weltedaef5212009-10-24 10:20:41 +02002804
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002805int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2806 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2807 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002808{
2809 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2810 obj_class, bts_nr, trx_nr, ts_nr,
2811 attr, attr_len);
2812}
Harald Welte0f255852009-11-12 14:48:42 +01002813
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002814void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002815{
2816 /* we simply reuse the GSM48 function and overwrite the RAC
2817 * with the Cell ID */
2818 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002819 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002820}
2821
Maxbe356ed2017-09-07 19:10:09 +02002822void gsm_trx_lock_rf(struct gsm_bts_trx *trx, bool locked, const char *reason)
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002823{
Maxbe356ed2017-09-07 19:10:09 +02002824 uint8_t new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2825
2826 LOGP(DNM, LOGL_NOTICE, "(bts=%d,trx=%d) Changing adm. state %s -> %s [%s]\n", trx->bts->nr, trx->nr,
2827 get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative),
2828 get_value_string(abis_nm_adm_state_names, new_state), reason);
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002829
Harald Welted64c0bc2011-05-30 12:07:53 +02002830 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002831 if (!trx->bts || !trx->bts->oml_link)
2832 return;
2833
2834 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2835 trx->bts->bts_nr, trx->nr, 0xff,
2836 new_state);
2837}
2838
Harald Welte92b1fe42010-03-25 11:45:30 +08002839static const struct value_string ipacc_testres_names[] = {
2840 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2841 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2842 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2843 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2844 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2845 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002846};
2847
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002848const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002849{
Harald Welte92b1fe42010-03-25 11:45:30 +08002850 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002851}
2852
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002853void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002854{
2855 cid->mcc = (buf[0] & 0xf) * 100;
2856 cid->mcc += (buf[0] >> 4) * 10;
2857 cid->mcc += (buf[1] & 0xf) * 1;
2858
2859 if (buf[1] >> 4 == 0xf) {
2860 cid->mnc = (buf[2] & 0xf) * 10;
2861 cid->mnc += (buf[2] >> 4) * 1;
2862 } else {
2863 cid->mnc = (buf[2] & 0xf) * 100;
2864 cid->mnc += (buf[2] >> 4) * 10;
2865 cid->mnc += (buf[1] >> 4) * 1;
2866 }
2867
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002868 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2869 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002870}
2871
Harald Welte0f255852009-11-12 14:48:42 +01002872/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002873int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002874{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002875 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002876 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002877
Harald Welteaf109b92010-07-22 18:14:36 +02002878 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002879
2880 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2881 return -EINVAL;
2882 cur++;
2883
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002884 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002885 cur += 2;
2886
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002887 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002888 cur += 2;
2889
2890 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2891 binf->freq_qual = *cur >> 2;
2892
Harald Welteaf109b92010-07-22 18:14:36 +02002893 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002894 binf->arfcn |= *cur++;
2895
2896 if (binf->info_type & IPAC_BINF_RXLEV)
2897 binf->rx_lev = *cur & 0x3f;
2898 cur++;
2899
2900 if (binf->info_type & IPAC_BINF_RXQUAL)
2901 binf->rx_qual = *cur & 0x7;
2902 cur++;
2903
2904 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002905 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002906 cur += 2;
2907
2908 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002909 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002910 cur += 2;
2911
2912 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002913 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002914 cur += 4;
2915
Harald Weltea780a3d2010-07-30 22:34:42 +02002916#if 0
2917 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002918 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002919#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002920 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002921 cur++;
2922
Harald Welteb40a38f2009-11-13 11:56:05 +01002923 ipac_parse_cgi(&binf->cgi, cur);
2924 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002925
2926 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2927 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2928 cur += sizeof(binf->ba_list_si2);
2929 }
2930
2931 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2932 memcpy(binf->ba_list_si2bis, cur,
2933 sizeof(binf->ba_list_si2bis));
2934 cur += sizeof(binf->ba_list_si2bis);
2935 }
2936
2937 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2938 memcpy(binf->ba_list_si2ter, cur,
2939 sizeof(binf->ba_list_si2ter));
2940 cur += sizeof(binf->ba_list_si2ter);
2941 }
2942
2943 return 0;
2944}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002945
2946void abis_nm_clear_queue(struct gsm_bts *bts)
2947{
2948 struct msgb *msg;
2949
2950 while (!llist_empty(&bts->abis_queue)) {
2951 msg = msgb_dequeue(&bts->abis_queue);
2952 msgb_free(msg);
2953 }
2954
2955 bts->abis_nm_pend = 0;
2956}