blob: 132e72d9d5359f826546db21a628426b72964662 [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,
412 uint8_t i2, const uint8_t *sw_desc, uint8_t swdesc_len)
Harald Welte34a99682009-02-13 02:41:40 +0000413{
414 struct abis_om_hdr *oh;
415 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200416 uint8_t len = swdesc_len;
417 uint8_t *trailer;
Harald Welte34a99682009-02-13 02:41:40 +0000418
419 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
420 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
421
422 trailer = msgb_put(msg, swdesc_len);
423 memcpy(trailer, sw_desc, swdesc_len);
424
425 return abis_nm_sendmsg(bts, msg);
426}
427
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100428int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len,
429 struct abis_nm_sw_descr *desc, const int res_len)
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100430{
431 static const struct tlv_definition sw_descr_def = {
432 .def = {
433 [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
434 [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
435 },
436 };
437
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100438 size_t pos = 0;
439 int desc_pos = 0;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100440
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100441 for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) {
442 uint8_t tag;
443 uint16_t tag_len;
444 const uint8_t *val;
445 int len;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100446
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100447 memset(&desc[desc_pos], 0, sizeof(desc[desc_pos]));
448 desc[desc_pos].start = &sw_descr[pos];
449
450 /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
451 * nested nature and the fact you have to assume it contains only two sub
452 * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
453 if (sw_descr[pos] != NM_ATT_SW_DESCR) {
454 LOGP(DNM, LOGL_ERROR,
455 "SW_DESCR attribute identifier not found!\n");
456 return -1;
457 }
458
459 pos += 1;
460 len = tlv_parse_one(&tag, &tag_len, &val,
461 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
462 if (len < 0 || (tag != NM_ATT_FILE_ID)) {
463 LOGP(DNM, LOGL_ERROR,
464 "FILE_ID attribute identifier not found!\n");
465 return -2;
466 }
467 desc[desc_pos].file_id = val;
468 desc[desc_pos].file_id_len = tag_len;
469 pos += len;
470
471
472 len = tlv_parse_one(&tag, &tag_len, &val,
473 &sw_descr_def, &sw_descr[pos], sw_descr_len - pos);
474 if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
475 LOGP(DNM, LOGL_ERROR,
476 "FILE_VERSION attribute identifier not found!\n");
477 return -3;
478 }
479 desc[desc_pos].file_ver = val;
480 desc[desc_pos].file_ver_len = tag_len;
481 pos += len;
482
483 /* final size */
484 desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100485 }
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100486
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100487 return desc_pos;
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100488}
489
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100490int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr,
491 const size_t size)
492{
493 int res = 0;
494 int i;
495
496 for (i = 1; i < size; ++i) {
497 if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver,
498 OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) {
499 res = i;
500 }
501 }
502
503 return res;
504}
505
Harald Welte34a99682009-02-13 02:41:40 +0000506static int abis_nm_rx_sw_act_req(struct msgb *mb)
507{
508 struct abis_om_hdr *oh = msgb_l2(mb);
509 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200510 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200511 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200512 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100513 int ret, sw_config_len, len;
514 struct abis_nm_sw_descr sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000515
Harald Welte15c61722011-05-22 22:45:37 +0200516 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200517
518 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000519
Harald Welte97a282b2010-03-14 15:37:43 +0800520 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000521
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200522 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000523 foh->obj_inst.bts_nr,
524 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800525 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000526 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100527 if (ret != 0) {
528 LOGP(DNM, LOGL_ERROR,
529 "Sending SW ActReq ACK failed: %d\n", ret);
530 return ret;
531 }
Harald Welte34a99682009-02-13 02:41:40 +0000532
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200533 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200534 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
535 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
536 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100537 LOGP(DNM, LOGL_ERROR,
538 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200539 return -EINVAL;
540 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200541 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200542 }
543
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100544 /* Parse up to two sw descriptions from the data */
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100545 len = abis_nm_parse_sw_config(sw_config, sw_config_len,
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100546 &sw_descr[0], ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100547 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100548 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100549 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100550 }
Mike Habena03f9772009-10-01 14:56:13 +0200551
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100552 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
553 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
554
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200555 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000556 foh->obj_inst.bts_nr,
557 foh->obj_inst.trx_nr,
558 foh->obj_inst.ts_nr,
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100559 sw_descr[ret].start, sw_descr[ret].len);
Harald Welte34a99682009-02-13 02:41:40 +0000560}
561
Harald Weltee0590df2009-02-15 03:34:15 +0000562/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
563static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
564{
565 struct abis_om_hdr *oh = msgb_l2(mb);
566 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200567 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000568 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200569 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000570
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200571 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000572 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
573 return -EINVAL;
574
575 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
576
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200577 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000578}
579
Harald Welteee670472009-02-22 21:58:49 +0000580static int abis_nm_rx_lmt_event(struct msgb *mb)
581{
582 struct abis_om_hdr *oh = msgb_l2(mb);
583 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200584 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000585 struct tlv_parsed tp;
586
587 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200588 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000589 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
590 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200591 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000592 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
593 }
594 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
595 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200596 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000597 DEBUGPC(DNM, "Level=%u ", level);
598 }
599 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
600 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
601 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
602 DEBUGPC(DNM, "Username=%s ", name);
603 }
604 DEBUGPC(DNM, "\n");
605 /* FIXME: parse LMT LOGON TIME */
606 return 0;
607}
608
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200609void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100610{
611 int wait = 0;
612 struct msgb *msg;
613 /* the queue is empty */
614 while (!llist_empty(&bts->abis_queue)) {
615 msg = msgb_dequeue(&bts->abis_queue);
616 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200617 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100618
619 if (wait)
620 break;
621 }
622
623 bts->abis_nm_pend = wait;
624}
625
Harald Welte52b1f982008-12-23 20:25:15 +0000626/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000627static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000628{
Harald Welte6c96ba52009-05-01 13:03:40 +0000629 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000630 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200631 struct e1inp_sign_link *sign_link = mb->dst;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200632 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100633 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
634 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100635 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000636
637 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000638 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100639 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000640
Harald Welte15c61722011-05-22 22:45:37 +0200641 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000642 return abis_nm_rcvmsg_sw(mb);
643
Harald Welte15c61722011-05-22 22:45:37 +0200644 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800645 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000646 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200647
Harald Welte15c61722011-05-22 22:45:37 +0200648 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200649
Harald Welte15c61722011-05-22 22:45:37 +0200650 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000651
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100652 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000653 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200654 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200655 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000656 else
657 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200658
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800659 nack_data.msg = mb;
660 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100661 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200662 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100663 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200664 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000665 }
Harald Weltead384642008-12-26 10:20:07 +0000666#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000667 /* check if last message is to be acked */
668 if (is_ack_nack(nmh->last_msgtype)) {
669 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100670 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000671 /* we got our ACK, continue sending the next msg */
672 } else if (mt == MT_NACK(nmh->last_msgtype)) {
673 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100674 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000675 /* FIXME: somehow signal this to the caller */
676 } else {
677 /* really strange things happen */
678 return -EINVAL;
679 }
680 }
Harald Weltead384642008-12-26 10:20:07 +0000681#endif
682
Harald Welte97ed1e72009-02-06 13:38:02 +0000683 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000684 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100685 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000686 break;
Harald Welte34a99682009-02-13 02:41:40 +0000687 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100688 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000689 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000690 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100691 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000692 break;
Max689e7e52017-04-04 19:21:24 +0200693 case NM_MT_OPSTART_ACK:
694 abis_nm_debugp_foh(DNM, foh);
695 DEBUGPC(DNM, "Opstart ACK\n");
696 break;
697 case NM_MT_SET_CHAN_ATTR_ACK:
698 abis_nm_debugp_foh(DNM, foh);
699 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
700 break;
701 case NM_MT_SET_RADIO_ATTR_ACK:
702 abis_nm_debugp_foh(DNM, foh);
703 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
704 break;
Harald Welte1989c082009-08-06 17:58:31 +0200705 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200706 abis_nm_debugp_foh(DNM, foh);
707 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200708 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100709 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200710 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100711 break;
712 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200713 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100714 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100715 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100716 break;
Max689e7e52017-04-04 19:21:24 +0200717 default:
718 abis_nm_debugp_foh(DNM, foh);
719 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
720 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000721 }
722
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100723 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100724 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000725}
726
Harald Welte677c21f2009-02-17 13:22:23 +0000727static int abis_nm_rx_ipacc(struct msgb *mb);
728
729static int abis_nm_rcvmsg_manuf(struct msgb *mb)
730{
731 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200732 struct e1inp_sign_link *sign_link = mb->dst;
733 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000734
735 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100736 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100737 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000738 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200739 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000740 break;
741 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100742 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
743 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000744 rc = 0;
745 break;
746 }
747
748 return rc;
749}
750
Harald Welte52b1f982008-12-23 20:25:15 +0000751/* High-Level API */
752/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000753int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000754{
Harald Welte52b1f982008-12-23 20:25:15 +0000755 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000756 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000757
758 /* Various consistency checks */
759 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100760 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000761 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200762 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
763 rc = -EINVAL;
764 goto err;
765 }
Harald Welte52b1f982008-12-23 20:25:15 +0000766 }
767 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100768 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000769 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200770 rc = -EINVAL;
771 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000772 }
Harald Welte702d8702008-12-26 20:25:35 +0000773#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200774 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000775 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000776 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100777 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000778 oh->length + sizeof(*oh), l2_len);
779 return -EINVAL;
780 }
Harald Welte702d8702008-12-26 20:25:35 +0000781 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100782 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 +0000783#endif
Harald Weltead384642008-12-26 10:20:07 +0000784 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000785
786 switch (oh->mdisc) {
787 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000788 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000789 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000790 case ABIS_OM_MDISC_MANUF:
791 rc = abis_nm_rcvmsg_manuf(msg);
792 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000793 case ABIS_OM_MDISC_MMI:
794 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100795 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000796 oh->mdisc);
797 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000798 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100799 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000800 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200801 rc = -EINVAL;
802 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000803 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200804err:
Harald Weltead384642008-12-26 10:20:07 +0000805 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000806 return rc;
807}
808
809#if 0
810/* initialized all resources */
811struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
812{
813 struct abis_nm_h *nmh;
814
815 nmh = malloc(sizeof(*nmh));
816 if (!nmh)
817 return NULL;
818
819 nmh->cfg = cfg;
820
821 return nmh;
822}
823
824/* free all resources */
825void abis_nm_fini(struct abis_nm_h *nmh)
826{
827 free(nmh);
828}
829#endif
830
831/* Here we are trying to define a high-level API that can be used by
832 * the actual BSC implementation. However, the architecture is currently
833 * still under design. Ideally the calls to this API would be synchronous,
834 * while the underlying stack behind the APi runs in a traditional select
835 * based state machine.
836 */
837
Harald Welte4724f992009-01-18 18:01:49 +0000838/* 6.2 Software Load: */
839enum sw_state {
840 SW_STATE_NONE,
841 SW_STATE_WAIT_INITACK,
842 SW_STATE_WAIT_SEGACK,
843 SW_STATE_WAIT_ENDACK,
844 SW_STATE_WAIT_ACTACK,
845 SW_STATE_ERROR,
846};
Harald Welte52b1f982008-12-23 20:25:15 +0000847
Harald Welte52b1f982008-12-23 20:25:15 +0000848struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000849 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800850 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000851 gsm_cbfn *cbfn;
852 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000853 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000854
Harald Welte52b1f982008-12-23 20:25:15 +0000855 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200856 uint8_t obj_class;
857 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000858
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200859 uint8_t file_id[255];
860 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000861
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200862 uint8_t file_version[255];
863 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000864
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200865 uint8_t window_size;
866 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000867
868 int fd;
869 FILE *stream;
870 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000871 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000872};
873
Harald Welte4724f992009-01-18 18:01:49 +0000874static struct abis_nm_sw g_sw;
875
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100876static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
877{
878 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
879 msgb_v_put(msg, NM_ATT_SW_DESCR);
880 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
881 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
882 sw->file_version);
883 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
884 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
885 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
886 sw->file_version);
887 } else {
888 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
889 }
890}
891
Harald Welte4724f992009-01-18 18:01:49 +0000892/* 6.2.1 / 8.3.1: Load Data Initiate */
893static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000894{
Harald Welte4724f992009-01-18 18:01:49 +0000895 struct abis_om_hdr *oh;
896 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200897 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000898
899 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
900 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
901 sw->obj_instance[0], sw->obj_instance[1],
902 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100903
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100904 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000905 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
906
907 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000908}
909
Harald Welte1602ade2009-01-29 21:12:39 +0000910static int is_last_line(FILE *stream)
911{
912 char next_seg_buf[256];
913 long pos;
914
915 /* check if we're sending the last line */
916 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200917
918 /* Did ftell fail? Then we are at the end for sure */
919 if (pos < 0)
920 return 1;
921
Harald Welte1602ade2009-01-29 21:12:39 +0000922 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100923 int rc = fseek(stream, pos, SEEK_SET);
924 if (rc < 0)
925 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000926 return 1;
927 }
928
929 fseek(stream, pos, SEEK_SET);
930 return 0;
931}
932
Harald Welte4724f992009-01-18 18:01:49 +0000933/* 6.2.2 / 8.3.2 Load Data Segment */
934static int sw_load_segment(struct abis_nm_sw *sw)
935{
936 struct abis_om_hdr *oh;
937 struct msgb *msg = nm_msgb_alloc();
938 char seg_buf[256];
939 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000940 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200941 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000942
943 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000944
945 switch (sw->bts->type) {
946 case GSM_BTS_TYPE_BS11:
947 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
948 perror("fgets reading segment");
949 return -EINVAL;
950 }
951 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000952
953 /* check if we're sending the last line */
954 sw->last_seg = is_last_line(sw->stream);
955 if (sw->last_seg)
956 seg_buf[1] = 0;
957 else
958 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000959
960 len = strlen(line_buf) + 2;
961 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200962 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000963 /* BS11 wants CR + LF in excess of the TLV length !?! */
964 tlv[1] -= 2;
965
966 /* we only now know the exact length for the OM hdr */
967 len = strlen(line_buf)+2;
968 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100969 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200970 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100971 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
972 if (len < 0) {
973 perror("read failed");
974 return -EINVAL;
975 }
976
977 if (len != IPACC_SEGMENT_SIZE)
978 sw->last_seg = 1;
979
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100980 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200981 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100982 len += 3;
983 break;
984 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000985 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100986 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000987 /* FIXME: Other BTS types */
988 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000989 }
Harald Welte4724f992009-01-18 18:01:49 +0000990
Harald Welte4724f992009-01-18 18:01:49 +0000991 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
992 sw->obj_instance[0], sw->obj_instance[1],
993 sw->obj_instance[2]);
994
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100995 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000996}
997
998/* 6.2.4 / 8.3.4 Load Data End */
999static int sw_load_end(struct abis_nm_sw *sw)
1000{
1001 struct abis_om_hdr *oh;
1002 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001003 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +00001004
1005 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1006 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
1007 sw->obj_instance[0], sw->obj_instance[1],
1008 sw->obj_instance[2]);
1009
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +01001010 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +00001011 return abis_nm_sendmsg(sw->bts, msg);
1012}
Harald Welte5e4d1b32009-02-01 13:36:56 +00001013
Harald Welte52b1f982008-12-23 20:25:15 +00001014/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +00001015static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +00001016{
Harald Welte4724f992009-01-18 18:01:49 +00001017 struct abis_om_hdr *oh;
1018 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001019 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +00001020
Harald Welte4724f992009-01-18 18:01:49 +00001021 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1022 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
1023 sw->obj_instance[0], sw->obj_instance[1],
1024 sw->obj_instance[2]);
1025
1026 /* FIXME: this is BS11 specific format */
1027 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
1028 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
1029 sw->file_version);
1030
1031 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +00001032}
Harald Welte4724f992009-01-18 18:01:49 +00001033
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001034struct sdp_firmware {
1035 char magic[4];
1036 char more_magic[4];
1037 unsigned int header_length;
1038 unsigned int file_length;
1039} __attribute__ ((packed));
1040
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001041static int parse_sdp_header(struct abis_nm_sw *sw)
1042{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +01001043 struct sdp_firmware firmware_header;
1044 int rc;
1045 struct stat stat;
1046
1047 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
1048 if (rc != sizeof(firmware_header)) {
1049 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
1050 return -1;
1051 }
1052
1053 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
1054 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
1055 return -1;
1056 }
1057
1058 if (firmware_header.more_magic[0] != 0x10 ||
1059 firmware_header.more_magic[1] != 0x02 ||
1060 firmware_header.more_magic[2] != 0x00 ||
1061 firmware_header.more_magic[3] != 0x00) {
1062 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
1063 return -1;
1064 }
1065
1066
1067 if (fstat(sw->fd, &stat) == -1) {
1068 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1069 return -1;
1070 }
1071
1072 if (ntohl(firmware_header.file_length) != stat.st_size) {
1073 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1074 return -1;
1075 }
1076
1077 /* go back to the start as we checked the whole filesize.. */
1078 lseek(sw->fd, 0l, SEEK_SET);
1079 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1080 "There might be checksums in the file that are not\n"
1081 "verified and incomplete firmware might be flashed.\n"
1082 "There is absolutely no WARRANTY that flashing will\n"
1083 "work.\n");
1084 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001085}
1086
Harald Welte4724f992009-01-18 18:01:49 +00001087static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1088{
1089 char file_id[12+1];
1090 char file_version[80+1];
1091 int rc;
1092
1093 sw->fd = open(fname, O_RDONLY);
1094 if (sw->fd < 0)
1095 return sw->fd;
1096
1097 switch (sw->bts->type) {
1098 case GSM_BTS_TYPE_BS11:
1099 sw->stream = fdopen(sw->fd, "r");
1100 if (!sw->stream) {
1101 perror("fdopen");
1102 return -1;
1103 }
1104 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001105 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001106 file_id, file_version);
1107 if (rc != 2) {
1108 perror("parsing header line of software file");
1109 return -1;
1110 }
1111 strcpy((char *)sw->file_id, file_id);
1112 sw->file_id_len = strlen(file_id);
1113 strcpy((char *)sw->file_version, file_version);
1114 sw->file_version_len = strlen(file_version);
1115 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001116 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001117 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001118 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001119 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001120 rc = parse_sdp_header(sw);
1121 if (rc < 0) {
1122 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1123 return -1;
1124 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001125
1126 strcpy((char *)sw->file_id, "id");
1127 sw->file_id_len = 3;
1128 strcpy((char *)sw->file_version, "version");
1129 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001130 break;
Harald Welte4724f992009-01-18 18:01:49 +00001131 default:
1132 /* We don't know how to treat them yet */
1133 close(sw->fd);
1134 return -EINVAL;
1135 }
1136
1137 return 0;
1138}
1139
1140static void sw_close_file(struct abis_nm_sw *sw)
1141{
1142 switch (sw->bts->type) {
1143 case GSM_BTS_TYPE_BS11:
1144 fclose(sw->stream);
1145 break;
1146 default:
1147 close(sw->fd);
1148 break;
1149 }
1150}
1151
1152/* Fill the window */
1153static int sw_fill_window(struct abis_nm_sw *sw)
1154{
1155 int rc;
1156
1157 while (sw->seg_in_window < sw->window_size) {
1158 rc = sw_load_segment(sw);
1159 if (rc < 0)
1160 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001161 if (sw->last_seg)
1162 break;
Harald Welte4724f992009-01-18 18:01:49 +00001163 }
1164 return 0;
1165}
1166
1167/* callback function from abis_nm_rcvmsg() handler */
1168static int abis_nm_rcvmsg_sw(struct msgb *mb)
1169{
1170 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001171 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001172 int rc = -1;
1173 struct abis_nm_sw *sw = &g_sw;
1174 enum sw_state old_state = sw->state;
1175
Harald Welte3ffd1372009-02-01 22:15:49 +00001176 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001177
1178 switch (sw->state) {
1179 case SW_STATE_WAIT_INITACK:
1180 switch (foh->msg_type) {
1181 case NM_MT_LOAD_INIT_ACK:
1182 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001183 if (sw->cbfn)
1184 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1185 NM_MT_LOAD_INIT_ACK, mb,
1186 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001187 rc = sw_fill_window(sw);
1188 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001189 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001190 break;
1191 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001192 if (sw->forced) {
1193 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1194 "Init NACK\n");
1195 if (sw->cbfn)
1196 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1197 NM_MT_LOAD_INIT_ACK, mb,
1198 sw->cb_data, NULL);
1199 rc = sw_fill_window(sw);
1200 sw->state = SW_STATE_WAIT_SEGACK;
1201 } else {
1202 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001203 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001204 if (sw->cbfn)
1205 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1206 NM_MT_LOAD_INIT_NACK, mb,
1207 sw->cb_data, NULL);
1208 sw->state = SW_STATE_ERROR;
1209 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001210 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001211 break;
1212 }
1213 break;
1214 case SW_STATE_WAIT_SEGACK:
1215 switch (foh->msg_type) {
1216 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001217 if (sw->cbfn)
1218 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1219 NM_MT_LOAD_SEG_ACK, mb,
1220 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001221 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001222 if (!sw->last_seg) {
1223 /* fill window with more segments */
1224 rc = sw_fill_window(sw);
1225 sw->state = SW_STATE_WAIT_SEGACK;
1226 } else {
1227 /* end the transfer */
1228 sw->state = SW_STATE_WAIT_ENDACK;
1229 rc = sw_load_end(sw);
1230 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001231 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001232 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001233 case NM_MT_LOAD_ABORT:
1234 if (sw->cbfn)
1235 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1236 NM_MT_LOAD_ABORT, mb,
1237 sw->cb_data, NULL);
1238 break;
Harald Welte4724f992009-01-18 18:01:49 +00001239 }
1240 break;
1241 case SW_STATE_WAIT_ENDACK:
1242 switch (foh->msg_type) {
1243 case NM_MT_LOAD_END_ACK:
1244 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001245 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1246 sw->bts->nr);
1247 sw->state = SW_STATE_NONE;
1248 if (sw->cbfn)
1249 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1250 NM_MT_LOAD_END_ACK, mb,
1251 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001252 rc = 0;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001253 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001254 break;
1255 case NM_MT_LOAD_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001256 if (sw->forced) {
1257 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1258 "End NACK\n");
1259 sw->state = SW_STATE_NONE;
1260 if (sw->cbfn)
1261 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1262 NM_MT_LOAD_END_ACK, mb,
1263 sw->cb_data, NULL);
1264 } else {
1265 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001266 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001267 sw->state = SW_STATE_ERROR;
1268 if (sw->cbfn)
1269 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1270 NM_MT_LOAD_END_NACK, mb,
1271 sw->cb_data, NULL);
1272 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001273 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001274 break;
1275 }
1276 case SW_STATE_WAIT_ACTACK:
1277 switch (foh->msg_type) {
1278 case NM_MT_ACTIVATE_SW_ACK:
1279 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001280 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001281 sw->state = SW_STATE_NONE;
1282 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001283 if (sw->cbfn)
1284 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1285 NM_MT_ACTIVATE_SW_ACK, mb,
1286 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001287 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001288 break;
1289 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001290 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001291 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001292 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001293 if (sw->cbfn)
1294 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1295 NM_MT_ACTIVATE_SW_NACK, mb,
1296 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001297 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001298 break;
1299 }
1300 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001301 switch (foh->msg_type) {
1302 case NM_MT_ACTIVATE_SW_ACK:
1303 rc = 0;
1304 break;
1305 }
1306 break;
Harald Welte4724f992009-01-18 18:01:49 +00001307 case SW_STATE_ERROR:
1308 break;
1309 }
1310
1311 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001312 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001313 foh->msg_type, old_state, sw->state);
1314
1315 return rc;
1316}
1317
1318/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001319int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001320 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001321 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001322{
1323 struct abis_nm_sw *sw = &g_sw;
1324 int rc;
1325
Harald Welte5e4d1b32009-02-01 13:36:56 +00001326 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1327 bts->nr, fname);
1328
Harald Welte4724f992009-01-18 18:01:49 +00001329 if (sw->state != SW_STATE_NONE)
1330 return -EBUSY;
1331
1332 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001333 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001334
1335 switch (bts->type) {
1336 case GSM_BTS_TYPE_BS11:
1337 sw->obj_class = NM_OC_SITE_MANAGER;
1338 sw->obj_instance[0] = 0xff;
1339 sw->obj_instance[1] = 0xff;
1340 sw->obj_instance[2] = 0xff;
1341 break;
1342 case GSM_BTS_TYPE_NANOBTS:
1343 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001344 sw->obj_instance[0] = sw->bts->nr;
1345 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001346 sw->obj_instance[2] = 0xff;
1347 break;
1348 case GSM_BTS_TYPE_UNKNOWN:
1349 default:
1350 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1351 return -1;
1352 break;
1353 }
Harald Welte4724f992009-01-18 18:01:49 +00001354 sw->window_size = win_size;
1355 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001356 sw->cbfn = cbfn;
1357 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001358 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001359
1360 rc = sw_open_file(sw, fname);
1361 if (rc < 0) {
1362 sw->state = SW_STATE_NONE;
1363 return rc;
1364 }
1365
1366 return sw_load_init(sw);
1367}
Harald Welte52b1f982008-12-23 20:25:15 +00001368
Harald Welte1602ade2009-01-29 21:12:39 +00001369int abis_nm_software_load_status(struct gsm_bts *bts)
1370{
1371 struct abis_nm_sw *sw = &g_sw;
1372 struct stat st;
1373 int rc, percent;
1374
1375 rc = fstat(sw->fd, &st);
1376 if (rc < 0) {
1377 perror("ERROR during stat");
1378 return rc;
1379 }
1380
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001381 if (sw->stream)
1382 percent = (ftell(sw->stream) * 100) / st.st_size;
1383 else
1384 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001385 return percent;
1386}
1387
Harald Welte5e4d1b32009-02-01 13:36:56 +00001388/* Activate the specified software into the BTS */
1389int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1390 gsm_cbfn *cbfn, void *cb_data)
1391{
1392 struct abis_nm_sw *sw = &g_sw;
1393 int rc;
1394
1395 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1396 bts->nr, fname);
1397
1398 if (sw->state != SW_STATE_NONE)
1399 return -EBUSY;
1400
1401 sw->bts = bts;
1402 sw->obj_class = NM_OC_SITE_MANAGER;
1403 sw->obj_instance[0] = 0xff;
1404 sw->obj_instance[1] = 0xff;
1405 sw->obj_instance[2] = 0xff;
1406 sw->state = SW_STATE_WAIT_ACTACK;
1407 sw->cbfn = cbfn;
1408 sw->cb_data = cb_data;
1409
1410 /* Open the file in order to fill some sw struct members */
1411 rc = sw_open_file(sw, fname);
1412 if (rc < 0) {
1413 sw->state = SW_STATE_NONE;
1414 return rc;
1415 }
1416 sw_close_file(sw);
1417
1418 return sw_activate(sw);
1419}
1420
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001421static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1422 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001423{
Harald Welteadaf08b2009-01-18 11:08:10 +00001424 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001425 ch->bts_port = bts_port;
1426 ch->timeslot = ts_nr;
1427 ch->subslot = subslot_nr;
1428}
1429
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001430int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1431 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1432 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001433{
1434 struct abis_om_hdr *oh;
1435 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001436 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001437 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001438
1439 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1440 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1441 bts->bts_nr, trx_nr, 0xff);
1442
Harald Welte8470bf22008-12-25 23:28:35 +00001443 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001444
1445 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1446 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1447
1448 return abis_nm_sendmsg(bts, msg);
1449}
1450
1451/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1452int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001453 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001454{
Harald Welte8470bf22008-12-25 23:28:35 +00001455 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001456 struct abis_om_hdr *oh;
1457 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001458 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001459
1460 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001461 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001462 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1463
1464 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1465 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1466
1467 return abis_nm_sendmsg(bts, msg);
1468}
1469
1470#if 0
1471int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1472 struct abis_nm_abis_channel *chan)
1473{
1474}
1475#endif
1476
1477int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001478 uint8_t e1_port, uint8_t e1_timeslot,
1479 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001480{
1481 struct gsm_bts *bts = ts->trx->bts;
1482 struct abis_om_hdr *oh;
1483 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001484 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001485
1486 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1487 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001488 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001489
1490 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1491 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1492
Harald Weltef325eb42009-02-19 17:07:39 +00001493 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1494 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001495 e1_port, e1_timeslot, e1_subslot);
1496
Harald Welte52b1f982008-12-23 20:25:15 +00001497 return abis_nm_sendmsg(bts, msg);
1498}
1499
1500#if 0
1501int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1502 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001503 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001504{
1505}
1506#endif
1507
Harald Weltefe568f22012-08-14 19:15:57 +02001508/* Chapter 8.11.1 */
1509int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1510 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1511 uint8_t *attr, uint8_t attr_len)
1512{
1513 struct abis_om_hdr *oh;
1514 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001515
1516 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1517
1518 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1519 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1520 bts_nr, trx_nr, ts_nr);
1521 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1522
1523 return abis_nm_sendmsg(bts, msg);
1524}
1525
Harald Welte22af0db2009-02-14 15:41:08 +00001526/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001527int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001528{
1529 struct abis_om_hdr *oh;
1530 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001531 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001532
1533 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1534
1535 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001536 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 +00001537 cur = msgb_put(msg, attr_len);
1538 memcpy(cur, attr, attr_len);
1539
1540 return abis_nm_sendmsg(bts, msg);
1541}
1542
1543/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001544int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001545{
1546 struct abis_om_hdr *oh;
1547 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001548 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001549
1550 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1551
1552 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1553 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001554 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001555 cur = msgb_put(msg, attr_len);
1556 memcpy(cur, attr, attr_len);
1557
1558 return abis_nm_sendmsg(trx->bts, msg);
1559}
1560
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001561int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1562{
1563 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1564 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1565}
1566
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001567static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1568 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001569{
1570 int i;
1571
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001572 *reason = "Reason unknown";
1573
Harald Welte39c7deb2009-08-09 21:49:48 +02001574 /* As it turns out, the BS-11 has some very peculiar restrictions
1575 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301576 switch (ts->trx->bts->type) {
1577 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001578 switch (chan_comb) {
1579 case NM_CHANC_TCHHalf:
1580 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001581 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001582 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001583 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001584 return -EINVAL;
1585 case NM_CHANC_SDCCH:
1586 /* only one SDCCH/8 per TRX */
1587 for (i = 0; i < TRX_NR_TS; i++) {
1588 if (i == ts->nr)
1589 continue;
1590 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001591 NM_CHANC_SDCCH) {
1592 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001593 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001594 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001595 }
1596 /* not allowed for TS0 of BCCH-TRX */
1597 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001598 ts->nr == 0) {
1599 *reason = "SDCCH/8 must be on TS0.";
1600 return -EINVAL;
1601 }
1602
Harald Welte39c7deb2009-08-09 21:49:48 +02001603 /* not on the same TRX that has a BCCH+SDCCH4
1604 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001605 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001606 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001607 ts->trx->ts[0].nm_chan_comb == 8)) {
1608 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1609 return -EINVAL;
1610 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001611 break;
1612 case NM_CHANC_mainBCCH:
1613 case NM_CHANC_BCCHComb:
1614 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001615 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1616 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001617 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001618 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001619 break;
1620 case NM_CHANC_BCCH:
1621 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001622 if (ts->trx != ts->trx->bts->c0) {
1623 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001624 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001625 }
1626 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1627 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001628 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001629 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001630 break;
1631 case 8: /* this is not like 08.58, but in fact
1632 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1633 /* FIXME: only one CBCH allowed per cell */
1634 break;
1635 }
Harald Welted6575f92009-12-02 02:45:23 +05301636 break;
1637 case GSM_BTS_TYPE_NANOBTS:
1638 switch (ts->nr) {
1639 case 0:
1640 if (ts->trx->nr == 0) {
1641 /* only on TRX0 */
1642 switch (chan_comb) {
1643 case NM_CHANC_BCCH:
1644 case NM_CHANC_mainBCCH:
1645 case NM_CHANC_BCCHComb:
1646 return 0;
1647 break;
1648 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001649 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301650 return -EINVAL;
1651 }
1652 } else {
1653 switch (chan_comb) {
1654 case NM_CHANC_TCHFull:
1655 case NM_CHANC_TCHHalf:
1656 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1657 return 0;
1658 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001659 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301660 return -EINVAL;
1661 }
1662 }
1663 break;
1664 case 1:
1665 if (ts->trx->nr == 0) {
1666 switch (chan_comb) {
1667 case NM_CHANC_SDCCH_CBCH:
1668 if (ts->trx->ts[0].nm_chan_comb ==
1669 NM_CHANC_mainBCCH)
1670 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001671 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301672 return -EINVAL;
1673 case NM_CHANC_SDCCH:
1674 case NM_CHANC_TCHFull:
1675 case NM_CHANC_TCHHalf:
1676 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1677 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001678 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301679 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001680 default:
1681 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1682 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301683 }
1684 } else {
1685 switch (chan_comb) {
1686 case NM_CHANC_SDCCH:
1687 case NM_CHANC_TCHFull:
1688 case NM_CHANC_TCHHalf:
1689 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1690 return 0;
1691 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001692 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301693 return -EINVAL;
1694 }
1695 }
1696 break;
1697 case 2:
1698 case 3:
1699 case 4:
1700 case 5:
1701 case 6:
1702 case 7:
1703 switch (chan_comb) {
1704 case NM_CHANC_TCHFull:
1705 case NM_CHANC_TCHHalf:
1706 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1707 return 0;
1708 case NM_CHANC_IPAC_PDCH:
1709 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001710 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301711 if (ts->trx->nr == 0)
1712 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001713 else {
1714 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301715 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001716 }
Harald Welted6575f92009-12-02 02:45:23 +05301717 }
1718 break;
1719 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001720 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301721 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001722 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001723 /* no known restrictions */
1724 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301725 default:
1726 /* unknown BTS type */
1727 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001728 }
1729 return 0;
1730}
1731
Harald Welte22af0db2009-02-14 15:41:08 +00001732/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001733int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001734{
1735 struct gsm_bts *bts = ts->trx->bts;
1736 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001737 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001738 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001739 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001740 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001741
1742 if (bts->type == GSM_BTS_TYPE_BS11)
1743 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001744
Harald Weltef325eb42009-02-19 17:07:39 +00001745 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001746 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001747 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001748 LOGP(DNM, LOGL_ERROR,
1749 "Invalid Channel Combination %d on %s. Reason: %s\n",
1750 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001751 return -EINVAL;
1752 }
1753 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001754
Harald Welte52b1f982008-12-23 20:25:15 +00001755 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001756 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001757 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001758 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001759 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001760 if (ts->hopping.enabled) {
1761 unsigned int i;
1762 uint8_t *len;
1763
Harald Welte6e0cd042009-09-12 13:05:33 +02001764 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1765 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001766
1767 /* build the ARFCN list */
1768 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1769 len = msgb_put(msg, 1);
1770 *len = 0;
1771 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1772 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1773 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001774 /* At least BS-11 wants a TLV16 here */
1775 if (bts->type == GSM_BTS_TYPE_BS11)
1776 *len += 1;
1777 else
1778 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001779 }
1780 }
Harald Weltee0590df2009-02-15 03:34:15 +00001781 }
Harald Welte1fe24122014-01-19 17:18:21 +01001782 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001783 if (bts->type == GSM_BTS_TYPE_BS11)
1784 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001785
1786 return abis_nm_sendmsg(bts, msg);
1787}
1788
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001789int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1790 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001791{
1792 struct abis_om_hdr *oh;
1793 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001794 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1795 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001796
1797 if (nack) {
1798 len += 2;
1799 msgtype = NM_MT_SW_ACT_REQ_NACK;
1800 }
Harald Welte34a99682009-02-13 02:41:40 +00001801
1802 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001803 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1804
Harald Welte34a99682009-02-13 02:41:40 +00001805 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001806 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001807 memcpy(ptr, attr, att_len);
1808 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001809 if (nack)
1810 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001811
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001812 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001813}
1814
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001815int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001816{
Harald Welte8470bf22008-12-25 23:28:35 +00001817 struct msgb *msg = nm_msgb_alloc();
1818 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001819 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001820
1821 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1822 fill_om_hdr(oh, len);
1823 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001824 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001825
1826 return abis_nm_sendmsg(bts, msg);
1827}
1828
1829/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001830static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001831{
1832 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001833 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001834
1835 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001836 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001837 0xff, 0xff, 0xff);
1838
1839 return abis_nm_sendmsg(bts, msg);
1840}
1841
Harald Welte34a99682009-02-13 02:41:40 +00001842/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001843int 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 +00001844{
1845 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001846 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001847 struct msgb *msg = nm_msgb_alloc();
1848
1849 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001850 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001851
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001852 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001853 DEBUGPC(DNM, "Sending OPSTART\n");
1854
Harald Welte34a99682009-02-13 02:41:40 +00001855 return abis_nm_sendmsg(bts, msg);
1856}
1857
1858/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001859int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1860 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001861{
1862 struct abis_om_hdr *oh;
1863 struct msgb *msg = nm_msgb_alloc();
1864
1865 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1866 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1867 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1868
1869 return abis_nm_sendmsg(bts, msg);
1870}
1871
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001872int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1873 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001874{
1875 struct abis_om_hdr *oh;
1876 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001877 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001878
1879 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1880 e1_port0, ts0, e1_port1, ts1);
1881
1882 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1883 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1884 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1885
1886 attr = msgb_put(msg, 3);
1887 attr[0] = NM_ATT_MDROP_LINK;
1888 attr[1] = e1_port0;
1889 attr[2] = ts0;
1890
1891 attr = msgb_put(msg, 3);
1892 attr[0] = NM_ATT_MDROP_NEXT;
1893 attr[1] = e1_port1;
1894 attr[2] = ts1;
1895
1896 return abis_nm_sendmsg(bts, msg);
1897}
Harald Welte34a99682009-02-13 02:41:40 +00001898
Harald Weltec7310382009-08-08 00:02:36 +02001899/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001900int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1901 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1902 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001903{
1904 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001905
Harald Welte15c61722011-05-22 22:45:37 +02001906 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001907
1908 if (!msg)
1909 msg = nm_msgb_alloc();
1910
1911 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1912 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1913 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1914 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001915 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001916
1917 return abis_nm_sendmsg(bts, msg);
1918}
1919
Harald Welte52b1f982008-12-23 20:25:15 +00001920int abis_nm_event_reports(struct gsm_bts *bts, int on)
1921{
1922 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001923 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001924 else
Harald Welte227d4072009-01-03 08:16:25 +00001925 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001926}
1927
Harald Welte47d88ae2009-01-04 12:02:08 +00001928/* Siemens (or BS-11) specific commands */
1929
Harald Welte3ffd1372009-02-01 22:15:49 +00001930int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1931{
1932 if (reconnect == 0)
1933 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1934 else
1935 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1936}
1937
Harald Welteb8427972009-02-05 19:27:17 +00001938int abis_nm_bs11_restart(struct gsm_bts *bts)
1939{
1940 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1941}
1942
1943
Harald Welte268bb402009-02-01 19:11:56 +00001944struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001945 uint16_t year;
1946 uint8_t month;
1947 uint8_t day;
1948 uint8_t hour;
1949 uint8_t min;
1950 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001951} __attribute__((packed));
1952
1953
1954void get_bs11_date_time(struct bs11_date_time *aet)
1955{
1956 time_t t;
1957 struct tm *tm;
1958
1959 t = time(NULL);
1960 tm = localtime(&t);
1961 aet->sec = tm->tm_sec;
1962 aet->min = tm->tm_min;
1963 aet->hour = tm->tm_hour;
1964 aet->day = tm->tm_mday;
1965 aet->month = tm->tm_mon;
1966 aet->year = htons(1900 + tm->tm_year);
1967}
1968
Harald Welte05188ee2009-01-18 11:39:08 +00001969int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001970{
Harald Welte4668fda2009-01-03 08:19:29 +00001971 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001972}
1973
Harald Welte05188ee2009-01-18 11:39:08 +00001974int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001975{
1976 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001977 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001978 else
Harald Welte4668fda2009-01-03 08:19:29 +00001979 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001980}
Harald Welte47d88ae2009-01-04 12:02:08 +00001981
Harald Welte05188ee2009-01-18 11:39:08 +00001982int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001983 enum abis_bs11_objtype type, uint8_t idx,
1984 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001985{
1986 struct abis_om_hdr *oh;
1987 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001988 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001989
1990 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001991 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001992 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001993 cur = msgb_put(msg, attr_len);
1994 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001995
1996 return abis_nm_sendmsg(bts, msg);
1997}
1998
Harald Welte78fc0d42009-02-19 02:50:57 +00001999int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002000 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00002001{
2002 struct abis_om_hdr *oh;
2003 struct msgb *msg = nm_msgb_alloc();
2004
2005 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2006 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
2007 NM_OC_BS11, type, 0, idx);
2008
2009 return abis_nm_sendmsg(bts, msg);
2010}
2011
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002012int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002013{
2014 struct abis_om_hdr *oh;
2015 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002016 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00002017
2018 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002019 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00002020 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
2021 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00002022
2023 return abis_nm_sendmsg(bts, msg);
2024}
2025
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002026int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00002027{
2028 struct abis_om_hdr *oh;
2029 struct msgb *msg = nm_msgb_alloc();
2030
2031 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2032 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002033 idx, 0xff, 0xff);
2034
2035 return abis_nm_sendmsg(bts, msg);
2036}
2037
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002038int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02002039{
2040 struct abis_om_hdr *oh;
2041 struct msgb *msg = nm_msgb_alloc();
2042
2043 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2044 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
2045 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00002046
2047 return abis_nm_sendmsg(bts, msg);
2048}
Harald Welte05188ee2009-01-18 11:39:08 +00002049
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002050static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00002051int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
2052{
2053 struct abis_om_hdr *oh;
2054 struct msgb *msg = nm_msgb_alloc();
2055
2056 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2057 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
2058 0xff, 0xff, 0xff);
2059 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
2060
2061 return abis_nm_sendmsg(bts, msg);
2062}
2063
Harald Welteb6c92ae2009-02-21 20:15:32 +00002064/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002065int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2066 uint8_t e1_timeslot, uint8_t e1_subslot,
2067 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002068{
2069 struct abis_om_hdr *oh;
2070 struct abis_nm_channel *ch;
2071 struct msgb *msg = nm_msgb_alloc();
2072
2073 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002074 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002075 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2076
2077 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2078 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002079 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002080
2081 return abis_nm_sendmsg(bts, msg);
2082}
2083
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002084int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002085{
2086 struct abis_om_hdr *oh;
2087 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002088
2089 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002090 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002091 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2092 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2093
2094 return abis_nm_sendmsg(trx->bts, msg);
2095}
2096
Harald Welte78fc0d42009-02-19 02:50:57 +00002097int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2098{
2099 struct abis_om_hdr *oh;
2100 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002101 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002102
2103 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2104 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2105 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2106 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2107
2108 return abis_nm_sendmsg(trx->bts, msg);
2109}
2110
Harald Welteaaf02d92009-04-29 13:25:57 +00002111int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2112{
2113 struct abis_om_hdr *oh;
2114 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002115 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002116
2117 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2118 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2119 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002120 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002121
2122 return abis_nm_sendmsg(bts, msg);
2123}
2124
Harald Welteef061952009-05-17 12:43:42 +00002125int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2126{
2127 struct abis_om_hdr *oh;
2128 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002129 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002130 NM_ATT_BS11_CCLK_TYPE };
2131
2132 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2133 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2134 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2135 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2136
2137 return abis_nm_sendmsg(bts, msg);
2138
2139}
Harald Welteaaf02d92009-04-29 13:25:57 +00002140
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002141//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002142
Harald Welte1bc09062009-01-18 14:17:52 +00002143int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002144{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002145 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2146}
2147
Daniel Willmann4b054c82010-01-07 00:46:26 +01002148int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2149{
2150 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2151}
2152
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002153int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002154{
Harald Welte05188ee2009-01-18 11:39:08 +00002155 struct abis_om_hdr *oh;
2156 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002157 struct bs11_date_time bdt;
2158
2159 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002160
2161 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002162 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002163 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002164 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002165 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002166 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002167 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002168 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002169 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002170 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002171 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002172 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002173 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002174 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002175 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002176 }
Harald Welte05188ee2009-01-18 11:39:08 +00002177
2178 return abis_nm_sendmsg(bts, msg);
2179}
Harald Welte1bc09062009-01-18 14:17:52 +00002180
2181int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2182{
2183 struct abis_om_hdr *oh;
2184 struct msgb *msg;
2185
2186 if (strlen(password) != 10)
2187 return -EINVAL;
2188
2189 msg = nm_msgb_alloc();
2190 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002191 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002192 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002193 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002194
2195 return abis_nm_sendmsg(bts, msg);
2196}
2197
Harald Weltee69f5fb2009-04-28 16:31:38 +00002198/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2199int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2200{
2201 struct abis_om_hdr *oh;
2202 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002203 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002204
2205 msg = nm_msgb_alloc();
2206 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2207 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2208 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002209
2210 if (locked)
2211 tlv_value = BS11_LI_PLL_LOCKED;
2212 else
2213 tlv_value = BS11_LI_PLL_STANDALONE;
2214
2215 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002216
2217 return abis_nm_sendmsg(bts, msg);
2218}
2219
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002220/* Set the calibration value of the PLL (work value/set value)
2221 * It depends on the login which one is changed */
2222int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2223{
2224 struct abis_om_hdr *oh;
2225 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002226 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002227
2228 msg = nm_msgb_alloc();
2229 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2230 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2231 BS11_OBJ_TRX1, 0x00, 0x00);
2232
2233 tlv_value[0] = value>>8;
2234 tlv_value[1] = value&0xff;
2235
2236 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2237
2238 return abis_nm_sendmsg(bts, msg);
2239}
2240
Harald Welte1bc09062009-01-18 14:17:52 +00002241int abis_nm_bs11_get_state(struct gsm_bts *bts)
2242{
2243 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2244}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002245
2246/* BS11 SWL */
2247
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002248void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002249
Harald Welte5e4d1b32009-02-01 13:36:56 +00002250struct abis_nm_bs11_sw {
2251 struct gsm_bts *bts;
2252 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002253 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002254 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002255 struct llist_head file_list;
2256 gsm_cbfn *user_cb; /* specified by the user */
2257};
2258static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2259
2260struct file_list_entry {
2261 struct llist_head list;
2262 char fname[PATH_MAX];
2263};
2264
2265struct file_list_entry *fl_dequeue(struct llist_head *queue)
2266{
2267 struct llist_head *lh;
2268
2269 if (llist_empty(queue))
2270 return NULL;
2271
2272 lh = queue->next;
2273 llist_del(lh);
2274
2275 return llist_entry(lh, struct file_list_entry, list);
2276}
2277
2278static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2279{
2280 char linebuf[255];
2281 struct llist_head *lh, *lh2;
2282 FILE *swl;
2283 int rc = 0;
2284
2285 swl = fopen(bs11_sw->swl_fname, "r");
2286 if (!swl)
2287 return -ENODEV;
2288
2289 /* zero the stale file list, if any */
2290 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2291 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002292 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002293 }
2294
2295 while (fgets(linebuf, sizeof(linebuf), swl)) {
2296 char file_id[12+1];
2297 char file_version[80+1];
2298 struct file_list_entry *fle;
2299 static char dir[PATH_MAX];
2300
2301 if (strlen(linebuf) < 4)
2302 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002303
Harald Welte5e4d1b32009-02-01 13:36:56 +00002304 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2305 if (rc < 0) {
2306 perror("ERR parsing SWL file");
2307 rc = -EINVAL;
2308 goto out;
2309 }
2310 if (rc < 2)
2311 continue;
2312
Harald Welte470ec292009-06-26 20:25:23 +02002313 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002314 if (!fle) {
2315 rc = -ENOMEM;
2316 goto out;
2317 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002318
2319 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002320 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002321 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2322 strcat(fle->fname, "/");
2323 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002324
2325 llist_add_tail(&fle->list, &bs11_sw->file_list);
2326 }
2327
2328out:
2329 fclose(swl);
2330 return rc;
2331}
2332
2333/* bs11 swload specific callback, passed to abis_nm core swload */
2334static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2335 struct msgb *msg, void *data, void *param)
2336{
2337 struct abis_nm_bs11_sw *bs11_sw = data;
2338 struct file_list_entry *fle;
2339 int rc = 0;
2340
Harald Welte5e4d1b32009-02-01 13:36:56 +00002341 switch (event) {
2342 case NM_MT_LOAD_END_ACK:
2343 fle = fl_dequeue(&bs11_sw->file_list);
2344 if (fle) {
2345 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002346 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002347 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002348 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002349 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002350 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002351 } else {
2352 /* activate the SWL */
2353 rc = abis_nm_software_activate(bs11_sw->bts,
2354 bs11_sw->swl_fname,
2355 bs11_swload_cbfn,
2356 bs11_sw);
2357 }
2358 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002359 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002360 case NM_MT_LOAD_END_NACK:
2361 case NM_MT_LOAD_INIT_ACK:
2362 case NM_MT_LOAD_INIT_NACK:
2363 case NM_MT_ACTIVATE_SW_NACK:
2364 case NM_MT_ACTIVATE_SW_ACK:
2365 default:
2366 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002367 if (bs11_sw->user_cb)
2368 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002369 break;
2370 }
2371
2372 return rc;
2373}
2374
2375/* Siemens provides a SWL file that is a mere listing of all the other
2376 * files that are part of a software release. We need to upload first
2377 * the list file, and then each file that is listed in the list file */
2378int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002379 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002380{
2381 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2382 struct file_list_entry *fle;
2383 int rc = 0;
2384
2385 INIT_LLIST_HEAD(&bs11_sw->file_list);
2386 bs11_sw->bts = bts;
2387 bs11_sw->win_size = win_size;
2388 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002389 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002390
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002391 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002392 rc = bs11_read_swl_file(bs11_sw);
2393 if (rc < 0)
2394 return rc;
2395
2396 /* dequeue next item in file list */
2397 fle = fl_dequeue(&bs11_sw->file_list);
2398 if (!fle)
2399 return -EINVAL;
2400
2401 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002402 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002403 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002404 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002405 return rc;
2406}
2407
Harald Welte5083b0b2009-02-02 19:20:52 +00002408#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002409static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002410 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2411 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2412 NM_ATT_BS11_LMT_USER_NAME,
2413
2414 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2415
2416 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2417
2418 NM_ATT_BS11_SW_LOAD_STORED };
2419
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002420static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002421 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2422 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2423 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2424 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002425#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002426
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002427static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002428 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2429 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002430 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002431
2432int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2433{
2434 struct abis_om_hdr *oh;
2435 struct msgb *msg = nm_msgb_alloc();
2436
2437 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2438 /* SiemensHW CCTRL object */
2439 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2440 0x03, 0x00, 0x00);
2441 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2442
2443 return abis_nm_sendmsg(bts, msg);
2444}
Harald Welte268bb402009-02-01 19:11:56 +00002445
2446int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2447{
2448 struct abis_om_hdr *oh;
2449 struct msgb *msg = nm_msgb_alloc();
2450 struct bs11_date_time aet;
2451
2452 get_bs11_date_time(&aet);
2453 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2454 /* SiemensHW CCTRL object */
2455 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2456 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002457 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002458
2459 return abis_nm_sendmsg(bts, msg);
2460}
Harald Welte5c1e4582009-02-15 11:57:29 +00002461
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002462int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002463{
2464 struct abis_om_hdr *oh;
2465 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002466 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002467
2468 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2469 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2470 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2471 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2472
2473 return abis_nm_sendmsg(bts, msg);
2474}
2475
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002476int 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 +02002477{
2478 struct abis_om_hdr *oh;
2479 struct msgb *msg = nm_msgb_alloc();
2480 struct bs11_date_time aet;
2481
2482 get_bs11_date_time(&aet);
2483 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2484 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2485 bport, 0xff, 0x02);
2486 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2487
2488 return abis_nm_sendmsg(bts, msg);
2489}
2490
Harald Welte5c1e4582009-02-15 11:57:29 +00002491/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002492static const char ipaccess_magic[] = "com.ipaccess";
2493
Harald Welte677c21f2009-02-17 13:22:23 +00002494
2495static int abis_nm_rx_ipacc(struct msgb *msg)
2496{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002497 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002498 struct abis_om_hdr *oh = msgb_l2(msg);
2499 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002500 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002501 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002502 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002503 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002504
2505 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002506 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002507 return -EINVAL;
2508 }
2509
Harald Welte193fefc2009-04-30 15:16:27 +00002510 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002511 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002512
Harald Welte15c61722011-05-22 22:45:37 +02002513 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002514
Harald Welte746d6092009-10-19 22:11:11 +02002515 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002516
Harald Welte677c21f2009-02-17 13:22:23 +00002517 switch (foh->msg_type) {
2518 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002519 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002520 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2521 memcpy(&addr,
2522 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2523
2524 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2525 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002526 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002527 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002528 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002529 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002530 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2531 DEBUGPC(DNM, "STREAM=0x%02x ",
2532 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002533 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002534 break;
2535 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002536 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002537 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002538 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002539 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002540 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002541 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002542 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002543 case NM_MT_IPACC_SET_NVATTR_ACK:
2544 DEBUGPC(DNM, "SET NVATTR ACK\n");
2545 /* FIXME: decode and show the actual attributes */
2546 break;
2547 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002548 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002549 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002550 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002551 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002552 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002553 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002554 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002555 case NM_MT_IPACC_GET_NVATTR_ACK:
2556 DEBUGPC(DNM, "GET NVATTR ACK\n");
2557 /* FIXME: decode and show the actual attributes */
2558 break;
2559 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002560 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002561 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002562 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002563 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002564 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002565 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002566 break;
Harald Welte15c44172009-10-08 20:15:24 +02002567 case NM_MT_IPACC_SET_ATTR_ACK:
2568 DEBUGPC(DNM, "SET ATTR ACK\n");
2569 break;
2570 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002571 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002572 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002573 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002574 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002575 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002576 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002577 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002578 default:
2579 DEBUGPC(DNM, "unknown\n");
2580 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002581 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002582
2583 /* signal handling */
2584 switch (foh->msg_type) {
2585 case NM_MT_IPACC_RSL_CONNECT_NACK:
2586 case NM_MT_IPACC_SET_NVATTR_NACK:
2587 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002588 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 +01002589 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002590 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002591 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002592 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002593 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 +01002594 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002595 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002596 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002597 default:
2598 break;
2599 }
2600
Harald Welte677c21f2009-02-17 13:22:23 +00002601 return 0;
2602}
2603
Harald Welte193fefc2009-04-30 15:16:27 +00002604/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002605int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2606 uint8_t obj_class, uint8_t bts_nr,
2607 uint8_t trx_nr, uint8_t ts_nr,
2608 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002609{
2610 struct msgb *msg = nm_msgb_alloc();
2611 struct abis_om_hdr *oh;
2612 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002613 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002614
2615 /* construct the 12.21 OM header, observe the erroneous length */
2616 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2617 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2618 oh->mdisc = ABIS_OM_MDISC_MANUF;
2619
2620 /* add the ip.access magic */
2621 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2622 *data++ = sizeof(ipaccess_magic);
2623 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2624
2625 /* fill the 12.21 FOM header */
2626 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2627 foh->msg_type = msg_type;
2628 foh->obj_class = obj_class;
2629 foh->obj_inst.bts_nr = bts_nr;
2630 foh->obj_inst.trx_nr = trx_nr;
2631 foh->obj_inst.ts_nr = ts_nr;
2632
2633 if (attr && attr_len) {
2634 data = msgb_put(msg, attr_len);
2635 memcpy(data, attr, attr_len);
2636 }
2637
2638 return abis_nm_sendmsg(bts, msg);
2639}
Harald Welte677c21f2009-02-17 13:22:23 +00002640
Harald Welte193fefc2009-04-30 15:16:27 +00002641/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002642int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002643 int attr_len)
2644{
Harald Welte2ef156d2010-01-07 20:39:42 +01002645 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2646 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002647 attr_len);
2648}
2649
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002650int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002651 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002652{
2653 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002654 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002655 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2656 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2657
2658 int attr_len = sizeof(attr);
2659
2660 ia.s_addr = htonl(ip);
2661 attr[1] = stream;
2662 attr[3] = port >> 8;
2663 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002664 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002665
2666 /* if ip == 0, we use the default IP */
2667 if (ip == 0)
2668 attr_len -= 5;
2669
2670 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002671 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002672
2673 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2674 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2675 trx->nr, 0xff, attr, attr_len);
2676}
2677
Harald Welte193fefc2009-04-30 15:16:27 +00002678/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002679int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002680{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002681 struct abis_om_hdr *oh;
2682 struct msgb *msg = nm_msgb_alloc();
2683
2684 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2685 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2686 trx->bts->nr, trx->nr, 0xff);
2687
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002688 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002689}
Harald Weltedaef5212009-10-24 10:20:41 +02002690
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002691int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2692 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2693 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002694{
2695 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2696 obj_class, bts_nr, trx_nr, ts_nr,
2697 attr, attr_len);
2698}
Harald Welte0f255852009-11-12 14:48:42 +01002699
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002700void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002701{
2702 /* we simply reuse the GSM48 function and overwrite the RAC
2703 * with the Cell ID */
2704 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002705 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002706}
2707
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002708void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2709{
2710 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2711
Harald Welted64c0bc2011-05-30 12:07:53 +02002712 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002713 if (!trx->bts || !trx->bts->oml_link)
2714 return;
2715
2716 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2717 trx->bts->bts_nr, trx->nr, 0xff,
2718 new_state);
2719}
2720
Harald Welte92b1fe42010-03-25 11:45:30 +08002721static const struct value_string ipacc_testres_names[] = {
2722 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2723 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2724 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2725 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2726 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2727 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002728};
2729
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002730const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002731{
Harald Welte92b1fe42010-03-25 11:45:30 +08002732 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002733}
2734
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002735void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002736{
2737 cid->mcc = (buf[0] & 0xf) * 100;
2738 cid->mcc += (buf[0] >> 4) * 10;
2739 cid->mcc += (buf[1] & 0xf) * 1;
2740
2741 if (buf[1] >> 4 == 0xf) {
2742 cid->mnc = (buf[2] & 0xf) * 10;
2743 cid->mnc += (buf[2] >> 4) * 1;
2744 } else {
2745 cid->mnc = (buf[2] & 0xf) * 100;
2746 cid->mnc += (buf[2] >> 4) * 10;
2747 cid->mnc += (buf[1] >> 4) * 1;
2748 }
2749
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002750 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2751 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002752}
2753
Harald Welte0f255852009-11-12 14:48:42 +01002754/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002755int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002756{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002757 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002758 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002759
Harald Welteaf109b92010-07-22 18:14:36 +02002760 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002761
2762 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2763 return -EINVAL;
2764 cur++;
2765
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002766 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002767 cur += 2;
2768
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002769 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002770 cur += 2;
2771
2772 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2773 binf->freq_qual = *cur >> 2;
2774
Harald Welteaf109b92010-07-22 18:14:36 +02002775 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002776 binf->arfcn |= *cur++;
2777
2778 if (binf->info_type & IPAC_BINF_RXLEV)
2779 binf->rx_lev = *cur & 0x3f;
2780 cur++;
2781
2782 if (binf->info_type & IPAC_BINF_RXQUAL)
2783 binf->rx_qual = *cur & 0x7;
2784 cur++;
2785
2786 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002787 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002788 cur += 2;
2789
2790 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002791 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002792 cur += 2;
2793
2794 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002795 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002796 cur += 4;
2797
Harald Weltea780a3d2010-07-30 22:34:42 +02002798#if 0
2799 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002800 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002801#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002802 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002803 cur++;
2804
Harald Welteb40a38f2009-11-13 11:56:05 +01002805 ipac_parse_cgi(&binf->cgi, cur);
2806 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002807
2808 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2809 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2810 cur += sizeof(binf->ba_list_si2);
2811 }
2812
2813 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2814 memcpy(binf->ba_list_si2bis, cur,
2815 sizeof(binf->ba_list_si2bis));
2816 cur += sizeof(binf->ba_list_si2bis);
2817 }
2818
2819 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2820 memcpy(binf->ba_list_si2ter, cur,
2821 sizeof(binf->ba_list_si2ter));
2822 cur += sizeof(binf->ba_list_si2ter);
2823 }
2824
2825 return 0;
2826}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002827
2828void abis_nm_clear_queue(struct gsm_bts *bts)
2829{
2830 struct msgb *msg;
2831
2832 while (!llist_empty(&bts->abis_queue)) {
2833 msg = msgb_dequeue(&bts->abis_queue);
2834 msgb_free(msg);
2835 }
2836
2837 bts->abis_nm_pend = 0;
2838}