blob: cf20d7c49fd47321204d7e333ba6fa6d1b96f9f0 [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
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/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>
Harald Welte8470bf22008-12-25 23:28:35 +000045#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000046#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000047#include <openbsc/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
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200686void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100687{
688 int wait = 0;
689 struct msgb *msg;
690 /* the queue is empty */
691 while (!llist_empty(&bts->abis_queue)) {
692 msg = msgb_dequeue(&bts->abis_queue);
693 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200694 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100695
696 if (wait)
697 break;
698 }
699
700 bts->abis_nm_pend = wait;
701}
702
Harald Welte52b1f982008-12-23 20:25:15 +0000703/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000704static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000705{
Harald Welte6c96ba52009-05-01 13:03:40 +0000706 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000707 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200708 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200709 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100710 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
711 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100712 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000713
714 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000715 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100716 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000717
Harald Welte15c61722011-05-22 22:45:37 +0200718 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000719 return abis_nm_rcvmsg_sw(mb);
720
Harald Welte15c61722011-05-22 22:45:37 +0200721 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800722 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000723 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200724
Harald Welte15c61722011-05-22 22:45:37 +0200725 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200726
Harald Welte15c61722011-05-22 22:45:37 +0200727 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000728
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100729 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000730 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200731 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200732 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000733 else
734 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200735
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800736 nack_data.msg = mb;
737 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100738 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200739 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100740 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200741 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000742 }
Harald Weltead384642008-12-26 10:20:07 +0000743#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000744 /* check if last message is to be acked */
745 if (is_ack_nack(nmh->last_msgtype)) {
746 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100747 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000748 /* we got our ACK, continue sending the next msg */
749 } else if (mt == MT_NACK(nmh->last_msgtype)) {
750 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100751 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000752 /* FIXME: somehow signal this to the caller */
753 } else {
754 /* really strange things happen */
755 return -EINVAL;
756 }
757 }
Harald Weltead384642008-12-26 10:20:07 +0000758#endif
759
Harald Welte97ed1e72009-02-06 13:38:02 +0000760 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000761 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100762 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000763 break;
Harald Welte34a99682009-02-13 02:41:40 +0000764 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100765 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000766 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000767 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100768 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000769 break;
Max689e7e52017-04-04 19:21:24 +0200770 case NM_MT_OPSTART_ACK:
771 abis_nm_debugp_foh(DNM, foh);
772 DEBUGPC(DNM, "Opstart ACK\n");
773 break;
774 case NM_MT_SET_CHAN_ATTR_ACK:
775 abis_nm_debugp_foh(DNM, foh);
776 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
777 break;
778 case NM_MT_SET_RADIO_ATTR_ACK:
779 abis_nm_debugp_foh(DNM, foh);
780 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
781 break;
Harald Welte1989c082009-08-06 17:58:31 +0200782 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200783 abis_nm_debugp_foh(DNM, foh);
784 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200785 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100786 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200787 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100788 break;
789 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200790 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100791 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100792 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100793 break;
Maxdefb6c92017-05-15 10:29:54 +0200794 case NM_MT_GET_ATTR_RESP:
Max33e13572017-05-29 11:48:29 +0200795 ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
Maxdefb6c92017-05-15 10:29:54 +0200796 break;
Max689e7e52017-04-04 19:21:24 +0200797 default:
798 abis_nm_debugp_foh(DNM, foh);
799 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
800 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000801 }
802
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100803 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100804 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000805}
806
Harald Welte677c21f2009-02-17 13:22:23 +0000807static int abis_nm_rx_ipacc(struct msgb *mb);
808
809static int abis_nm_rcvmsg_manuf(struct msgb *mb)
810{
811 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200812 struct e1inp_sign_link *sign_link = mb->dst;
813 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000814
815 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100816 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100817 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000818 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200819 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000820 break;
821 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100822 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
823 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000824 rc = 0;
825 break;
826 }
827
828 return rc;
829}
830
Harald Welte52b1f982008-12-23 20:25:15 +0000831/* High-Level API */
832/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000833int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000834{
Harald Welte52b1f982008-12-23 20:25:15 +0000835 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000836 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000837
838 /* Various consistency checks */
839 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100840 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000841 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200842 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
843 rc = -EINVAL;
844 goto err;
845 }
Harald Welte52b1f982008-12-23 20:25:15 +0000846 }
847 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100848 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000849 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200850 rc = -EINVAL;
851 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000852 }
Harald Welte702d8702008-12-26 20:25:35 +0000853#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200854 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000855 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000856 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100857 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000858 oh->length + sizeof(*oh), l2_len);
859 return -EINVAL;
860 }
Harald Welte702d8702008-12-26 20:25:35 +0000861 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100862 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 +0000863#endif
Harald Weltead384642008-12-26 10:20:07 +0000864 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000865
866 switch (oh->mdisc) {
867 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000868 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000869 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000870 case ABIS_OM_MDISC_MANUF:
871 rc = abis_nm_rcvmsg_manuf(msg);
872 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000873 case ABIS_OM_MDISC_MMI:
874 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100875 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000876 oh->mdisc);
877 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000878 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100879 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000880 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200881 rc = -EINVAL;
882 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000883 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200884err:
Harald Weltead384642008-12-26 10:20:07 +0000885 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000886 return rc;
887}
888
889#if 0
890/* initialized all resources */
891struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
892{
893 struct abis_nm_h *nmh;
894
895 nmh = malloc(sizeof(*nmh));
896 if (!nmh)
897 return NULL;
898
899 nmh->cfg = cfg;
900
901 return nmh;
902}
903
904/* free all resources */
905void abis_nm_fini(struct abis_nm_h *nmh)
906{
907 free(nmh);
908}
909#endif
910
911/* Here we are trying to define a high-level API that can be used by
912 * the actual BSC implementation. However, the architecture is currently
913 * still under design. Ideally the calls to this API would be synchronous,
914 * while the underlying stack behind the APi runs in a traditional select
915 * based state machine.
916 */
917
Harald Welte4724f992009-01-18 18:01:49 +0000918/* 6.2 Software Load: */
919enum sw_state {
920 SW_STATE_NONE,
921 SW_STATE_WAIT_INITACK,
922 SW_STATE_WAIT_SEGACK,
923 SW_STATE_WAIT_ENDACK,
924 SW_STATE_WAIT_ACTACK,
925 SW_STATE_ERROR,
926};
Harald Welte52b1f982008-12-23 20:25:15 +0000927
Harald Welte52b1f982008-12-23 20:25:15 +0000928struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000929 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800930 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000931 gsm_cbfn *cbfn;
932 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000933 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000934
Harald Welte52b1f982008-12-23 20:25:15 +0000935 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200936 uint8_t obj_class;
937 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000938
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200939 uint8_t file_id[255];
940 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000941
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200942 uint8_t file_version[255];
943 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000944
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200945 uint8_t window_size;
946 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000947
948 int fd;
949 FILE *stream;
950 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000951 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000952};
953
Harald Welte4724f992009-01-18 18:01:49 +0000954static struct abis_nm_sw g_sw;
955
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100956static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
957{
958 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
959 msgb_v_put(msg, NM_ATT_SW_DESCR);
960 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
961 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
962 sw->file_version);
963 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
964 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
965 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
966 sw->file_version);
967 } else {
968 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
969 }
970}
971
Harald Welte4724f992009-01-18 18:01:49 +0000972/* 6.2.1 / 8.3.1: Load Data Initiate */
973static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000974{
Harald Welte4724f992009-01-18 18:01:49 +0000975 struct abis_om_hdr *oh;
976 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200977 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000978
979 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
980 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
981 sw->obj_instance[0], sw->obj_instance[1],
982 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100983
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100984 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000985 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
986
987 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000988}
989
Harald Welte1602ade2009-01-29 21:12:39 +0000990static int is_last_line(FILE *stream)
991{
992 char next_seg_buf[256];
993 long pos;
994
995 /* check if we're sending the last line */
996 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200997
998 /* Did ftell fail? Then we are at the end for sure */
999 if (pos < 0)
1000 return 1;
1001
Harald Welte1602ade2009-01-29 21:12:39 +00001002 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +01001003 int rc = fseek(stream, pos, SEEK_SET);
1004 if (rc < 0)
1005 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001006 return 1;
1007 }
1008
1009 fseek(stream, pos, SEEK_SET);
1010 return 0;
1011}
1012
Harald Welte4724f992009-01-18 18:01:49 +00001013/* 6.2.2 / 8.3.2 Load Data Segment */
1014static int sw_load_segment(struct abis_nm_sw *sw)
1015{
1016 struct abis_om_hdr *oh;
1017 struct msgb *msg = nm_msgb_alloc();
1018 char seg_buf[256];
1019 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +00001020 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +02001021 int len;
Harald Welte4724f992009-01-18 18:01:49 +00001022
1023 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +00001024
1025 switch (sw->bts->type) {
1026 case GSM_BTS_TYPE_BS11:
1027 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
1028 perror("fgets reading segment");
1029 return -EINVAL;
1030 }
1031 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +00001032
1033 /* check if we're sending the last line */
1034 sw->last_seg = is_last_line(sw->stream);
1035 if (sw->last_seg)
1036 seg_buf[1] = 0;
1037 else
1038 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +00001039
1040 len = strlen(line_buf) + 2;
1041 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001042 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +00001043 /* BS11 wants CR + LF in excess of the TLV length !?! */
1044 tlv[1] -= 2;
1045
1046 /* we only now know the exact length for the OM hdr */
1047 len = strlen(line_buf)+2;
1048 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001049 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001050 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001051 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
1052 if (len < 0) {
1053 perror("read failed");
1054 return -EINVAL;
1055 }
1056
1057 if (len != IPACC_SEGMENT_SIZE)
1058 sw->last_seg = 1;
1059
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +01001060 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001061 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +01001062 len += 3;
1063 break;
1064 }
Harald Welte3b8ba212009-01-29 12:27:58 +00001065 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +01001066 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +00001067 /* FIXME: Other BTS types */
1068 return -1;
Harald Welte4724f992009-01-18 18:01:49 +00001069 }
Harald Welte4724f992009-01-18 18:01:49 +00001070
Harald Welte4724f992009-01-18 18:01:49 +00001071 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
1072 sw->obj_instance[0], sw->obj_instance[1],
1073 sw->obj_instance[2]);
1074
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001075 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001076}
1077
1078/* 6.2.4 / 8.3.4 Load Data End */
1079static int sw_load_end(struct abis_nm_sw *sw)
1080{
1081 struct abis_om_hdr *oh;
1082 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001083 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001084
1085 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1086 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1087 sw->obj_instance[0], sw->obj_instance[1],
1088 sw->obj_instance[2]);
1089
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001090 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001091 return abis_nm_sendmsg(sw->bts, msg);
1092}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001093
Harald Welte52b1f982008-12-23 20:25:15 +00001094/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001095static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001096{
Harald Welte4724f992009-01-18 18:01:49 +00001097 struct abis_om_hdr *oh;
1098 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001099 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001100
Harald Welte4724f992009-01-18 18:01:49 +00001101 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1102 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1103 sw->obj_instance[0], sw->obj_instance[1],
1104 sw->obj_instance[2]);
1105
1106 /* FIXME: this is BS11 specific format */
1107 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1108 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1109 sw->file_version);
1110
1111 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001112}
Harald Welte4724f992009-01-18 18:01:49 +00001113
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001114struct sdp_firmware {
1115 char magic[4];
1116 char more_magic[4];
1117 unsigned int header_length;
1118 unsigned int file_length;
1119} __attribute__ ((packed));
1120
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001121static int parse_sdp_header(struct abis_nm_sw *sw)
1122{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001123 struct sdp_firmware firmware_header;
1124 int rc;
1125 struct stat stat;
1126
1127 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1128 if (rc != sizeof(firmware_header)) {
1129 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1130 return -1;
1131 }
1132
1133 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1134 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1135 return -1;
1136 }
1137
1138 if (firmware_header.more_magic[0] != 0x10 ||
1139 firmware_header.more_magic[1] != 0x02 ||
1140 firmware_header.more_magic[2] != 0x00 ||
1141 firmware_header.more_magic[3] != 0x00) {
1142 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1143 return -1;
1144 }
1145
1146
1147 if (fstat(sw->fd, &stat) == -1) {
1148 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1149 return -1;
1150 }
1151
1152 if (ntohl(firmware_header.file_length) != stat.st_size) {
1153 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1154 return -1;
1155 }
1156
1157 /* go back to the start as we checked the whole filesize.. */
1158 lseek(sw->fd, 0l, SEEK_SET);
1159 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1160 "There might be checksums in the file that are not\n"
1161 "verified and incomplete firmware might be flashed.\n"
1162 "There is absolutely no WARRANTY that flashing will\n"
1163 "work.\n");
1164 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001165}
1166
Harald Welte4724f992009-01-18 18:01:49 +00001167static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1168{
1169 char file_id[12+1];
1170 char file_version[80+1];
1171 int rc;
1172
1173 sw->fd = open(fname, O_RDONLY);
1174 if (sw->fd < 0)
1175 return sw->fd;
1176
1177 switch (sw->bts->type) {
1178 case GSM_BTS_TYPE_BS11:
1179 sw->stream = fdopen(sw->fd, "r");
1180 if (!sw->stream) {
1181 perror("fdopen");
1182 return -1;
1183 }
1184 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001185 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001186 file_id, file_version);
1187 if (rc != 2) {
1188 perror("parsing header line of software file");
1189 return -1;
1190 }
1191 strcpy((char *)sw->file_id, file_id);
1192 sw->file_id_len = strlen(file_id);
1193 strcpy((char *)sw->file_version, file_version);
1194 sw->file_version_len = strlen(file_version);
1195 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001196 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001197 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001198 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001199 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001200 rc = parse_sdp_header(sw);
1201 if (rc < 0) {
1202 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1203 return -1;
1204 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001205
1206 strcpy((char *)sw->file_id, "id");
1207 sw->file_id_len = 3;
1208 strcpy((char *)sw->file_version, "version");
1209 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001210 break;
Harald Welte4724f992009-01-18 18:01:49 +00001211 default:
1212 /* We don't know how to treat them yet */
1213 close(sw->fd);
1214 return -EINVAL;
1215 }
1216
1217 return 0;
1218}
1219
1220static void sw_close_file(struct abis_nm_sw *sw)
1221{
1222 switch (sw->bts->type) {
1223 case GSM_BTS_TYPE_BS11:
1224 fclose(sw->stream);
1225 break;
1226 default:
1227 close(sw->fd);
1228 break;
1229 }
1230}
1231
1232/* Fill the window */
1233static int sw_fill_window(struct abis_nm_sw *sw)
1234{
1235 int rc;
1236
1237 while (sw->seg_in_window < sw->window_size) {
1238 rc = sw_load_segment(sw);
1239 if (rc < 0)
1240 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001241 if (sw->last_seg)
1242 break;
Harald Welte4724f992009-01-18 18:01:49 +00001243 }
1244 return 0;
1245}
1246
1247/* callback function from abis_nm_rcvmsg() handler */
1248static int abis_nm_rcvmsg_sw(struct msgb *mb)
1249{
1250 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001251 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001252 int rc = -1;
1253 struct abis_nm_sw *sw = &g_sw;
1254 enum sw_state old_state = sw->state;
1255
Harald Welte3ffd1372009-02-01 22:15:49 +00001256 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001257
1258 switch (sw->state) {
1259 case SW_STATE_WAIT_INITACK:
1260 switch (foh->msg_type) {
1261 case NM_MT_LOAD_INIT_ACK:
1262 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001263 if (sw->cbfn)
1264 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1265 NM_MT_LOAD_INIT_ACK, mb,
1266 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001267 rc = sw_fill_window(sw);
1268 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001269 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001270 break;
1271 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001272 if (sw->forced) {
1273 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1274 "Init NACK\n");
1275 if (sw->cbfn)
1276 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1277 NM_MT_LOAD_INIT_ACK, mb,
1278 sw->cb_data, NULL);
1279 rc = sw_fill_window(sw);
1280 sw->state = SW_STATE_WAIT_SEGACK;
1281 } else {
1282 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001283 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001284 if (sw->cbfn)
1285 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1286 NM_MT_LOAD_INIT_NACK, mb,
1287 sw->cb_data, NULL);
1288 sw->state = SW_STATE_ERROR;
1289 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001290 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001291 break;
1292 }
1293 break;
1294 case SW_STATE_WAIT_SEGACK:
1295 switch (foh->msg_type) {
1296 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001297 if (sw->cbfn)
1298 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1299 NM_MT_LOAD_SEG_ACK, mb,
1300 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001301 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001302 if (!sw->last_seg) {
1303 /* fill window with more segments */
1304 rc = sw_fill_window(sw);
1305 sw->state = SW_STATE_WAIT_SEGACK;
1306 } else {
1307 /* end the transfer */
1308 sw->state = SW_STATE_WAIT_ENDACK;
1309 rc = sw_load_end(sw);
1310 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001311 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001312 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001313 case NM_MT_LOAD_ABORT:
1314 if (sw->cbfn)
1315 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1316 NM_MT_LOAD_ABORT, mb,
1317 sw->cb_data, NULL);
1318 break;
Harald Welte4724f992009-01-18 18:01:49 +00001319 }
1320 break;
1321 case SW_STATE_WAIT_ENDACK:
1322 switch (foh->msg_type) {
1323 case NM_MT_LOAD_END_ACK:
1324 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001325 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1326 sw->bts->nr);
1327 sw->state = SW_STATE_NONE;
1328 if (sw->cbfn)
1329 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1330 NM_MT_LOAD_END_ACK, mb,
1331 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001332 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001333 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001334 break;
1335 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001336 if (sw->forced) {
1337 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1338 "End NACK\n");
1339 sw->state = SW_STATE_NONE;
1340 if (sw->cbfn)
1341 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1342 NM_MT_LOAD_END_ACK, mb,
1343 sw->cb_data, NULL);
1344 } else {
1345 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001346 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001347 sw->state = SW_STATE_ERROR;
1348 if (sw->cbfn)
1349 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1350 NM_MT_LOAD_END_NACK, mb,
1351 sw->cb_data, NULL);
1352 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001353 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001354 break;
1355 }
1356 case SW_STATE_WAIT_ACTACK:
1357 switch (foh->msg_type) {
1358 case NM_MT_ACTIVATE_SW_ACK:
1359 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001360 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001361 sw->state = SW_STATE_NONE;
1362 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001363 if (sw->cbfn)
1364 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1365 NM_MT_ACTIVATE_SW_ACK, mb,
1366 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001367 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001368 break;
1369 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001370 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001371 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001372 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001373 if (sw->cbfn)
1374 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1375 NM_MT_ACTIVATE_SW_NACK, mb,
1376 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001377 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001378 break;
1379 }
1380 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001381 switch (foh->msg_type) {
1382 case NM_MT_ACTIVATE_SW_ACK:
1383 rc = 0;
1384 break;
1385 }
1386 break;
Harald Welte4724f992009-01-18 18:01:49 +00001387 case SW_STATE_ERROR:
1388 break;
1389 }
1390
1391 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001392 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001393 foh->msg_type, old_state, sw->state);
1394
1395 return rc;
1396}
1397
1398/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001399int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001400 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001401 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001402{
1403 struct abis_nm_sw *sw = &g_sw;
1404 int rc;
1405
Harald Welte5e4d1b32009-02-01 13:36:56 +00001406 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1407 bts->nr, fname);
1408
Harald Welte4724f992009-01-18 18:01:49 +00001409 if (sw->state != SW_STATE_NONE)
1410 return -EBUSY;
1411
1412 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001413 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001414
1415 switch (bts->type) {
1416 case GSM_BTS_TYPE_BS11:
1417 sw->obj_class = NM_OC_SITE_MANAGER;
1418 sw->obj_instance[0] = 0xff;
1419 sw->obj_instance[1] = 0xff;
1420 sw->obj_instance[2] = 0xff;
1421 break;
1422 case GSM_BTS_TYPE_NANOBTS:
1423 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001424 sw->obj_instance[0] = sw->bts->nr;
1425 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001426 sw->obj_instance[2] = 0xff;
1427 break;
1428 case GSM_BTS_TYPE_UNKNOWN:
1429 default:
1430 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1431 return -1;
1432 break;
1433 }
Harald Welte4724f992009-01-18 18:01:49 +00001434 sw->window_size = win_size;
1435 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001436 sw->cbfn = cbfn;
1437 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001438 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001439
1440 rc = sw_open_file(sw, fname);
1441 if (rc < 0) {
1442 sw->state = SW_STATE_NONE;
1443 return rc;
1444 }
1445
1446 return sw_load_init(sw);
1447}
Harald Welte52b1f982008-12-23 20:25:15 +00001448
Harald Welte1602ade2009-01-29 21:12:39 +00001449int abis_nm_software_load_status(struct gsm_bts *bts)
1450{
1451 struct abis_nm_sw *sw = &g_sw;
1452 struct stat st;
1453 int rc, percent;
1454
1455 rc = fstat(sw->fd, &st);
1456 if (rc < 0) {
1457 perror("ERROR during stat");
1458 return rc;
1459 }
1460
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001461 if (sw->stream)
1462 percent = (ftell(sw->stream) * 100) / st.st_size;
1463 else
1464 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001465 return percent;
1466}
1467
Harald Welte5e4d1b32009-02-01 13:36:56 +00001468/* Activate the specified software into the BTS */
1469int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1470 gsm_cbfn *cbfn, void *cb_data)
1471{
1472 struct abis_nm_sw *sw = &g_sw;
1473 int rc;
1474
1475 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1476 bts->nr, fname);
1477
1478 if (sw->state != SW_STATE_NONE)
1479 return -EBUSY;
1480
1481 sw->bts = bts;
1482 sw->obj_class = NM_OC_SITE_MANAGER;
1483 sw->obj_instance[0] = 0xff;
1484 sw->obj_instance[1] = 0xff;
1485 sw->obj_instance[2] = 0xff;
1486 sw->state = SW_STATE_WAIT_ACTACK;
1487 sw->cbfn = cbfn;
1488 sw->cb_data = cb_data;
1489
1490 /* Open the file in order to fill some sw struct members */
1491 rc = sw_open_file(sw, fname);
1492 if (rc < 0) {
1493 sw->state = SW_STATE_NONE;
1494 return rc;
1495 }
1496 sw_close_file(sw);
1497
1498 return sw_activate(sw);
1499}
1500
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001501static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1502 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001503{
Harald Welteadaf08b2009-01-18 11:08:10 +00001504 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001505 ch->bts_port = bts_port;
1506 ch->timeslot = ts_nr;
1507 ch->subslot = subslot_nr;
1508}
1509
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001510int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1511 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1512 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001513{
1514 struct abis_om_hdr *oh;
1515 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001516 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001517 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001518
1519 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1520 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1521 bts->bts_nr, trx_nr, 0xff);
1522
Harald Welte8470bf22008-12-25 23:28:35 +00001523 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001524
1525 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1526 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1527
1528 return abis_nm_sendmsg(bts, msg);
1529}
1530
1531/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1532int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001533 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001534{
Harald Welte8470bf22008-12-25 23:28:35 +00001535 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001536 struct abis_om_hdr *oh;
1537 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001538 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001539
1540 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001541 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001542 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1543
1544 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1545 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1546
1547 return abis_nm_sendmsg(bts, msg);
1548}
1549
1550#if 0
1551int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1552 struct abis_nm_abis_channel *chan)
1553{
1554}
1555#endif
1556
1557int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001558 uint8_t e1_port, uint8_t e1_timeslot,
1559 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001560{
1561 struct gsm_bts *bts = ts->trx->bts;
1562 struct abis_om_hdr *oh;
1563 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001564 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001565
1566 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1567 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001568 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001569
1570 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1571 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1572
Harald Weltef325eb42009-02-19 17:07:39 +00001573 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1574 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001575 e1_port, e1_timeslot, e1_subslot);
1576
Harald Welte52b1f982008-12-23 20:25:15 +00001577 return abis_nm_sendmsg(bts, msg);
1578}
1579
1580#if 0
1581int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1582 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001583 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001584{
1585}
1586#endif
1587
Max1ebf23b2017-05-10 12:21:17 +02001588/* 3GPP TS 52.021 § 8.11.1 */
1589int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1590 const uint8_t *attr, uint8_t attr_len)
Harald Weltefe568f22012-08-14 19:15:57 +02001591{
1592 struct abis_om_hdr *oh;
Maxb9d13bf2017-06-09 17:15:45 +02001593 struct msgb *msg;
1594
1595 if (bts->type != GSM_BTS_TYPE_OSMOBTS) {
1596 LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n",
1597 bts->nr, btstype2str(bts->type));
1598 return -EINVAL;
1599 }
Harald Weltefe568f22012-08-14 19:15:57 +02001600
1601 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1602
Maxb9d13bf2017-06-09 17:15:45 +02001603 msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001604 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1605 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1606 bts_nr, trx_nr, ts_nr);
1607 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1608
1609 return abis_nm_sendmsg(bts, msg);
1610}
1611
Harald Welte22af0db2009-02-14 15:41:08 +00001612/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001613int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001614{
1615 struct abis_om_hdr *oh;
1616 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001617 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001618
1619 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1620
1621 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001622 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 +00001623 cur = msgb_put(msg, attr_len);
1624 memcpy(cur, attr, attr_len);
1625
1626 return abis_nm_sendmsg(bts, msg);
1627}
1628
1629/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001630int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001631{
1632 struct abis_om_hdr *oh;
1633 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001634 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001635
1636 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1637
1638 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1639 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001640 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001641 cur = msgb_put(msg, attr_len);
1642 memcpy(cur, attr, attr_len);
1643
1644 return abis_nm_sendmsg(trx->bts, msg);
1645}
1646
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001647int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1648{
1649 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1650 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1651}
1652
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001653static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1654 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001655{
1656 int i;
1657
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001658 *reason = "Reason unknown";
1659
Harald Welte39c7deb2009-08-09 21:49:48 +02001660 /* As it turns out, the BS-11 has some very peculiar restrictions
1661 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301662 switch (ts->trx->bts->type) {
1663 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001664 switch (chan_comb) {
1665 case NM_CHANC_TCHHalf:
1666 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001667 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001668 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001669 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001670 return -EINVAL;
1671 case NM_CHANC_SDCCH:
1672 /* only one SDCCH/8 per TRX */
1673 for (i = 0; i < TRX_NR_TS; i++) {
1674 if (i == ts->nr)
1675 continue;
1676 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001677 NM_CHANC_SDCCH) {
1678 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001679 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001680 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001681 }
1682 /* not allowed for TS0 of BCCH-TRX */
1683 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001684 ts->nr == 0) {
1685 *reason = "SDCCH/8 must be on TS0.";
1686 return -EINVAL;
1687 }
1688
Harald Welte39c7deb2009-08-09 21:49:48 +02001689 /* not on the same TRX that has a BCCH+SDCCH4
1690 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001691 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001692 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001693 ts->trx->ts[0].nm_chan_comb == 8)) {
1694 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1695 return -EINVAL;
1696 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001697 break;
1698 case NM_CHANC_mainBCCH:
1699 case NM_CHANC_BCCHComb:
1700 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001701 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1702 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001703 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001704 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001705 break;
1706 case NM_CHANC_BCCH:
1707 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001708 if (ts->trx != ts->trx->bts->c0) {
1709 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001710 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001711 }
1712 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1713 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001714 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001715 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001716 break;
1717 case 8: /* this is not like 08.58, but in fact
1718 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1719 /* FIXME: only one CBCH allowed per cell */
1720 break;
1721 }
Harald Welted6575f92009-12-02 02:45:23 +05301722 break;
1723 case GSM_BTS_TYPE_NANOBTS:
1724 switch (ts->nr) {
1725 case 0:
1726 if (ts->trx->nr == 0) {
1727 /* only on TRX0 */
1728 switch (chan_comb) {
1729 case NM_CHANC_BCCH:
1730 case NM_CHANC_mainBCCH:
1731 case NM_CHANC_BCCHComb:
1732 return 0;
1733 break;
1734 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001735 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301736 return -EINVAL;
1737 }
1738 } else {
1739 switch (chan_comb) {
1740 case NM_CHANC_TCHFull:
1741 case NM_CHANC_TCHHalf:
1742 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1743 return 0;
1744 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001745 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301746 return -EINVAL;
1747 }
1748 }
1749 break;
1750 case 1:
1751 if (ts->trx->nr == 0) {
1752 switch (chan_comb) {
1753 case NM_CHANC_SDCCH_CBCH:
1754 if (ts->trx->ts[0].nm_chan_comb ==
1755 NM_CHANC_mainBCCH)
1756 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001757 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301758 return -EINVAL;
1759 case NM_CHANC_SDCCH:
1760 case NM_CHANC_TCHFull:
1761 case NM_CHANC_TCHHalf:
1762 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1763 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001764 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301765 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001766 default:
1767 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1768 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301769 }
1770 } else {
1771 switch (chan_comb) {
1772 case NM_CHANC_SDCCH:
1773 case NM_CHANC_TCHFull:
1774 case NM_CHANC_TCHHalf:
1775 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1776 return 0;
1777 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001778 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301779 return -EINVAL;
1780 }
1781 }
1782 break;
1783 case 2:
1784 case 3:
1785 case 4:
1786 case 5:
1787 case 6:
1788 case 7:
1789 switch (chan_comb) {
1790 case NM_CHANC_TCHFull:
1791 case NM_CHANC_TCHHalf:
1792 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1793 return 0;
1794 case NM_CHANC_IPAC_PDCH:
1795 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001796 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301797 if (ts->trx->nr == 0)
1798 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001799 else {
1800 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301801 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001802 }
Harald Welted6575f92009-12-02 02:45:23 +05301803 }
1804 break;
1805 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001806 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301807 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001808 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001809 /* no known restrictions */
1810 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301811 default:
1812 /* unknown BTS type */
1813 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001814 }
1815 return 0;
1816}
1817
Harald Welte22af0db2009-02-14 15:41:08 +00001818/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001819int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001820{
1821 struct gsm_bts *bts = ts->trx->bts;
1822 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001823 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001824 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001825 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001826 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001827
1828 if (bts->type == GSM_BTS_TYPE_BS11)
1829 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001830
Harald Weltef325eb42009-02-19 17:07:39 +00001831 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001832 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001833 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001834 LOGP(DNM, LOGL_ERROR,
1835 "Invalid Channel Combination %d on %s. Reason: %s\n",
1836 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001837 return -EINVAL;
1838 }
1839 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001840
Harald Welte52b1f982008-12-23 20:25:15 +00001841 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001842 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001843 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001844 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001845 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001846 if (ts->hopping.enabled) {
1847 unsigned int i;
1848 uint8_t *len;
1849
Harald Welte6e0cd042009-09-12 13:05:33 +02001850 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1851 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001852
1853 /* build the ARFCN list */
1854 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1855 len = msgb_put(msg, 1);
1856 *len = 0;
1857 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1858 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1859 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001860 /* At least BS-11 wants a TLV16 here */
1861 if (bts->type == GSM_BTS_TYPE_BS11)
1862 *len += 1;
1863 else
1864 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001865 }
1866 }
Harald Weltee0590df2009-02-15 03:34:15 +00001867 }
Harald Welte1fe24122014-01-19 17:18:21 +01001868 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001869 if (bts->type == GSM_BTS_TYPE_BS11)
1870 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001871
1872 return abis_nm_sendmsg(bts, msg);
1873}
1874
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001875int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1876 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001877{
1878 struct abis_om_hdr *oh;
1879 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001880 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1881 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001882
1883 if (nack) {
1884 len += 2;
1885 msgtype = NM_MT_SW_ACT_REQ_NACK;
1886 }
Harald Welte34a99682009-02-13 02:41:40 +00001887
1888 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001889 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1890
Harald Welte34a99682009-02-13 02:41:40 +00001891 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001892 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001893 memcpy(ptr, attr, att_len);
1894 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001895 if (nack)
1896 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001897
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001898 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001899}
1900
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001901int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001902{
Harald Welte8470bf22008-12-25 23:28:35 +00001903 struct msgb *msg = nm_msgb_alloc();
1904 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001905 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001906
1907 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1908 fill_om_hdr(oh, len);
1909 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001910 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001911
1912 return abis_nm_sendmsg(bts, msg);
1913}
1914
1915/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001916static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001917{
1918 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001919 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001920
1921 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001922 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001923 0xff, 0xff, 0xff);
1924
1925 return abis_nm_sendmsg(bts, msg);
1926}
1927
Harald Welte34a99682009-02-13 02:41:40 +00001928/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001929int 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 +00001930{
1931 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001932 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001933 struct msgb *msg = nm_msgb_alloc();
1934
1935 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001936 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001937
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001938 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001939 DEBUGPC(DNM, "Sending OPSTART\n");
1940
Harald Welte34a99682009-02-13 02:41:40 +00001941 return abis_nm_sendmsg(bts, msg);
1942}
1943
1944/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001945int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1946 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001947{
1948 struct abis_om_hdr *oh;
1949 struct msgb *msg = nm_msgb_alloc();
1950
1951 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1952 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1953 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1954
1955 return abis_nm_sendmsg(bts, msg);
1956}
1957
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001958int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1959 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001960{
1961 struct abis_om_hdr *oh;
1962 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001963 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001964
1965 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1966 e1_port0, ts0, e1_port1, ts1);
1967
1968 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1969 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1970 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1971
1972 attr = msgb_put(msg, 3);
1973 attr[0] = NM_ATT_MDROP_LINK;
1974 attr[1] = e1_port0;
1975 attr[2] = ts0;
1976
1977 attr = msgb_put(msg, 3);
1978 attr[0] = NM_ATT_MDROP_NEXT;
1979 attr[1] = e1_port1;
1980 attr[2] = ts1;
1981
1982 return abis_nm_sendmsg(bts, msg);
1983}
Harald Welte34a99682009-02-13 02:41:40 +00001984
Harald Weltec7310382009-08-08 00:02:36 +02001985/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001986int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1987 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1988 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001989{
1990 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001991
Harald Welte15c61722011-05-22 22:45:37 +02001992 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001993
1994 if (!msg)
1995 msg = nm_msgb_alloc();
1996
1997 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1998 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1999 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
2000 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02002001 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02002002
2003 return abis_nm_sendmsg(bts, msg);
2004}
2005
Harald Welte52b1f982008-12-23 20:25:15 +00002006int abis_nm_event_reports(struct gsm_bts *bts, int on)
2007{
2008 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00002009 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002010 else
Harald Welte227d4072009-01-03 08:16:25 +00002011 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00002012}
2013
Harald Welte47d88ae2009-01-04 12:02:08 +00002014/* Siemens (or BS-11) specific commands */
2015
Harald Welte3ffd1372009-02-01 22:15:49 +00002016int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
2017{
2018 if (reconnect == 0)
2019 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
2020 else
2021 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
2022}
2023
Harald Welteb8427972009-02-05 19:27:17 +00002024int abis_nm_bs11_restart(struct gsm_bts *bts)
2025{
2026 return __simple_cmd(bts, NM_MT_BS11_RESTART);
2027}
2028
2029
Harald Welte268bb402009-02-01 19:11:56 +00002030struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002031 uint16_t year;
2032 uint8_t month;
2033 uint8_t day;
2034 uint8_t hour;
2035 uint8_t min;
2036 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00002037} __attribute__((packed));
2038
2039
2040void get_bs11_date_time(struct bs11_date_time *aet)
2041{
2042 time_t t;
2043 struct tm *tm;
2044
2045 t = time(NULL);
2046 tm = localtime(&t);
2047 aet->sec = tm->tm_sec;
2048 aet->min = tm->tm_min;
2049 aet->hour = tm->tm_hour;
2050 aet->day = tm->tm_mday;
2051 aet->month = tm->tm_mon;
2052 aet->year = htons(1900 + tm->tm_year);
2053}
2054
Harald Welte05188ee2009-01-18 11:39:08 +00002055int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00002056{
Harald Welte4668fda2009-01-03 08:19:29 +00002057 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00002058}
2059
Harald Welte05188ee2009-01-18 11:39:08 +00002060int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00002061{
2062 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00002063 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002064 else
Harald Welte4668fda2009-01-03 08:19:29 +00002065 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00002066}
Harald Welte47d88ae2009-01-04 12:02:08 +00002067
Harald Welte05188ee2009-01-18 11:39:08 +00002068int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002069 enum abis_bs11_objtype type, uint8_t idx,
2070 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00002071{
2072 struct abis_om_hdr *oh;
2073 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002074 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00002075
2076 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002077 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00002078 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00002079 cur = msgb_put(msg, attr_len);
2080 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00002081
2082 return abis_nm_sendmsg(bts, msg);
2083}
2084
Harald Welte78fc0d42009-02-19 02:50:57 +00002085int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002086 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002087{
2088 struct abis_om_hdr *oh;
2089 struct msgb *msg = nm_msgb_alloc();
2090
2091 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2092 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2093 NM_OC_BS11, type, 0, idx);
2094
2095 return abis_nm_sendmsg(bts, msg);
2096}
2097
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002098int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
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 zero = 0x00;
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, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002106 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2107 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002108
2109 return abis_nm_sendmsg(bts, msg);
2110}
2111
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002112int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002113{
2114 struct abis_om_hdr *oh;
2115 struct msgb *msg = nm_msgb_alloc();
2116
2117 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2118 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002119 idx, 0xff, 0xff);
2120
2121 return abis_nm_sendmsg(bts, msg);
2122}
2123
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002124int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002125{
2126 struct abis_om_hdr *oh;
2127 struct msgb *msg = nm_msgb_alloc();
2128
2129 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2130 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2131 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002132
2133 return abis_nm_sendmsg(bts, msg);
2134}
Harald Welte05188ee2009-01-18 11:39:08 +00002135
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002136static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002137int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2138{
2139 struct abis_om_hdr *oh;
2140 struct msgb *msg = nm_msgb_alloc();
2141
2142 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2143 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2144 0xff, 0xff, 0xff);
2145 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2146
2147 return abis_nm_sendmsg(bts, msg);
2148}
2149
Harald Welteb6c92ae2009-02-21 20:15:32 +00002150/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002151int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2152 uint8_t e1_timeslot, uint8_t e1_subslot,
2153 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002154{
2155 struct abis_om_hdr *oh;
2156 struct abis_nm_channel *ch;
2157 struct msgb *msg = nm_msgb_alloc();
2158
2159 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002160 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002161 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2162
2163 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2164 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002165 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002166
2167 return abis_nm_sendmsg(bts, msg);
2168}
2169
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002170int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002171{
2172 struct abis_om_hdr *oh;
2173 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002174
2175 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002176 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002177 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2178 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2179
2180 return abis_nm_sendmsg(trx->bts, msg);
2181}
2182
Harald Welte78fc0d42009-02-19 02:50:57 +00002183int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2184{
2185 struct abis_om_hdr *oh;
2186 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002187 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002188
2189 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2190 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2191 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2192 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2193
2194 return abis_nm_sendmsg(trx->bts, msg);
2195}
2196
Harald Welteaaf02d92009-04-29 13:25:57 +00002197int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2198{
2199 struct abis_om_hdr *oh;
2200 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002201 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002202
2203 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2204 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2205 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002206 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002207
2208 return abis_nm_sendmsg(bts, msg);
2209}
2210
Harald Welteef061952009-05-17 12:43:42 +00002211int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
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_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002216 NM_ATT_BS11_CCLK_TYPE };
2217
2218 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2219 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2220 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2221 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2222
2223 return abis_nm_sendmsg(bts, msg);
2224
2225}
Harald Welteaaf02d92009-04-29 13:25:57 +00002226
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002227//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002228
Harald Welte1bc09062009-01-18 14:17:52 +00002229int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002230{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002231 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2232}
2233
Daniel Willmann4b054c82010-01-07 00:46:26 +01002234int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2235{
2236 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2237}
2238
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002239int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002240{
Harald Welte05188ee2009-01-18 11:39:08 +00002241 struct abis_om_hdr *oh;
2242 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002243 struct bs11_date_time bdt;
2244
2245 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002246
2247 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002248 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002249 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002250 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002251 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002252 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002253 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002254 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002255 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002256 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002257 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002258 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002259 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002260 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002261 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002262 }
Harald Welte05188ee2009-01-18 11:39:08 +00002263
2264 return abis_nm_sendmsg(bts, msg);
2265}
Harald Welte1bc09062009-01-18 14:17:52 +00002266
2267int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2268{
2269 struct abis_om_hdr *oh;
2270 struct msgb *msg;
2271
2272 if (strlen(password) != 10)
2273 return -EINVAL;
2274
2275 msg = nm_msgb_alloc();
2276 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002277 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002278 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002279 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002280
2281 return abis_nm_sendmsg(bts, msg);
2282}
2283
Harald Weltee69f5fb2009-04-28 16:31:38 +00002284/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2285int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2286{
2287 struct abis_om_hdr *oh;
2288 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002289 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002290
2291 msg = nm_msgb_alloc();
2292 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2293 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2294 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002295
2296 if (locked)
2297 tlv_value = BS11_LI_PLL_LOCKED;
2298 else
2299 tlv_value = BS11_LI_PLL_STANDALONE;
2300
2301 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002302
2303 return abis_nm_sendmsg(bts, msg);
2304}
2305
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002306/* Set the calibration value of the PLL (work value/set value)
2307 * It depends on the login which one is changed */
2308int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2309{
2310 struct abis_om_hdr *oh;
2311 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002312 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002313
2314 msg = nm_msgb_alloc();
2315 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2316 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2317 BS11_OBJ_TRX1, 0x00, 0x00);
2318
2319 tlv_value[0] = value>>8;
2320 tlv_value[1] = value&0xff;
2321
2322 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2323
2324 return abis_nm_sendmsg(bts, msg);
2325}
2326
Harald Welte1bc09062009-01-18 14:17:52 +00002327int abis_nm_bs11_get_state(struct gsm_bts *bts)
2328{
2329 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2330}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002331
2332/* BS11 SWL */
2333
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002334void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002335
Harald Welte5e4d1b32009-02-01 13:36:56 +00002336struct abis_nm_bs11_sw {
2337 struct gsm_bts *bts;
2338 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002339 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002340 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002341 struct llist_head file_list;
2342 gsm_cbfn *user_cb; /* specified by the user */
2343};
2344static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2345
2346struct file_list_entry {
2347 struct llist_head list;
2348 char fname[PATH_MAX];
2349};
2350
2351struct file_list_entry *fl_dequeue(struct llist_head *queue)
2352{
2353 struct llist_head *lh;
2354
2355 if (llist_empty(queue))
2356 return NULL;
2357
2358 lh = queue->next;
2359 llist_del(lh);
2360
2361 return llist_entry(lh, struct file_list_entry, list);
2362}
2363
2364static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2365{
2366 char linebuf[255];
2367 struct llist_head *lh, *lh2;
2368 FILE *swl;
2369 int rc = 0;
2370
2371 swl = fopen(bs11_sw->swl_fname, "r");
2372 if (!swl)
2373 return -ENODEV;
2374
2375 /* zero the stale file list, if any */
2376 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2377 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002378 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002379 }
2380
2381 while (fgets(linebuf, sizeof(linebuf), swl)) {
2382 char file_id[12+1];
2383 char file_version[80+1];
2384 struct file_list_entry *fle;
2385 static char dir[PATH_MAX];
2386
2387 if (strlen(linebuf) < 4)
2388 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002389
Harald Welte5e4d1b32009-02-01 13:36:56 +00002390 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2391 if (rc < 0) {
2392 perror("ERR parsing SWL file");
2393 rc = -EINVAL;
2394 goto out;
2395 }
2396 if (rc < 2)
2397 continue;
2398
Harald Welte470ec292009-06-26 20:25:23 +02002399 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002400 if (!fle) {
2401 rc = -ENOMEM;
2402 goto out;
2403 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002404
2405 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002406 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002407 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2408 strcat(fle->fname, "/");
2409 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002410
2411 llist_add_tail(&fle->list, &bs11_sw->file_list);
2412 }
2413
2414out:
2415 fclose(swl);
2416 return rc;
2417}
2418
2419/* bs11 swload specific callback, passed to abis_nm core swload */
2420static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2421 struct msgb *msg, void *data, void *param)
2422{
2423 struct abis_nm_bs11_sw *bs11_sw = data;
2424 struct file_list_entry *fle;
2425 int rc = 0;
2426
Harald Welte5e4d1b32009-02-01 13:36:56 +00002427 switch (event) {
2428 case NM_MT_LOAD_END_ACK:
2429 fle = fl_dequeue(&bs11_sw->file_list);
2430 if (fle) {
2431 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002432 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002433 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002434 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002435 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002436 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002437 } else {
2438 /* activate the SWL */
2439 rc = abis_nm_software_activate(bs11_sw->bts,
2440 bs11_sw->swl_fname,
2441 bs11_swload_cbfn,
2442 bs11_sw);
2443 }
2444 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002445 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002446 case NM_MT_LOAD_END_NACK:
2447 case NM_MT_LOAD_INIT_ACK:
2448 case NM_MT_LOAD_INIT_NACK:
2449 case NM_MT_ACTIVATE_SW_NACK:
2450 case NM_MT_ACTIVATE_SW_ACK:
2451 default:
2452 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002453 if (bs11_sw->user_cb)
2454 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002455 break;
2456 }
2457
2458 return rc;
2459}
2460
2461/* Siemens provides a SWL file that is a mere listing of all the other
2462 * files that are part of a software release. We need to upload first
2463 * the list file, and then each file that is listed in the list file */
2464int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002465 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002466{
2467 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2468 struct file_list_entry *fle;
2469 int rc = 0;
2470
2471 INIT_LLIST_HEAD(&bs11_sw->file_list);
2472 bs11_sw->bts = bts;
2473 bs11_sw->win_size = win_size;
2474 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002475 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002476
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002477 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002478 rc = bs11_read_swl_file(bs11_sw);
2479 if (rc < 0)
2480 return rc;
2481
2482 /* dequeue next item in file list */
2483 fle = fl_dequeue(&bs11_sw->file_list);
2484 if (!fle)
2485 return -EINVAL;
2486
2487 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002488 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002489 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002490 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002491 return rc;
2492}
2493
Harald Welte5083b0b2009-02-02 19:20:52 +00002494#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002495static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002496 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2497 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2498 NM_ATT_BS11_LMT_USER_NAME,
2499
2500 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2501
2502 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2503
2504 NM_ATT_BS11_SW_LOAD_STORED };
2505
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002506static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002507 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2508 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2509 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2510 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002511#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002512
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002513static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002514 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2515 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002516 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002517
2518int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2519{
2520 struct abis_om_hdr *oh;
2521 struct msgb *msg = nm_msgb_alloc();
2522
2523 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2524 /* SiemensHW CCTRL object */
2525 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2526 0x03, 0x00, 0x00);
2527 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2528
2529 return abis_nm_sendmsg(bts, msg);
2530}
Harald Welte268bb402009-02-01 19:11:56 +00002531
2532int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2533{
2534 struct abis_om_hdr *oh;
2535 struct msgb *msg = nm_msgb_alloc();
2536 struct bs11_date_time aet;
2537
2538 get_bs11_date_time(&aet);
2539 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2540 /* SiemensHW CCTRL object */
2541 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2542 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002543 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002544
2545 return abis_nm_sendmsg(bts, msg);
2546}
Harald Welte5c1e4582009-02-15 11:57:29 +00002547
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002548int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002549{
2550 struct abis_om_hdr *oh;
2551 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002552 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002553
2554 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2555 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2556 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2557 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2558
2559 return abis_nm_sendmsg(bts, msg);
2560}
2561
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002562int 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 +02002563{
2564 struct abis_om_hdr *oh;
2565 struct msgb *msg = nm_msgb_alloc();
2566 struct bs11_date_time aet;
2567
2568 get_bs11_date_time(&aet);
2569 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2570 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2571 bport, 0xff, 0x02);
2572 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2573
2574 return abis_nm_sendmsg(bts, msg);
2575}
2576
Harald Welte5c1e4582009-02-15 11:57:29 +00002577/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002578static const char ipaccess_magic[] = "com.ipaccess";
2579
Harald Welte677c21f2009-02-17 13:22:23 +00002580
2581static int abis_nm_rx_ipacc(struct msgb *msg)
2582{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002583 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002584 struct abis_om_hdr *oh = msgb_l2(msg);
2585 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002586 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002587 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002588 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002589 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002590
2591 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002592 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002593 return -EINVAL;
2594 }
2595
Harald Welte193fefc2009-04-30 15:16:27 +00002596 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002597 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002598
Harald Welte15c61722011-05-22 22:45:37 +02002599 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002600
Harald Welte746d6092009-10-19 22:11:11 +02002601 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002602
Harald Welte677c21f2009-02-17 13:22:23 +00002603 switch (foh->msg_type) {
2604 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002605 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002606 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2607 memcpy(&addr,
2608 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2609
2610 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2611 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002612 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002613 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002614 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002615 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002616 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2617 DEBUGPC(DNM, "STREAM=0x%02x ",
2618 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002619 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002620 break;
2621 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002622 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002623 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002624 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002625 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002626 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002627 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002628 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002629 case NM_MT_IPACC_SET_NVATTR_ACK:
2630 DEBUGPC(DNM, "SET NVATTR ACK\n");
2631 /* FIXME: decode and show the actual attributes */
2632 break;
2633 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002634 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002635 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002636 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002637 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002638 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002639 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002640 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002641 case NM_MT_IPACC_GET_NVATTR_ACK:
2642 DEBUGPC(DNM, "GET NVATTR ACK\n");
2643 /* FIXME: decode and show the actual attributes */
2644 break;
2645 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002646 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002647 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002648 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002649 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002650 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002651 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002652 break;
Harald Welte15c44172009-10-08 20:15:24 +02002653 case NM_MT_IPACC_SET_ATTR_ACK:
2654 DEBUGPC(DNM, "SET ATTR ACK\n");
2655 break;
2656 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002657 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002658 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002659 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002660 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002661 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002662 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002663 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002664 default:
2665 DEBUGPC(DNM, "unknown\n");
2666 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002667 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002668
2669 /* signal handling */
2670 switch (foh->msg_type) {
2671 case NM_MT_IPACC_RSL_CONNECT_NACK:
2672 case NM_MT_IPACC_SET_NVATTR_NACK:
2673 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002674 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 +01002675 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002676 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002677 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002678 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002679 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 +01002680 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002681 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002682 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002683 default:
2684 break;
2685 }
2686
Harald Welte677c21f2009-02-17 13:22:23 +00002687 return 0;
2688}
2689
Harald Welte193fefc2009-04-30 15:16:27 +00002690/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002691int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2692 uint8_t obj_class, uint8_t bts_nr,
2693 uint8_t trx_nr, uint8_t ts_nr,
2694 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002695{
2696 struct msgb *msg = nm_msgb_alloc();
2697 struct abis_om_hdr *oh;
2698 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002699 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002700
2701 /* construct the 12.21 OM header, observe the erroneous length */
2702 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2703 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2704 oh->mdisc = ABIS_OM_MDISC_MANUF;
2705
2706 /* add the ip.access magic */
2707 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2708 *data++ = sizeof(ipaccess_magic);
2709 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2710
2711 /* fill the 12.21 FOM header */
2712 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2713 foh->msg_type = msg_type;
2714 foh->obj_class = obj_class;
2715 foh->obj_inst.bts_nr = bts_nr;
2716 foh->obj_inst.trx_nr = trx_nr;
2717 foh->obj_inst.ts_nr = ts_nr;
2718
2719 if (attr && attr_len) {
2720 data = msgb_put(msg, attr_len);
2721 memcpy(data, attr, attr_len);
2722 }
2723
2724 return abis_nm_sendmsg(bts, msg);
2725}
Harald Welte677c21f2009-02-17 13:22:23 +00002726
Harald Welte193fefc2009-04-30 15:16:27 +00002727/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002728int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002729 int attr_len)
2730{
Harald Welte2ef156d2010-01-07 20:39:42 +01002731 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2732 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002733 attr_len);
2734}
2735
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002736int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002737 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002738{
2739 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002740 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002741 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2742 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2743
2744 int attr_len = sizeof(attr);
2745
2746 ia.s_addr = htonl(ip);
2747 attr[1] = stream;
2748 attr[3] = port >> 8;
2749 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002750 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002751
2752 /* if ip == 0, we use the default IP */
2753 if (ip == 0)
2754 attr_len -= 5;
2755
2756 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002757 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002758
2759 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2760 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2761 trx->nr, 0xff, attr, attr_len);
2762}
2763
Harald Welte193fefc2009-04-30 15:16:27 +00002764/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002765int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002766{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002767 struct abis_om_hdr *oh;
2768 struct msgb *msg = nm_msgb_alloc();
2769
2770 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2771 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2772 trx->bts->nr, trx->nr, 0xff);
2773
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002774 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002775}
Harald Weltedaef5212009-10-24 10:20:41 +02002776
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002777int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2778 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2779 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002780{
2781 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2782 obj_class, bts_nr, trx_nr, ts_nr,
2783 attr, attr_len);
2784}
Harald Welte0f255852009-11-12 14:48:42 +01002785
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002786void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002787{
2788 /* we simply reuse the GSM48 function and overwrite the RAC
2789 * with the Cell ID */
2790 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002791 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002792}
2793
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002794void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2795{
2796 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2797
Harald Welted64c0bc2011-05-30 12:07:53 +02002798 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002799 if (!trx->bts || !trx->bts->oml_link)
2800 return;
2801
2802 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2803 trx->bts->bts_nr, trx->nr, 0xff,
2804 new_state);
2805}
2806
Harald Welte92b1fe42010-03-25 11:45:30 +08002807static const struct value_string ipacc_testres_names[] = {
2808 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2809 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2810 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2811 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2812 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2813 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002814};
2815
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002816const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002817{
Harald Welte92b1fe42010-03-25 11:45:30 +08002818 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002819}
2820
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002821void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002822{
2823 cid->mcc = (buf[0] & 0xf) * 100;
2824 cid->mcc += (buf[0] >> 4) * 10;
2825 cid->mcc += (buf[1] & 0xf) * 1;
2826
2827 if (buf[1] >> 4 == 0xf) {
2828 cid->mnc = (buf[2] & 0xf) * 10;
2829 cid->mnc += (buf[2] >> 4) * 1;
2830 } else {
2831 cid->mnc = (buf[2] & 0xf) * 100;
2832 cid->mnc += (buf[2] >> 4) * 10;
2833 cid->mnc += (buf[1] >> 4) * 1;
2834 }
2835
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002836 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2837 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002838}
2839
Harald Welte0f255852009-11-12 14:48:42 +01002840/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002841int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002842{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002843 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002844 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002845
Harald Welteaf109b92010-07-22 18:14:36 +02002846 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002847
2848 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2849 return -EINVAL;
2850 cur++;
2851
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002852 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002853 cur += 2;
2854
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002855 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002856 cur += 2;
2857
2858 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2859 binf->freq_qual = *cur >> 2;
2860
Harald Welteaf109b92010-07-22 18:14:36 +02002861 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002862 binf->arfcn |= *cur++;
2863
2864 if (binf->info_type & IPAC_BINF_RXLEV)
2865 binf->rx_lev = *cur & 0x3f;
2866 cur++;
2867
2868 if (binf->info_type & IPAC_BINF_RXQUAL)
2869 binf->rx_qual = *cur & 0x7;
2870 cur++;
2871
2872 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002873 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002874 cur += 2;
2875
2876 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002877 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002878 cur += 2;
2879
2880 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002881 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002882 cur += 4;
2883
Harald Weltea780a3d2010-07-30 22:34:42 +02002884#if 0
2885 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002886 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002887#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002888 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002889 cur++;
2890
Harald Welteb40a38f2009-11-13 11:56:05 +01002891 ipac_parse_cgi(&binf->cgi, cur);
2892 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002893
2894 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2895 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2896 cur += sizeof(binf->ba_list_si2);
2897 }
2898
2899 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2900 memcpy(binf->ba_list_si2bis, cur,
2901 sizeof(binf->ba_list_si2bis));
2902 cur += sizeof(binf->ba_list_si2bis);
2903 }
2904
2905 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2906 memcpy(binf->ba_list_si2ter, cur,
2907 sizeof(binf->ba_list_si2ter));
2908 cur += sizeof(binf->ba_list_si2ter);
2909 }
2910
2911 return 0;
2912}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002913
2914void abis_nm_clear_queue(struct gsm_bts *bts)
2915{
2916 struct msgb *msg;
2917
2918 while (!llist_empty(&bts->abis_queue)) {
2919 msg = msgb_dequeue(&bts->abis_queue);
2920 msgb_free(msg);
2921 }
2922
2923 bts->abis_nm_pend = 0;
2924}