blob: db0dbd2b72611d7cfc25543bad7e1abc5f0306bb [file] [log] [blame]
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001/* GSM Network Management (OML) messages on the A-bis interface
Harald Welte52b1f982008-12-23 20:25:15 +00002 * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
3
Harald Welte4724f992009-01-18 18:01:49 +00004/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
Harald Welte8470bf22008-12-25 23:28:35 +00005 *
Harald Welte52b1f982008-12-23 20:25:15 +00006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte52b1f982008-12-23 20:25:15 +000011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte52b1f982008-12-23 20:25:15 +000017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte52b1f982008-12-23 20:25:15 +000020 *
21 */
22
23
24#include <errno.h>
Harald Welte4724f992009-01-18 18:01:49 +000025#include <unistd.h>
Harald Welte52b1f982008-12-23 20:25:15 +000026#include <stdio.h>
Harald Welte4724f992009-01-18 18:01:49 +000027#include <fcntl.h>
Harald Welte12247c62009-05-21 07:23:02 +000028#include <stdlib.h>
Harald Welte5e4d1b32009-02-01 13:36:56 +000029#include <libgen.h>
Harald Welte268bb402009-02-01 19:11:56 +000030#include <time.h>
Harald Welte5f6f1492009-02-02 14:50:29 +000031#include <limits.h>
Harald Welte4724f992009-01-18 18:01:49 +000032
Harald Welte4724f992009-01-18 18:01:49 +000033#include <sys/stat.h>
Harald Welte8470bf22008-12-25 23:28:35 +000034#include <netinet/in.h>
Harald Welte677c21f2009-02-17 13:22:23 +000035#include <arpa/inet.h>
Harald Welte52b1f982008-12-23 20:25:15 +000036
Harald Welte8470bf22008-12-25 23:28:35 +000037#include <openbsc/gsm_data.h>
38#include <openbsc/debug.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/msgb.h>
Maxa5e36932017-01-11 11:51:28 +010040#include <osmocom/gsm/protocol/gsm_12_21.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010041#include <osmocom/gsm/tlv.h>
Harald Welte15c61722011-05-22 22:45:37 +020042#include <osmocom/gsm/abis_nm.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010043#include <osmocom/core/talloc.h>
Neels Hofmeyr93bafb62017-01-13 03:12:08 +010044#include <osmocom/core/utils.h>
Harald Welte8470bf22008-12-25 23:28:35 +000045#include <openbsc/abis_nm.h>
Holger Freytherca362a62009-01-04 21:05:01 +000046#include <openbsc/misdn.h>
Harald Weltef9a8cc32009-05-01 15:39:49 +000047#include <openbsc/signal.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020048#include <osmocom/abis/e1_input.h>
Harald Welte52b1f982008-12-23 20:25:15 +000049
Harald Welte8470bf22008-12-25 23:28:35 +000050#define OM_ALLOC_SIZE 1024
51#define OM_HEADROOM_SIZE 128
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +010052#define IPACC_SEGMENT_SIZE 245
Harald Welte52b1f982008-12-23 20:25:15 +000053
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020054int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len)
Harald Welte03133942009-02-18 19:51:53 +000055{
Harald Welte39315c42010-01-10 18:01:52 +010056 if (!bts->model)
57 return -EIO;
58 return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0);
Harald Welte03133942009-02-18 19:51:53 +000059}
Harald Weltee0590df2009-02-15 03:34:15 +000060
Harald Welte52b1f982008-12-23 20:25:15 +000061static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
62{
63 int i;
64
65 for (i = 0; i < size; i++) {
66 if (arr[i] == mt)
67 return 1;
68 }
69
70 return 0;
71}
72
Holger Freytherca362a62009-01-04 21:05:01 +000073#if 0
Harald Welte52b1f982008-12-23 20:25:15 +000074/* is this msgtype the usual ACK/NACK type ? */
75static int is_ack_nack(enum abis_nm_msgtype mt)
76{
77 return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
78}
Holger Freytherca362a62009-01-04 21:05:01 +000079#endif
Harald Welte52b1f982008-12-23 20:25:15 +000080
81/* is this msgtype a report ? */
82static int is_report(enum abis_nm_msgtype mt)
83{
Harald Welte15c61722011-05-22 22:45:37 +020084 return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
Harald Welte52b1f982008-12-23 20:25:15 +000085}
86
87#define MT_ACK(x) (x+1)
88#define MT_NACK(x) (x+2)
89
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020090static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
Harald Welte52b1f982008-12-23 20:25:15 +000091{
92 oh->mdisc = ABIS_OM_MDISC_FOM;
93 oh->placement = ABIS_OM_PLACEMENT_ONLY;
94 oh->sequence = 0;
95 oh->length = len;
96}
97
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +020098static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +020099 uint8_t msg_type, uint8_t obj_class,
100 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte52b1f982008-12-23 20:25:15 +0000101{
102 struct abis_om_fom_hdr *foh =
103 (struct abis_om_fom_hdr *) oh->data;
104
Harald Welte702d8702008-12-26 20:25:35 +0000105 fill_om_hdr(oh, len+sizeof(*foh));
Harald Welte52b1f982008-12-23 20:25:15 +0000106 foh->msg_type = msg_type;
107 foh->obj_class = obj_class;
108 foh->obj_inst.bts_nr = bts_nr;
109 foh->obj_inst.trx_nr = trx_nr;
110 foh->obj_inst.ts_nr = ts_nr;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +0200111 return foh;
Harald Welte52b1f982008-12-23 20:25:15 +0000112}
113
Harald Welte8470bf22008-12-25 23:28:35 +0000114static struct msgb *nm_msgb_alloc(void)
115{
Harald Welte966636f2009-06-26 19:39:35 +0200116 return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
117 "OML");
Harald Welte8470bf22008-12-25 23:28:35 +0000118}
119
Harald Welte15eae8d2011-09-26 23:43:23 +0200120int _abis_nm_sendmsg(struct msgb *msg)
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200121{
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200122 msg->l2h = msg->data;
123
124 if (!msg->dst) {
125 LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
126 return -EINVAL;
127 }
128
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200129 return abis_sendmsg(msg);
130}
131
Harald Welte52b1f982008-12-23 20:25:15 +0000132/* Send a OML NM Message from BSC to BTS */
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100133static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000134{
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200135 msg->dst = bts->oml_link;
Holger Freyther59639e82009-02-09 23:09:55 +0000136
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100137 /* queue OML messages */
138 if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
139 bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200140 return _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100141 } else {
142 msgb_enqueue(&bts->abis_queue, msg);
143 return 0;
144 }
145
146}
147
148int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
149{
150 OBSC_NM_W_ACK_CB(msg) = 1;
151 return abis_nm_queue_msg(bts, msg);
152}
153
154static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
155{
156 OBSC_NM_W_ACK_CB(msg) = 0;
157 return abis_nm_queue_msg(bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000158}
159
Harald Welte4724f992009-01-18 18:01:49 +0000160static int abis_nm_rcvmsg_sw(struct msgb *mb);
161
Sylvain Munaut1f6c11f2010-01-02 16:32:17 +0100162int nm_is_running(struct gsm_nm_state *s) {
163 return (s->operational == NM_OPSTATE_ENABLED) && (
164 (s->availability == NM_AVSTATE_OK) ||
165 (s->availability == 0xff)
166 );
167}
168
Harald Weltee0590df2009-02-15 03:34:15 +0000169/* Update the administrative state of a given object in our in-memory data
170 * structures and send an event to the higher layer */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200171static int update_admstate(struct gsm_bts *bts, uint8_t obj_class,
172 struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
Harald Weltee0590df2009-02-15 03:34:15 +0000173{
Harald Welteaeedeb42009-05-01 13:08:14 +0000174 struct gsm_nm_state *nm_state, new_state;
Harald Weltef338a032011-01-14 15:55:42 +0100175 struct nm_statechg_signal_data nsd;
Harald Weltee0590df2009-02-15 03:34:15 +0000176
Harald Welteaf9b8102011-03-06 21:20:38 +0100177 memset(&nsd, 0, sizeof(nsd));
178
Harald Welte978714d2011-06-06 18:31:20 +0200179 nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100180 if (!nsd.obj)
Harald Welte999549d2009-11-13 12:10:18 +0100181 return -EINVAL;
Harald Welte978714d2011-06-06 18:31:20 +0200182 nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
Harald Welteaeedeb42009-05-01 13:08:14 +0000183 if (!nm_state)
184 return -1;
185
186 new_state = *nm_state;
187 new_state.administrative = adm_state;
188
Harald Weltef38ca9a2011-03-06 22:11:32 +0100189 nsd.bts = bts;
Harald Weltef338a032011-01-14 15:55:42 +0100190 nsd.obj_class = obj_class;
191 nsd.old_state = nm_state;
192 nsd.new_state = &new_state;
193 nsd.obj_inst = obj_inst;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200194 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
Harald Welteaeedeb42009-05-01 13:08:14 +0000195
196 nm_state->administrative = adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000197
Harald Weltef338a032011-01-14 15:55:42 +0100198 return 0;
Harald Weltee0590df2009-02-15 03:34:15 +0000199}
200
Harald Welte97ed1e72009-02-06 13:38:02 +0000201static int abis_nm_rx_statechg_rep(struct msgb *mb)
202{
Harald Weltee0590df2009-02-15 03:34:15 +0000203 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000204 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200205 struct e1inp_sign_link *sign_link = mb->dst;
206 struct gsm_bts *bts = sign_link->trx->bts;
Harald Weltee0590df2009-02-15 03:34:15 +0000207 struct tlv_parsed tp;
208 struct gsm_nm_state *nm_state, new_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000209
Harald Welte23897662009-05-01 14:52:51 +0000210 DEBUGPC(DNM, "STATE CHG: ");
Harald Weltee0590df2009-02-15 03:34:15 +0000211
Harald Welte8b697c72009-06-05 19:18:45 +0000212 memset(&new_state, 0, sizeof(new_state));
213
Harald Welte978714d2011-06-06 18:31:20 +0200214 nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
Harald Weltee0590df2009-02-15 03:34:15 +0000215 if (!nm_state) {
Harald Welte999549d2009-11-13 12:10:18 +0100216 DEBUGPC(DNM, "unknown object class\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000217 return -EINVAL;
Harald Welte22af0db2009-02-14 15:41:08 +0000218 }
Harald Weltee0590df2009-02-15 03:34:15 +0000219
220 new_state = *nm_state;
221
Harald Welte39315c42010-01-10 18:01:52 +0100222 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000223 if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
224 new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200225 DEBUGPC(DNM, "OP_STATE=%s ",
226 abis_nm_opstate_name(new_state.operational));
Harald Weltee0590df2009-02-15 03:34:15 +0000227 }
228 if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
Harald Welte0b8348d2009-02-18 03:43:01 +0000229 if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
230 new_state.availability = 0xff;
231 else
232 new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
Harald Welte15c61722011-05-22 22:45:37 +0200233 DEBUGPC(DNM, "AVAIL=%s(%02x) ",
234 abis_nm_avail_name(new_state.availability),
Harald Weltee0590df2009-02-15 03:34:15 +0000235 new_state.availability);
Sylvain Munaut65542c72010-01-02 16:35:26 +0100236 } else
237 new_state.availability = 0xff;
Harald Weltee0590df2009-02-15 03:34:15 +0000238 if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
239 new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
Harald Welte15c61722011-05-22 22:45:37 +0200240 DEBUGPC(DNM, "ADM=%2s ",
Harald Weltecdc59ff2011-05-23 20:42:26 +0200241 get_value_string(abis_nm_adm_state_names,
242 new_state.administrative));
Harald Welte97ed1e72009-02-06 13:38:02 +0000243 }
244 DEBUGPC(DNM, "\n");
Harald Weltee0590df2009-02-15 03:34:15 +0000245
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100246 if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
247 new_state.operational != nm_state->operational ||
248 new_state.availability != nm_state->availability) {
Harald Weltee0590df2009-02-15 03:34:15 +0000249 /* Update the operational state of a given object in our in-memory data
250 * structures and send an event to the higher layer */
Harald Weltef338a032011-01-14 15:55:42 +0100251 struct nm_statechg_signal_data nsd;
Harald Welte978714d2011-06-06 18:31:20 +0200252 nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
Harald Weltef338a032011-01-14 15:55:42 +0100253 nsd.obj_class = foh->obj_class;
254 nsd.old_state = nm_state;
255 nsd.new_state = &new_state;
256 nsd.obj_inst = &foh->obj_inst;
Harald Weltef38ca9a2011-03-06 22:11:32 +0100257 nsd.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200258 osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd);
Holger Hans Peter Freytherf31e4742009-12-31 03:05:52 +0100259 nm_state->operational = new_state.operational;
260 nm_state->availability = new_state.availability;
261 if (nm_state->administrative == 0)
262 nm_state->administrative = new_state.administrative;
Harald Weltee0590df2009-02-15 03:34:15 +0000263 }
264#if 0
Harald Welte22af0db2009-02-14 15:41:08 +0000265 if (op_state == 1) {
266 /* try to enable objects that are disabled */
267 abis_nm_opstart(bts, foh->obj_class,
268 foh->obj_inst.bts_nr,
269 foh->obj_inst.trx_nr,
270 foh->obj_inst.ts_nr);
271 }
Harald Weltee0590df2009-02-15 03:34:15 +0000272#endif
Harald Welte97ed1e72009-02-06 13:38:02 +0000273 return 0;
274}
275
Maxb1e6b372017-03-15 14:30:21 +0100276static inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type,
277 const char *severity, const uint8_t *p_val,
278 const char *text)
279{
280 enum abis_nm_pcause_type pcause = p_val[0];
281 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
282
283 LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr);
284 if (type)
285 LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type);
286 if (severity)
287 LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity);
288
289 LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
290 get_value_string(abis_nm_pcause_type_names, pcause));
291
292 if (pcause == NM_PCAUSE_T_MANUF)
293 LOGPC(DNM, LOGL_ERROR, "%s, ",
294 get_value_string(abis_mm_event_cause_names, cause));
295 else
296 LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
297
298 if (text) {
299 LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text);
300 }
301
302 LOGPC(DNM, LOGL_ERROR, "\n");
303}
304
Maxa18001d2017-04-10 16:47:17 +0200305static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type,
Maxb1e6b372017-03-15 14:30:21 +0100306 const char *severity, const char *text)
307{
308 enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
309
310 switch (cause) {
311 case OSMO_EVT_PCU_VERS:
Maxa18001d2017-04-10 16:47:17 +0200312 if (text) {
313 LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text);
314 osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version));
315 } else {
316 LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr);
317 bts->pcu_version[0] = '\0';
318 }
Maxb1e6b372017-03-15 14:30:21 +0100319 break;
320 default:
321 log_oml_fail_rep(bts, type, severity, p_val, text);
322 };
323}
324
Maxa18001d2017-04-10 16:47:17 +0200325static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts)
Harald Welte0db97b22009-05-01 17:22:47 +0000326{
327 struct abis_om_hdr *oh = msgb_l2(mb);
328 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200329 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte0db97b22009-05-01 17:22:47 +0000330 struct tlv_parsed tp;
Maxb1e6b372017-03-15 14:30:21 +0100331 int rc = 0;
332 const uint8_t *p_val = NULL;
333 char *p_text = NULL;
334 const char *e_type = NULL, *severity = NULL;
Harald Welte0db97b22009-05-01 17:22:47 +0000335
Maxb1e6b372017-03-15 14:30:21 +0100336 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
337 oh->length-sizeof(*foh));
Maxa5e36932017-01-11 11:51:28 +0100338
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100339 if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
340 p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
Maxb1e6b372017-03-15 14:30:21 +0100341 p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val,
342 TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
Dieter Spaar6a458ea2011-02-18 11:06:51 +0100343 }
Harald Welte0db97b22009-05-01 17:22:47 +0000344
Maxb1e6b372017-03-15 14:30:21 +0100345 if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
346 e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
347 NM_ATT_EVENT_TYPE));
Harald Welte0db97b22009-05-01 17:22:47 +0000348
Maxb1e6b372017-03-15 14:30:21 +0100349 if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
350 severity = abis_nm_severity_name(*TLVP_VAL(&tp,
351 NM_ATT_SEVERITY));
352
353 if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
354 p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
355
356 switch (p_val[0]) {
357 case NM_PCAUSE_T_MANUF:
358 handle_manufact_report(bts, p_val, e_type, severity,
359 p_text);
360 break;
361 default:
362 log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
363 };
364 } else {
365 LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without "
366 "Probable Cause?!\n", bts->nr);
367 rc = -EINVAL;
368 }
369
370 if (p_text)
371 talloc_free(p_text);
372
373 return rc;
Harald Welte0db97b22009-05-01 17:22:47 +0000374}
375
Maxb1e6b372017-03-15 14:30:21 +0100376static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
Harald Welte97ed1e72009-02-06 13:38:02 +0000377{
378 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200379 uint8_t mt = foh->msg_type;
Harald Welte97ed1e72009-02-06 13:38:02 +0000380
Harald Welte15c61722011-05-22 22:45:37 +0200381 abis_nm_debugp_foh(DNM, foh);
Harald Welte23897662009-05-01 14:52:51 +0000382
Harald Welte97ed1e72009-02-06 13:38:02 +0000383 //nmh->cfg->report_cb(mb, foh);
384
385 switch (mt) {
386 case NM_MT_STATECHG_EVENT_REP:
387 return abis_nm_rx_statechg_rep(mb);
388 break;
Harald Welte34a99682009-02-13 02:41:40 +0000389 case NM_MT_SW_ACTIVATED_REP:
Harald Welte23897662009-05-01 14:52:51 +0000390 DEBUGPC(DNM, "Software Activated Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200391 osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
Harald Welte34a99682009-02-13 02:41:40 +0000392 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000393 case NM_MT_FAILURE_EVENT_REP:
Maxb1e6b372017-03-15 14:30:21 +0100394 rx_fail_evt_rep(mb, bts);
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200395 osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000396 break;
Harald Weltec7310382009-08-08 00:02:36 +0200397 case NM_MT_TEST_REP:
398 DEBUGPC(DNM, "Test Report\n");
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200399 osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb);
Harald Weltec7310382009-08-08 00:02:36 +0200400 break;
Harald Weltee0590df2009-02-15 03:34:15 +0000401 default:
Harald Welte23897662009-05-01 14:52:51 +0000402 DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
Harald Weltee0590df2009-02-15 03:34:15 +0000403 break;
404
Harald Welte97ed1e72009-02-06 13:38:02 +0000405 };
406
Harald Welte97ed1e72009-02-06 13:38:02 +0000407 return 0;
408}
409
Harald Welte34a99682009-02-13 02:41:40 +0000410/* Activate the specified software into the BTS */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200411static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1,
Maxfd2c1f92017-03-24 21:04:57 +0100412 uint8_t i2, const struct abis_nm_sw_desc *sw_desc)
Harald Welte34a99682009-02-13 02:41:40 +0000413{
414 struct abis_om_hdr *oh;
415 struct msgb *msg = nm_msgb_alloc();
Maxfd2c1f92017-03-24 21:04:57 +0100416 uint16_t len = abis_nm_sw_desc_len(sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000417
418 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
419 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
Maxfd2c1f92017-03-24 21:04:57 +0100420 abis_nm_put_sw_desc(msg, sw_desc, true);
Harald Welte34a99682009-02-13 02:41:40 +0000421
422 return abis_nm_sendmsg(bts, msg);
423}
424
Maxfd2c1f92017-03-24 21:04:57 +0100425int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr,
426 const size_t size)
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100427{
428 int res = 0;
429 int i;
430
431 for (i = 1; i < size; ++i) {
Maxfd2c1f92017-03-24 21:04:57 +0100432 if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version,
433 OSMO_MIN(sw_descr[i].file_version_len,
434 sw_descr[res].file_version_len)) < 0) {
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100435 res = i;
436 }
437 }
438
439 return res;
440}
441
Harald Welte34a99682009-02-13 02:41:40 +0000442static int abis_nm_rx_sw_act_req(struct msgb *mb)
443{
444 struct abis_om_hdr *oh = msgb_l2(mb);
445 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200446 struct e1inp_sign_link *sign_link = mb->dst;
Mike Habena03f9772009-10-01 14:56:13 +0200447 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200448 const uint8_t *sw_config;
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100449 int ret, sw_config_len, len;
Maxfd2c1f92017-03-24 21:04:57 +0100450 struct abis_nm_sw_desc sw_descr[5];
Harald Welte34a99682009-02-13 02:41:40 +0000451
Harald Welte15c61722011-05-22 22:45:37 +0200452 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +0200453
454 DEBUGPC(DNM, "SW Activate Request: ");
Harald Welte34a99682009-02-13 02:41:40 +0000455
Harald Welte97a282b2010-03-14 15:37:43 +0800456 DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
Harald Welte5c1e4582009-02-15 11:57:29 +0000457
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200458 ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000459 foh->obj_inst.bts_nr,
460 foh->obj_inst.trx_nr,
Harald Welte97a282b2010-03-14 15:37:43 +0800461 foh->obj_inst.ts_nr, 0,
Harald Welte34a99682009-02-13 02:41:40 +0000462 foh->data, oh->length-sizeof(*foh));
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100463 if (ret != 0) {
464 LOGP(DNM, LOGL_ERROR,
465 "Sending SW ActReq ACK failed: %d\n", ret);
466 return ret;
467 }
Harald Welte34a99682009-02-13 02:41:40 +0000468
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200469 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Mike Habena03f9772009-10-01 14:56:13 +0200470 sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
471 sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
472 if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
Holger Hans Peter Freytherdae53072012-02-03 19:48:30 +0100473 LOGP(DNM, LOGL_ERROR,
474 "SW config not found! Can't continue.\n");
Mike Habena03f9772009-10-01 14:56:13 +0200475 return -EINVAL;
476 } else {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200477 DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
Mike Habena03f9772009-10-01 14:56:13 +0200478 }
479
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100480 /* Parse up to two sw descriptions from the data */
Maxfd2c1f92017-03-24 21:04:57 +0100481 len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
482 ARRAY_SIZE(sw_descr));
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100483 if (len <= 0) {
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100484 LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
Sylvain Munautb998d7b2009-10-25 17:48:42 +0100485 return -EINVAL;
Holger Hans Peter Freytherbce56752012-11-22 14:59:46 +0100486 }
Mike Habena03f9772009-10-01 14:56:13 +0200487
Holger Hans Peter Freyther2f257472012-11-22 19:04:10 +0100488 ret = abis_nm_select_newest_sw(&sw_descr[0], len);
489 DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
490
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200491 return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
Harald Welte34a99682009-02-13 02:41:40 +0000492 foh->obj_inst.bts_nr,
493 foh->obj_inst.trx_nr,
494 foh->obj_inst.ts_nr,
Maxfd2c1f92017-03-24 21:04:57 +0100495 &sw_descr[ret]);
Harald Welte34a99682009-02-13 02:41:40 +0000496}
497
Harald Weltee0590df2009-02-15 03:34:15 +0000498/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
499static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
500{
501 struct abis_om_hdr *oh = msgb_l2(mb);
502 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200503 struct e1inp_sign_link *sign_link = mb->dst;
Harald Weltee0590df2009-02-15 03:34:15 +0000504 struct tlv_parsed tp;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200505 uint8_t adm_state;
Harald Weltee0590df2009-02-15 03:34:15 +0000506
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200507 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Weltee0590df2009-02-15 03:34:15 +0000508 if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
509 return -EINVAL;
510
511 adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
512
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200513 return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
Harald Weltee0590df2009-02-15 03:34:15 +0000514}
515
Harald Welteee670472009-02-22 21:58:49 +0000516static int abis_nm_rx_lmt_event(struct msgb *mb)
517{
518 struct abis_om_hdr *oh = msgb_l2(mb);
519 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200520 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welteee670472009-02-22 21:58:49 +0000521 struct tlv_parsed tp;
522
523 DEBUGP(DNM, "LMT Event ");
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200524 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welteee670472009-02-22 21:58:49 +0000525 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
526 TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200527 uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
Harald Welteee670472009-02-22 21:58:49 +0000528 DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
529 }
530 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
531 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200532 uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
Harald Welteee670472009-02-22 21:58:49 +0000533 DEBUGPC(DNM, "Level=%u ", level);
534 }
535 if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
536 TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
537 char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
538 DEBUGPC(DNM, "Username=%s ", name);
539 }
540 DEBUGPC(DNM, "\n");
541 /* FIXME: parse LMT LOGON TIME */
542 return 0;
543}
544
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +0200545void abis_nm_queue_send_next(struct gsm_bts *bts)
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100546{
547 int wait = 0;
548 struct msgb *msg;
549 /* the queue is empty */
550 while (!llist_empty(&bts->abis_queue)) {
551 msg = msgb_dequeue(&bts->abis_queue);
552 wait = OBSC_NM_W_ACK_CB(msg);
Harald Welte15eae8d2011-09-26 23:43:23 +0200553 _abis_nm_sendmsg(msg);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100554
555 if (wait)
556 break;
557 }
558
559 bts->abis_nm_pend = wait;
560}
561
Harald Welte52b1f982008-12-23 20:25:15 +0000562/* Receive a OML NM Message from BTS */
Harald Welte8470bf22008-12-25 23:28:35 +0000563static int abis_nm_rcvmsg_fom(struct msgb *mb)
Harald Welte52b1f982008-12-23 20:25:15 +0000564{
Harald Welte6c96ba52009-05-01 13:03:40 +0000565 struct abis_om_hdr *oh = msgb_l2(mb);
Harald Welte52b1f982008-12-23 20:25:15 +0000566 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;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200568 uint8_t mt = foh->msg_type;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100569 /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
570 struct gsm_bts *bts = sign_link->trx->bts;
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100571 int ret = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000572
573 /* check for unsolicited message */
Harald Welte97ed1e72009-02-06 13:38:02 +0000574 if (is_report(mt))
Maxb1e6b372017-03-15 14:30:21 +0100575 return abis_nm_rcvmsg_report(mb, bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000576
Harald Welte15c61722011-05-22 22:45:37 +0200577 if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
Harald Welte4724f992009-01-18 18:01:49 +0000578 return abis_nm_rcvmsg_sw(mb);
579
Harald Welte15c61722011-05-22 22:45:37 +0200580 if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800581 struct nm_nack_signal_data nack_data;
Harald Welte6c96ba52009-05-01 13:03:40 +0000582 struct tlv_parsed tp;
Harald Welte4bd0a982009-10-08 20:18:59 +0200583
Harald Welte15c61722011-05-22 22:45:37 +0200584 abis_nm_debugp_foh(DNM, foh);
Harald Welte4bd0a982009-10-08 20:18:59 +0200585
Harald Welte15c61722011-05-22 22:45:37 +0200586 DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
Harald Welte6c96ba52009-05-01 13:03:40 +0000587
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100588 abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
Harald Welte6c96ba52009-05-01 13:03:40 +0000589 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +0200590 DEBUGPC(DNM, "CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +0200591 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +0000592 else
593 DEBUGPC(DNM, "\n");
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200594
Holger Hans Peter Freyther6d2b66e2010-07-14 02:08:35 +0800595 nack_data.msg = mb;
596 nack_data.mt = mt;
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100597 nack_data.bts = bts;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200598 osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100599 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther500f3ca2009-06-10 10:48:14 +0200600 return 0;
Harald Welte78fc0d42009-02-19 02:50:57 +0000601 }
Harald Weltead384642008-12-26 10:20:07 +0000602#if 0
Harald Welte52b1f982008-12-23 20:25:15 +0000603 /* check if last message is to be acked */
604 if (is_ack_nack(nmh->last_msgtype)) {
605 if (mt == MT_ACK(nmh->last_msgtype)) {
Harald Welte5b8ed432009-12-24 12:20:20 +0100606 DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000607 /* we got our ACK, continue sending the next msg */
608 } else if (mt == MT_NACK(nmh->last_msgtype)) {
609 /* we got a NACK, signal this to the caller */
Harald Welte5b8ed432009-12-24 12:20:20 +0100610 DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type);
Harald Welte52b1f982008-12-23 20:25:15 +0000611 /* FIXME: somehow signal this to the caller */
612 } else {
613 /* really strange things happen */
614 return -EINVAL;
615 }
616 }
Harald Weltead384642008-12-26 10:20:07 +0000617#endif
618
Harald Welte97ed1e72009-02-06 13:38:02 +0000619 switch (mt) {
Harald Weltee0590df2009-02-15 03:34:15 +0000620 case NM_MT_CHG_ADM_STATE_ACK:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100621 ret = abis_nm_rx_chg_adm_state_ack(mb);
Harald Weltee0590df2009-02-15 03:34:15 +0000622 break;
Harald Welte34a99682009-02-13 02:41:40 +0000623 case NM_MT_SW_ACT_REQ:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100624 ret = abis_nm_rx_sw_act_req(mb);
Harald Welte34a99682009-02-13 02:41:40 +0000625 break;
Harald Welte97ed1e72009-02-06 13:38:02 +0000626 case NM_MT_BS11_LMT_SESSION:
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100627 ret = abis_nm_rx_lmt_event(mb);
Harald Welte97ed1e72009-02-06 13:38:02 +0000628 break;
Max689e7e52017-04-04 19:21:24 +0200629 case NM_MT_OPSTART_ACK:
630 abis_nm_debugp_foh(DNM, foh);
631 DEBUGPC(DNM, "Opstart ACK\n");
632 break;
633 case NM_MT_SET_CHAN_ATTR_ACK:
634 abis_nm_debugp_foh(DNM, foh);
635 DEBUGPC(DNM, "Set Channel Attributes ACK\n");
636 break;
637 case NM_MT_SET_RADIO_ATTR_ACK:
638 abis_nm_debugp_foh(DNM, foh);
639 DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
640 break;
Harald Welte1989c082009-08-06 17:58:31 +0200641 case NM_MT_CONN_MDROP_LINK_ACK:
Max689e7e52017-04-04 19:21:24 +0200642 abis_nm_debugp_foh(DNM, foh);
643 DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
Harald Welte1989c082009-08-06 17:58:31 +0200644 break;
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100645 case NM_MT_IPACC_RESTART_ACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200646 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100647 break;
648 case NM_MT_IPACC_RESTART_NACK:
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200649 osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
Holger Hans Peter Freyther1356c082009-12-30 09:00:01 +0100650 break;
Harald Weltefd355a32011-03-04 13:41:31 +0100651 case NM_MT_SET_BTS_ATTR_ACK:
Harald Weltefd355a32011-03-04 13:41:31 +0100652 break;
Max689e7e52017-04-04 19:21:24 +0200653 default:
654 abis_nm_debugp_foh(DNM, foh);
655 LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
656 get_value_string(abis_nm_msgtype_names, mt));
Harald Welte97ed1e72009-02-06 13:38:02 +0000657 }
658
Jacob Erlbeck74b20282014-11-10 08:30:31 +0100659 abis_nm_queue_send_next(bts);
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100660 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000661}
662
Harald Welte677c21f2009-02-17 13:22:23 +0000663static int abis_nm_rx_ipacc(struct msgb *mb);
664
665static int abis_nm_rcvmsg_manuf(struct msgb *mb)
666{
667 int rc;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200668 struct e1inp_sign_link *sign_link = mb->dst;
669 int bts_type = sign_link->trx->bts->type;
Harald Welte677c21f2009-02-17 13:22:23 +0000670
671 switch (bts_type) {
Mike Habene2d82272009-10-02 12:19:34 +0100672 case GSM_BTS_TYPE_NANOBTS:
Maxf9685c12017-03-23 12:01:07 +0100673 case GSM_BTS_TYPE_OSMOBTS:
Harald Welte677c21f2009-02-17 13:22:23 +0000674 rc = abis_nm_rx_ipacc(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +0200675 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte677c21f2009-02-17 13:22:23 +0000676 break;
677 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100678 LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this "
679 "BTS type (%u)\n", bts_type);
Harald Welte677c21f2009-02-17 13:22:23 +0000680 rc = 0;
681 break;
682 }
683
684 return rc;
685}
686
Harald Welte52b1f982008-12-23 20:25:15 +0000687/* High-Level API */
688/* Entry-point where L2 OML from BTS enters the NM code */
Harald Welte8470bf22008-12-25 23:28:35 +0000689int abis_nm_rcvmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000690{
Harald Welte52b1f982008-12-23 20:25:15 +0000691 struct abis_om_hdr *oh = msgb_l2(msg);
Harald Welte677c21f2009-02-17 13:22:23 +0000692 int rc = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000693
694 /* Various consistency checks */
695 if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100696 LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000697 oh->placement);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200698 if (oh->placement != ABIS_OM_PLACEMENT_FIRST) {
699 rc = -EINVAL;
700 goto err;
701 }
Harald Welte52b1f982008-12-23 20:25:15 +0000702 }
703 if (oh->sequence != 0) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100704 LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000705 oh->sequence);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200706 rc = -EINVAL;
707 goto err;
Harald Welte52b1f982008-12-23 20:25:15 +0000708 }
Harald Welte702d8702008-12-26 20:25:35 +0000709#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200710 unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg);
Holger Freytherca362a62009-01-04 21:05:01 +0000711 unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
Harald Welte702d8702008-12-26 20:25:35 +0000712 if (oh->length + hlen > l2_len) {
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100713 LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000714 oh->length + sizeof(*oh), l2_len);
715 return -EINVAL;
716 }
Harald Welte702d8702008-12-26 20:25:35 +0000717 if (oh->length + hlen < l2_len)
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100718 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 +0000719#endif
Harald Weltead384642008-12-26 10:20:07 +0000720 msg->l3h = (unsigned char *)oh + sizeof(*oh);
Harald Welte52b1f982008-12-23 20:25:15 +0000721
722 switch (oh->mdisc) {
723 case ABIS_OM_MDISC_FOM:
Harald Welte8470bf22008-12-25 23:28:35 +0000724 rc = abis_nm_rcvmsg_fom(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000725 break;
Harald Welte677c21f2009-02-17 13:22:23 +0000726 case ABIS_OM_MDISC_MANUF:
727 rc = abis_nm_rcvmsg_manuf(msg);
728 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000729 case ABIS_OM_MDISC_MMI:
730 case ABIS_OM_MDISC_TRAU:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100731 LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
Harald Welte677c21f2009-02-17 13:22:23 +0000732 oh->mdisc);
733 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000734 default:
Harald Welteb1d4c8e2009-12-17 23:10:46 +0100735 LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000736 oh->mdisc);
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200737 rc = -EINVAL;
738 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000739 }
Pablo Neira Ayusod49eb742012-10-18 19:03:52 +0200740err:
Harald Weltead384642008-12-26 10:20:07 +0000741 msgb_free(msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000742 return rc;
743}
744
745#if 0
746/* initialized all resources */
747struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
748{
749 struct abis_nm_h *nmh;
750
751 nmh = malloc(sizeof(*nmh));
752 if (!nmh)
753 return NULL;
754
755 nmh->cfg = cfg;
756
757 return nmh;
758}
759
760/* free all resources */
761void abis_nm_fini(struct abis_nm_h *nmh)
762{
763 free(nmh);
764}
765#endif
766
767/* Here we are trying to define a high-level API that can be used by
768 * the actual BSC implementation. However, the architecture is currently
769 * still under design. Ideally the calls to this API would be synchronous,
770 * while the underlying stack behind the APi runs in a traditional select
771 * based state machine.
772 */
773
Harald Welte4724f992009-01-18 18:01:49 +0000774/* 6.2 Software Load: */
775enum sw_state {
776 SW_STATE_NONE,
777 SW_STATE_WAIT_INITACK,
778 SW_STATE_WAIT_SEGACK,
779 SW_STATE_WAIT_ENDACK,
780 SW_STATE_WAIT_ACTACK,
781 SW_STATE_ERROR,
782};
Harald Welte52b1f982008-12-23 20:25:15 +0000783
Harald Welte52b1f982008-12-23 20:25:15 +0000784struct abis_nm_sw {
Harald Welte4724f992009-01-18 18:01:49 +0000785 struct gsm_bts *bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +0800786 int trx_nr;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000787 gsm_cbfn *cbfn;
788 void *cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +0000789 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +0000790
Harald Welte52b1f982008-12-23 20:25:15 +0000791 /* this will become part of the SW LOAD INITIATE */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200792 uint8_t obj_class;
793 uint8_t obj_instance[3];
Harald Welte4724f992009-01-18 18:01:49 +0000794
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200795 uint8_t file_id[255];
796 uint8_t file_id_len;
Harald Welte4724f992009-01-18 18:01:49 +0000797
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200798 uint8_t file_version[255];
799 uint8_t file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000800
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200801 uint8_t window_size;
802 uint8_t seg_in_window;
Harald Welte4724f992009-01-18 18:01:49 +0000803
804 int fd;
805 FILE *stream;
806 enum sw_state state;
Harald Welte1602ade2009-01-29 21:12:39 +0000807 int last_seg;
Harald Welte52b1f982008-12-23 20:25:15 +0000808};
809
Harald Welte4724f992009-01-18 18:01:49 +0000810static struct abis_nm_sw g_sw;
811
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100812static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
813{
814 if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
815 msgb_v_put(msg, NM_ATT_SW_DESCR);
816 msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
817 msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
818 sw->file_version);
819 } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
820 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
821 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
822 sw->file_version);
823 } else {
824 LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
825 }
826}
827
Harald Welte4724f992009-01-18 18:01:49 +0000828/* 6.2.1 / 8.3.1: Load Data Initiate */
829static int sw_load_init(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000830{
Harald Welte4724f992009-01-18 18:01:49 +0000831 struct abis_om_hdr *oh;
832 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200833 uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000834
835 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
836 fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
837 sw->obj_instance[0], sw->obj_instance[1],
838 sw->obj_instance[2]);
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +0100839
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100840 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000841 msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
842
843 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000844}
845
Harald Welte1602ade2009-01-29 21:12:39 +0000846static int is_last_line(FILE *stream)
847{
848 char next_seg_buf[256];
849 long pos;
850
851 /* check if we're sending the last line */
852 pos = ftell(stream);
Holger Hans Peter Freyther8a080be2014-04-04 11:48:32 +0200853
854 /* Did ftell fail? Then we are at the end for sure */
855 if (pos < 0)
856 return 1;
857
Harald Welte1602ade2009-01-29 21:12:39 +0000858 if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
Harald Weltebe670502016-11-26 14:11:16 +0100859 int rc = fseek(stream, pos, SEEK_SET);
860 if (rc < 0)
861 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +0000862 return 1;
863 }
864
865 fseek(stream, pos, SEEK_SET);
866 return 0;
867}
868
Harald Welte4724f992009-01-18 18:01:49 +0000869/* 6.2.2 / 8.3.2 Load Data Segment */
870static int sw_load_segment(struct abis_nm_sw *sw)
871{
872 struct abis_om_hdr *oh;
873 struct msgb *msg = nm_msgb_alloc();
874 char seg_buf[256];
875 char *line_buf = seg_buf+2;
Harald Welte3b8ba212009-01-29 12:27:58 +0000876 unsigned char *tlv;
Harald Welte142c4b82011-07-16 13:03:29 +0200877 int len;
Harald Welte4724f992009-01-18 18:01:49 +0000878
879 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte3b8ba212009-01-29 12:27:58 +0000880
881 switch (sw->bts->type) {
882 case GSM_BTS_TYPE_BS11:
883 if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
884 perror("fgets reading segment");
885 return -EINVAL;
886 }
887 seg_buf[0] = 0x00;
Harald Welte1602ade2009-01-29 21:12:39 +0000888
889 /* check if we're sending the last line */
890 sw->last_seg = is_last_line(sw->stream);
891 if (sw->last_seg)
892 seg_buf[1] = 0;
893 else
894 seg_buf[1] = 1 + sw->seg_in_window++;
Harald Welte3b8ba212009-01-29 12:27:58 +0000895
896 len = strlen(line_buf) + 2;
897 tlv = msgb_put(msg, TLV_GROSS_LEN(len));
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200898 tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf);
Harald Welte3b8ba212009-01-29 12:27:58 +0000899 /* BS11 wants CR + LF in excess of the TLV length !?! */
900 tlv[1] -= 2;
901
902 /* we only now know the exact length for the OM hdr */
903 len = strlen(line_buf)+2;
904 break;
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100905 case GSM_BTS_TYPE_NANOBTS: {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200906 osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100907 len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
908 if (len < 0) {
909 perror("read failed");
910 return -EINVAL;
911 }
912
913 if (len != IPACC_SEGMENT_SIZE)
914 sw->last_seg = 1;
915
Holger Hans Peter Freytherc5dc0f72009-12-28 11:28:51 +0100916 ++sw->seg_in_window;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200917 msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf);
Holger Hans Peter Freyther71bc11e2009-12-28 10:04:26 +0100918 len += 3;
919 break;
920 }
Harald Welte3b8ba212009-01-29 12:27:58 +0000921 default:
Holger Hans Peter Freyther64d9ddd2009-12-28 09:21:18 +0100922 LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
Harald Welte3b8ba212009-01-29 12:27:58 +0000923 /* FIXME: Other BTS types */
924 return -1;
Harald Welte4724f992009-01-18 18:01:49 +0000925 }
Harald Welte4724f992009-01-18 18:01:49 +0000926
Harald Welte4724f992009-01-18 18:01:49 +0000927 fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
928 sw->obj_instance[0], sw->obj_instance[1],
929 sw->obj_instance[2]);
930
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +0100931 return abis_nm_sendmsg_direct(sw->bts, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000932}
933
934/* 6.2.4 / 8.3.4 Load Data End */
935static int sw_load_end(struct abis_nm_sw *sw)
936{
937 struct abis_om_hdr *oh;
938 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200939 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte4724f992009-01-18 18:01:49 +0000940
941 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
942 fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
943 sw->obj_instance[0], sw->obj_instance[1],
944 sw->obj_instance[2]);
945
Holger Hans Peter Freyther79928672009-12-30 09:23:48 +0100946 sw_add_file_id_and_ver(sw, msg);
Harald Welte4724f992009-01-18 18:01:49 +0000947 return abis_nm_sendmsg(sw->bts, msg);
948}
Harald Welte5e4d1b32009-02-01 13:36:56 +0000949
Harald Welte52b1f982008-12-23 20:25:15 +0000950/* Activate the specified software into the BTS */
Harald Welte4724f992009-01-18 18:01:49 +0000951static int sw_activate(struct abis_nm_sw *sw)
Harald Welte52b1f982008-12-23 20:25:15 +0000952{
Harald Welte4724f992009-01-18 18:01:49 +0000953 struct abis_om_hdr *oh;
954 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200955 uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
Harald Welte52b1f982008-12-23 20:25:15 +0000956
Harald Welte4724f992009-01-18 18:01:49 +0000957 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
958 fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
959 sw->obj_instance[0], sw->obj_instance[1],
960 sw->obj_instance[2]);
961
962 /* FIXME: this is BS11 specific format */
963 msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
964 msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
965 sw->file_version);
966
967 return abis_nm_sendmsg(sw->bts, msg);
Harald Welte52b1f982008-12-23 20:25:15 +0000968}
Harald Welte4724f992009-01-18 18:01:49 +0000969
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100970struct sdp_firmware {
971 char magic[4];
972 char more_magic[4];
973 unsigned int header_length;
974 unsigned int file_length;
975} __attribute__ ((packed));
976
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +0100977static int parse_sdp_header(struct abis_nm_sw *sw)
978{
Holger Hans Peter Freythera6faea82009-12-28 07:28:43 +0100979 struct sdp_firmware firmware_header;
980 int rc;
981 struct stat stat;
982
983 rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
984 if (rc != sizeof(firmware_header)) {
985 LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
986 return -1;
987 }
988
989 if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
990 LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
991 return -1;
992 }
993
994 if (firmware_header.more_magic[0] != 0x10 ||
995 firmware_header.more_magic[1] != 0x02 ||
996 firmware_header.more_magic[2] != 0x00 ||
997 firmware_header.more_magic[3] != 0x00) {
998 LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
999 return -1;
1000 }
1001
1002
1003 if (fstat(sw->fd, &stat) == -1) {
1004 LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
1005 return -1;
1006 }
1007
1008 if (ntohl(firmware_header.file_length) != stat.st_size) {
1009 LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
1010 return -1;
1011 }
1012
1013 /* go back to the start as we checked the whole filesize.. */
1014 lseek(sw->fd, 0l, SEEK_SET);
1015 LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
1016 "There might be checksums in the file that are not\n"
1017 "verified and incomplete firmware might be flashed.\n"
1018 "There is absolutely no WARRANTY that flashing will\n"
1019 "work.\n");
1020 return 0;
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001021}
1022
Harald Welte4724f992009-01-18 18:01:49 +00001023static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
1024{
1025 char file_id[12+1];
1026 char file_version[80+1];
1027 int rc;
1028
1029 sw->fd = open(fname, O_RDONLY);
1030 if (sw->fd < 0)
1031 return sw->fd;
1032
1033 switch (sw->bts->type) {
1034 case GSM_BTS_TYPE_BS11:
1035 sw->stream = fdopen(sw->fd, "r");
1036 if (!sw->stream) {
1037 perror("fdopen");
1038 return -1;
1039 }
1040 /* read first line and parse file ID and VERSION */
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001041 rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
Harald Welte4724f992009-01-18 18:01:49 +00001042 file_id, file_version);
1043 if (rc != 2) {
1044 perror("parsing header line of software file");
1045 return -1;
1046 }
1047 strcpy((char *)sw->file_id, file_id);
1048 sw->file_id_len = strlen(file_id);
1049 strcpy((char *)sw->file_version, file_version);
1050 sw->file_version_len = strlen(file_version);
1051 /* rewind to start of file */
Harald Welte3b8ba212009-01-29 12:27:58 +00001052 rewind(sw->stream);
Harald Welte4724f992009-01-18 18:01:49 +00001053 break;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001054 case GSM_BTS_TYPE_NANOBTS:
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001055 /* TODO: extract that from the filename or content */
Holger Hans Peter Freyther66e82192009-12-23 08:06:31 +01001056 rc = parse_sdp_header(sw);
1057 if (rc < 0) {
1058 fprintf(stderr, "Could not parse the ipaccess SDP header\n");
1059 return -1;
1060 }
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001061
1062 strcpy((char *)sw->file_id, "id");
1063 sw->file_id_len = 3;
1064 strcpy((char *)sw->file_version, "version");
1065 sw->file_version_len = 8;
Holger Hans Peter Freythere7ff9132009-12-23 07:26:57 +01001066 break;
Harald Welte4724f992009-01-18 18:01:49 +00001067 default:
1068 /* We don't know how to treat them yet */
1069 close(sw->fd);
1070 return -EINVAL;
1071 }
1072
1073 return 0;
1074}
1075
1076static void sw_close_file(struct abis_nm_sw *sw)
1077{
1078 switch (sw->bts->type) {
1079 case GSM_BTS_TYPE_BS11:
1080 fclose(sw->stream);
1081 break;
1082 default:
1083 close(sw->fd);
1084 break;
1085 }
1086}
1087
1088/* Fill the window */
1089static int sw_fill_window(struct abis_nm_sw *sw)
1090{
1091 int rc;
1092
1093 while (sw->seg_in_window < sw->window_size) {
1094 rc = sw_load_segment(sw);
1095 if (rc < 0)
1096 return rc;
Harald Welte1602ade2009-01-29 21:12:39 +00001097 if (sw->last_seg)
1098 break;
Harald Welte4724f992009-01-18 18:01:49 +00001099 }
1100 return 0;
1101}
1102
1103/* callback function from abis_nm_rcvmsg() handler */
1104static int abis_nm_rcvmsg_sw(struct msgb *mb)
1105{
1106 struct abis_om_fom_hdr *foh = msgb_l3(mb);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001107 struct e1inp_sign_link *sign_link = mb->dst;
Harald Welte4724f992009-01-18 18:01:49 +00001108 int rc = -1;
1109 struct abis_nm_sw *sw = &g_sw;
1110 enum sw_state old_state = sw->state;
1111
Harald Welte3ffd1372009-02-01 22:15:49 +00001112 //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
Harald Welte4724f992009-01-18 18:01:49 +00001113
1114 switch (sw->state) {
1115 case SW_STATE_WAIT_INITACK:
1116 switch (foh->msg_type) {
1117 case NM_MT_LOAD_INIT_ACK:
1118 /* fill window with segments */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001119 if (sw->cbfn)
1120 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1121 NM_MT_LOAD_INIT_ACK, mb,
1122 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001123 rc = sw_fill_window(sw);
1124 sw->state = SW_STATE_WAIT_SEGACK;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001125 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001126 break;
1127 case NM_MT_LOAD_INIT_NACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001128 if (sw->forced) {
1129 DEBUGP(DNM, "FORCED: Ignoring Software Load "
1130 "Init NACK\n");
1131 if (sw->cbfn)
1132 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1133 NM_MT_LOAD_INIT_ACK, mb,
1134 sw->cb_data, NULL);
1135 rc = sw_fill_window(sw);
1136 sw->state = SW_STATE_WAIT_SEGACK;
1137 } else {
1138 DEBUGP(DNM, "Software Load Init NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001139 /* FIXME: cause */
Harald Welte3ffd1372009-02-01 22:15:49 +00001140 if (sw->cbfn)
1141 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1142 NM_MT_LOAD_INIT_NACK, mb,
1143 sw->cb_data, NULL);
1144 sw->state = SW_STATE_ERROR;
1145 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001146 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001147 break;
1148 }
1149 break;
1150 case SW_STATE_WAIT_SEGACK:
1151 switch (foh->msg_type) {
1152 case NM_MT_LOAD_SEG_ACK:
Harald Welte3ffd1372009-02-01 22:15:49 +00001153 if (sw->cbfn)
1154 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1155 NM_MT_LOAD_SEG_ACK, mb,
1156 sw->cb_data, NULL);
Harald Welte4724f992009-01-18 18:01:49 +00001157 sw->seg_in_window = 0;
Harald Welte1602ade2009-01-29 21:12:39 +00001158 if (!sw->last_seg) {
1159 /* fill window with more segments */
1160 rc = sw_fill_window(sw);
1161 sw->state = SW_STATE_WAIT_SEGACK;
1162 } else {
1163 /* end the transfer */
1164 sw->state = SW_STATE_WAIT_ENDACK;
1165 rc = sw_load_end(sw);
1166 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001167 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001168 break;
Holger Hans Peter Freytherc7aabca2009-12-28 12:23:02 +01001169 case NM_MT_LOAD_ABORT:
1170 if (sw->cbfn)
1171 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1172 NM_MT_LOAD_ABORT, mb,
1173 sw->cb_data, NULL);
1174 break;
Harald Welte4724f992009-01-18 18:01:49 +00001175 }
1176 break;
1177 case SW_STATE_WAIT_ENDACK:
1178 switch (foh->msg_type) {
1179 case NM_MT_LOAD_END_ACK:
1180 sw_close_file(sw);
Harald Welte5e4d1b32009-02-01 13:36:56 +00001181 DEBUGP(DNM, "Software Load End (BTS %u)\n",
1182 sw->bts->nr);
1183 sw->state = SW_STATE_NONE;
1184 if (sw->cbfn)
1185 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1186 NM_MT_LOAD_END_ACK, mb,
1187 sw->cb_data, NULL);
Holger Hans Peter Freyther8f31a8f2009-12-28 11:48:12 +01001188 rc = 0;
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_END_NACK:
Holger Freyther31338a12009-02-06 17:43:50 +00001192 if (sw->forced) {
1193 DEBUGP(DNM, "FORCED: Ignoring Software Load"
1194 "End NACK\n");
1195 sw->state = SW_STATE_NONE;
1196 if (sw->cbfn)
1197 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1198 NM_MT_LOAD_END_ACK, mb,
1199 sw->cb_data, NULL);
1200 } else {
1201 DEBUGP(DNM, "Software Load End NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001202 /* FIXME: cause */
Holger Freyther31338a12009-02-06 17:43:50 +00001203 sw->state = SW_STATE_ERROR;
1204 if (sw->cbfn)
1205 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1206 NM_MT_LOAD_END_NACK, mb,
1207 sw->cb_data, NULL);
1208 }
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001209 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001210 break;
1211 }
1212 case SW_STATE_WAIT_ACTACK:
1213 switch (foh->msg_type) {
1214 case NM_MT_ACTIVATE_SW_ACK:
1215 /* we're done */
Harald Welte5e4d1b32009-02-01 13:36:56 +00001216 DEBUGP(DNM, "Activate Software DONE!\n");
Harald Welte4724f992009-01-18 18:01:49 +00001217 sw->state = SW_STATE_NONE;
1218 rc = 0;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001219 if (sw->cbfn)
1220 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1221 NM_MT_ACTIVATE_SW_ACK, mb,
1222 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001223 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001224 break;
1225 case NM_MT_ACTIVATE_SW_NACK:
Harald Welte1602ade2009-01-29 21:12:39 +00001226 DEBUGP(DNM, "Activate Software NACK\n");
Harald Welte6c96ba52009-05-01 13:03:40 +00001227 /* FIXME: cause */
Harald Welte4724f992009-01-18 18:01:49 +00001228 sw->state = SW_STATE_ERROR;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001229 if (sw->cbfn)
1230 sw->cbfn(GSM_HOOK_NM_SWLOAD,
1231 NM_MT_ACTIVATE_SW_NACK, mb,
1232 sw->cb_data, NULL);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02001233 abis_nm_queue_send_next(sign_link->trx->bts);
Harald Welte4724f992009-01-18 18:01:49 +00001234 break;
1235 }
1236 case SW_STATE_NONE:
Harald Weltea994a482009-05-01 15:54:23 +00001237 switch (foh->msg_type) {
1238 case NM_MT_ACTIVATE_SW_ACK:
1239 rc = 0;
1240 break;
1241 }
1242 break;
Harald Welte4724f992009-01-18 18:01:49 +00001243 case SW_STATE_ERROR:
1244 break;
1245 }
1246
1247 if (rc)
Harald Weltea994a482009-05-01 15:54:23 +00001248 DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
Harald Welte4724f992009-01-18 18:01:49 +00001249 foh->msg_type, old_state, sw->state);
1250
1251 return rc;
1252}
1253
1254/* Load the specified software into the BTS */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001255int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001256 uint8_t win_size, int forced,
Harald Welte3ffd1372009-02-01 22:15:49 +00001257 gsm_cbfn *cbfn, void *cb_data)
Harald Welte4724f992009-01-18 18:01:49 +00001258{
1259 struct abis_nm_sw *sw = &g_sw;
1260 int rc;
1261
Harald Welte5e4d1b32009-02-01 13:36:56 +00001262 DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
1263 bts->nr, fname);
1264
Harald Welte4724f992009-01-18 18:01:49 +00001265 if (sw->state != SW_STATE_NONE)
1266 return -EBUSY;
1267
1268 sw->bts = bts;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001269 sw->trx_nr = trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001270
1271 switch (bts->type) {
1272 case GSM_BTS_TYPE_BS11:
1273 sw->obj_class = NM_OC_SITE_MANAGER;
1274 sw->obj_instance[0] = 0xff;
1275 sw->obj_instance[1] = 0xff;
1276 sw->obj_instance[2] = 0xff;
1277 break;
1278 case GSM_BTS_TYPE_NANOBTS:
1279 sw->obj_class = NM_OC_BASEB_TRANSC;
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08001280 sw->obj_instance[0] = sw->bts->nr;
1281 sw->obj_instance[1] = sw->trx_nr;
Holger Hans Peter Freythercf269a72009-12-28 09:02:41 +01001282 sw->obj_instance[2] = 0xff;
1283 break;
1284 case GSM_BTS_TYPE_UNKNOWN:
1285 default:
1286 LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
1287 return -1;
1288 break;
1289 }
Harald Welte4724f992009-01-18 18:01:49 +00001290 sw->window_size = win_size;
1291 sw->state = SW_STATE_WAIT_INITACK;
Harald Welte5e4d1b32009-02-01 13:36:56 +00001292 sw->cbfn = cbfn;
1293 sw->cb_data = cb_data;
Harald Welte3ffd1372009-02-01 22:15:49 +00001294 sw->forced = forced;
Harald Welte4724f992009-01-18 18:01:49 +00001295
1296 rc = sw_open_file(sw, fname);
1297 if (rc < 0) {
1298 sw->state = SW_STATE_NONE;
1299 return rc;
1300 }
1301
1302 return sw_load_init(sw);
1303}
Harald Welte52b1f982008-12-23 20:25:15 +00001304
Harald Welte1602ade2009-01-29 21:12:39 +00001305int abis_nm_software_load_status(struct gsm_bts *bts)
1306{
1307 struct abis_nm_sw *sw = &g_sw;
1308 struct stat st;
1309 int rc, percent;
1310
1311 rc = fstat(sw->fd, &st);
1312 if (rc < 0) {
1313 perror("ERROR during stat");
1314 return rc;
1315 }
1316
Holger Hans Peter Freyther5a2291e2009-12-28 10:16:54 +01001317 if (sw->stream)
1318 percent = (ftell(sw->stream) * 100) / st.st_size;
1319 else
1320 percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size;
Harald Welte1602ade2009-01-29 21:12:39 +00001321 return percent;
1322}
1323
Harald Welte5e4d1b32009-02-01 13:36:56 +00001324/* Activate the specified software into the BTS */
1325int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
1326 gsm_cbfn *cbfn, void *cb_data)
1327{
1328 struct abis_nm_sw *sw = &g_sw;
1329 int rc;
1330
1331 DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
1332 bts->nr, fname);
1333
1334 if (sw->state != SW_STATE_NONE)
1335 return -EBUSY;
1336
1337 sw->bts = bts;
1338 sw->obj_class = NM_OC_SITE_MANAGER;
1339 sw->obj_instance[0] = 0xff;
1340 sw->obj_instance[1] = 0xff;
1341 sw->obj_instance[2] = 0xff;
1342 sw->state = SW_STATE_WAIT_ACTACK;
1343 sw->cbfn = cbfn;
1344 sw->cb_data = cb_data;
1345
1346 /* Open the file in order to fill some sw struct members */
1347 rc = sw_open_file(sw, fname);
1348 if (rc < 0) {
1349 sw->state = SW_STATE_NONE;
1350 return rc;
1351 }
1352 sw_close_file(sw);
1353
1354 return sw_activate(sw);
1355}
1356
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001357static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port,
1358 uint8_t ts_nr, uint8_t subslot_nr)
Harald Welte52b1f982008-12-23 20:25:15 +00001359{
Harald Welteadaf08b2009-01-18 11:08:10 +00001360 ch->attrib = NM_ATT_ABIS_CHANNEL;
Harald Welte52b1f982008-12-23 20:25:15 +00001361 ch->bts_port = bts_port;
1362 ch->timeslot = ts_nr;
1363 ch->subslot = subslot_nr;
1364}
1365
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001366int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr,
1367 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
1368 uint8_t tei)
Harald Welte52b1f982008-12-23 20:25:15 +00001369{
1370 struct abis_om_hdr *oh;
1371 struct abis_nm_channel *ch;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001372 uint8_t len = sizeof(*ch) + 2;
Harald Welte8470bf22008-12-25 23:28:35 +00001373 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001374
1375 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1376 fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
1377 bts->bts_nr, trx_nr, 0xff);
1378
Harald Welte8470bf22008-12-25 23:28:35 +00001379 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte52b1f982008-12-23 20:25:15 +00001380
1381 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1382 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1383
1384 return abis_nm_sendmsg(bts, msg);
1385}
1386
1387/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
1388int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001389 uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001390{
Harald Welte8470bf22008-12-25 23:28:35 +00001391 struct gsm_bts *bts = trx->bts;
Harald Welte52b1f982008-12-23 20:25:15 +00001392 struct abis_om_hdr *oh;
1393 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001394 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001395
1396 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001397 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
Harald Welte52b1f982008-12-23 20:25:15 +00001398 NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
1399
1400 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1401 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1402
1403 return abis_nm_sendmsg(bts, msg);
1404}
1405
1406#if 0
1407int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1408 struct abis_nm_abis_channel *chan)
1409{
1410}
1411#endif
1412
1413int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001414 uint8_t e1_port, uint8_t e1_timeslot,
1415 uint8_t e1_subslot)
Harald Welte52b1f982008-12-23 20:25:15 +00001416{
1417 struct gsm_bts *bts = ts->trx->bts;
1418 struct abis_om_hdr *oh;
1419 struct abis_nm_channel *ch;
Harald Welte8470bf22008-12-25 23:28:35 +00001420 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001421
1422 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1423 fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
Harald Welteb110cee2009-02-18 03:42:35 +00001424 NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001425
1426 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
1427 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
1428
Harald Weltef325eb42009-02-19 17:07:39 +00001429 DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
1430 gsm_ts_name(ts),
Harald Welteb110cee2009-02-18 03:42:35 +00001431 e1_port, e1_timeslot, e1_subslot);
1432
Harald Welte52b1f982008-12-23 20:25:15 +00001433 return abis_nm_sendmsg(bts, msg);
1434}
1435
1436#if 0
1437int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
1438 struct abis_nm_abis_channel *chan,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001439 uint8_t subchan)
Harald Welte52b1f982008-12-23 20:25:15 +00001440{
1441}
1442#endif
1443
Harald Weltefe568f22012-08-14 19:15:57 +02001444/* Chapter 8.11.1 */
1445int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class,
1446 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1447 uint8_t *attr, uint8_t attr_len)
1448{
1449 struct abis_om_hdr *oh;
1450 struct msgb *msg = nm_msgb_alloc();
Harald Weltefe568f22012-08-14 19:15:57 +02001451
1452 DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr);
1453
1454 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1455 fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class,
1456 bts_nr, trx_nr, ts_nr);
1457 msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
1458
1459 return abis_nm_sendmsg(bts, msg);
1460}
1461
Harald Welte22af0db2009-02-14 15:41:08 +00001462/* Chapter 8.6.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001463int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001464{
1465 struct abis_om_hdr *oh;
1466 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001467 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001468
1469 DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
1470
1471 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte191280d2009-05-01 13:20:04 +00001472 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 +00001473 cur = msgb_put(msg, attr_len);
1474 memcpy(cur, attr, attr_len);
1475
1476 return abis_nm_sendmsg(bts, msg);
1477}
1478
1479/* Chapter 8.6.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001480int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len)
Harald Welte22af0db2009-02-14 15:41:08 +00001481{
1482 struct abis_om_hdr *oh;
1483 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001484 uint8_t *cur;
Harald Welte22af0db2009-02-14 15:41:08 +00001485
1486 DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
1487
1488 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1489 fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
Harald Welte191280d2009-05-01 13:20:04 +00001490 trx->bts->bts_nr, trx->nr, 0xff);
Harald Welte22af0db2009-02-14 15:41:08 +00001491 cur = msgb_put(msg, attr_len);
1492 memcpy(cur, attr, attr_len);
1493
1494 return abis_nm_sendmsg(trx->bts, msg);
1495}
1496
Holger Hans Peter Freyther8a158bb2014-03-26 14:24:42 +01001497int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
1498{
1499 uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
1500 return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
1501}
1502
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001503static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
1504 const char **reason)
Harald Welte39c7deb2009-08-09 21:49:48 +02001505{
1506 int i;
1507
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001508 *reason = "Reason unknown";
1509
Harald Welte39c7deb2009-08-09 21:49:48 +02001510 /* As it turns out, the BS-11 has some very peculiar restrictions
1511 * on the channel combinations it allows */
Harald Welted6575f92009-12-02 02:45:23 +05301512 switch (ts->trx->bts->type) {
1513 case GSM_BTS_TYPE_BS11:
Harald Welte39c7deb2009-08-09 21:49:48 +02001514 switch (chan_comb) {
1515 case NM_CHANC_TCHHalf:
1516 case NM_CHANC_TCHHalf2:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001517 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welte39c7deb2009-08-09 21:49:48 +02001518 /* not supported */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001519 *reason = "TCH/H is not supported.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001520 return -EINVAL;
1521 case NM_CHANC_SDCCH:
1522 /* only one SDCCH/8 per TRX */
1523 for (i = 0; i < TRX_NR_TS; i++) {
1524 if (i == ts->nr)
1525 continue;
1526 if (ts->trx->ts[i].nm_chan_comb ==
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001527 NM_CHANC_SDCCH) {
1528 *reason = "Only one SDCCH/8 per TRX allowed.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001529 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001530 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001531 }
1532 /* not allowed for TS0 of BCCH-TRX */
1533 if (ts->trx == ts->trx->bts->c0 &&
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001534 ts->nr == 0) {
1535 *reason = "SDCCH/8 must be on TS0.";
1536 return -EINVAL;
1537 }
1538
Harald Welte39c7deb2009-08-09 21:49:48 +02001539 /* not on the same TRX that has a BCCH+SDCCH4
1540 * combination */
Holger Hans Peter Freyther608ac2a2013-01-08 19:30:14 +01001541 if (ts->trx != ts->trx->bts->c0 &&
Harald Welte39c7deb2009-08-09 21:49:48 +02001542 (ts->trx->ts[0].nm_chan_comb == 5 ||
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001543 ts->trx->ts[0].nm_chan_comb == 8)) {
1544 *reason = "SDCCH/8 and BCCH must be on the same TRX.";
1545 return -EINVAL;
1546 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001547 break;
1548 case NM_CHANC_mainBCCH:
1549 case NM_CHANC_BCCHComb:
1550 /* allowed only for TS0 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001551 if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) {
1552 *reason = "Main BCCH must be on TS0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001553 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001554 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001555 break;
1556 case NM_CHANC_BCCH:
1557 /* allowed only for TS 2/4/6 of C0 */
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001558 if (ts->trx != ts->trx->bts->c0) {
1559 *reason = "BCCH must be on C0.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001560 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001561 }
1562 if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
1563 *reason = "BCCH must be on TS 2/4/6.";
Harald Welte39c7deb2009-08-09 21:49:48 +02001564 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001565 }
Harald Welte39c7deb2009-08-09 21:49:48 +02001566 break;
1567 case 8: /* this is not like 08.58, but in fact
1568 * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
1569 /* FIXME: only one CBCH allowed per cell */
1570 break;
1571 }
Harald Welted6575f92009-12-02 02:45:23 +05301572 break;
1573 case GSM_BTS_TYPE_NANOBTS:
1574 switch (ts->nr) {
1575 case 0:
1576 if (ts->trx->nr == 0) {
1577 /* only on TRX0 */
1578 switch (chan_comb) {
1579 case NM_CHANC_BCCH:
1580 case NM_CHANC_mainBCCH:
1581 case NM_CHANC_BCCHComb:
1582 return 0;
1583 break;
1584 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001585 *reason = "TS0 of TRX0 must carry a BCCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301586 return -EINVAL;
1587 }
1588 } else {
1589 switch (chan_comb) {
1590 case NM_CHANC_TCHFull:
1591 case NM_CHANC_TCHHalf:
1592 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1593 return 0;
1594 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001595 *reason = "TS0 must carry a TCH/F or TCH/H.";
Harald Welted6575f92009-12-02 02:45:23 +05301596 return -EINVAL;
1597 }
1598 }
1599 break;
1600 case 1:
1601 if (ts->trx->nr == 0) {
1602 switch (chan_comb) {
1603 case NM_CHANC_SDCCH_CBCH:
1604 if (ts->trx->ts[0].nm_chan_comb ==
1605 NM_CHANC_mainBCCH)
1606 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001607 *reason = "TS0 must be the main BCCH for CBCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301608 return -EINVAL;
1609 case NM_CHANC_SDCCH:
1610 case NM_CHANC_TCHFull:
1611 case NM_CHANC_TCHHalf:
1612 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1613 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001614 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301615 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001616 default:
1617 *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
1618 return -EINVAL;
Harald Welted6575f92009-12-02 02:45:23 +05301619 }
1620 } else {
1621 switch (chan_comb) {
1622 case NM_CHANC_SDCCH:
1623 case NM_CHANC_TCHFull:
1624 case NM_CHANC_TCHHalf:
1625 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1626 return 0;
1627 default:
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001628 *reason = "TS1 must carry a SDCCH or TCH.";
Harald Welted6575f92009-12-02 02:45:23 +05301629 return -EINVAL;
1630 }
1631 }
1632 break;
1633 case 2:
1634 case 3:
1635 case 4:
1636 case 5:
1637 case 6:
1638 case 7:
1639 switch (chan_comb) {
1640 case NM_CHANC_TCHFull:
1641 case NM_CHANC_TCHHalf:
1642 case NM_CHANC_IPAC_TCHFull_TCHHalf:
1643 return 0;
1644 case NM_CHANC_IPAC_PDCH:
1645 case NM_CHANC_IPAC_TCHFull_PDCH:
Neels Hofmeyr9518ffc2016-07-14 03:09:56 +02001646 case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
Harald Welted6575f92009-12-02 02:45:23 +05301647 if (ts->trx->nr == 0)
1648 return 0;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001649 else {
1650 *reason = "PDCH must be on TRX0.";
Harald Welted6575f92009-12-02 02:45:23 +05301651 return -EINVAL;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001652 }
Harald Welted6575f92009-12-02 02:45:23 +05301653 }
1654 break;
1655 }
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001656 *reason = "Unknown combination";
Harald Welted6575f92009-12-02 02:45:23 +05301657 return -EINVAL;
Maxf9685c12017-03-23 12:01:07 +01001658 case GSM_BTS_TYPE_OSMOBTS:
Harald Weltef383aa12012-07-02 19:51:55 +02001659 /* no known restrictions */
1660 return 0;
Harald Welted6575f92009-12-02 02:45:23 +05301661 default:
1662 /* unknown BTS type */
1663 return 0;
Harald Welte39c7deb2009-08-09 21:49:48 +02001664 }
1665 return 0;
1666}
1667
Harald Welte22af0db2009-02-14 15:41:08 +00001668/* Chapter 8.6.3 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001669int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
Harald Welte52b1f982008-12-23 20:25:15 +00001670{
1671 struct gsm_bts *bts = ts->trx->bts;
1672 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001673 uint8_t zero = 0x00;
Harald Welte8470bf22008-12-25 23:28:35 +00001674 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001675 uint8_t len = 2 + 2;
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001676 const char *reason = NULL;
Harald Weltee0590df2009-02-15 03:34:15 +00001677
1678 if (bts->type == GSM_BTS_TYPE_BS11)
1679 len += 4 + 2 + 2 + 3;
Harald Welte52b1f982008-12-23 20:25:15 +00001680
Harald Weltef325eb42009-02-19 17:07:39 +00001681 DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001682 if (verify_chan_comb(ts, chan_comb, &reason) < 0) {
Harald Welte39c7deb2009-08-09 21:49:48 +02001683 msgb_free(msg);
Holger Hans Peter Freyther34203bd2012-09-17 15:49:16 +02001684 LOGP(DNM, LOGL_ERROR,
1685 "Invalid Channel Combination %d on %s. Reason: %s\n",
1686 chan_comb, gsm_ts_name(ts), reason);
Harald Welte39c7deb2009-08-09 21:49:48 +02001687 return -EINVAL;
1688 }
1689 ts->nm_chan_comb = chan_comb;
Harald Welte22af0db2009-02-14 15:41:08 +00001690
Harald Welte52b1f982008-12-23 20:25:15 +00001691 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001692 fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
Holger Freyther6b2d2622009-02-14 23:16:59 +00001693 NM_OC_CHANNEL, bts->bts_nr,
Harald Welte52b1f982008-12-23 20:25:15 +00001694 ts->trx->nr, ts->nr);
Harald Welte52b1f982008-12-23 20:25:15 +00001695 msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
Harald Weltea39b0f22010-06-14 22:26:10 +02001696 if (ts->hopping.enabled) {
1697 unsigned int i;
1698 uint8_t *len;
1699
Harald Welte6e0cd042009-09-12 13:05:33 +02001700 msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
1701 msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
Harald Weltea39b0f22010-06-14 22:26:10 +02001702
1703 /* build the ARFCN list */
1704 msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
1705 len = msgb_put(msg, 1);
1706 *len = 0;
1707 for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
1708 if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
1709 msgb_put_u16(msg, i);
laforgef87ebe62010-06-20 15:20:02 +02001710 /* At least BS-11 wants a TLV16 here */
1711 if (bts->type == GSM_BTS_TYPE_BS11)
1712 *len += 1;
1713 else
1714 *len += sizeof(uint16_t);
Harald Weltea39b0f22010-06-14 22:26:10 +02001715 }
1716 }
Harald Weltee0590df2009-02-15 03:34:15 +00001717 }
Harald Welte1fe24122014-01-19 17:18:21 +01001718 msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */
Harald Weltee0590df2009-02-15 03:34:15 +00001719 if (bts->type == GSM_BTS_TYPE_BS11)
1720 msgb_tlv_put(msg, 0x59, 1, &zero);
Harald Welte52b1f982008-12-23 20:25:15 +00001721
1722 return abis_nm_sendmsg(bts, msg);
1723}
1724
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001725int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1,
1726 uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
Harald Welte34a99682009-02-13 02:41:40 +00001727{
1728 struct abis_om_hdr *oh;
1729 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001730 uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
1731 uint8_t len = att_len;
Harald Welte5c1e4582009-02-15 11:57:29 +00001732
1733 if (nack) {
1734 len += 2;
1735 msgtype = NM_MT_SW_ACT_REQ_NACK;
1736 }
Harald Welte34a99682009-02-13 02:41:40 +00001737
1738 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte5c1e4582009-02-15 11:57:29 +00001739 fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
1740
Harald Welte34a99682009-02-13 02:41:40 +00001741 if (attr) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001742 uint8_t *ptr = msgb_put(msg, att_len);
Harald Welte34a99682009-02-13 02:41:40 +00001743 memcpy(ptr, attr, att_len);
1744 }
Harald Welte5c1e4582009-02-15 11:57:29 +00001745 if (nack)
1746 msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
Harald Welte34a99682009-02-13 02:41:40 +00001747
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01001748 return abis_nm_sendmsg_direct(bts, msg);
Harald Welte34a99682009-02-13 02:41:40 +00001749}
1750
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001751int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg)
Harald Welte52b1f982008-12-23 20:25:15 +00001752{
Harald Welte8470bf22008-12-25 23:28:35 +00001753 struct msgb *msg = nm_msgb_alloc();
1754 struct abis_om_hdr *oh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001755 uint8_t *data;
Harald Welte52b1f982008-12-23 20:25:15 +00001756
1757 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
1758 fill_om_hdr(oh, len);
1759 data = msgb_put(msg, len);
Harald Weltead384642008-12-26 10:20:07 +00001760 memcpy(data, rawmsg, len);
Harald Welte52b1f982008-12-23 20:25:15 +00001761
1762 return abis_nm_sendmsg(bts, msg);
1763}
1764
1765/* Siemens specific commands */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001766static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type)
Harald Welte52b1f982008-12-23 20:25:15 +00001767{
1768 struct abis_om_hdr *oh;
Harald Welte8470bf22008-12-25 23:28:35 +00001769 struct msgb *msg = nm_msgb_alloc();
Harald Welte52b1f982008-12-23 20:25:15 +00001770
1771 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte702d8702008-12-26 20:25:35 +00001772 fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
Harald Welte52b1f982008-12-23 20:25:15 +00001773 0xff, 0xff, 0xff);
1774
1775 return abis_nm_sendmsg(bts, msg);
1776}
1777
Harald Welte34a99682009-02-13 02:41:40 +00001778/* Chapter 8.9.2 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001779int 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 +00001780{
1781 struct abis_om_hdr *oh;
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001782 struct abis_om_fom_hdr *foh;
Harald Welte34a99682009-02-13 02:41:40 +00001783 struct msgb *msg = nm_msgb_alloc();
1784
1785 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001786 foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
Harald Welte34a99682009-02-13 02:41:40 +00001787
Holger Hans Peter Freyther686191a2014-04-04 12:56:34 +02001788 abis_nm_debugp_foh(DNM, foh);
Harald Weltea8bd6d42009-10-20 09:56:18 +02001789 DEBUGPC(DNM, "Sending OPSTART\n");
1790
Harald Welte34a99682009-02-13 02:41:40 +00001791 return abis_nm_sendmsg(bts, msg);
1792}
1793
1794/* Chapter 8.8.5 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001795int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0,
1796 uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state)
Harald Welte34a99682009-02-13 02:41:40 +00001797{
1798 struct abis_om_hdr *oh;
1799 struct msgb *msg = nm_msgb_alloc();
1800
1801 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1802 fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
1803 msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
1804
1805 return abis_nm_sendmsg(bts, msg);
1806}
1807
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001808int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0,
1809 uint8_t e1_port1, uint8_t ts1)
Harald Welte1989c082009-08-06 17:58:31 +02001810{
1811 struct abis_om_hdr *oh;
1812 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001813 uint8_t *attr;
Harald Welte1989c082009-08-06 17:58:31 +02001814
1815 DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
1816 e1_port0, ts0, e1_port1, ts1);
1817
1818 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1819 fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
1820 NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
1821
1822 attr = msgb_put(msg, 3);
1823 attr[0] = NM_ATT_MDROP_LINK;
1824 attr[1] = e1_port0;
1825 attr[2] = ts0;
1826
1827 attr = msgb_put(msg, 3);
1828 attr[0] = NM_ATT_MDROP_NEXT;
1829 attr[1] = e1_port1;
1830 attr[2] = ts1;
1831
1832 return abis_nm_sendmsg(bts, msg);
1833}
Harald Welte34a99682009-02-13 02:41:40 +00001834
Harald Weltec7310382009-08-08 00:02:36 +02001835/* Chapter 8.7.1 */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001836int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class,
1837 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
1838 uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
Harald Weltec7310382009-08-08 00:02:36 +02001839{
1840 struct abis_om_hdr *oh;
Harald Weltec7310382009-08-08 00:02:36 +02001841
Harald Welte15c61722011-05-22 22:45:37 +02001842 DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr));
Harald Welte887deab2010-03-06 11:38:05 +01001843
1844 if (!msg)
1845 msg = nm_msgb_alloc();
1846
1847 msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
1848 msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
1849 oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
1850 fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
Harald Weltec7310382009-08-08 00:02:36 +02001851 obj_class, bts_nr, trx_nr, ts_nr);
Harald Weltec7310382009-08-08 00:02:36 +02001852
1853 return abis_nm_sendmsg(bts, msg);
1854}
1855
Harald Welte52b1f982008-12-23 20:25:15 +00001856int abis_nm_event_reports(struct gsm_bts *bts, int on)
1857{
1858 if (on == 0)
Harald Welte227d4072009-01-03 08:16:25 +00001859 return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001860 else
Harald Welte227d4072009-01-03 08:16:25 +00001861 return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
Harald Welte52b1f982008-12-23 20:25:15 +00001862}
1863
Harald Welte47d88ae2009-01-04 12:02:08 +00001864/* Siemens (or BS-11) specific commands */
1865
Harald Welte3ffd1372009-02-01 22:15:49 +00001866int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
1867{
1868 if (reconnect == 0)
1869 return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
1870 else
1871 return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
1872}
1873
Harald Welteb8427972009-02-05 19:27:17 +00001874int abis_nm_bs11_restart(struct gsm_bts *bts)
1875{
1876 return __simple_cmd(bts, NM_MT_BS11_RESTART);
1877}
1878
1879
Harald Welte268bb402009-02-01 19:11:56 +00001880struct bs11_date_time {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001881 uint16_t year;
1882 uint8_t month;
1883 uint8_t day;
1884 uint8_t hour;
1885 uint8_t min;
1886 uint8_t sec;
Harald Welte268bb402009-02-01 19:11:56 +00001887} __attribute__((packed));
1888
1889
1890void get_bs11_date_time(struct bs11_date_time *aet)
1891{
1892 time_t t;
1893 struct tm *tm;
1894
1895 t = time(NULL);
1896 tm = localtime(&t);
1897 aet->sec = tm->tm_sec;
1898 aet->min = tm->tm_min;
1899 aet->hour = tm->tm_hour;
1900 aet->day = tm->tm_mday;
1901 aet->month = tm->tm_mon;
1902 aet->year = htons(1900 + tm->tm_year);
1903}
1904
Harald Welte05188ee2009-01-18 11:39:08 +00001905int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
Harald Welte52b1f982008-12-23 20:25:15 +00001906{
Harald Welte4668fda2009-01-03 08:19:29 +00001907 return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
Harald Welte52b1f982008-12-23 20:25:15 +00001908}
1909
Harald Welte05188ee2009-01-18 11:39:08 +00001910int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
Harald Welte52b1f982008-12-23 20:25:15 +00001911{
1912 if (begin)
Harald Welte4668fda2009-01-03 08:19:29 +00001913 return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001914 else
Harald Welte4668fda2009-01-03 08:19:29 +00001915 return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
Harald Welte52b1f982008-12-23 20:25:15 +00001916}
Harald Welte47d88ae2009-01-04 12:02:08 +00001917
Harald Welte05188ee2009-01-18 11:39:08 +00001918int abis_nm_bs11_create_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001919 enum abis_bs11_objtype type, uint8_t idx,
1920 uint8_t attr_len, const uint8_t *attr)
Harald Welte47d88ae2009-01-04 12:02:08 +00001921{
1922 struct abis_om_hdr *oh;
1923 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001924 uint8_t *cur;
Harald Welte47d88ae2009-01-04 12:02:08 +00001925
1926 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001927 fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
Harald Welte268bb402009-02-01 19:11:56 +00001928 NM_OC_BS11, type, 0, idx);
Harald Welte1bc09062009-01-18 14:17:52 +00001929 cur = msgb_put(msg, attr_len);
1930 memcpy(cur, attr, attr_len);
Harald Welte47d88ae2009-01-04 12:02:08 +00001931
1932 return abis_nm_sendmsg(bts, msg);
1933}
1934
Harald Welte78fc0d42009-02-19 02:50:57 +00001935int abis_nm_bs11_delete_object(struct gsm_bts *bts,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001936 enum abis_bs11_objtype type, uint8_t idx)
Harald Welte78fc0d42009-02-19 02:50:57 +00001937{
1938 struct abis_om_hdr *oh;
1939 struct msgb *msg = nm_msgb_alloc();
1940
1941 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1942 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
1943 NM_OC_BS11, type, 0, idx);
1944
1945 return abis_nm_sendmsg(bts, msg);
1946}
1947
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001948int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001949{
1950 struct abis_om_hdr *oh;
1951 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001952 uint8_t zero = 0x00;
Harald Welte47d88ae2009-01-04 12:02:08 +00001953
1954 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00001955 fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
Harald Welte1bc09062009-01-18 14:17:52 +00001956 NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
1957 msgb_tlv_put(msg, 0x99, 1, &zero);
Harald Welte47d88ae2009-01-04 12:02:08 +00001958
1959 return abis_nm_sendmsg(bts, msg);
1960}
1961
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001962int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx)
Harald Welte47d88ae2009-01-04 12:02:08 +00001963{
1964 struct abis_om_hdr *oh;
1965 struct msgb *msg = nm_msgb_alloc();
1966
1967 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1968 fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001969 idx, 0xff, 0xff);
1970
1971 return abis_nm_sendmsg(bts, msg);
1972}
1973
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001974int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx)
Daniel Willmann65f68fa2009-08-10 11:49:36 +02001975{
1976 struct abis_om_hdr *oh;
1977 struct msgb *msg = nm_msgb_alloc();
1978
1979 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1980 fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT,
1981 idx, 0xff, 0xff);
Harald Welte47d88ae2009-01-04 12:02:08 +00001982
1983 return abis_nm_sendmsg(bts, msg);
1984}
Harald Welte05188ee2009-01-18 11:39:08 +00001985
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001986static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
Harald Welte78fc0d42009-02-19 02:50:57 +00001987int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
1988{
1989 struct abis_om_hdr *oh;
1990 struct msgb *msg = nm_msgb_alloc();
1991
1992 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
1993 fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
1994 0xff, 0xff, 0xff);
1995 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
1996
1997 return abis_nm_sendmsg(bts, msg);
1998}
1999
Harald Welteb6c92ae2009-02-21 20:15:32 +00002000/* like abis_nm_conn_terr_traf + set_tei */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002001int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port,
2002 uint8_t e1_timeslot, uint8_t e1_subslot,
2003 uint8_t tei)
Harald Welte05188ee2009-01-18 11:39:08 +00002004{
2005 struct abis_om_hdr *oh;
2006 struct abis_nm_channel *ch;
2007 struct msgb *msg = nm_msgb_alloc();
2008
2009 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002010 fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002011 NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
2012
2013 ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
2014 fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
Harald Welteb6c92ae2009-02-21 20:15:32 +00002015 msgb_tv_put(msg, NM_ATT_TEI, tei);
Harald Welte05188ee2009-01-18 11:39:08 +00002016
2017 return abis_nm_sendmsg(bts, msg);
2018}
2019
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002020int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level)
Harald Welte05188ee2009-01-18 11:39:08 +00002021{
2022 struct abis_om_hdr *oh;
2023 struct msgb *msg = nm_msgb_alloc();
Harald Welte05188ee2009-01-18 11:39:08 +00002024
2025 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002026 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
Harald Welte05188ee2009-01-18 11:39:08 +00002027 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2028 msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
2029
2030 return abis_nm_sendmsg(trx->bts, msg);
2031}
2032
Harald Welte78fc0d42009-02-19 02:50:57 +00002033int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
2034{
2035 struct abis_om_hdr *oh;
2036 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002037 uint8_t attr = NM_ATT_BS11_TXPWR;
Harald Welte78fc0d42009-02-19 02:50:57 +00002038
2039 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2040 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2041 NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
2042 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2043
2044 return abis_nm_sendmsg(trx->bts, msg);
2045}
2046
Harald Welteaaf02d92009-04-29 13:25:57 +00002047int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
2048{
2049 struct abis_om_hdr *oh;
2050 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002051 uint8_t attr[] = { NM_ATT_BS11_PLL_MODE };
Harald Welteaaf02d92009-04-29 13:25:57 +00002052
2053 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2054 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2055 NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
Harald Welteaeedeb42009-05-01 13:08:14 +00002056 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
Harald Welteaaf02d92009-04-29 13:25:57 +00002057
2058 return abis_nm_sendmsg(bts, msg);
2059}
2060
Harald Welteef061952009-05-17 12:43:42 +00002061int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
2062{
2063 struct abis_om_hdr *oh;
2064 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002065 uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
Harald Welteef061952009-05-17 12:43:42 +00002066 NM_ATT_BS11_CCLK_TYPE };
2067
2068 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2069 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2070 NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
2071 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
2072
2073 return abis_nm_sendmsg(bts, msg);
2074
2075}
Harald Welteaaf02d92009-04-29 13:25:57 +00002076
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002077//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
Harald Welte05188ee2009-01-18 11:39:08 +00002078
Harald Welte1bc09062009-01-18 14:17:52 +00002079int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
Harald Welte05188ee2009-01-18 11:39:08 +00002080{
Daniel Willmann493db4e2010-01-07 00:43:11 +01002081 return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
2082}
2083
Daniel Willmann4b054c82010-01-07 00:46:26 +01002084int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
2085{
2086 return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
2087}
2088
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002089int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002090{
Harald Welte05188ee2009-01-18 11:39:08 +00002091 struct abis_om_hdr *oh;
2092 struct msgb *msg = nm_msgb_alloc();
Harald Welte268bb402009-02-01 19:11:56 +00002093 struct bs11_date_time bdt;
2094
2095 get_bs11_date_time(&bdt);
Harald Welte05188ee2009-01-18 11:39:08 +00002096
2097 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte1bc09062009-01-18 14:17:52 +00002098 if (on) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002099 uint8_t len = 3*2 + sizeof(bdt)
Daniel Willmann493db4e2010-01-07 00:43:11 +01002100 + 1 + strlen(name);
Harald Welte043d04a2009-01-29 23:15:30 +00002101 fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002102 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte043d04a2009-01-29 23:15:30 +00002103 msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002104 sizeof(bdt), (uint8_t *) &bdt);
Harald Welte043d04a2009-01-29 23:15:30 +00002105 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
Daniel Willmann493db4e2010-01-07 00:43:11 +01002106 1, &level);
Harald Welte043d04a2009-01-29 23:15:30 +00002107 msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002108 strlen(name), (uint8_t *)name);
Harald Welte1bc09062009-01-18 14:17:52 +00002109 } else {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002110 fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
Harald Welte7b26bcb2009-05-28 11:39:21 +00002111 NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
Harald Welte1bc09062009-01-18 14:17:52 +00002112 }
Harald Welte05188ee2009-01-18 11:39:08 +00002113
2114 return abis_nm_sendmsg(bts, msg);
2115}
Harald Welte1bc09062009-01-18 14:17:52 +00002116
2117int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
2118{
2119 struct abis_om_hdr *oh;
2120 struct msgb *msg;
2121
2122 if (strlen(password) != 10)
2123 return -EINVAL;
2124
2125 msg = nm_msgb_alloc();
2126 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
Harald Welte6f676a32009-01-18 14:27:48 +00002127 fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
Harald Welte1bc09062009-01-18 14:17:52 +00002128 NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002129 msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password);
Harald Welte1bc09062009-01-18 14:17:52 +00002130
2131 return abis_nm_sendmsg(bts, msg);
2132}
2133
Harald Weltee69f5fb2009-04-28 16:31:38 +00002134/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
2135int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
2136{
2137 struct abis_om_hdr *oh;
2138 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002139 uint8_t tlv_value;
Harald Weltee69f5fb2009-04-28 16:31:38 +00002140
2141 msg = nm_msgb_alloc();
2142 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2143 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2144 BS11_OBJ_LI, 0x00, 0x00);
Harald Weltea432cd32009-04-29 13:01:50 +00002145
2146 if (locked)
2147 tlv_value = BS11_LI_PLL_LOCKED;
2148 else
2149 tlv_value = BS11_LI_PLL_STANDALONE;
2150
2151 msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
Harald Weltee69f5fb2009-04-28 16:31:38 +00002152
2153 return abis_nm_sendmsg(bts, msg);
2154}
2155
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002156/* Set the calibration value of the PLL (work value/set value)
2157 * It depends on the login which one is changed */
2158int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
2159{
2160 struct abis_om_hdr *oh;
2161 struct msgb *msg;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002162 uint8_t tlv_value[2];
Daniel Willmann7b1dd742010-01-07 00:54:01 +01002163
2164 msg = nm_msgb_alloc();
2165 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2166 fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
2167 BS11_OBJ_TRX1, 0x00, 0x00);
2168
2169 tlv_value[0] = value>>8;
2170 tlv_value[1] = value&0xff;
2171
2172 msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value);
2173
2174 return abis_nm_sendmsg(bts, msg);
2175}
2176
Harald Welte1bc09062009-01-18 14:17:52 +00002177int abis_nm_bs11_get_state(struct gsm_bts *bts)
2178{
2179 return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
2180}
Harald Welte5e4d1b32009-02-01 13:36:56 +00002181
2182/* BS11 SWL */
2183
Harald Welte (local)d19e58b2009-08-15 02:30:58 +02002184void *tall_fle_ctx;
Harald Welte2cf161b2009-06-20 22:36:41 +02002185
Harald Welte5e4d1b32009-02-01 13:36:56 +00002186struct abis_nm_bs11_sw {
2187 struct gsm_bts *bts;
2188 char swl_fname[PATH_MAX];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002189 uint8_t win_size;
Harald Welte3ffd1372009-02-01 22:15:49 +00002190 int forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002191 struct llist_head file_list;
2192 gsm_cbfn *user_cb; /* specified by the user */
2193};
2194static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
2195
2196struct file_list_entry {
2197 struct llist_head list;
2198 char fname[PATH_MAX];
2199};
2200
2201struct file_list_entry *fl_dequeue(struct llist_head *queue)
2202{
2203 struct llist_head *lh;
2204
2205 if (llist_empty(queue))
2206 return NULL;
2207
2208 lh = queue->next;
2209 llist_del(lh);
2210
2211 return llist_entry(lh, struct file_list_entry, list);
2212}
2213
2214static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
2215{
2216 char linebuf[255];
2217 struct llist_head *lh, *lh2;
2218 FILE *swl;
2219 int rc = 0;
2220
2221 swl = fopen(bs11_sw->swl_fname, "r");
2222 if (!swl)
2223 return -ENODEV;
2224
2225 /* zero the stale file list, if any */
2226 llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
2227 llist_del(lh);
Harald Welte2cf161b2009-06-20 22:36:41 +02002228 talloc_free(lh);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002229 }
2230
2231 while (fgets(linebuf, sizeof(linebuf), swl)) {
2232 char file_id[12+1];
2233 char file_version[80+1];
2234 struct file_list_entry *fle;
2235 static char dir[PATH_MAX];
2236
2237 if (strlen(linebuf) < 4)
2238 continue;
Harald Welte3ffd1372009-02-01 22:15:49 +00002239
Harald Welte5e4d1b32009-02-01 13:36:56 +00002240 rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
2241 if (rc < 0) {
2242 perror("ERR parsing SWL file");
2243 rc = -EINVAL;
2244 goto out;
2245 }
2246 if (rc < 2)
2247 continue;
2248
Harald Welte470ec292009-06-26 20:25:23 +02002249 fle = talloc_zero(tall_fle_ctx, struct file_list_entry);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002250 if (!fle) {
2251 rc = -ENOMEM;
2252 goto out;
2253 }
Harald Welte5e4d1b32009-02-01 13:36:56 +00002254
2255 /* construct new filename */
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002256 osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002257 strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
2258 strcat(fle->fname, "/");
2259 strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002260
2261 llist_add_tail(&fle->list, &bs11_sw->file_list);
2262 }
2263
2264out:
2265 fclose(swl);
2266 return rc;
2267}
2268
2269/* bs11 swload specific callback, passed to abis_nm core swload */
2270static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
2271 struct msgb *msg, void *data, void *param)
2272{
2273 struct abis_nm_bs11_sw *bs11_sw = data;
2274 struct file_list_entry *fle;
2275 int rc = 0;
2276
Harald Welte5e4d1b32009-02-01 13:36:56 +00002277 switch (event) {
2278 case NM_MT_LOAD_END_ACK:
2279 fle = fl_dequeue(&bs11_sw->file_list);
2280 if (fle) {
2281 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002282 rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002283 bs11_sw->win_size,
Harald Welte3ffd1372009-02-01 22:15:49 +00002284 bs11_sw->forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002285 &bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002286 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002287 } else {
2288 /* activate the SWL */
2289 rc = abis_nm_software_activate(bs11_sw->bts,
2290 bs11_sw->swl_fname,
2291 bs11_swload_cbfn,
2292 bs11_sw);
2293 }
2294 break;
Harald Welte3ffd1372009-02-01 22:15:49 +00002295 case NM_MT_LOAD_SEG_ACK:
Harald Welte5e4d1b32009-02-01 13:36:56 +00002296 case NM_MT_LOAD_END_NACK:
2297 case NM_MT_LOAD_INIT_ACK:
2298 case NM_MT_LOAD_INIT_NACK:
2299 case NM_MT_ACTIVATE_SW_NACK:
2300 case NM_MT_ACTIVATE_SW_ACK:
2301 default:
2302 /* fallthrough to the user callback */
Harald Welte97ed1e72009-02-06 13:38:02 +00002303 if (bs11_sw->user_cb)
2304 rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002305 break;
2306 }
2307
2308 return rc;
2309}
2310
2311/* Siemens provides a SWL file that is a mere listing of all the other
2312 * files that are part of a software release. We need to upload first
2313 * the list file, and then each file that is listed in the list file */
2314int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002315 uint8_t win_size, int forced, gsm_cbfn *cbfn)
Harald Welte5e4d1b32009-02-01 13:36:56 +00002316{
2317 struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
2318 struct file_list_entry *fle;
2319 int rc = 0;
2320
2321 INIT_LLIST_HEAD(&bs11_sw->file_list);
2322 bs11_sw->bts = bts;
2323 bs11_sw->win_size = win_size;
2324 bs11_sw->user_cb = cbfn;
Harald Welte3ffd1372009-02-01 22:15:49 +00002325 bs11_sw->forced = forced;
Harald Welte5e4d1b32009-02-01 13:36:56 +00002326
Neels Hofmeyr93bafb62017-01-13 03:12:08 +01002327 osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
Harald Welte5e4d1b32009-02-01 13:36:56 +00002328 rc = bs11_read_swl_file(bs11_sw);
2329 if (rc < 0)
2330 return rc;
2331
2332 /* dequeue next item in file list */
2333 fle = fl_dequeue(&bs11_sw->file_list);
2334 if (!fle)
2335 return -EINVAL;
2336
2337 /* start download the next file of our file list */
Holger Hans Peter Freyther64278ed2010-05-12 23:51:46 +08002338 rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
Harald Welte5e4d1b32009-02-01 13:36:56 +00002339 bs11_swload_cbfn, bs11_sw);
Harald Welteac606dc2009-08-06 15:44:18 +02002340 talloc_free(fle);
Harald Welte5e4d1b32009-02-01 13:36:56 +00002341 return rc;
2342}
2343
Harald Welte5083b0b2009-02-02 19:20:52 +00002344#if 0
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002345static uint8_t req_attr_btse[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002346 NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
2347 NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
2348 NM_ATT_BS11_LMT_USER_NAME,
2349
2350 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
2351
2352 NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
2353
2354 NM_ATT_BS11_SW_LOAD_STORED };
2355
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002356static uint8_t req_attr_btsm[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002357 NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
2358 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
2359 NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
2360 NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
Harald Welte5083b0b2009-02-02 19:20:52 +00002361#endif
Harald Welte5e4d1b32009-02-01 13:36:56 +00002362
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002363static uint8_t req_attr[] = {
Harald Welte5e4d1b32009-02-01 13:36:56 +00002364 NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
2365 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
Harald Weltea7cfa032009-04-29 22:33:02 +00002366 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
Harald Welte5e4d1b32009-02-01 13:36:56 +00002367
2368int abis_nm_bs11_get_serno(struct gsm_bts *bts)
2369{
2370 struct abis_om_hdr *oh;
2371 struct msgb *msg = nm_msgb_alloc();
2372
2373 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2374 /* SiemensHW CCTRL object */
2375 fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
2376 0x03, 0x00, 0x00);
2377 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
2378
2379 return abis_nm_sendmsg(bts, msg);
2380}
Harald Welte268bb402009-02-01 19:11:56 +00002381
2382int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
2383{
2384 struct abis_om_hdr *oh;
2385 struct msgb *msg = nm_msgb_alloc();
2386 struct bs11_date_time aet;
2387
2388 get_bs11_date_time(&aet);
2389 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2390 /* SiemensHW CCTRL object */
2391 fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
2392 0xff, 0xff, 0xff);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002393 msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet);
Harald Welte268bb402009-02-01 19:11:56 +00002394
2395 return abis_nm_sendmsg(bts, msg);
2396}
Harald Welte5c1e4582009-02-15 11:57:29 +00002397
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002398int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
Harald Weltef751a102010-12-14 12:52:16 +01002399{
2400 struct abis_om_hdr *oh;
2401 struct msgb *msg = nm_msgb_alloc();
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002402 uint8_t attr = NM_ATT_BS11_LINE_CFG;
Harald Weltef751a102010-12-14 12:52:16 +01002403
2404 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2405 fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
2406 NM_OC_BS11_BPORT, bport, 0xff, 0x02);
2407 msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
2408
2409 return abis_nm_sendmsg(bts, msg);
2410}
2411
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002412int 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 +02002413{
2414 struct abis_om_hdr *oh;
2415 struct msgb *msg = nm_msgb_alloc();
2416 struct bs11_date_time aet;
2417
2418 get_bs11_date_time(&aet);
2419 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2420 fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
2421 bport, 0xff, 0x02);
2422 msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
2423
2424 return abis_nm_sendmsg(bts, msg);
2425}
2426
Harald Welte5c1e4582009-02-15 11:57:29 +00002427/* ip.access nanoBTS specific commands */
Harald Welte5c1e4582009-02-15 11:57:29 +00002428static const char ipaccess_magic[] = "com.ipaccess";
2429
Harald Welte677c21f2009-02-17 13:22:23 +00002430
2431static int abis_nm_rx_ipacc(struct msgb *msg)
2432{
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002433 struct in_addr addr;
Harald Welte677c21f2009-02-17 13:22:23 +00002434 struct abis_om_hdr *oh = msgb_l2(msg);
2435 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002436 uint8_t idstrlen = oh->data[0];
Harald Welte677c21f2009-02-17 13:22:23 +00002437 struct tlv_parsed tp;
Holger Hans Peter Freyther2e837822009-12-30 08:38:43 +01002438 struct ipacc_ack_signal_data signal;
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002439 struct e1inp_sign_link *sign_link = msg->dst;
Harald Welte677c21f2009-02-17 13:22:23 +00002440
2441 if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
Harald Welte5b8ed432009-12-24 12:20:20 +01002442 LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002443 return -EINVAL;
2444 }
2445
Harald Welte193fefc2009-04-30 15:16:27 +00002446 foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002447 abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
Harald Welte677c21f2009-02-17 13:22:23 +00002448
Harald Welte15c61722011-05-22 22:45:37 +02002449 abis_nm_debugp_foh(DNM, foh);
Harald Weltea62202b2009-10-19 21:46:54 +02002450
Harald Welte746d6092009-10-19 22:11:11 +02002451 DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
Harald Welte193fefc2009-04-30 15:16:27 +00002452
Harald Welte677c21f2009-02-17 13:22:23 +00002453 switch (foh->msg_type) {
2454 case NM_MT_IPACC_RSL_CONNECT_ACK:
Harald Welte193fefc2009-04-30 15:16:27 +00002455 DEBUGPC(DNM, "RSL CONNECT ACK ");
Holger Hans Peter Freyther1afbd762010-06-21 10:22:26 +08002456 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) {
2457 memcpy(&addr,
2458 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
2459
2460 DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
2461 }
Harald Welte0efe9b72009-07-12 09:33:54 +02002462 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
Harald Welte9de2bf82009-04-30 15:59:55 +00002463 DEBUGPC(DNM, "PORT=%u ",
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002464 ntohs(*((uint16_t *)
Harald Welte0efe9b72009-07-12 09:33:54 +02002465 TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
Harald Welte35d447b2009-10-19 22:49:33 +02002466 if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
2467 DEBUGPC(DNM, "STREAM=0x%02x ",
2468 *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
Harald Welte9de2bf82009-04-30 15:59:55 +00002469 DEBUGPC(DNM, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002470 break;
2471 case NM_MT_IPACC_RSL_CONNECT_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002472 LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
Harald Welte677c21f2009-02-17 13:22:23 +00002473 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002474 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002475 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte677c21f2009-02-17 13:22:23 +00002476 else
Alexander Chemeris0c48fc72013-10-06 23:35:39 +02002477 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte677c21f2009-02-17 13:22:23 +00002478 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002479 case NM_MT_IPACC_SET_NVATTR_ACK:
2480 DEBUGPC(DNM, "SET NVATTR ACK\n");
2481 /* FIXME: decode and show the actual attributes */
2482 break;
2483 case NM_MT_IPACC_SET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002484 LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
Harald Welte6c96ba52009-05-01 13:03:40 +00002485 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002486 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002487 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte6c96ba52009-05-01 13:03:40 +00002488 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002489 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte193fefc2009-04-30 15:16:27 +00002490 break;
Harald Welte684b1a82009-07-03 11:26:45 +02002491 case NM_MT_IPACC_GET_NVATTR_ACK:
2492 DEBUGPC(DNM, "GET NVATTR ACK\n");
2493 /* FIXME: decode and show the actual attributes */
2494 break;
2495 case NM_MT_IPACC_GET_NVATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002496 LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
Harald Welte684b1a82009-07-03 11:26:45 +02002497 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002498 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002499 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte684b1a82009-07-03 11:26:45 +02002500 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002501 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte684b1a82009-07-03 11:26:45 +02002502 break;
Harald Welte15c44172009-10-08 20:15:24 +02002503 case NM_MT_IPACC_SET_ATTR_ACK:
2504 DEBUGPC(DNM, "SET ATTR ACK\n");
2505 break;
2506 case NM_MT_IPACC_SET_ATTR_NACK:
Harald Welte5b8ed432009-12-24 12:20:20 +01002507 LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
Harald Welte15c44172009-10-08 20:15:24 +02002508 if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002509 LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
Harald Welte15c61722011-05-22 22:45:37 +02002510 abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
Harald Welte15c44172009-10-08 20:15:24 +02002511 else
Harald Welte5b8ed432009-12-24 12:20:20 +01002512 LOGPC(DNM, LOGL_ERROR, "\n");
Harald Welte15c44172009-10-08 20:15:24 +02002513 break;
Harald Welte193fefc2009-04-30 15:16:27 +00002514 default:
2515 DEBUGPC(DNM, "unknown\n");
2516 break;
Harald Welte677c21f2009-02-17 13:22:23 +00002517 }
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002518
2519 /* signal handling */
2520 switch (foh->msg_type) {
2521 case NM_MT_IPACC_RSL_CONNECT_NACK:
2522 case NM_MT_IPACC_SET_NVATTR_NACK:
2523 case NM_MT_IPACC_GET_NVATTR_NACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002524 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 +01002525 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002526 osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002527 break;
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002528 case NM_MT_IPACC_SET_NVATTR_ACK:
Pablo Neira Ayuso7abecfc2011-08-17 22:43:54 +02002529 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 +01002530 signal.msg_type = foh->msg_type;
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +02002531 osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal);
Holger Hans Peter Freyther086ffa52009-12-29 11:26:38 +01002532 break;
Holger Hans Peter Freythera7cd9fc2009-07-07 12:40:07 +02002533 default:
2534 break;
2535 }
2536
Harald Welte677c21f2009-02-17 13:22:23 +00002537 return 0;
2538}
2539
Harald Welte193fefc2009-04-30 15:16:27 +00002540/* send an ip-access manufacturer specific message */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002541int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type,
2542 uint8_t obj_class, uint8_t bts_nr,
2543 uint8_t trx_nr, uint8_t ts_nr,
2544 uint8_t *attr, int attr_len)
Harald Welte5c1e4582009-02-15 11:57:29 +00002545{
2546 struct msgb *msg = nm_msgb_alloc();
2547 struct abis_om_hdr *oh;
2548 struct abis_om_fom_hdr *foh;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002549 uint8_t *data;
Harald Welte5c1e4582009-02-15 11:57:29 +00002550
2551 /* construct the 12.21 OM header, observe the erroneous length */
2552 oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
2553 fill_om_hdr(oh, sizeof(*foh) + attr_len);
2554 oh->mdisc = ABIS_OM_MDISC_MANUF;
2555
2556 /* add the ip.access magic */
2557 data = msgb_put(msg, sizeof(ipaccess_magic)+1);
2558 *data++ = sizeof(ipaccess_magic);
2559 memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
2560
2561 /* fill the 12.21 FOM header */
2562 foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
2563 foh->msg_type = msg_type;
2564 foh->obj_class = obj_class;
2565 foh->obj_inst.bts_nr = bts_nr;
2566 foh->obj_inst.trx_nr = trx_nr;
2567 foh->obj_inst.ts_nr = ts_nr;
2568
2569 if (attr && attr_len) {
2570 data = msgb_put(msg, attr_len);
2571 memcpy(data, attr, attr_len);
2572 }
2573
2574 return abis_nm_sendmsg(bts, msg);
2575}
Harald Welte677c21f2009-02-17 13:22:23 +00002576
Harald Welte193fefc2009-04-30 15:16:27 +00002577/* set some attributes in NVRAM */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002578int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002579 int attr_len)
2580{
Harald Welte2ef156d2010-01-07 20:39:42 +01002581 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
2582 NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
Harald Welte193fefc2009-04-30 15:16:27 +00002583 attr_len);
2584}
2585
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02002586int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002587 uint32_t ip, uint16_t port, uint8_t stream)
Harald Welte746d6092009-10-19 22:11:11 +02002588{
2589 struct in_addr ia;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002590 uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
Harald Welte746d6092009-10-19 22:11:11 +02002591 NM_ATT_IPACC_DST_IP_PORT, 0, 0,
2592 NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
2593
2594 int attr_len = sizeof(attr);
2595
2596 ia.s_addr = htonl(ip);
2597 attr[1] = stream;
2598 attr[3] = port >> 8;
2599 attr[4] = port & 0xff;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002600 *(uint32_t *)(attr+6) = ia.s_addr;
Harald Welte746d6092009-10-19 22:11:11 +02002601
2602 /* if ip == 0, we use the default IP */
2603 if (ip == 0)
2604 attr_len -= 5;
2605
2606 DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
Harald Welte31a74902009-10-19 22:50:30 +02002607 inet_ntoa(ia), port, stream);
Harald Welte746d6092009-10-19 22:11:11 +02002608
2609 return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
2610 NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
2611 trx->nr, 0xff, attr, attr_len);
2612}
2613
Harald Welte193fefc2009-04-30 15:16:27 +00002614/* restart / reboot an ip.access nanoBTS */
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002615int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
Harald Welte193fefc2009-04-30 15:16:27 +00002616{
Holger Hans Peter Freyther52fd4e42010-05-12 23:34:51 +08002617 struct abis_om_hdr *oh;
2618 struct msgb *msg = nm_msgb_alloc();
2619
2620 oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
2621 fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
2622 trx->bts->nr, trx->nr, 0xff);
2623
Holger Hans Peter Freyther3a38ee62016-03-16 14:27:29 +01002624 return abis_nm_sendmsg_direct(trx->bts, msg);
Harald Welte193fefc2009-04-30 15:16:27 +00002625}
Harald Weltedaef5212009-10-24 10:20:41 +02002626
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002627int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
2628 uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
2629 uint8_t *attr, uint8_t attr_len)
Harald Weltedaef5212009-10-24 10:20:41 +02002630{
2631 return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
2632 obj_class, bts_nr, trx_nr, ts_nr,
2633 attr, attr_len);
2634}
Harald Welte0f255852009-11-12 14:48:42 +01002635
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002636void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts)
Harald Welte97a282b2010-03-14 15:37:43 +08002637{
2638 /* we simply reuse the GSM48 function and overwrite the RAC
2639 * with the Cell ID */
2640 gsm48_ra_id_by_bts(buf, bts);
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002641 *((uint16_t *)(buf + 5)) = htons(bts->cell_identity);
Harald Welte97a282b2010-03-14 15:37:43 +08002642}
2643
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002644void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
2645{
2646 int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
2647
Harald Welted64c0bc2011-05-30 12:07:53 +02002648 trx->mo.nm_state.administrative = new_state;
Holger Hans Peter Freyther2d501ea2009-11-11 11:54:24 +01002649 if (!trx->bts || !trx->bts->oml_link)
2650 return;
2651
2652 abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
2653 trx->bts->bts_nr, trx->nr, 0xff,
2654 new_state);
2655}
2656
Harald Welte92b1fe42010-03-25 11:45:30 +08002657static const struct value_string ipacc_testres_names[] = {
2658 { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
2659 { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
2660 { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
2661 { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
2662 { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
2663 { 0, NULL }
Harald Welte0f255852009-11-12 14:48:42 +01002664};
2665
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002666const char *ipacc_testres_name(uint8_t res)
Harald Welte0f255852009-11-12 14:48:42 +01002667{
Harald Welte92b1fe42010-03-25 11:45:30 +08002668 return get_value_string(ipacc_testres_names, res);
Harald Welte0f255852009-11-12 14:48:42 +01002669}
2670
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002671void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf)
Harald Welteb40a38f2009-11-13 11:56:05 +01002672{
2673 cid->mcc = (buf[0] & 0xf) * 100;
2674 cid->mcc += (buf[0] >> 4) * 10;
2675 cid->mcc += (buf[1] & 0xf) * 1;
2676
2677 if (buf[1] >> 4 == 0xf) {
2678 cid->mnc = (buf[2] & 0xf) * 10;
2679 cid->mnc += (buf[2] >> 4) * 1;
2680 } else {
2681 cid->mnc = (buf[2] & 0xf) * 100;
2682 cid->mnc += (buf[2] >> 4) * 10;
2683 cid->mnc += (buf[1] >> 4) * 1;
2684 }
2685
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002686 cid->lac = ntohs(*((uint16_t *)&buf[3]));
2687 cid->ci = ntohs(*((uint16_t *)&buf[5]));
Harald Welteb40a38f2009-11-13 11:56:05 +01002688}
2689
Harald Welte0f255852009-11-12 14:48:42 +01002690/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002691int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf)
Harald Welte0f255852009-11-12 14:48:42 +01002692{
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002693 uint8_t *cur = buf;
Holger Hans Peter Freythera5050b12012-09-11 11:55:03 +02002694 uint16_t len __attribute__((unused));
Harald Welte0f255852009-11-12 14:48:42 +01002695
Harald Welteaf109b92010-07-22 18:14:36 +02002696 memset(binf, 0, sizeof(*binf));
Harald Welte0f255852009-11-12 14:48:42 +01002697
2698 if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
2699 return -EINVAL;
2700 cur++;
2701
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002702 len = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002703 cur += 2;
2704
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002705 binf->info_type = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002706 cur += 2;
2707
2708 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
2709 binf->freq_qual = *cur >> 2;
2710
Harald Welteaf109b92010-07-22 18:14:36 +02002711 binf->arfcn = (*cur++ & 3) << 8;
Harald Welte0f255852009-11-12 14:48:42 +01002712 binf->arfcn |= *cur++;
2713
2714 if (binf->info_type & IPAC_BINF_RXLEV)
2715 binf->rx_lev = *cur & 0x3f;
2716 cur++;
2717
2718 if (binf->info_type & IPAC_BINF_RXQUAL)
2719 binf->rx_qual = *cur & 0x7;
2720 cur++;
2721
2722 if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002723 binf->freq_err = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002724 cur += 2;
2725
2726 if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002727 binf->frame_offset = ntohs(*(uint16_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002728 cur += 2;
2729
2730 if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02002731 binf->frame_nr_offset = ntohl(*(uint32_t *)cur);
Harald Welte0f255852009-11-12 14:48:42 +01002732 cur += 4;
2733
Harald Weltea780a3d2010-07-30 22:34:42 +02002734#if 0
2735 /* Somehow this is not set correctly */
Harald Welte0f255852009-11-12 14:48:42 +01002736 if (binf->info_type & IPAC_BINF_BSIC)
Harald Weltea780a3d2010-07-30 22:34:42 +02002737#endif
Harald Welteaff237d2009-11-13 14:41:52 +01002738 binf->bsic = *cur & 0x3f;
Harald Welte0f255852009-11-12 14:48:42 +01002739 cur++;
2740
Harald Welteb40a38f2009-11-13 11:56:05 +01002741 ipac_parse_cgi(&binf->cgi, cur);
2742 cur += 7;
Harald Welte0f255852009-11-12 14:48:42 +01002743
2744 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
2745 memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
2746 cur += sizeof(binf->ba_list_si2);
2747 }
2748
2749 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
2750 memcpy(binf->ba_list_si2bis, cur,
2751 sizeof(binf->ba_list_si2bis));
2752 cur += sizeof(binf->ba_list_si2bis);
2753 }
2754
2755 if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
2756 memcpy(binf->ba_list_si2ter, cur,
2757 sizeof(binf->ba_list_si2ter));
2758 cur += sizeof(binf->ba_list_si2ter);
2759 }
2760
2761 return 0;
2762}
Holger Hans Peter Freyther6f615552010-11-15 20:50:42 +01002763
2764void abis_nm_clear_queue(struct gsm_bts *bts)
2765{
2766 struct msgb *msg;
2767
2768 while (!llist_empty(&bts->abis_queue)) {
2769 msg = msgb_dequeue(&bts->abis_queue);
2770 msgb_free(msg);
2771 }
2772
2773 bts->abis_nm_pend = 0;
2774}